diff --git a/src/index.ts b/src/index.ts index bb93f6640..0497a0d4b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,6 +30,7 @@ import { ensureGateway, findExistingGatewayProcess, killGateway } from './gatewa import { publicRoutes, api, adminUi, debug, cdp } from './routes'; import { redactSensitiveParams } from './utils/logging'; import { restoreIfNeeded, createSnapshot } from './persistence'; +import { normalizeWebSocketCloseCode } from './websocket-close'; import { handleScheduled } from './cron/handler'; import loadingPageHtml from './assets/loading.html'; import configErrorHtml from './assets/config-error.html'; @@ -439,7 +440,7 @@ app.all('*', async (c) => { if (debugLogs) { console.log('[WS] Client closed:', event.code, event.reason); } - containerWs.close(event.code, event.reason); + containerWs.close(normalizeWebSocketCloseCode(event.code), event.reason); }); containerWs.addEventListener('close', (event) => { @@ -454,7 +455,7 @@ app.all('*', async (c) => { if (debugLogs) { console.log('[WS] Transformed close reason:', reason); } - serverWs.close(event.code, reason); + serverWs.close(normalizeWebSocketCloseCode(event.code), reason); }); // Handle errors diff --git a/src/websocket-close.test.ts b/src/websocket-close.test.ts new file mode 100644 index 000000000..b802cdfa2 --- /dev/null +++ b/src/websocket-close.test.ts @@ -0,0 +1,22 @@ +import { describe, expect, it } from 'vitest'; +import { normalizeWebSocketCloseCode } from './websocket-close'; + +describe('normalizeWebSocketCloseCode', () => { + it('preserves valid standard close codes', () => { + expect(normalizeWebSocketCloseCode(1000)).toBe(1000); + expect(normalizeWebSocketCloseCode(1001)).toBe(1001); + expect(normalizeWebSocketCloseCode(1011)).toBe(1011); + }); + + it('preserves valid application close codes', () => { + expect(normalizeWebSocketCloseCode(3000)).toBe(3000); + expect(normalizeWebSocketCloseCode(4999)).toBe(4999); + }); + + it('maps reserved close codes to a safe fallback', () => { + expect(normalizeWebSocketCloseCode(1004)).toBe(1011); + expect(normalizeWebSocketCloseCode(1005)).toBe(1011); + expect(normalizeWebSocketCloseCode(1006)).toBe(1011); + expect(normalizeWebSocketCloseCode(1015)).toBe(1011); + }); +}); diff --git a/src/websocket-close.ts b/src/websocket-close.ts new file mode 100644 index 000000000..597cce8fa --- /dev/null +++ b/src/websocket-close.ts @@ -0,0 +1,14 @@ +export function normalizeWebSocketCloseCode(code: number): number { + if ( + code === 1000 || + code === 1001 || + code === 1002 || + code === 1003 || + (code >= 1007 && code <= 1014) || + (code >= 3000 && code <= 4999) + ) { + return code; + } + + return 1011; +}