Skip to content

Commit 6f9aefd

Browse files
authored
fix: page response missing CSP and Link headers when return promise in load (#12418)
* fix: page response missing CSP and Link headers when return promise in `load` (#11801) * fix: add nonce in stream data part * test: ensure CSP header in stream response
1 parent 92301c5 commit 6f9aefd

File tree

5 files changed

+35
-5
lines changed

5 files changed

+35
-5
lines changed

.changeset/tidy-timers-perform.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: page response missing CSP and Link headers when return promise in `load`

packages/kit/src/runtime/server/page/render.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ export async function render_response({
265265
event,
266266
options,
267267
branch.map((b) => b.server_data),
268+
csp,
268269
global
269270
);
270271

@@ -511,9 +512,7 @@ export async function render_response({
511512
type: 'bytes'
512513
}),
513514
{
514-
headers: {
515-
'content-type': 'text/html'
516-
}
515+
headers
517516
}
518517
);
519518
}
@@ -524,10 +523,11 @@ export async function render_response({
524523
* @param {import('@sveltejs/kit').RequestEvent} event
525524
* @param {import('types').SSROptions} options
526525
* @param {Array<import('types').ServerDataNode | null>} nodes
526+
* @param {import('./csp.js').Csp} csp
527527
* @param {string} global
528528
* @returns {{ data: string, chunks: AsyncIterable<string> | null }}
529529
*/
530-
function get_data(event, options, nodes, global) {
530+
function get_data(event, options, nodes, csp, global) {
531531
let promise_id = 1;
532532
let count = 0;
533533

@@ -566,7 +566,9 @@ function get_data(event, options, nodes, global) {
566566
str = devalue.uneval({ id, data, error }, replacer);
567567
}
568568

569-
push(`<script>${global}.resolve(${str})</script>\n`);
569+
push(
570+
`<script${csp.script_needs_nonce ? ` nonce="${csp.nonce}"` : ''}>${global}.resolve(${str})</script>\n`
571+
);
570572
if (count === 0) done();
571573
}
572574
);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export function load() {
2+
return {
3+
lazy: new Promise((resolve) => setTimeout(() => resolve(), 1000)).then(() => 'Moo Deng!')
4+
};
5+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
export let data;
3+
</script>
4+
5+
{#await data.lazy}
6+
Loading...
7+
{:then value}
8+
<h2>{value}</h2>
9+
{/await}

packages/kit/test/apps/options/test/test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ test.describe('CSP', () => {
130130
expect(await page.evaluate('window.pwned')).toBe(undefined);
131131
});
132132

133+
test('ensure CSP header in stream response', async ({ page, javaScriptEnabled }) => {
134+
if (!javaScriptEnabled) return;
135+
const response = await page.goto('/path-base/csp-with-stream');
136+
expect(response.headers()['content-security-policy']).toMatch(
137+
/require-trusted-types-for 'script'/
138+
);
139+
expect(await page.textContent('h2')).toBe('Moo Deng!');
140+
});
141+
133142
test("quotes 'script'", async ({ page }) => {
134143
const response = await page.goto('/path-base');
135144
expect(response.headers()['content-security-policy']).toMatch(

0 commit comments

Comments
 (0)