Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing CSP header for pre-rendered streamed promises #9235

Open
mastermakrela opened this issue Feb 27, 2023 · 3 comments
Open

Missing CSP header for pre-rendered streamed promises #9235

mastermakrela opened this issue Feb 27, 2023 · 3 comments

Comments

@mastermakrela
Copy link
Contributor

mastermakrela commented Feb 27, 2023

Describe the bug

Streaming promise after prerendering becomes a script tag that isn't included in the automatic CSP header.

This

/** @type {import('@sveltejs/kit').Config} */
const config = {
	kit: {
		adapter: adapterStatic(),

		csp: {
			directives: {
				'script-src': ['self', 'unsafe-inline']
			}
		}
	}
};
export const prerender = true;

/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
	return {
		data: { normal: 'data' },
		streamed: {
			delayedData: sleep(5000).then(() => ({ delayed: 'data' }))
		}
	};
}

leads to following error:

Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-inline' 'sha256-OoJGIbcMedj8pJLEC3ObYW2A5hC4wSoBxJJlIbJBobw='". Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.

this error comes from following line:

<script>__sveltekit_4xqbjq.resolve({id:1,data:{delayed:"data"},error:void 0})</script>

Reproduction

Visit :

https://stackblitz.com/edit/streaming-prerender-bug?file=src/routes/+page.server.js

  1. build the project with npm run build (the issue doesn't appear in dev mode)
  2. start server with npm run preview
  3. Visit the preview in a new tab
    • the second promise ("Loading streamed...") won't resolve
    • the CSP error should be visible in the console

(There are timeouts (≤ 2s) to simulate fetching, so if it looks stuck just wait a second)

Logs

No response

System Info

System:
    OS: macOS 13.3
    CPU: (8) arm64 Apple M1
    Memory: 665.36 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 19.7.0 - /opt/homebrew/bin/node
    npm: 9.5.0 - /opt/homebrew/bin/npm
  Browsers:
    Brave Browser: 109.1.47.186
    Chrome Canary: 112.0.5607.0
    Safari: 16.4
  npmPackages:
    @sveltejs/adapter-cloudflare: ^2.0.0 => 2.0.2 
    @sveltejs/kit: ^1.8.0 => 1.8.5 
    svelte: ^3.54.0 => 3.55.1 
    vite: ^4.1.0 => 4.1.4 

But also happens on StackBlitz

Severity

annoyance

Additional Information

Can be easily fixed by:

  1. not using CSP
  2. not using streaming, when prerendering

But runtime warning or mention in the docs would be nice,
because the behaviour differs in dev and build modes.

@Rich-Harris
Copy link
Member

Ah, good catch. For non-prerendered pages we can use the nonce. For prerendered pages, using a nonce isn't an option, so we would need to generate CSP headers after the promise resolutions have been buffered.

(Aside: there's arguably no point using streaming with prerendering, but there are cases where e.g. a layout streams some data and some of its children are prerendered while others aren't, so we probably don't want to warn/error in that case.)

@dummdidumm
Copy link
Member

dummdidumm commented Mar 6, 2023

A different solution to this would be to not have html streamed this way for prerendering and instead await all promises. We would have to wrap every solution with Promise.resolve to keep the type correct. Not sure which approach is easier to implement.

The above example would be

<script>
  // ...
  app.init({
    ..
    data: {
		data: { normal: 'data' },
		streamed: {
			delayedData: Promise.resolve({ delayed: 'data' })
		}
	}
  });
</script>

@Rich-Harris
Copy link
Member

I don't understand — wouldn't that defeat the object?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants