net/http: roundtrip_js.go fails to handle fetch() Promise if RoundTrip context is canceled #57098
Labels
arch-wasm
WebAssembly issues
NeedsInvestigation
Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
OS-JS
Milestone
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release? Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
See the following sample reproduction program
This sample program consists of two binaries:
cmd/wasm/main.go
a simple binary that sends a request to GET http://localhost:9091, logging the result or the error and then exits. The key thing here is the GET has a context that times out after a second.cmd/server/main.go
which is simple web server that serves two ports::9090
serves up a simple index.html file that uses the above wasm binary:9091
is "slow" and takes 10 seconds before responding with "ok" (socmd/wasm/main.go
will always timeout)It is also worth noting that the
index.html
willconsole.log('WASM Done')
oncecmd/wasm/main.go
has exited.What did you expect to see?
When I run
./server
and then visit http://localhost:9090 I expect the wasm binary to reach out to:9091
but timeout after 1 second. So it should show the following in the debugger console:What did you see instead?
Instead I see the following error get thrown to the debugger console after the WASM program exits:
I can reproduce this when loading the webpage from both firefox 102.5.0esr and chrome 106.0.5249.119
Problem
The problem is when we do
ac.Call("abort")
it results in thefetch()
promise being rejected.See: https://developer.mozilla.org/en-US/docs/Web/API/AbortController
So
ac.Call("abort")
aborts thefetch()
and thenTransport.RoundTrip
exits imediatly. In the sample program the WASM main.go also exits right away. After it exits thefetch()
promise gets a chance to be rejected which attempts to call back into the Go WASM to call the failure function. But the Go WASM has already exited, so we see the "Error: Go program has already exited"Fix
One possible fix would be to replace
ac.Call("abort")
with
This way we wait for the
fetch()
promise to be rejected prior to exiting out ofTransport.RoundTrip
.But why the
case <- respCh
part too? I am not entirely sure if this is necessary, however I could see there being a race where ifac.Call("abort")
is called right whenfetch()
also successfully resolves the promise. If this is possible thenrespCh
might be written to instead oferrCh
and if we don't also havecase <- respCh
then we would deadlock becauseerrCh
would never be written to.I tried this fix out and it seems to resolve the issue for me in both firefox and chrome, not sure if there might be any other fallout though.
The text was updated successfully, but these errors were encountered: