Source file
src/net/http/roundtrip_js.go
1
2
3
4
5
6
7
8 package http
9
10 import (
11 "errors"
12 "fmt"
13 "io"
14 "strconv"
15 "syscall/js"
16 )
17
18 var uint8Array = js.Global().Get("Uint8Array")
19
20
21
22
23
24
25
26 const jsFetchMode = "js.fetch:mode"
27
28
29
30
31
32
33
34 const jsFetchCreds = "js.fetch:credentials"
35
36
37
38
39
40
41
42 const jsFetchRedirect = "js.fetch:redirect"
43
44 var useFakeNetwork = js.Global().Get("fetch").IsUndefined()
45
46
47 func (t *Transport) RoundTrip(req *Request) (*Response, error) {
48 if useFakeNetwork {
49 return t.roundTrip(req)
50 }
51
52 ac := js.Global().Get("AbortController")
53 if !ac.IsUndefined() {
54
55
56
57 ac = ac.New()
58 }
59
60 opt := js.Global().Get("Object").New()
61
62
63 opt.Set("method", req.Method)
64 opt.Set("credentials", "same-origin")
65 if h := req.Header.Get(jsFetchCreds); h != "" {
66 opt.Set("credentials", h)
67 req.Header.Del(jsFetchCreds)
68 }
69 if h := req.Header.Get(jsFetchMode); h != "" {
70 opt.Set("mode", h)
71 req.Header.Del(jsFetchMode)
72 }
73 if h := req.Header.Get(jsFetchRedirect); h != "" {
74 opt.Set("redirect", h)
75 req.Header.Del(jsFetchRedirect)
76 }
77 if !ac.IsUndefined() {
78 opt.Set("signal", ac.Get("signal"))
79 }
80 headers := js.Global().Get("Headers").New()
81 for key, values := range req.Header {
82 for _, value := range values {
83 headers.Call("append", key, value)
84 }
85 }
86 opt.Set("headers", headers)
87
88 if req.Body != nil {
89
90
91
92
93
94
95 body, err := io.ReadAll(req.Body)
96 if err != nil {
97 req.Body.Close()
98 return nil, err
99 }
100 req.Body.Close()
101 if len(body) != 0 {
102 buf := uint8Array.New(len(body))
103 js.CopyBytesToJS(buf, body)
104 opt.Set("body", buf)
105 }
106 }
107
108 fetchPromise := js.Global().Call("fetch", req.URL.String(), opt)
109 var (
110 respCh = make(chan *Response, 1)
111 errCh = make(chan error, 1)
112 success, failure js.Func
113 )
114 success = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
115 success.Release()
116 failure.Release()
117
118 result := args[0]
119 header := Header{}
120
121 headersIt := result.Get("headers").Call("entries")
122 for {
123 n := headersIt.Call("next")
124 if n.Get("done").Bool() {
125 break
126 }
127 pair := n.Get("value")
128 key, value := pair.Index(0).String(), pair.Index(1).String()
129 ck := CanonicalHeaderKey(key)
130 header[ck] = append(header[ck], value)
131 }
132
133 contentLength := int64(0)
134 if cl, err := strconv.ParseInt(header.Get("Content-Length"), 10, 64); err == nil {
135 contentLength = cl
136 }
137
138 b := result.Get("body")
139 var body io.ReadCloser
140
141
142 if !b.IsUndefined() && !b.IsNull() {
143 body = &streamReader{stream: b.Call("getReader")}
144 } else {
145
146
147 body = &arrayReader{arrayPromise: result.Call("arrayBuffer")}
148 }
149
150 code := result.Get("status").Int()
151 respCh <- &Response{
152 Status: fmt.Sprintf("%d %s", code, StatusText(code)),
153 StatusCode: code,
154 Header: header,
155 ContentLength: contentLength,
156 Body: body,
157 Request: req,
158 }
159
160 return nil
161 })
162 failure = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
163 success.Release()
164 failure.Release()
165 errCh <- fmt.Errorf("net/http: fetch() failed: %s", args[0].Get("message").String())
166 return nil
167 })
168
169 fetchPromise.Call("then", success, failure)
170 select {
171 case <-req.Context().Done():
172 if !ac.IsUndefined() {
173
174 ac.Call("abort")
175 }
176 return nil, req.Context().Err()
177 case resp := <-respCh:
178 return resp, nil
179 case err := <-errCh:
180 return nil, err
181 }
182 }
183
184 var errClosed = errors.New("net/http: reader is closed")
185
186
187
188 type streamReader struct {
189 pending []byte
190 stream js.Value
191 err error
192 }
193
194 func (r *streamReader) Read(p []byte) (n int, err error) {
195 if r.err != nil {
196 return 0, r.err
197 }
198 if len(r.pending) == 0 {
199 var (
200 bCh = make(chan []byte, 1)
201 errCh = make(chan error, 1)
202 )
203 success := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
204 result := args[0]
205 if result.Get("done").Bool() {
206 errCh <- io.EOF
207 return nil
208 }
209 value := make([]byte, result.Get("value").Get("byteLength").Int())
210 js.CopyBytesToGo(value, result.Get("value"))
211 bCh <- value
212 return nil
213 })
214 defer success.Release()
215 failure := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
216
217
218
219
220
221 errCh <- errors.New(args[0].Get("message").String())
222 return nil
223 })
224 defer failure.Release()
225 r.stream.Call("read").Call("then", success, failure)
226 select {
227 case b := <-bCh:
228 r.pending = b
229 case err := <-errCh:
230 r.err = err
231 return 0, err
232 }
233 }
234 n = copy(p, r.pending)
235 r.pending = r.pending[n:]
236 return n, nil
237 }
238
239 func (r *streamReader) Close() error {
240
241
242
243 r.stream.Call("cancel")
244 if r.err == nil {
245 r.err = errClosed
246 }
247 return nil
248 }
249
250
251
252 type arrayReader struct {
253 arrayPromise js.Value
254 pending []byte
255 read bool
256 err error
257 }
258
259 func (r *arrayReader) Read(p []byte) (n int, err error) {
260 if r.err != nil {
261 return 0, r.err
262 }
263 if !r.read {
264 r.read = true
265 var (
266 bCh = make(chan []byte, 1)
267 errCh = make(chan error, 1)
268 )
269 success := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
270
271 uint8arrayWrapper := uint8Array.New(args[0])
272 value := make([]byte, uint8arrayWrapper.Get("byteLength").Int())
273 js.CopyBytesToGo(value, uint8arrayWrapper)
274 bCh <- value
275 return nil
276 })
277 defer success.Release()
278 failure := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
279
280
281
282
283 errCh <- errors.New(args[0].Get("message").String())
284 return nil
285 })
286 defer failure.Release()
287 r.arrayPromise.Call("then", success, failure)
288 select {
289 case b := <-bCh:
290 r.pending = b
291 case err := <-errCh:
292 return 0, err
293 }
294 }
295 if len(r.pending) == 0 {
296 return 0, io.EOF
297 }
298 n = copy(p, r.pending)
299 r.pending = r.pending[n:]
300 return n, nil
301 }
302
303 func (r *arrayReader) Close() error {
304 if r.err == nil {
305 r.err = errClosed
306 }
307 return nil
308 }
309
View as plain text