Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-prerender-malformed-urls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@sveltejs/kit": patch
---

fix: prevent prerender memory issues with malformed URLs in meta tags
28 changes: 27 additions & 1 deletion packages/kit/src/core/postbuild/prerender.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,26 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
const file = decoded.slice(config.paths.base.length + 1);
if (files.has(file)) return;

// Check for URLs that contain the prerender origin hostname in the path
// This can happen when meta tags reference URLs like "{page.url.host}/file.jpg"
// and can cause infinite loops during prerendering
if (config.prerender.origin !== 'http://sveltekit-prerender') {
// Extract hostname from prerender origin
const prerenderHost = new URL(config.prerender.origin).hostname;
// Check if the path starts with the prerender hostname (avoiding circular references)
if (decoded.startsWith(`/${prerenderHost}/`)) {
// This looks like a circular reference - handle as 404
handle_http_error({ status: 404, path: decoded, referrer, referenceType: 'linked' });
return;
}
} else {
// For the default sveltekit-prerender origin, check for the specific pattern
if (decoded.startsWith('/sveltekit-prerender/')) {
handle_http_error({ status: 404, path: decoded, referrer, referenceType: 'linked' });
return;
}
}

return q.add(() => visit(decoded, encoded || encodeURI(decoded), referrer, generated_from_id));
}

Expand Down Expand Up @@ -258,7 +278,13 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
}

// stuff in `static`
return readFileSync(join(config.files.assets, file));
const static_path = join(config.files.assets, file);
// Check if the static file exists before trying to read it
// This prevents potential issues with malformed paths or non-existent files
if (!existsSync(static_path)) {
throw new Error(`Static file not found: ${file}`);
}
return readFileSync(static_path);
},
emulator
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script>
import { page } from '$app/stores';

let dynamic_title = 'My Page';
let dynamic_desc = 'Description';
// Simulate the scenario where paths might have leading slashes creating circular references
let a_path_to_svelte_kit_static_content = '/me.jpg';
</script>

<svelte:head>
<meta property="og:title" content={dynamic_title} />
<meta property="og:description" content={dynamic_desc} />
<meta property="og:url" content={$page.url.origin} />
<meta property="og:image" content="{$page.url.host}/{a_path_to_svelte_kit_static_content}" />
</svelte:head>

<h1>Circular Reference Test</h1>
<p>This page tests that circular references in meta tags don't cause infinite loops</p>
8 changes: 8 additions & 0 deletions packages/kit/test/prerendering/basics/test/tests.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,3 +286,11 @@ test('identifies missing ids', () => {
const missing_ids = JSON.parse(`[${missing_ids_content.slice(0, -1)}]`);
expect(missing_ids).toEqual(['missing-id']);
});

test('handles circular references in meta tags without infinite loops', () => {
// This test verifies that the circular-ref route was prerendered successfully
// without causing memory issues or infinite loops
const content = read('circular-ref.html');
expect(content).toMatch('<h1>Circular Reference Test</h1>');
expect(content).toMatch('This page tests that circular references in meta tags');
});
21 changes: 21 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading