Skip to content

Commit

Permalink
fix: don't fail on immutable headers when using native fetch
Browse files Browse the repository at this point in the history
According to the `fetch()`-specification, a header can have
an `immutable`-guard which will throw a `TypeError` if the
header is changed:
https://fetch.spec.whatwg.org/#headers-class

When using `fetch()`, the spec requires the response
header to be `immutable` (see step 12/4):
https://fetch.spec.whatwg.org/#fetch-method

This is implemented in undici (used by Node.js for native
fetch() under the hood):
https://github.com/nodejs/undici/blob/22bdbd8c7820035276b4e876daccef513c29f5c4/lib/fetch/headers.js#L234-L239
  • Loading branch information
Jakob Linskeseder committed Jul 11, 2023
1 parent 23d1df7 commit f4ad607
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/violet-pans-scream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

fix: gracefully handle server endpoints that return `Response`s with immutable `Headers`
7 changes: 7 additions & 0 deletions packages/kit/src/runtime/server/respond.js
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,13 @@ export async function respond(request, options, manifest, state) {
?.split(',')
?.map((v) => v.trim().toLowerCase());
if (!(vary?.includes('accept') || vary?.includes('*'))) {
// the returned response might have immutable headers,
// so we have to clone them before trying to mutate them
response = new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: new Headers(response.headers)
});
response.headers.append('Vary', 'Accept');
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// This file will trigger the vary-header code-path in `src/runtime/server/respond.js`
export function load() {
return { foo: 'bar' };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const GET = () => {
const response = new Response('foo');
// this simulates immutable Response Headers, like those returned by undici
Object.defineProperty(response.headers, 'append', { value: null });
Object.defineProperty(response.headers, 'set', { value: null });
return response;
};
6 changes: 6 additions & 0 deletions packages/kit/test/apps/basics/test/server.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -569,4 +569,10 @@ test.describe('Miscellaneous', () => {
const headers = response.headers();
expect(headers['cache-control'] || '').not.toContain('immutable');
});

test('handles responses with immutable headers', async ({ request }) => {
const response = await request.get('/immutable-headers');
expect(response.status()).toBe(200);
expect(await response.text()).toBe('foo');
});
});

0 comments on commit f4ad607

Please sign in to comment.