Skip to content

Commit 4b0f27d

Browse files
authored
Fixes adding set-cookie headers multiple times (#3026)
* Fixes adding set-cookie headers multiple times * Adds a changeset
1 parent c3b083f commit 4b0f27d

File tree

4 files changed

+42
-1
lines changed

4 files changed

+42
-1
lines changed

.changeset/calm-dolphins-remain.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': patch
3+
---
4+
5+
Fix for adding set-cookie multiple times

packages/astro/src/vite-plugin-astro-server/index.ts

+18-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,24 @@ function writeHtmlResponse(res: http.ServerResponse, statusCode: number, html: s
4747

4848
async function writeWebResponse(res: http.ServerResponse, webResponse: Response) {
4949
const { status, headers, body } = webResponse;
50-
res.writeHead(status, Object.fromEntries(headers.entries()));
50+
51+
let _headers = {};
52+
if('raw' in headers) {
53+
// Node fetch allows you to get the raw headers, which includes multiples of the same type.
54+
// This is needed because Set-Cookie *must* be called for each cookie, and can't be
55+
// concatenated together.
56+
type HeadersWithRaw = Headers & {
57+
raw: () => Record<string, string[]>
58+
};
59+
60+
for(const [key, value] of Object.entries((headers as HeadersWithRaw).raw())) {
61+
res.setHeader(key, value);
62+
}
63+
} else {
64+
_headers = Object.fromEntries(headers.entries());
65+
}
66+
67+
res.writeHead(status, _headers);
5168
if (body) {
5269
if (body instanceof Readable) {
5370
body.pipe(res);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
export function post() {
3+
const headers = new Headers();
4+
headers.append('Set-Cookie', `foo=foo; HttpOnly`);
5+
headers.append('Set-Cookie', `bar=bar; HttpOnly`);
6+
7+
return new Response('', {
8+
status: 201,
9+
headers,
10+
});
11+
}

packages/astro/test/ssr-api-route.test.js

+8
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,13 @@ describe('API routes in SSR', () => {
5656
const text = await response.text();
5757
expect(text).to.equal(`ok`);
5858
});
59+
60+
it('Can set multiple headers of the same type', async () => {
61+
const response = await fixture.fetch('/login', {
62+
method: 'POST',
63+
});
64+
const setCookie = response.headers.get('set-cookie');
65+
expect(setCookie).to.equal('foo=foo; HttpOnly, bar=bar; HttpOnly');
66+
});
5967
});
6068
});

0 commit comments

Comments
 (0)