Skip to content

Instantly share code, notes, and snippets.

@jeromegn

jeromegn/xhr.go Secret

Created November 24, 2017 21:25
Show Gist options
  • Save jeromegn/cb76ba14437ab688074c6b2d607d358d to your computer and use it in GitHub Desktop.
Save jeromegn/cb76ba14437ab688074c6b2d607d358d to your computer and use it in GitHub Desktop.
package xhr
import (
"bytes"
"io"
"io/ioutil"
"net/http"
"net/textproto"
"github.com/dop251/goja"
"github.com/dop251/goja_nodejs/eventloop"
)
var program *goja.Program
// Enable ...
func Enable(r *goja.Runtime, loop *eventloop.EventLoop) {
r.Set("__xhr__", xhr(loop))
_, err := r.RunProgram(program)
if err != nil {
panic(err)
}
}
func xhr(loop *eventloop.EventLoop) func(goja.FunctionCall) goja.Value {
return func(call goja.FunctionCall) goja.Value {
if fn, ok := goja.AssertFunction(call.Argument(1)); ok {
o := call.Argument(0).Export().(map[string]interface{})
go func() {
var body io.Reader
method := http.MethodGet
header := make(http.Header)
if headers, ex := o["headers"]; ex {
if hmap, okh := headers.(map[string]interface{}); okh {
for key, value := range hmap {
v := value.([]interface{})
for _, item := range v {
var i []string
i = append(i, item.(string))
header[textproto.CanonicalMIMEHeaderKey(key)] = i
}
}
}
}
if b, ex := o["body"]; ex {
if bo, ok := b.(string); ok {
body = bytes.NewBufferString(bo)
}
}
if m, ex := o["method"]; ex {
if me, ok := m.(string); ok {
method = me
}
}
var url string
if u, ex := o["url"]; ex {
if ur, ok := u.(string); ok {
url = ur
} else {
panic("bad url")
}
}
var toRet map[string]interface{}
req, err := http.NewRequest(method, url, body)
if err != nil {
toRet = map[string]interface{}{
"status": 0,
}
} else {
req.Header = header
res, err := http.DefaultClient.Do(req)
if err != nil {
toRet = map[string]interface{}{
"status": 0,
}
} else {
toRet = map[string]interface{}{
"headers": res.Header,
"status": res.StatusCode,
"statusText": res.Status,
"method": method,
"url": url,
}
}
}
loop.RunOnLoop(func(r *goja.Runtime) {
fn(nil, r.ToValue(toRet))
})
}()
}
return nil
}
}
func init() {
b, err := ioutil.ReadFile("xhr.js")
if err != nil {
panic(err)
}
program = goja.MustCompile("xhr.js", string(b), false)
}
var __goxhr__ = global.__xhr__;
delete global.__xhr__;
function XMLHttpRequest() {
// console.log("create a xhr")
}
XMLHttpRequest.UNSENT = 0
XMLHttpRequest.OPENED = 1
XMLHttpRequest.HEADERS_RECEIVED = 2
XMLHttpRequest.LOADING = 3
XMLHttpRequest.DONE = 4
XMLHttpRequest.prototype = {
open: function (method, url, async) {
// console.log("opened a xhr", method, url, async);
this.__method = method
this.__url = url
this.__async = !!async
this._updateReadyState(XMLHttpRequest.OPENED)
},
setRequestHeader: function (name, value) {
this.__headers || (this.__headers = {})
this.__headers[name] = value
},
send: function (body) {
// console.log("xhr send");
var that = this
__goxhr__({
url: this.__url,
method: this.__method,
headers: this.__headers,
body: body
}, function (res) {
// console.log("xhr got response")//, JSON.stringify(res));
that.status = res.status
that.statusText = res.statusText
that.responseHeaders = res.headers
that.responseText = res.body
that._updateReadyState(XMLHttpRequest.DONE)
})
this._updateReadyState(XMLHttpRequest.LOADING)
},
getResponseHeader: function (name) {
// console.log("get response header");
this.responseHeaders || (this.responseHeaders = {})
return this.responseHeaders[name]
},
getAllResponseHeaders: function () {
// console.log("get all response headers")
this.responseHeaders || (this.responseHeaders = {});
var keys = Object.keys(this.responseHeaders)
var str = ""
for (var i = keys.length; i <= 0; i--) {
str += keys[i] + ": " + this.responseHeaders[keys[i]] + "\n"
}
return str
},
_updateReadyState: function (state) {
// console.log("set ready state:", state)
this.readyState = state
if (typeof this.onreadystatechange == 'function') {
this.onreadystatechange()
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment