Skip to content

Commit 31f27c2

Browse files
author
Jay Linski
authored
fix: don't fail on immutable headers when using native fetch (#10367)
Fixes #10366, related to #10030. 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
1 parent d25e227 commit 31f27c2

File tree

5 files changed

+29
-0
lines changed

5 files changed

+29
-0
lines changed

.changeset/violet-pans-scream.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
fix: gracefully handle server endpoints that return `Response`s with immutable `Headers`

packages/kit/src/runtime/server/respond.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,13 @@ export async function respond(request, options, manifest, state) {
440440
?.split(',')
441441
?.map((v) => v.trim().toLowerCase());
442442
if (!(vary?.includes('accept') || vary?.includes('*'))) {
443+
// the returned response might have immutable headers,
444+
// so we have to clone them before trying to mutate them
445+
response = new Response(response.body, {
446+
status: response.status,
447+
statusText: response.statusText,
448+
headers: new Headers(response.headers)
449+
});
443450
response.headers.append('Vary', 'Accept');
444451
}
445452
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// This file will trigger the vary-header code-path in `src/runtime/server/respond.js`
2+
export function load() {
3+
return { foo: 'bar' };
4+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const GET = () => {
2+
const response = new Response('foo');
3+
// this simulates immutable Response Headers, like those returned by undici
4+
Object.defineProperty(response.headers, 'append', { value: null });
5+
Object.defineProperty(response.headers, 'set', { value: null });
6+
return response;
7+
};

packages/kit/test/apps/basics/test/server.test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,4 +569,10 @@ test.describe('Miscellaneous', () => {
569569
const headers = response.headers();
570570
expect(headers['cache-control'] || '').not.toContain('immutable');
571571
});
572+
573+
test('handles responses with immutable headers', async ({ request }) => {
574+
const response = await request.get('/immutable-headers');
575+
expect(response.status()).toBe(200);
576+
expect(await response.text()).toBe('foo');
577+
});
572578
});

0 commit comments

Comments
 (0)