diff --git a/packages/playwright/src/mcp/browser/context.ts b/packages/playwright/src/mcp/browser/context.ts index cabfa540ad622..3b9584802bb81 100644 --- a/packages/playwright/src/mcp/browser/context.ts +++ b/packages/playwright/src/mcp/browser/context.ts @@ -177,12 +177,12 @@ export class Context { await context.route('**', route => route.abort('blockedbyclient')); for (const origin of this.config.network.allowedOrigins) - await context.route(`*://${origin}/**`, route => route.continue()); + await context.route(originOrHostGlob(origin), route => route.continue()); } if (this.config.network?.blockedOrigins?.length) { for (const origin of this.config.network.blockedOrigins) - await context.route(`*://${origin}/**`, route => route.abort('blockedbyclient')); + await context.route(originOrHostGlob(origin), route => route.abort('blockedbyclient')); } } @@ -234,6 +234,18 @@ export class Context { } } +function originOrHostGlob(originOrHost: string) { + try { + const url = new URL(originOrHost); + // localhost:1234 will parse as protocol 'localhost:' and 'null' origin. + if (url.origin !== 'null') + return `${url.origin}/**`; + } catch { + } + // Support for legacy host-only mode. + return `*://${originOrHost}/**`; +} + export class InputRecorder { private _context: Context; private _browserContext: playwright.BrowserContext; diff --git a/tests/mcp/request-blocking.spec.ts b/tests/mcp/request-blocking.spec.ts index 0bcfd343010af..a2ca31879ba70 100644 --- a/tests/mcp/request-blocking.spec.ts +++ b/tests/mcp/request-blocking.spec.ts @@ -36,7 +36,7 @@ test('default to allow all', async ({ server, client }) => { expect(result).toContain('content:PPP'); }); -test('blocked works', async ({ startClient }) => { +test('blocked works (hostname)', async ({ startClient }) => { const { client } = await startClient({ args: ['--blocked-origins', 'microsoft.com;example.com;playwright.dev'] }); @@ -44,7 +44,15 @@ test('blocked works', async ({ startClient }) => { expect(result).toMatch(BLOCK_MESSAGE); }); -test('allowed works', async ({ server, startClient }) => { +test('blocked works (origin)', async ({ startClient }) => { + const { client } = await startClient({ + args: ['--blocked-origins', 'https://microsoft.com;https://example.com;https://playwright.dev'] + }); + const result = await fetchPage(client, 'https://example.com/'); + expect(result).toMatch(BLOCK_MESSAGE); +}); + +test('allowed works (hostname)', async ({ server, startClient }) => { server.setContent('/ppp', 'content:PPP', 'text/html'); const { client } = await startClient({ args: ['--allowed-origins', `microsoft.com;${new URL(server.PREFIX).host};playwright.dev`] @@ -53,7 +61,16 @@ test('allowed works', async ({ server, startClient }) => { expect(result).toContain('content:PPP'); }); -test('blocked takes precedence', async ({ startClient }) => { +test('allowed works (origin)', async ({ server, startClient }) => { + server.setContent('/ppp', 'content:PPP', 'text/html'); + const { client } = await startClient({ + args: ['--allowed-origins', `https://microsoft.com;${new URL(server.PREFIX).origin};https://playwright.dev`] + }); + const result = await fetchPage(client, server.PREFIX + '/ppp'); + expect(result).toContain('content:PPP'); +}); + +test('blocked takes precedence (hostname)', async ({ startClient }) => { const { client } = await startClient({ args: [ '--blocked-origins', 'example.com', @@ -64,7 +81,18 @@ test('blocked takes precedence', async ({ startClient }) => { expect(result).toMatch(BLOCK_MESSAGE); }); -test('allowed without blocked blocks all non-explicitly specified origins', async ({ startClient }) => { +test('blocked takes precedence (origin)', async ({ startClient }) => { + const { client } = await startClient({ + args: [ + '--blocked-origins', 'https://example.com', + '--allowed-origins', 'https://example.com', + ], + }); + const result = await fetchPage(client, 'https://example.com/'); + expect(result).toMatch(BLOCK_MESSAGE); +}); + +test('allowed without blocked blocks all non-explicitly specified origins (hostname)', async ({ startClient }) => { const { client } = await startClient({ args: ['--allowed-origins', 'playwright.dev'], }); @@ -72,7 +100,15 @@ test('allowed without blocked blocks all non-explicitly specified origins', asyn expect(result).toMatch(BLOCK_MESSAGE); }); -test('blocked without allowed allows non-explicitly specified origins', async ({ server, startClient }) => { +test('allowed without blocked blocks all non-explicitly specified origins (origin)', async ({ startClient }) => { + const { client } = await startClient({ + args: ['--allowed-origins', 'https://playwright.dev'], + }); + const result = await fetchPage(client, 'https://example.com/'); + expect(result).toMatch(BLOCK_MESSAGE); +}); + +test('blocked without allowed allows non-explicitly specified origins (hostname)', async ({ server, startClient }) => { server.setContent('/ppp', 'content:PPP', 'text/html'); const { client } = await startClient({ args: ['--blocked-origins', 'example.com'], @@ -80,3 +116,12 @@ test('blocked without allowed allows non-explicitly specified origins', async ({ const result = await fetchPage(client, server.PREFIX + '/ppp'); expect(result).toContain('content:PPP'); }); + +test('blocked without allowed allows non-explicitly specified origins (origin)', async ({ server, startClient }) => { + server.setContent('/ppp', 'content:PPP', 'text/html'); + const { client } = await startClient({ + args: ['--blocked-origins', 'https://example.com'], + }); + const result = await fetchPage(client, server.PREFIX + '/ppp'); + expect(result).toContain('content:PPP'); +});