summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/calm-dolphins-remain.md5
-rw-r--r--packages/astro/src/vite-plugin-astro-server/index.ts19
-rw-r--r--packages/astro/test/fixtures/ssr-api-route/src/pages/login.js11
-rw-r--r--packages/astro/test/ssr-api-route.test.js8
4 files changed, 42 insertions, 1 deletions
diff --git a/.changeset/calm-dolphins-remain.md b/.changeset/calm-dolphins-remain.md
new file mode 100644
index 000000000..4d2af1f17
--- /dev/null
+++ b/.changeset/calm-dolphins-remain.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Fix for adding set-cookie multiple times
diff --git a/packages/astro/src/vite-plugin-astro-server/index.ts b/packages/astro/src/vite-plugin-astro-server/index.ts
index e162b4cd1..67f951422 100644
--- a/packages/astro/src/vite-plugin-astro-server/index.ts
+++ b/packages/astro/src/vite-plugin-astro-server/index.ts
@@ -47,7 +47,24 @@ function writeHtmlResponse(res: http.ServerResponse, statusCode: number, html: s
async function writeWebResponse(res: http.ServerResponse, webResponse: Response) {
const { status, headers, body } = webResponse;
- res.writeHead(status, Object.fromEntries(headers.entries()));
+
+ let _headers = {};
+ if('raw' in headers) {
+ // Node fetch allows you to get the raw headers, which includes multiples of the same type.
+ // This is needed because Set-Cookie *must* be called for each cookie, and can't be
+ // concatenated together.
+ type HeadersWithRaw = Headers & {
+ raw: () => Record<string, string[]>
+ };
+
+ for(const [key, value] of Object.entries((headers as HeadersWithRaw).raw())) {
+ res.setHeader(key, value);
+ }
+ } else {
+ _headers = Object.fromEntries(headers.entries());
+ }
+
+ res.writeHead(status, _headers);
if (body) {
if (body instanceof Readable) {
body.pipe(res);
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
new file mode 100644
index 000000000..f486927a0
--- /dev/null
+++ b/packages/astro/test/fixtures/ssr-api-route/src/pages/login.js
@@ -0,0 +1,11 @@
+
+export function post() {
+ const headers = new Headers();
+ headers.append('Set-Cookie', `foo=foo; HttpOnly`);
+ headers.append('Set-Cookie', `bar=bar; HttpOnly`);
+
+ 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 666fd217d..496b3a412 100644
--- a/packages/astro/test/ssr-api-route.test.js
+++ b/packages/astro/test/ssr-api-route.test.js
@@ -56,5 +56,13 @@ describe('API routes in SSR', () => {
const text = await response.text();
expect(text).to.equal(`ok`);
});
+
+ it('Can set multiple headers of the same type', async () => {
+ const response = await fixture.fetch('/login', {
+ method: 'POST',
+ });
+ const setCookie = response.headers.get('set-cookie');
+ expect(setCookie).to.equal('foo=foo; HttpOnly, bar=bar; HttpOnly');
+ });
});
});