From 3aa7bf9fad5042f963be6308057fdc088d0bf80e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Tue, 13 Oct 2026 00:57:27 +0200 Subject: [PATCH 1/2] refactor(client): merge the two worker close-code normalizers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit normalizeCloseCode widened a bridge code into 1001-1015 and normalizeOutgoingCloseCode then narrowed everything unwelcome to 3001, so the pair composed to `1000 | 3000-4999 | 3001` — exactly what the second stage alone answers for any input. One normalizer, and the bridge-close handler stops normalizing before the normalizer. --- src/client/client-companion-tunnel-worker.ts | 27 ++++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/src/client/client-companion-tunnel-worker.ts b/src/client/client-companion-tunnel-worker.ts index 2864b80364..c9831087bb 100644 --- a/src/client/client-companion-tunnel-worker.ts +++ b/src/client/client-companion-tunnel-worker.ts @@ -206,17 +206,13 @@ function toUpstreamWebSocketUrl(localBaseUrl: string, requestPath: string): stri return upstream.toString(); } +/** + * The only code shape `WebSocket.close` may be handed: 1000 or the 3000-4999 private range. Any + * other code, including the 1001-1015 range and a missing one, leaves as 3001 so the close lands + * instead of being refused by the client. + */ function normalizeCloseCode(code: number | undefined): number { - if (typeof code !== 'number' || !Number.isInteger(code)) return 1011; - if (code === 1000) return code; - if (code >= 3000 && code <= 4999) return code; - if (code >= 1001 && code <= 1015 && code !== 1004 && code !== 1005 && code !== 1006) { - return code; - } - return 1011; -} - -function normalizeOutgoingCloseCode(code: number): number { + if (typeof code !== 'number' || !Number.isInteger(code)) return 3001; if (code === 1000) return code; if (code >= 3000 && code <= 4999) return code; return 3001; @@ -272,9 +268,10 @@ async function waitForSocketShutdown(socket: WebSocket): Promise { }); } -function closeSocketQuietly(socket: WebSocket, code: number, reason: string): void { +/** Closes one socket with the only code a client may send, ignoring shutdown races. */ +function closeSocketQuietly(socket: WebSocket, code: number | undefined, reason: string): void { try { - socket.close(normalizeOutgoingCloseCode(code), reason); + socket.close(normalizeCloseCode(code), reason); } catch { // ignore shutdown races } @@ -396,11 +393,7 @@ function handleBridgeWebSocketClose( const upstreamSocket = upstreamSockets.get(message.streamId); if (!upstreamSocket) return; upstreamSockets.delete(message.streamId); - closeSocketQuietly( - upstreamSocket, - normalizeCloseCode(message.code), - message.reason ?? 'bridge requested close', - ); + closeSocketQuietly(upstreamSocket, message.code, message.reason ?? 'bridge requested close'); } async function handleBridgeMessage( From 063fc974ac1f68691b158754053109fcd9ab21f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Tue, 13 Oct 2026 01:40:01 +0200 Subject: [PATCH 2/2] docs(client): name the RFC 6455 subranges the worker close-code shape keeps --- src/client/client-companion-tunnel-worker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/client/client-companion-tunnel-worker.ts b/src/client/client-companion-tunnel-worker.ts index c9831087bb..f072de5f81 100644 --- a/src/client/client-companion-tunnel-worker.ts +++ b/src/client/client-companion-tunnel-worker.ts @@ -207,7 +207,8 @@ function toUpstreamWebSocketUrl(localBaseUrl: string, requestPath: string): stri } /** - * The only code shape `WebSocket.close` may be handed: 1000 or the 3000-4999 private range. Any + * The only code shape `WebSocket.close` may be handed: 1000, or the 3000-4999 range RFC 6455 keeps + * for this program's own use (3000-3999 for libraries and applications, 4000-4999 private). Any * other code, including the 1001-1015 range and a missing one, leaves as 3001 so the close lands * instead of being refused by the client. */