Skip to content

Commit

Permalink
Adds ability to add more than one cookie per response (#1161)
Browse files Browse the repository at this point in the history
* Adds ability to set more than one set-cookie header on the response

* some adjustments to avoid clobbering other headers

* Fix cookie headers for worker environments

* Add note

* Remove unnecessary return

Co-authored-by: Bret Little <[email protected]>
  • Loading branch information
merwan7 and blittle authored May 4, 2022
1 parent 5f39c61 commit 6b963fb
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changeset/fuzzy-jeans-tickle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/hydrogen': patch
---

Adds ability to add multiple cookies in one response
42 changes: 40 additions & 2 deletions packages/hydrogen/src/entry-server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -475,14 +475,20 @@ async function stream(
}

if (await isStreamingSupported()) {
return new Response(transform.readable, responseOptions);
return new Response(transform.readable, {
...responseOptions,
headers: getHeaders(responseOptions.headers),
});
}

const bufferedBody = await bufferReadableStream(
transform.readable.getReader()
);

return new Response(bufferedBody, responseOptions);
return new Response(bufferedBody, {
...responseOptions,
headers: getHeaders(responseOptions.headers),
});
} else if (response) {
const {pipe} = ssrRenderToPipeableStream(AppSSR, {
nonce,
Expand Down Expand Up @@ -818,9 +824,22 @@ function getResponseOptions(
error?: Error
) {
const responseInit = {} as ResponseOptions;

// @ts-ignore
responseInit.headers = Object.fromEntries(headers.entries());

// @ts-ignore
const rawHeaders = headers.raw();
// Warning! Headers.raw is non-standard and might disappear in undici or newer versions of node-fetch
// See: https://github.com/whatwg/fetch/issues/973
const setCookieKey = Object.keys(rawHeaders).find(
(key) => key.toLowerCase() === 'set-cookie'
);

if (setCookieKey) {
responseInit.headers['set-cookie'] = rawHeaders[setCookieKey];
}

if (error) {
responseInit.status = 500;
} else {
Expand Down Expand Up @@ -911,3 +930,22 @@ function postRequestTasks(
logQueryTimings(type, request);
request.savePreloadQueries();
}

function getHeaders(rawHeaders: Record<string, String | Array<String>> = {}) {
const headers = new Headers();

for (const [key, values] of Object.entries(rawHeaders)) {
// values doesn't have an array prototype, so instanceof doesn't work.
// Check for .splice instead
// @ts-ignore
if (values?.splice) {
for (const value of values) {
headers.append(key, value as string);
}
} else {
headers.append(key, values as string);
}
}

return headers;
}
8 changes: 4 additions & 4 deletions packages/playground/server-components/tests/e2e-test-cases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,11 @@ export default async function testCases({
expect(response.status).toEqual(201);
// statusText cannot be modified in workers
expect(response.statusText).toEqual(isWorker ? 'Created' : 'hey');

expect(response.headers.get('Accept-Encoding')).toBe('deflate, gzip');
expect(response.headers.get('Set-Cookie')).toBe(
'hello=world, hello2=world2'
);
expect(response.headers.raw()['set-cookie']).toEqual([
'hello=world',
'hello2=world2',
]);
});

it('uses the provided custom body', async () => {
Expand Down

0 comments on commit 6b963fb

Please sign in to comment.