Skip to content

Commit 7b16660

Browse files
haruyama480johanbrandhorst
authored andcommitted
net/http: revert "support streaming POST content in wasm"
CL 458395 added support for streaming POST content in Wasm. Unfortunately, this breaks requests to servers that only support HTTP/1.1. Revert the change until a suitable fallback or opt-in strategy can be decided. Fixes #61889 Change-Id: If53a77e1890132063b39abde867d34515d4ac2af Reviewed-on: https://go-review.googlesource.com/c/go/+/522955 Run-TryBot: Johan Brandhorst-Satzkorn <[email protected]> Reviewed-by: Damien Neil <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Bryan Mills <[email protected]> Reviewed-by: Johan Brandhorst-Satzkorn <[email protected]>
1 parent 19e2e3c commit 7b16660

File tree

1 file changed

+18
-90
lines changed

1 file changed

+18
-90
lines changed

src/net/http/roundtrip_js.go

Lines changed: 18 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"io"
1313
"strconv"
1414
"strings"
15-
"sync"
1615
"syscall/js"
1716
)
1817

@@ -56,38 +55,6 @@ var jsFetchMissing = js.Global().Get("fetch").IsUndefined()
5655
var jsFetchDisabled = js.Global().Get("process").Type() == js.TypeObject &&
5756
strings.HasPrefix(js.Global().Get("process").Get("argv0").String(), "node")
5857

59-
// Determine whether the JS runtime supports streaming request bodies.
60-
// Courtesy: https://developer.chrome.com/articles/fetch-streaming-requests/#feature-detection
61-
var supportsPostRequestStreams = sync.OnceValue(func() bool {
62-
requestOpt := js.Global().Get("Object").New()
63-
requestBody := js.Global().Get("ReadableStream").New()
64-
65-
requestOpt.Set("method", "POST")
66-
requestOpt.Set("body", requestBody)
67-
68-
// There is quite a dance required to define a getter if you do not have the { get property() { ... } }
69-
// syntax available. However, it is possible:
70-
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#defining_a_getter_on_existing_objects_using_defineproperty
71-
duplexCalled := false
72-
duplexGetterObj := js.Global().Get("Object").New()
73-
duplexGetterFunc := js.FuncOf(func(this js.Value, args []js.Value) any {
74-
duplexCalled = true
75-
return "half"
76-
})
77-
defer duplexGetterFunc.Release()
78-
duplexGetterObj.Set("get", duplexGetterFunc)
79-
js.Global().Get("Object").Call("defineProperty", requestOpt, "duplex", duplexGetterObj)
80-
81-
// Slight difference here between the aforementioned example: Non-browser-based runtimes
82-
// do not have a non-empty API Base URL (https://html.spec.whatwg.org/multipage/webappapis.html#api-base-url)
83-
// so we have to supply a valid URL here.
84-
requestObject := js.Global().Get("Request").New("https://www.example.org", requestOpt)
85-
86-
hasContentTypeHeader := requestObject.Get("headers").Call("has", "Content-Type").Bool()
87-
88-
return duplexCalled && !hasContentTypeHeader
89-
})
90-
9158
// RoundTrip implements the RoundTripper interface using the WHATWG Fetch API.
9259
func (t *Transport) RoundTrip(req *Request) (*Response, error) {
9360
// The Transport has a documented contract that states that if the DialContext or
@@ -137,63 +104,24 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
137104
opt.Set("headers", headers)
138105

139106
if req.Body != nil {
140-
if !supportsPostRequestStreams() {
141-
body, err := io.ReadAll(req.Body)
142-
if err != nil {
143-
req.Body.Close() // RoundTrip must always close the body, including on errors.
144-
return nil, err
145-
}
146-
req.Body.Close()
147-
if len(body) != 0 {
148-
buf := uint8Array.New(len(body))
149-
js.CopyBytesToJS(buf, body)
150-
opt.Set("body", buf)
151-
}
152-
} else {
153-
readableStreamCtorArg := js.Global().Get("Object").New()
154-
readableStreamCtorArg.Set("type", "bytes")
155-
readableStreamCtorArg.Set("autoAllocateChunkSize", t.writeBufferSize())
156-
157-
readableStreamPull := js.FuncOf(func(this js.Value, args []js.Value) any {
158-
controller := args[0]
159-
byobRequest := controller.Get("byobRequest")
160-
if byobRequest.IsNull() {
161-
controller.Call("close")
162-
}
163-
164-
byobRequestView := byobRequest.Get("view")
165-
166-
bodyBuf := make([]byte, byobRequestView.Get("byteLength").Int())
167-
readBytes, readErr := io.ReadFull(req.Body, bodyBuf)
168-
if readBytes > 0 {
169-
buf := uint8Array.New(byobRequestView.Get("buffer"))
170-
js.CopyBytesToJS(buf, bodyBuf)
171-
byobRequest.Call("respond", readBytes)
172-
}
173-
174-
if readErr == io.EOF || readErr == io.ErrUnexpectedEOF {
175-
controller.Call("close")
176-
} else if readErr != nil {
177-
readErrCauseObject := js.Global().Get("Object").New()
178-
readErrCauseObject.Set("cause", readErr.Error())
179-
readErr := js.Global().Get("Error").New("io.ReadFull failed while streaming POST body", readErrCauseObject)
180-
controller.Call("error", readErr)
181-
}
182-
// Note: This a return from the pull callback of the controller and *not* RoundTrip().
183-
return nil
184-
})
185-
defer func() {
186-
readableStreamPull.Release()
187-
req.Body.Close()
188-
}()
189-
readableStreamCtorArg.Set("pull", readableStreamPull)
190-
191-
opt.Set("body", js.Global().Get("ReadableStream").New(readableStreamCtorArg))
192-
// There is a requirement from the WHATWG fetch standard that the duplex property of
193-
// the object given as the options argument to the fetch call be set to 'half'
194-
// when the body property of the same options object is a ReadableStream:
195-
// https://fetch.spec.whatwg.org/#dom-requestinit-duplex
196-
opt.Set("duplex", "half")
107+
// TODO(johanbrandhorst): Stream request body when possible.
108+
// See https://bugs.chromium.org/p/chromium/issues/detail?id=688906 for Blink issue.
109+
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1387483 for Firefox issue.
110+
// See https://github.com/web-platform-tests/wpt/issues/7693 for WHATWG tests issue.
111+
// See https://developer.mozilla.org/en-US/docs/Web/API/Streams_API for more details on the Streams API
112+
// and browser support.
113+
// NOTE(haruyama480): Ensure HTTP/1 fallback exists.
114+
// See https://go.dev/issue/61889 for discussion.
115+
body, err := io.ReadAll(req.Body)
116+
if err != nil {
117+
req.Body.Close() // RoundTrip must always close the body, including on errors.
118+
return nil, err
119+
}
120+
req.Body.Close()
121+
if len(body) != 0 {
122+
buf := uint8Array.New(len(body))
123+
js.CopyBytesToJS(buf, body)
124+
opt.Set("body", buf)
197125
}
198126
}
199127

0 commit comments

Comments
 (0)