Allow setting multiple cookies in Netlify adapter (#3092)
* Allow setting multiple cookies in Netlify adapter * Adds a changeset * Set the response status code * Add a comment on why this is needed
This commit is contained in:
parent
c459c87325
commit
a5caf08e24
5 changed files with 100 additions and 4 deletions
5
.changeset/sharp-moose-perform.md
Normal file
5
.changeset/sharp-moose-perform.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@astrojs/netlify': patch
|
||||
---
|
||||
|
||||
Fixes setting multiple cookies with the Netlify adapter
|
|
@ -33,14 +33,37 @@ export const createExports = (manifest: SSRManifest, args: Args) => {
|
|||
};
|
||||
}
|
||||
|
||||
const response = await app.render(request);
|
||||
const response: Response = await app.render(request);
|
||||
const responseBody = await response.text();
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: Object.fromEntries(response.headers.entries()),
|
||||
const responseHeaders = Object.fromEntries(response.headers.entries());
|
||||
const fnResponse: any = {
|
||||
statusCode: response.status,
|
||||
headers: responseHeaders,
|
||||
body: responseBody,
|
||||
};
|
||||
|
||||
// Special-case set-cookie which has to be set an different way :/
|
||||
// The fetch API does not have a way to get multiples of a single header, but instead concatenates
|
||||
// them. There are non-standard ways to do it, and node-fetch gives us headers.raw()
|
||||
// See https://github.com/whatwg/fetch/issues/973 for discussion
|
||||
if (response.headers.has('set-cookie') && 'raw' in response.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[]>;
|
||||
};
|
||||
|
||||
const rawPacked = (response.headers as HeadersWithRaw).raw();
|
||||
if('set-cookie' in rawPacked) {
|
||||
fnResponse.multiValueHeaders = {
|
||||
'set-cookie': rawPacked['set-cookie']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fnResponse;
|
||||
};
|
||||
|
||||
return { handler };
|
||||
|
|
50
packages/integrations/netlify/test/cookies.test.js
Normal file
50
packages/integrations/netlify/test/cookies.test.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
import { expect } from 'chai';
|
||||
import { load as cheerioLoad } from 'cheerio';
|
||||
import { loadFixture } from '../../../astro/test/test-utils.js';
|
||||
import netlifyAdapter from '../dist/index.js';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
describe('Cookies', () => {
|
||||
/** @type {import('../../../astro/test/test-utils').Fixture} */
|
||||
let fixture;
|
||||
|
||||
before(async () => {
|
||||
fixture = await loadFixture({
|
||||
root: new URL('./fixtures/cookies/', import.meta.url).toString(),
|
||||
experimental: {
|
||||
ssr: true,
|
||||
},
|
||||
adapter: netlifyAdapter({
|
||||
dist: new URL('./fixtures/cookies/dist/', import.meta.url),
|
||||
}),
|
||||
site: `http://example.com`,
|
||||
vite: {
|
||||
resolve: {
|
||||
alias: {
|
||||
'@astrojs/netlify/netlify-functions.js': fileURLToPath(
|
||||
new URL('../dist/netlify-functions.js', import.meta.url)
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
await fixture.build();
|
||||
});
|
||||
|
||||
it('Can set multiple', async () => {
|
||||
const entryURL = new URL('./fixtures/cookies/dist/functions/entry.mjs', import.meta.url);
|
||||
const { handler } = await import(entryURL);
|
||||
const resp = await handler({
|
||||
httpMethod: 'POST',
|
||||
headers: {},
|
||||
rawUrl: 'http://example.com/login',
|
||||
body: '{}',
|
||||
isBase64Encoded: false
|
||||
});
|
||||
expect(resp.statusCode).to.equal(301);
|
||||
expect(resp.headers.location).to.equal('/');
|
||||
expect(resp.multiValueHeaders).to.be.deep.equal({
|
||||
'set-cookie': [ 'foo=foo; HttpOnly', 'bar=bar; HttpOnly' ]
|
||||
});
|
||||
});
|
||||
});
|
6
packages/integrations/netlify/test/fixtures/cookies/src/pages/index.astro
vendored
Normal file
6
packages/integrations/netlify/test/fixtures/cookies/src/pages/index.astro
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
<html>
|
||||
<head><title>Testing</title></head>
|
||||
<body>
|
||||
<h1>Testing</h1>
|
||||
</body>
|
||||
</html>
|
12
packages/integrations/netlify/test/fixtures/cookies/src/pages/login.js
vendored
Normal file
12
packages/integrations/netlify/test/fixtures/cookies/src/pages/login.js
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
export function post() {
|
||||
const headers = new Headers();
|
||||
headers.append('Set-Cookie', `foo=foo; HttpOnly`);
|
||||
headers.append('Set-Cookie', `bar=bar; HttpOnly`);
|
||||
headers.append('Location', '/');
|
||||
|
||||
return new Response('', {
|
||||
status: 301,
|
||||
headers,
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue