Skip to content

Commit da55f7c

Browse files
committed
Add test
1 parent a25804d commit da55f7c

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

integration/redirects-test.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,42 @@ test.describe("redirects", () => {
150150
return <h1 id="d">D</h1>
151151
}
152152
`,
153+
154+
"app/routes/headers.tsx": js`
155+
import * as React from 'react';
156+
import { Link, Form, redirect, useLocation } from 'react-router';
157+
158+
export function action() {
159+
return redirect('/headers?action-redirect', {
160+
headers: { 'X-Test': 'Foo' }
161+
})
162+
}
163+
164+
export function loader({ request }) {
165+
let url = new URL(request.url);
166+
if (url.searchParams.has('redirect')) {
167+
return redirect('/headers?loader-redirect', {
168+
headers: { 'X-Test': 'Foo' }
169+
})
170+
}
171+
return null
172+
}
173+
174+
export default function Component() {
175+
let location = useLocation()
176+
return (
177+
<>
178+
<Link id="loader-redirect" to="/headers?redirect">Redirect</Link>
179+
<Form method="post">
180+
<button id="action-redirect" type="submit">Action Redirect</button>
181+
</Form>
182+
<p id="search-params">
183+
Search Params: {location.search}
184+
</p>
185+
</>
186+
);
187+
}
188+
`,
153189
},
154190
});
155191

@@ -224,6 +260,49 @@ test.describe("redirects", () => {
224260
await page.goBack();
225261
await page.waitForSelector("#a"); // [/a]
226262
});
263+
264+
test("maintains custom headers on redirects", async ({ page }) => {
265+
let app = new PlaywrightFixture(appFixture, page);
266+
267+
let hasGetHeader = false;
268+
let hasPostHeader = false;
269+
page.on("request", async (request) => {
270+
let extension = /^rsc/.test(templateName) ? "rsc" : "data";
271+
if (
272+
request.method() === "GET" &&
273+
request.url().endsWith(`headers.${extension}?redirect=`)
274+
) {
275+
const headers = (await request.response())?.headers() || {};
276+
hasGetHeader = headers["x-test"] === "Foo";
277+
}
278+
if (
279+
request.method() === "POST" &&
280+
request.url().endsWith(`headers.${extension}`)
281+
) {
282+
const headers = (await request.response())?.headers() || {};
283+
hasPostHeader = headers["x-test"] === "Foo";
284+
}
285+
});
286+
287+
await app.goto("/headers", true);
288+
await app.clickElement("#loader-redirect");
289+
await expect(page.locator("#search-params")).toHaveText(
290+
"Search Params: ?loader-redirect"
291+
);
292+
expect(hasGetHeader).toBe(true);
293+
expect(hasPostHeader).toBe(false);
294+
295+
hasGetHeader = false;
296+
hasPostHeader = false;
297+
298+
await app.goto("/headers", true);
299+
await app.clickElement("#action-redirect");
300+
await expect(page.locator("#search-params")).toHaveText(
301+
"Search Params: ?action-redirect"
302+
);
303+
expect(hasGetHeader).toBe(false);
304+
expect(hasPostHeader).toBe(true);
305+
});
227306
});
228307
}
229308
});

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,11 @@ function generateRedirectResponse(
655655
headers.delete("Location");
656656
headers.delete("X-Remix-Reload-Document");
657657
headers.delete("X-Remix-Replace");
658+
// Remove Content-Length because node:http will truncate the response body
659+
// to match the Content-Length header, which can result in incomplete data
660+
// if the actual encoded body is longer.
661+
// https://nodejs.org/api/http.html#class-httpclientrequest
662+
headers.delete("Content-Length");
658663
headers.set("Content-Type", "text/x-component");
659664
headers.set("Vary", "Content-Type");
660665

@@ -714,6 +719,12 @@ async function generateStaticContextResponse(
714719
(match) => (match as RouteMatch<string, RSCRouteConfigEntry>).route.headers
715720
);
716721

722+
// Remove Content-Length because node:http will truncate the response body
723+
// to match the Content-Length header, which can result in incomplete data
724+
// if the actual encoded body is longer.
725+
// https://nodejs.org/api/http.html#class-httpclientrequest
726+
headers.delete("Content-Length");
727+
717728
const baseRenderPayload: Omit<RSCRenderPayload, "matches" | "patches"> = {
718729
type: "render",
719730
actionData: staticContext.actionData,

0 commit comments

Comments
 (0)