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"]');