diff --git a/.changeset/twenty-numbers-destroy.md b/.changeset/twenty-numbers-destroy.md new file mode 100644 index 000000000000..83ea9d0fb832 --- /dev/null +++ b/.changeset/twenty-numbers-destroy.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +Include page request headers in server-side fetches diff --git a/packages/kit/src/runtime/server/page/load_node.js b/packages/kit/src/runtime/server/page/load_node.js index bb878ae14b61..f7c90171e36e 100644 --- a/packages/kit/src/runtime/server/page/load_node.js +++ b/packages/kit/src/runtime/server/page/load_node.js @@ -94,6 +94,15 @@ export async function load_node({ opts.headers = new Headers(opts.headers); + // merge headers from request + for (const [key, value] of event.request.headers) { + if (opts.headers.has(key)) continue; + if (key === 'cookie' || key === 'authorization' || key === 'if-none-match') continue; + opts.headers.set(key, value); + } + + opts.headers.set('referer', event.url.href); + const resolved = resolve(event.url.pathname, requested.split('?')[0]); /** @type {Response} */ @@ -209,10 +218,10 @@ export async function load_node({ if (!opts.body || typeof opts.body === 'string') { // prettier-ignore fetched.push({ - url: requested, - body: /** @type {string} */ (opts.body), - json: `{"status":${response.status},"statusText":${s(response.statusText)},"headers":${s(headers)},"body":"${escape_json_string_in_html(body)}"}` - }); + url: requested, + body: /** @type {string} */ (opts.body), + json: `{"status":${response.status},"statusText":${s(response.statusText)},"headers":${s(headers)},"body":"${escape_json_string_in_html(body)}"}` + }); } if (dependency) { diff --git a/packages/kit/test/apps/basics/src/routes/load/fetch-headers.json.js b/packages/kit/test/apps/basics/src/routes/load/fetch-headers.json.js new file mode 100644 index 000000000000..0a2705016617 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/load/fetch-headers.json.js @@ -0,0 +1,6 @@ +/** @type {import('@sveltejs/kit').RequestHandler} */ +export function get({ request }) { + return { + body: Object.fromEntries(request.headers) + }; +} diff --git a/packages/kit/test/apps/basics/src/routes/load/fetch-headers.svelte b/packages/kit/test/apps/basics/src/routes/load/fetch-headers.svelte new file mode 100644 index 000000000000..6b20202ef583 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/load/fetch-headers.svelte @@ -0,0 +1,26 @@ + + + + +
{json}
diff --git a/packages/kit/test/apps/basics/src/routes/load/index.svelte b/packages/kit/test/apps/basics/src/routes/load/index.svelte index 52a1929099b4..5cffb7e2a2ff 100644 --- a/packages/kit/test/apps/basics/src/routes/load/index.svelte +++ b/packages/kit/test/apps/basics/src/routes/load/index.svelte @@ -22,6 +22,7 @@ fetch request fetch credentialed +fetch headers large response raw body server fetch request diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js index ab7fc4be653f..1292f2fd8ab5 100644 --- a/packages/kit/test/apps/basics/test/test.js +++ b/packages/kit/test/apps/basics/test/test.js @@ -1036,6 +1036,25 @@ test.describe.parallel('Load', () => { expect(await page.textContent('h1')).toBe('Hello SvelteKit!'); }); + test('includes correct page request headers', async ({ + baseURL, + page, + clicknav, + javaScriptEnabled + }) => { + await page.goto('/load'); + await clicknav('[href="/load/fetch-headers"]'); + + const json = /** @type {string} */ (await page.textContent('pre')); + expect(JSON.parse(json)).toEqual({ + referer: `${baseURL}/load/fetch-headers`, + // these headers aren't particularly useful, but they allow us to verify + // that page headers are being forwarded + 'sec-fetch-dest': javaScriptEnabled ? 'empty' : 'document', + 'sec-fetch-mode': javaScriptEnabled ? 'cors' : 'navigate' + }); + }); + test('exposes rawBody to endpoints', async ({ page, clicknav }) => { await page.goto('/load'); await clicknav('[href="/load/raw-body"]');