From 26f78751d33ac329f5d747c51502cea400d67458 Mon Sep 17 00:00:00 2001 From: lilnasy <69170106+lilnasy@users.noreply.github.com> Date: Tue, 30 Jan 2024 20:53:22 +0000 Subject: [PATCH 1/3] fix(dev): prevent comma-separating multiple Set-Cookie headers --- .../astro/src/vite-plugin-astro-server/response.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/astro/src/vite-plugin-astro-server/response.ts b/packages/astro/src/vite-plugin-astro-server/response.ts index ac36e703b072..75649a714482 100644 --- a/packages/astro/src/vite-plugin-astro-server/response.ts +++ b/packages/astro/src/vite-plugin-astro-server/response.ts @@ -62,16 +62,10 @@ export async function writeWebResponse(res: http.ServerResponse, webResponse: Re res.setHeader('set-cookie', setCookieHeaders); } - const _headers = Object.fromEntries(headers.entries()); + const _headers: http.OutgoingHttpHeaders = Object.fromEntries(headers.entries()); - // Undici 5.20.0+ includes a `getSetCookie` helper that returns an array of all the `set-cookies` headers. - // Previously, `headers.entries()` would already have these merged, but it seems like this isn't the case anymore. if (headers.has('set-cookie')) { - if ('getSetCookie' in headers && typeof headers.getSetCookie === 'function') { - _headers['set-cookie'] = headers.getSetCookie().toString(); - } else { - _headers['set-cookie'] = headers.get('set-cookie')!; - } + _headers['set-cookie'] = headers.getSetCookie(); } res.writeHead(status, _headers); From 1dc9b91ec4103bdaf6eefe535df9ed707b2f88df Mon Sep 17 00:00:00 2001 From: lilnasy <69170106+lilnasy@users.noreply.github.com> Date: Tue, 30 Jan 2024 20:54:39 +0000 Subject: [PATCH 2/3] add changeset --- .changeset/long-peaches-fetch.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/long-peaches-fetch.md diff --git a/.changeset/long-peaches-fetch.md b/.changeset/long-peaches-fetch.md new file mode 100644 index 000000000000..810b067be804 --- /dev/null +++ b/.changeset/long-peaches-fetch.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Fixes an issue where multiple cookies were sent in a single Set-Cookie header in the dev mode. From 96eb8d79a01bf7334b8c05293819476a832d3379 Mon Sep 17 00:00:00 2001 From: lilnasy <69170106+lilnasy@users.noreply.github.com> Date: Tue, 30 Jan 2024 21:17:03 +0000 Subject: [PATCH 3/3] add test --- .../vite-plugin-astro-server/response.test.js | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 packages/astro/test/units/vite-plugin-astro-server/response.test.js diff --git a/packages/astro/test/units/vite-plugin-astro-server/response.test.js b/packages/astro/test/units/vite-plugin-astro-server/response.test.js new file mode 100644 index 000000000000..780a725f5055 --- /dev/null +++ b/packages/astro/test/units/vite-plugin-astro-server/response.test.js @@ -0,0 +1,63 @@ +import { + createBasicSettings, + createFs, + createRequestAndResponse, + defaultLogger, +} from '../test-utils.js'; +import { fileURLToPath } from 'node:url'; +import { expect } from 'chai'; +import { createContainer } from '../../../dist/core/dev/container.js'; +import testAdapter from '../../test-adapter.js'; + +const root = new URL('../../fixtures/api-routes/', import.meta.url); +const fileSystem = { + '/src/pages/index.js': `export const GET = () => { + const headers = new Headers(); + headers.append('x-single', 'single'); + headers.append('x-triple', 'one'); + headers.append('x-triple', 'two'); + headers.append('x-triple', 'three'); + headers.append('Set-cookie', 'hello'); + headers.append('Set-Cookie', 'world'); + return new Response(null, { headers }); + }`, +}; + +describe('endpoints', () => { + let container; + let settings; + + before(async () => { + const fs = createFs(fileSystem, root); + settings = await createBasicSettings({ + root: fileURLToPath(root), + output: 'server', + adapter: testAdapter(), + }); + container = await createContainer({ + fs, + settings, + logger: defaultLogger, + }); + }); + + after(async () => { + await container.close(); + }); + + it('Headers with multiple values (set-cookie special case)', async () => { + const { req, res, done } = createRequestAndResponse({ + method: 'GET', + url: '/', + }); + container.handle(req, res); + await done; + const headers = res.getHeaders(); + expect(headers).to.deep.equal({ + "access-control-allow-origin": "*", + 'x-single': 'single', + 'x-triple': 'one, two, three', + 'set-cookie': ['hello', 'world'], + }); + }); +});