From 153bf27f3edbb1af1c6fcc5e2c3a026f6bfd0551 Mon Sep 17 00:00:00 2001 From: Alexander Kireev Date: Wed, 1 Jul 2026 04:47:01 +0700 Subject: [PATCH] fix(routing): match ws(s) baseURL rewrite case-insensitively toWebSocketBaseUrl() only rewrote http(s) to ws(s) when the scheme was lowercase, so a baseURL like 'HTTP://x.com' was left untouched and routeWebSocket()/waitForEvent('websocket') would never match. Schemes are case-insensitive per RFC 3986, and the rest of urlMatch.ts already treats them that way, so do the same here. --- packages/isomorphic/urlMatch.ts | 7 ++++--- tests/library/route-web-socket.spec.ts | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/isomorphic/urlMatch.ts b/packages/isomorphic/urlMatch.ts index 455147898098f..30cd9a95694d0 100644 --- a/packages/isomorphic/urlMatch.ts +++ b/packages/isomorphic/urlMatch.ts @@ -202,9 +202,10 @@ export function resolveGlobToRegexPattern(baseURL: string | undefined, glob: str } function toWebSocketBaseUrl(baseURL: string | undefined) { - // Allow http(s) baseURL to match ws(s) urls. - if (baseURL && /^https?:\/\//.test(baseURL)) - baseURL = baseURL.replace(/^http/, 'ws'); + // Allow http(s) baseURL to match ws(s) urls. Schemes are case-insensitive, + // same as elsewhere in this file, so 'HTTP://...' should be rewritten too. + if (baseURL && /^https?:\/\//i.test(baseURL)) + baseURL = baseURL.replace(/^https?/i, scheme => scheme.toLowerCase() === 'https' ? 'wss' : 'ws'); return baseURL; } diff --git a/tests/library/route-web-socket.spec.ts b/tests/library/route-web-socket.spec.ts index d968889490b4a..21b1b7efc1c45 100644 --- a/tests/library/route-web-socket.spec.ts +++ b/tests/library/route-web-socket.spec.ts @@ -646,6 +646,30 @@ test('should work with baseURL', async ({ contextFactory, server }) => { ]); }); +test('should work with baseURL regardless of scheme casing', async ({ contextFactory, server }) => { + // baseURL schemes are case-insensitive, same as everywhere else in URL matching. + const context = await contextFactory({ baseURL: 'HTTP://' + server.HOST }); + const page = await context.newPage(); + + await page.routeWebSocket('/ws', ws => { + ws.onMessage(message => { + ws.send(message); + }); + }); + + await setupWS(page, server, 'blob'); + + await page.evaluate(async () => { + await window.wsOpened; + window.ws.send('echo'); + }); + + await expect.poll(() => page.evaluate(() => window.log)).toEqual([ + 'open', + `message: data=echo origin=ws://${server.HOST} lastEventId=`, + ]); +}); + test('should expose protocols to the route handler', async ({ page, server }) => { const routes: WebSocketRoute[] = []; await page.routeWebSocket(/.*/, ws => {