From 9b35a8071f2afbd6fb123bf418b8c734f8daa2e8 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Fri, 30 Sep 2022 15:01:59 -0700 Subject: [PATCH] fix(fetch): support SameSite attribute (#17748) Fixes https://github.com/microsoft/playwright/issues/17398 --- packages/playwright-core/src/server/fetch.ts | 17 ++++++++- tests/library/browsercontext-fetch.spec.ts | 36 ++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/packages/playwright-core/src/server/fetch.ts b/packages/playwright-core/src/server/fetch.ts index 4e129ec930..d9130a9a9f 100644 --- a/packages/playwright-core/src/server/fetch.ts +++ b/packages/playwright-core/src/server/fetch.ts @@ -566,7 +566,9 @@ function parseCookie(header: string): channels.NetworkCookie | null { expires: -1, httpOnly: false, secure: false, - sameSite: 'Lax' // None for non-chromium + // From https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite + // The cookie-sending behavior if SameSite is not specified is SameSite=Lax. + sameSite: 'Lax' }; for (let i = 1; i < pairs.length; i++) { const [name, value] = pairs[i]; @@ -595,6 +597,19 @@ function parseCookie(header: string): channels.NetworkCookie | null { case 'httponly': cookie.httpOnly = true; break; + case 'samesite': + switch (value.toLowerCase()) { + case 'none': + cookie.sameSite = 'None'; + break; + case 'lax': + cookie.sameSite = 'Lax'; + break; + case 'strict': + cookie.sameSite = 'Strict'; + break; + } + break; } } return cookie; diff --git a/tests/library/browsercontext-fetch.spec.ts b/tests/library/browsercontext-fetch.spec.ts index c10ccfc7f9..ab854a57fc 100644 --- a/tests/library/browsercontext-fetch.spec.ts +++ b/tests/library/browsercontext-fetch.spec.ts @@ -1026,3 +1026,39 @@ it('should work with connectOverCDP', async ({ browserName, browserType, server await browserServer.close(); } }); + +it('should support SameSite cookie attribute over https', async ({ contextFactory, httpsServer }) => { + // Cookies with SameSite=None must also specify the Secure attribute. WebKit navigation + // to HTTP url will fail if the response contains a cookie with Secure attribute, so + // we do HTTPS navigation. + const context = await contextFactory({ ignoreHTTPSErrors: true }); + const page = await context.newPage(); + for (const value of ['None', 'Lax', 'Strict']) { + await it.step(`SameSite=${value}`, async () => { + httpsServer.setRoute('/empty.html', (req, res) => { + res.setHeader('Set-Cookie', `SID=2022; Path=/; Secure; SameSite=${value}`); + res.end(); + }); + await page.request.get(httpsServer.EMPTY_PAGE); + const [cookie] = await page.context().cookies(); + expect(cookie.sameSite).toBe(value); + }); + } +}); + +it('should support set-cookie with SameSite and without Secure attribute over HTTP', async ({ page, server, browserName }) => { + for (const value of ['None', 'Lax', 'Strict']) { + await it.step(`SameSite=${value}`, async () => { + server.setRoute('/empty.html', (req, res) => { + res.setHeader('Set-Cookie', `SID=2022; Path=/; SameSite=${value}`); + res.end(); + }); + await page.request.get(server.EMPTY_PAGE); + const [cookie] = await page.context().cookies(); + if (browserName === 'chromium' && value === 'None') + expect(cookie).toBeFalsy(); + else + expect(cookie.sameSite).toBe(value); + }); + } +}); \ No newline at end of file