Skip to content

Commit

Permalink
fix(ext/websocket): don't throw exception when sending to closed sock…
Browse files Browse the repository at this point in the history
…et (#26932)

[The WebSocket specification for the `send`
function](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send)
says:

> The browser will throw an exception if you call `send()` when the
connection is in the `CONNECTING` state. If you call `send()` when the
connection is in the `CLOSING` or `CLOSED` states, the browser will
silently discard the data.

and:

> ### Exceptions
> 
> `InvalidStateError`
[`DOMException`](https://developer.mozilla.org/en-US/docs/Web/API/DOMException)
> 
> Thrown if
[`WebSocket.readyState`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState)
is `CONNECTING`.

This pull request fixes the current behavior to match the specification.
Also, I believe it fixes #17586.
  • Loading branch information
bellinitte authored Nov 21, 2024
1 parent a19b3f4 commit 8f7787f
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 3 deletions.
6 changes: 5 additions & 1 deletion ext/websocket/01_websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -330,10 +330,14 @@ class WebSocket extends EventTarget {
webidl.requiredArguments(arguments.length, 1, prefix);
data = webidl.converters.WebSocketSend(data, prefix, "Argument 1");

if (this[_readyState] !== OPEN) {
if (this[_readyState] === CONNECTING) {
throw new DOMException("'readyState' not OPEN", "InvalidStateError");
}

if (this[_readyState] !== OPEN) {
return;
}

if (this[_sendQueue].length === 0) {
// Fast path if the send queue is empty, for example when only synchronous
// data is being sent.
Expand Down
15 changes: 15 additions & 0 deletions tests/unit/websocket_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -806,3 +806,18 @@ Deno.test("Close connection", async () => {
await server.finished;
conn.close();
});

Deno.test("send to a closed socket", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const ws = new WebSocket("ws://localhost:4242");
const blob = new Blob(["foo"]);
ws.onerror = () => fail();
ws.onopen = () => {
ws.close();
ws.send(blob);
};
ws.onclose = () => {
resolve();
};
await promise;
});
4 changes: 2 additions & 2 deletions tests/wpt/runner/expectation.json
Original file line number Diff line number Diff line change
Expand Up @@ -11303,10 +11303,10 @@
"006.html?default": true,
"006.html?wpt_flags=h2": false,
"006.html?wss": false,
"007.html?default": false,
"007.html?default": true,
"007.html?wpt_flags=h2": false,
"007.html?wss": false,
"008.html?default": false,
"008.html?default": true,
"008.html?wss": false,
"009.html?default": {
"ignore": true
Expand Down

0 comments on commit 8f7787f

Please sign in to comment.