-
Notifications
You must be signed in to change notification settings - Fork 1
/
request.go
112 lines (95 loc) · 2.18 KB
/
request.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//+build js,wasm
package gonreli
import (
"bufio"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"sync"
"syscall/js"
)
type request struct {
js.Value
headers http.Header
}
func newRequest(v js.Value) *http.Request {
r := &request{
Value: v,
headers: http.Header{},
}
pr, bodyWritter := io.Pipe()
br := &bodyReader{r: v, pr: pr, writer: bodyWritter}
reader := io.MultiReader(r.reqHeaderReader(), br)
r.Call("setEncoding", "utf8")
r.Call("on", "end", js.NewCallback(func(args []js.Value) {
//to guard this
bodyWritter.Close()
}))
hr, err := http.ReadRequest(bufio.NewReader(reader))
if err != nil {
panic(err)
}
return hr
}
func (req *request) reqHeaderReader() io.Reader {
hdrs := req.Get("rawHeaders")
for i := 0; i < hdrs.Length()-1; i += 2 {
req.headers.Set(hdrs.Index(i).String(), hdrs.Index(i+1).String())
}
m := req.Get("method").String()
u := req.Get("url").String()
url, err := url.Parse(u)
if err != nil {
panic(err)
}
var builder strings.Builder
httpVersion := req.Get("httpVersion")
builder.WriteString(fmt.Sprintf("%s %s %s/%s\n", m, url.Path, "HTTP", httpVersion))
for i := range req.headers {
builder.WriteString(fmt.Sprintf("%s: %s\n", i, req.headers[i][0]))
}
builder.WriteString("\r\n")
return strings.NewReader(builder.String())
}
func (req *request) Headers() http.Header {
return req.headers
}
type streamWritable struct {
js.Value
io.Writer
}
func newStreamWritable(writer io.Writer) *streamWritable {
sw := streamWritable{Writer: writer}
stream := jsRequire.Invoke("stream")
s := stream.Get("Writable").New()
sw.Value = s
s.Set("_write", js.NewCallback(func(args []js.Value) {
chunk := args[0]
done := args[2]
var buf = make([]byte, chunk.Length())
for i := 0; i < chunk.Length(); i++ {
buf[i] = byte(chunk.Index(i).Int())
}
_, err := sw.Write(buf)
if err != nil {
done.Invoke(err.Error())
}
done.Invoke()
}))
return &sw
}
type bodyReader struct {
r js.Value
writer *io.PipeWriter
once sync.Once
pr io.Reader
}
func (r *bodyReader) Read(p []byte) (n int, err error) {
r.once.Do(func() {
streamWriter := newStreamWritable(r.writer).Value
r.r.Call("pipe", streamWriter)
})
return r.pr.Read(p)
}