fix(websocket-websys): change close code in drop implementation to 1000 #5229
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description
In browsers, only the code 1000 and codes between 3000-4999 are allowed to be set by userland code: https://websockets.spec.whatwg.org/#dom-websocket-close
I found this while debugging use-after-free errors in our WASM application. Turns out, when connections are timing out, libp2p in rust drops them, but does not seem to close them explicitly (we are using libp2p-swarm). This led to these WebSockets still emitting events, the handlers of which were already dropped on the rust side, though.
A long investigation led me to have a look into the
Result
that gets returned fromclose_with_code_and_reason
, and it turns out it's an error! Specifically:This PR only fixes the failing closing of the WebSocket, not the remaining use-after-free problem.
Notes & open questions
Not ignoring error results
Can
Err
results not be ignored, but instead logged? That would have shown this problem a long time ago.Use-after-free event handlers
Calling
.close()
on the WebSocket leads to the WebSocket still emitting its"close"
event (and also an"error"
event, if the connection is still pending and ran into the time-out), for which thewebsocket-websys
transport registers a handler. This handler is dropped though together with the connection, so when the event comes into WASM, the handler is already free'd and this error is thrown (by wasm-bindgen?):This error is not critical in browsers (only annoying in the console) but exits NodeJS programs due to an uncaught exception.
A quick-fix would be to unregister the relevant event handlers in the
Drop
implementation, like so:According to @nibhar, there must be a better way, though. He suggests storing the socket's event handlers outside the connection, having them clean-up themselves when the onclose handler is called.
Change checklist