Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 351f95a

Browse files
committed
Allow invalid code on WebSocket close from clients, closes #86
1 parent e94713d commit 351f95a

File tree

3 files changed

+17
-9
lines changed

3 files changed

+17
-9
lines changed

packages/web-sockets/src/couple.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
ErrorEvent,
55
WebSocket,
66
kAccepted,
7+
kClose,
78
kClosed,
89
kCoupled,
910
} from "./websocket";
@@ -32,7 +33,7 @@ export async function coupleWebSocket(
3233
}
3334
});
3435
ws.on("close", (code: number, reason: Buffer) => {
35-
if (!pair[kClosed]) pair.close(code, reason.toString());
36+
if (!pair[kClosed]) pair[kClose](code, reason.toString());
3637
});
3738
ws.on("error", (error) => {
3839
pair.dispatchEvent(new ErrorEvent(error));

packages/web-sockets/src/websocket.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ const kPair = Symbol("kPair");
3434
export const kAccepted = Symbol("kAccepted");
3535
export const kCoupled = Symbol("kCoupled");
3636
export const kClosed = Symbol("kClosed");
37+
// Internal close method exposed to bypass close code checking
38+
export const kClose = Symbol("kClose");
3739

3840
export type WebSocketEventMap = {
3941
message: MessageEvent;
@@ -91,13 +93,6 @@ export class WebSocket extends InputGatedEventTarget<WebSocketEventMap> {
9193
}
9294

9395
close(code?: number, reason?: string): void {
94-
const pair = this[kPair];
95-
if (!this[kAccepted]) {
96-
throw new TypeError(
97-
"You must call accept() on this WebSocket before sending messages."
98-
);
99-
}
100-
if (this[kClosed]) throw new TypeError("WebSocket already closed");
10196
if (code) {
10297
// https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code
10398
const validCode =
@@ -114,9 +109,20 @@ export class WebSocket extends InputGatedEventTarget<WebSocketEventMap> {
114109
"If you specify a WebSocket close reason, you must also specify a code."
115110
);
116111
}
112+
this[kClose](code, reason);
113+
}
117114

115+
[kClose](code?: number, reason?: string): void {
116+
// Split from close() so we don't check the close code when forwarding close
117+
// events from the client
118+
if (!this[kAccepted]) {
119+
throw new TypeError(
120+
"You must call accept() on this WebSocket before sending messages."
121+
);
122+
}
123+
if (this[kClosed]) throw new TypeError("WebSocket already closed");
118124
this[kClosed] = true;
119-
pair[kClosed] = true;
125+
this[kPair][kClosed] = true;
120126
void this.#dispatchCloseEvent(code, reason);
121127
}
122128

packages/web-sockets/test/couple.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ test("coupleWebSocket: closes worker socket on client close", async (t) => {
9797
t.is(event.code, 1000);
9898
t.is(event.reason, "Test Closure");
9999
});
100+
// TODO: add test for invalid WebSocket close code
100101

101102
test("coupleWebSocket: forwards messages from worker to client before coupling", async (t) => {
102103
const [eventTrigger, eventPromise] = triggerPromise<{ data: any }>();

0 commit comments

Comments
 (0)