diff --git a/.changeset/tidy-timers-perform.md b/.changeset/tidy-timers-perform.md new file mode 100644 index 000000000000..b23476a0e3aa --- /dev/null +++ b/.changeset/tidy-timers-perform.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: page response missing CSP and Link headers when return promise in `load` diff --git a/packages/kit/src/runtime/server/page/render.js b/packages/kit/src/runtime/server/page/render.js index d260eb18e82c..6c275c6d968e 100644 --- a/packages/kit/src/runtime/server/page/render.js +++ b/packages/kit/src/runtime/server/page/render.js @@ -265,6 +265,7 @@ export async function render_response({ event, options, branch.map((b) => b.server_data), + csp, global ); @@ -511,9 +512,7 @@ export async function render_response({ type: 'bytes' }), { - headers: { - 'content-type': 'text/html' - } + headers } ); } @@ -524,10 +523,11 @@ export async function render_response({ * @param {import('@sveltejs/kit').RequestEvent} event * @param {import('types').SSROptions} options * @param {Array} nodes + * @param {import('./csp.js').Csp} csp * @param {string} global * @returns {{ data: string, chunks: AsyncIterable | null }} */ -function get_data(event, options, nodes, global) { +function get_data(event, options, nodes, csp, global) { let promise_id = 1; let count = 0; @@ -566,7 +566,9 @@ function get_data(event, options, nodes, global) { str = devalue.uneval({ id, data, error }, replacer); } - push(`\n`); + push( + `${global}.resolve(${str})\n` + ); if (count === 0) done(); } ); diff --git a/packages/kit/test/apps/options/source/pages/csp-with-stream/+page.server.js b/packages/kit/test/apps/options/source/pages/csp-with-stream/+page.server.js new file mode 100644 index 000000000000..968df8f5d440 --- /dev/null +++ b/packages/kit/test/apps/options/source/pages/csp-with-stream/+page.server.js @@ -0,0 +1,5 @@ +export function load() { + return { + lazy: new Promise((resolve) => setTimeout(() => resolve(), 1000)).then(() => 'Moo Deng!') + }; +} diff --git a/packages/kit/test/apps/options/source/pages/csp-with-stream/+page.svelte b/packages/kit/test/apps/options/source/pages/csp-with-stream/+page.svelte new file mode 100644 index 000000000000..ebf0bb40e051 --- /dev/null +++ b/packages/kit/test/apps/options/source/pages/csp-with-stream/+page.svelte @@ -0,0 +1,9 @@ + + +{#await data.lazy} + Loading... +{:then value} +

{value}

+{/await} diff --git a/packages/kit/test/apps/options/test/test.js b/packages/kit/test/apps/options/test/test.js index cce1d30355b4..921c0ef913c1 100644 --- a/packages/kit/test/apps/options/test/test.js +++ b/packages/kit/test/apps/options/test/test.js @@ -130,6 +130,15 @@ test.describe('CSP', () => { expect(await page.evaluate('window.pwned')).toBe(undefined); }); + test('ensure CSP header in stream response', async ({ page, javaScriptEnabled }) => { + if (!javaScriptEnabled) return; + const response = await page.goto('/path-base/csp-with-stream'); + expect(response.headers()['content-security-policy']).toMatch( + /require-trusted-types-for 'script'/ + ); + expect(await page.textContent('h2')).toBe('Moo Deng!'); + }); + test("quotes 'script'", async ({ page }) => { const response = await page.goto('/path-base'); expect(response.headers()['content-security-policy']).toMatch(