From d3f41eaa47de5630592b90096e99416d7c63f237 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Wed, 23 Nov 2022 09:22:49 -0800 Subject: [PATCH] fix(fetch): cookie with domain=localhost (#18998) Fixes https://github.com/microsoft/playwright/issues/18362 --- packages/playwright-core/src/server/fetch.ts | 4 ++-- tests/library/browsercontext-fetch.spec.ts | 13 +++++++++++++ tests/library/browsercontext-proxy.spec.ts | 20 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/playwright-core/src/server/fetch.ts b/packages/playwright-core/src/server/fetch.ts index 45ec599ead..1b070531eb 100644 --- a/packages/playwright-core/src/server/fetch.ts +++ b/packages/playwright-core/src/server/fetch.ts @@ -207,7 +207,7 @@ export abstract class APIRequestContext extends SdkObject { if (!cookie.domain) cookie.domain = url.hostname; else - assert(cookie.domain.startsWith('.')); + assert(cookie.domain.startsWith('.') || !cookie.domain.includes('.')); if (!domainMatches(url.hostname, cookie.domain!)) continue; // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.4 @@ -587,7 +587,7 @@ function parseCookie(header: string): channels.NetworkCookie | null { break; case 'domain': cookie.domain = value.toLocaleLowerCase() || ''; - if (cookie.domain && !cookie.domain.startsWith('.')) + if (cookie.domain && !cookie.domain.startsWith('.') && cookie.domain.includes('.')) cookie.domain = '.' + cookie.domain; break; case 'path': diff --git a/tests/library/browsercontext-fetch.spec.ts b/tests/library/browsercontext-fetch.spec.ts index cb2fb335c0..ac8f85ae64 100644 --- a/tests/library/browsercontext-fetch.spec.ts +++ b/tests/library/browsercontext-fetch.spec.ts @@ -1072,6 +1072,19 @@ it('should support SameSite cookie attribute over https', async ({ contextFactor } }); +it('should set domain=localhost cookie', async ({ context, server, browserName, isWindows }) => { + server.setRoute('/empty.html', (req, res) => { + res.setHeader('Set-Cookie', `name=val; Domain=localhost; Path=/;`); + res.end(); + }); + await context.request.get(server.EMPTY_PAGE); + const [cookie] = await context.cookies(); + expect(cookie).toBeTruthy(); + expect(cookie.name).toBe('name'); + expect(cookie.value).toBe('val'); +}); + + it('should support set-cookie with SameSite and without Secure attribute over HTTP', async ({ page, server, browserName, isWindows }) => { for (const value of ['None', 'Lax', 'Strict']) { await it.step(`SameSite=${value}`, async () => { diff --git a/tests/library/browsercontext-proxy.spec.ts b/tests/library/browsercontext-proxy.spec.ts index ee50c17951..f9d0fe340b 100644 --- a/tests/library/browsercontext-proxy.spec.ts +++ b/tests/library/browsercontext-proxy.spec.ts @@ -91,6 +91,26 @@ it('should use proxy', async ({ contextFactory, server, proxyServer }) => { await context.close(); }); + +it('should set cookie for top-level domain', async ({ contextFactory, server, proxyServer, browserName, isLinux }) => { + it.fixme(browserName === 'webkit' && isLinux); + proxyServer.forwardTo(server.PORT); + const context = await contextFactory({ + proxy: { server: `localhost:${proxyServer.PORT}` } + }); + server.setRoute('/empty.html', (req, res) => { + res.setHeader('Set-Cookie', `name=val; Domain=codes; Path=/;`); + res.end(); + }); + + await context.request.get('http://codes/empty.html'); + const [cookie] = await context.cookies(); + expect(cookie).toBeTruthy(); + expect(cookie.name).toBe('name'); + expect(cookie.value).toBe('val'); + await context.close(); +}); + it.describe('should proxy local network requests', () => { for (const additionalBypass of [false, true]) { it.describe(additionalBypass ? 'with other bypasses' : 'by default', () => {