Skip to content

Commit 0883fd4

Browse files
authored
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
1 parent 66ada56 commit 0883fd4

4 files changed

Lines changed: 45 additions & 14 deletions

File tree

.changeset/twelve-feet-switch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': patch
3+
---
4+
5+
Ensure multiple cookies set in dev result in multiple set-cookie headers

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,10 @@ export async function writeWebResponse(res: http.ServerResponse, webResponse: Re
5757

5858
// Attach any set-cookie headers added via Astro.cookies.set()
5959
const setCookieHeaders = Array.from(getSetCookiesFromResponse(webResponse));
60-
setCookieHeaders.forEach((cookie) => {
61-
headers.append('set-cookie', cookie);
62-
});
60+
if(setCookieHeaders.length) {
61+
// Always use `res.setHeader` because headers.append causes them to be concatenated.
62+
res.setHeader('set-cookie', setCookieHeaders);
63+
}
6364

6465
const _headers = Object.fromEntries(headers.entries());
6566

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
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-
1+
/** @type {import('astro').APIRoute} */
2+
export function post({ cookies }) {
3+
cookies.set('foo', 'foo', {
4+
httpOnly: true
5+
});
6+
cookies.set('bar', 'bar', {
7+
httpOnly: true
8+
});
79
return new Response('', {
810
status: 201,
9-
headers,
1011
});
1112
}

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

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { expect } from 'chai';
22
import { File, FormData } from 'undici';
33
import testAdapter from './test-adapter.js';
44
import { loadFixture } from './test-utils.js';
5+
import net from 'net';
56

67
describe('API routes in SSR', () => {
78
/** @type {import('./test-utils').Fixture} */
@@ -95,11 +96,34 @@ describe('API routes in SSR', () => {
9596
});
9697

9798
it('Can set multiple headers of the same type', async () => {
98-
const response = await fixture.fetch('/login', {
99-
method: 'POST',
99+
const response = await new Promise(resolve => {
100+
let { port } = devServer.address;
101+
let host = 'localhost';
102+
let socket = new net.Socket();
103+
socket.connect(port, host);
104+
socket.on('connect', () => {
105+
let rawRequest = `POST /login HTTP/1.1\r\nHost: ${host}\r\n\r\n`;
106+
socket.write(rawRequest);
107+
});
108+
109+
let rawResponse = '';
110+
socket.setEncoding('utf-8')
111+
socket.on('data', chunk => {
112+
rawResponse += chunk.toString();
113+
socket.destroy();
114+
});
115+
socket.on('close', () => {
116+
resolve(rawResponse);
117+
});
100118
});
101-
const setCookie = response.headers.get('set-cookie');
102-
expect(setCookie).to.equal('foo=foo; HttpOnly, bar=bar; HttpOnly');
119+
120+
let count = 0;
121+
let exp = /set-cookie\:/g;
122+
while(exp.exec(response)) {
123+
count++;
124+
}
125+
126+
expect(count).to.equal(2, 'Found two seperate set-cookie response headers')
103127
});
104128
});
105129
});

0 commit comments

Comments
 (0)