Skip to content

Commit bbab296

Browse files
authored
fix: do not re-escape cookies collected from fetch calls during SSR (#11904)
* fix: do not re-escape cookies collected from fetch calls during SSR * add test * add changeset
1 parent ed8970e commit bbab296

File tree

6 files changed

+33
-1
lines changed

6 files changed

+33
-1
lines changed

.changeset/fair-suns-report.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: avoid incorrectly un- and re-escaping cookies collected during a server-side `fetch`

packages/kit/src/runtime/server/fetch.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,16 @@ export function create_fetch({ event, options, manifest, state, get_cookie_heade
132132
const set_cookie = response.headers.get('set-cookie');
133133
if (set_cookie) {
134134
for (const str of set_cookie_parser.splitCookiesString(set_cookie)) {
135-
const { name, value, ...options } = set_cookie_parser.parseString(str);
135+
const { name, value, ...options } = set_cookie_parser.parseString(str, {
136+
decodeValues: false
137+
});
136138

137139
const path = options.path ?? (url.pathname.split('/').slice(0, -1).join('/') || '/');
138140

139141
// options.sameSite is string, something more specific is required - type cast is safe
140142
set_internal(name, value, {
141143
path,
144+
encode: (value) => value,
142145
.../** @type {import('cookie').CookieSerializeOptions} */ (options)
143146
});
144147
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { browser } from '$app/environment';
2+
3+
/** @type {import('@sveltejs/kit').Load}*/
4+
export async function load({ fetch }) {
5+
if (!browser) {
6+
// We don't want the client-side collected cookie to clobber the
7+
// server-side collected cookie that we're actually testing.
8+
await fetch('/cookies/collect-without-re-escaping/set-cookie');
9+
}
10+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
import { browser } from '$app/environment';
3+
</script>
4+
5+
<p>{browser && document.cookie}</p>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/** @type {import('@sveltejs/kit').RequestHandler} */
2+
export async function GET() {
3+
return new Response(null, { headers: { 'set-cookie': 'cookie-special-characters="foo"' } });
4+
}

packages/kit/test/apps/basics/test/cross-platform/client.test.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,11 @@ test.describe('cookies', () => {
827827
await page.locator('button').click();
828828
await expect(page.locator('p')).toHaveText('foo=bar');
829829
});
830+
831+
test("fetch during SSR doesn't un- and re-escape cookies", async ({ page }) => {
832+
await page.goto('/cookies/collect-without-re-escaping');
833+
await expect(page.locator('p')).toHaveText('cookie-special-characters="foo"');
834+
});
830835
});
831836

832837
test.describe('Interactivity', () => {

0 commit comments

Comments
 (0)