Skip to content

Commit 8f42290

Browse files
authored
Fix bugs with thrown data headers and duplciated set-cookie headers (#12846)
1 parent 90d6e43 commit 8f42290

File tree

5 files changed

+83
-7
lines changed

5 files changed

+83
-7
lines changed

.changeset/rich-pans-fail.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"react-router": patch
3+
---
4+
5+
- Properly bubble headers as `errorHeaders` when throwing a `data()` result
6+
- Avoid duplication of `Set-Cookie` headers could be duplicated if also returned from `headers`

.vscode/settings.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"typescript.tsdk": "node_modules/typescript/lib",
3+
"typescript.enablePromptUseWorkspaceTsdk": true
4+
}

integration/headers-test.ts

+54-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { UNSAFE_ServerMode as ServerMode } from "react-router";
44
import { createFixture, js } from "./helpers/create-fixture.js";
55
import type { Fixture } from "./helpers/create-fixture.js";
66

7-
test.describe.skip("headers export", () => {
7+
test.describe("headers export", () => {
88
let ROOT_HEADER_KEY = "X-Test";
99
let ROOT_HEADER_VALUE = "SUCCESS";
1010
let ACTION_HKEY = "X-Test-Action";
@@ -416,4 +416,57 @@ test.describe.skip("headers export", () => {
416416
])
417417
);
418418
});
419+
420+
test("does not duplicate set-cookie headers also returned via headers() function", async () => {
421+
let fixture = await createFixture(
422+
{
423+
files: {
424+
"app/root.tsx": js`
425+
import { Links, Meta, Outlet, Scripts } from "react-router";
426+
427+
export default function Root() {
428+
return (
429+
<html lang="en">
430+
<head>
431+
<Meta />
432+
<Links />
433+
</head>
434+
<body>
435+
<Outlet />
436+
<Scripts />
437+
</body>
438+
</html>
439+
);
440+
}
441+
`,
442+
443+
"app/routes/_index.tsx": js`
444+
export function headers({ loaderHeaders }) {
445+
return loaderHeaders;
446+
}
447+
448+
export function loader() {
449+
return new Response(null, {
450+
headers: {
451+
"X-Test": "value",
452+
"Set-Cookie": "cookie=yum"
453+
}
454+
})
455+
}
456+
457+
export default function Index() {
458+
return <div>Heyo!</div>
459+
}
460+
`,
461+
},
462+
},
463+
ServerMode.Test
464+
);
465+
let response = await fixture.requestDocument("/");
466+
expect([...response.headers.entries()]).toEqual([
467+
["content-type", "text/html"],
468+
["set-cookie", "cookie=yum"],
469+
["x-test", "value"],
470+
]);
471+
});
419472
});

packages/react-router/lib/router/router.ts

+15-5
Original file line numberDiff line numberDiff line change
@@ -4867,15 +4867,25 @@ async function convertDataStrategyResultToDataResult(
48674867
type: ResultType.error,
48684868
error: result.data,
48694869
statusCode: result.init?.status,
4870+
headers: result.init?.headers
4871+
? new Headers(result.init.headers)
4872+
: undefined,
48704873
};
48714874
}
48724875

48734876
// Convert thrown data() to ErrorResponse instances
4874-
result = new ErrorResponseImpl(
4875-
result.init?.status || 500,
4876-
undefined,
4877-
result.data
4878-
);
4877+
return {
4878+
type: ResultType.error,
4879+
error: new ErrorResponseImpl(
4880+
result.init?.status || 500,
4881+
undefined,
4882+
result.data
4883+
),
4884+
statusCode: isRouteErrorResponse(result) ? result.status : undefined,
4885+
headers: result.init?.headers
4886+
? new Headers(result.init.headers)
4887+
: undefined,
4888+
};
48794889
}
48804890

48814891
return {

packages/react-router/lib/server-runtime/headers.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,11 @@ function prependCookies(parentHeaders: Headers, childHeaders: Headers): void {
9898

9999
if (parentSetCookieString) {
100100
let cookies = splitCookiesString(parentSetCookieString);
101+
let childCookies = new Set(childHeaders.getSetCookie());
101102
cookies.forEach((cookie) => {
102-
childHeaders.append("Set-Cookie", cookie);
103+
if (!childCookies.has(cookie)) {
104+
childHeaders.append("Set-Cookie", cookie);
105+
}
103106
});
104107
}
105108
}

0 commit comments

Comments
 (0)