From 0883fd4875548a613df122f0b87a1ca8b7a7cf7d Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Wed, 3 May 2023 11:26:02 -0400 Subject: [PATCH] Ensure multiple cookies set in dev result in multiple set-cookie headers (#6973) * Ensure multiple cookies set in dev result in multiple set-cookie headers * Adding a changeset * Try connecting to localhost instead * use localhost in the Host header * Use 0.0.0.0 * localhost it is --- .changeset/twelve-feet-switch.md | 5 +++ .../src/vite-plugin-astro-server/response.ts | 7 ++-- .../fixtures/ssr-api-route/src/pages/login.js | 15 +++++---- packages/astro/test/ssr-api-route.test.js | 32 ++++++++++++++++--- 4 files changed, 45 insertions(+), 14 deletions(-) create mode 100644 .changeset/twelve-feet-switch.md diff --git a/.changeset/twelve-feet-switch.md b/.changeset/twelve-feet-switch.md new file mode 100644 index 0000000000..b581fb4c33 --- /dev/null +++ b/.changeset/twelve-feet-switch.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Ensure multiple cookies set in dev result in multiple set-cookie headers diff --git a/packages/astro/src/vite-plugin-astro-server/response.ts b/packages/astro/src/vite-plugin-astro-server/response.ts index 3c075405fe..e2f38beb76 100644 --- a/packages/astro/src/vite-plugin-astro-server/response.ts +++ b/packages/astro/src/vite-plugin-astro-server/response.ts @@ -57,9 +57,10 @@ export async function writeWebResponse(res: http.ServerResponse, webResponse: Re // Attach any set-cookie headers added via Astro.cookies.set() const setCookieHeaders = Array.from(getSetCookiesFromResponse(webResponse)); - setCookieHeaders.forEach((cookie) => { - headers.append('set-cookie', cookie); - }); + if(setCookieHeaders.length) { + // Always use `res.setHeader` because headers.append causes them to be concatenated. + res.setHeader('set-cookie', setCookieHeaders); + } const _headers = Object.fromEntries(headers.entries()); diff --git a/packages/astro/test/fixtures/ssr-api-route/src/pages/login.js b/packages/astro/test/fixtures/ssr-api-route/src/pages/login.js index f486927a0e..dfce0b5d69 100644 --- a/packages/astro/test/fixtures/ssr-api-route/src/pages/login.js +++ b/packages/astro/test/fixtures/ssr-api-route/src/pages/login.js @@ -1,11 +1,12 @@ - -export function post() { - const headers = new Headers(); - headers.append('Set-Cookie', `foo=foo; HttpOnly`); - headers.append('Set-Cookie', `bar=bar; HttpOnly`); - +/** @type {import('astro').APIRoute} */ +export function post({ cookies }) { + cookies.set('foo', 'foo', { + httpOnly: true + }); + cookies.set('bar', 'bar', { + httpOnly: true + }); return new Response('', { status: 201, - headers, }); } diff --git a/packages/astro/test/ssr-api-route.test.js b/packages/astro/test/ssr-api-route.test.js index cafbdf32c7..419282b5a3 100644 --- a/packages/astro/test/ssr-api-route.test.js +++ b/packages/astro/test/ssr-api-route.test.js @@ -2,6 +2,7 @@ import { expect } from 'chai'; import { File, FormData } from 'undici'; import testAdapter from './test-adapter.js'; import { loadFixture } from './test-utils.js'; +import net from 'net'; describe('API routes in SSR', () => { /** @type {import('./test-utils').Fixture} */ @@ -95,11 +96,34 @@ describe('API routes in SSR', () => { }); it('Can set multiple headers of the same type', async () => { - const response = await fixture.fetch('/login', { - method: 'POST', + const response = await new Promise(resolve => { + let { port } = devServer.address; + let host = 'localhost'; + let socket = new net.Socket(); + socket.connect(port, host); + socket.on('connect', () => { + let rawRequest = `POST /login HTTP/1.1\r\nHost: ${host}\r\n\r\n`; + socket.write(rawRequest); + }); + + let rawResponse = ''; + socket.setEncoding('utf-8') + socket.on('data', chunk => { + rawResponse += chunk.toString(); + socket.destroy(); + }); + socket.on('close', () => { + resolve(rawResponse); + }); }); - const setCookie = response.headers.get('set-cookie'); - expect(setCookie).to.equal('foo=foo; HttpOnly, bar=bar; HttpOnly'); + + let count = 0; + let exp = /set-cookie\:/g; + while(exp.exec(response)) { + count++; + } + + expect(count).to.equal(2, 'Found two seperate set-cookie response headers') }); }); });