From c1d34584f2404b9c80a547c8138264cac2a813b6 Mon Sep 17 00:00:00 2001 From: Conduitry Date: Thu, 25 May 2023 17:26:58 -0400 Subject: [PATCH] fix: clone Headers before mutating them during prerendering (#10030) * clone request and headers before setting x-sveltekit-prerender * add changeset * add test --- .changeset/curly-onions-compare.md | 5 +++++ packages/kit/src/runtime/server/endpoint.js | 9 ++++++++- .../basics/src/routes/immutable-headers/+server.js | 8 ++++++++ packages/kit/test/prerendering/basics/test/tests.spec.js | 5 +++++ 4 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 .changeset/curly-onions-compare.md create mode 100644 packages/kit/test/prerendering/basics/src/routes/immutable-headers/+server.js diff --git a/.changeset/curly-onions-compare.md b/.changeset/curly-onions-compare.md new file mode 100644 index 000000000000..5c2516c6dbf7 --- /dev/null +++ b/.changeset/curly-onions-compare.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: gracefully handle server endpoints that return `Response`s with immutable `Headers` when prerendering diff --git a/packages/kit/src/runtime/server/endpoint.js b/packages/kit/src/runtime/server/endpoint.js index 28e57eb047d5..3bb5f15a2863 100644 --- a/packages/kit/src/runtime/server/endpoint.js +++ b/packages/kit/src/runtime/server/endpoint.js @@ -39,7 +39,7 @@ export async function render_endpoint(event, mod, state) { } try { - const response = await handler( + let response = await handler( /** @type {import('@sveltejs/kit').RequestEvent>} */ (event) ); @@ -50,6 +50,13 @@ export async function render_endpoint(event, mod, state) { } if (state.prerendering) { + // the returned Response might have immutable Headers + // so we should 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.set('x-sveltekit-prerender', String(prerender)); } diff --git a/packages/kit/test/prerendering/basics/src/routes/immutable-headers/+server.js b/packages/kit/test/prerendering/basics/src/routes/immutable-headers/+server.js new file mode 100644 index 000000000000..64688cc5b77e --- /dev/null +++ b/packages/kit/test/prerendering/basics/src/routes/immutable-headers/+server.js @@ -0,0 +1,8 @@ +export const prerender = true; + +export const GET = () => { + const response = new Response('foo'); + // this simulates immutable Response Headers, like those returned by undici + Object.defineProperty(response.headers, 'set', { value: null }); + return response; +}; diff --git a/packages/kit/test/prerendering/basics/test/tests.spec.js b/packages/kit/test/prerendering/basics/test/tests.spec.js index ed29320fcd52..6fee0f46b141 100644 --- a/packages/kit/test/prerendering/basics/test/tests.spec.js +++ b/packages/kit/test/prerendering/basics/test/tests.spec.js @@ -223,3 +223,8 @@ test('prerendered.paths omits trailing slashes for endpoints', () => { expect(content, `Missing ${path}`).toMatch(`"${path}"`); } }); + +test('prerenders responses with immutable Headers', () => { + const content = read('immutable-headers'); + expect(content).toMatch('foo'); +});