From b83e010db124888c448f21bddfcc6b881fdb9d19 Mon Sep 17 00:00:00 2001 From: magnus Date: Wed, 21 May 2025 09:38:49 +0200 Subject: [PATCH 1/5] fix: ensure Location header is encoded in redirects --- packages/open-next/src/core/routingHandler.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/open-next/src/core/routingHandler.ts b/packages/open-next/src/core/routingHandler.ts index ed3f926e..01fb43fb 100644 --- a/packages/open-next/src/core/routingHandler.ts +++ b/packages/open-next/src/core/routingHandler.ts @@ -96,6 +96,11 @@ export default async function routingHandler( const redirect = handleRedirects(internalEvent, RoutesManifest.redirects); if (redirect) { + // We need to encode query params in the Location header to make sure it is valid according to RFC + // https://stackoverflow.com/a/7654605/16587222 + redirect.headers.Location = new URL( + redirect.headers.Location as string, + ).href; debug("redirect", redirect); return redirect; } From 11b2ceb870c2e3a57f4603e49772766263bd4e03 Mon Sep 17 00:00:00 2001 From: magnus Date: Wed, 21 May 2025 11:35:14 +0200 Subject: [PATCH 2/5] e2e --- .../app/config-redirect/dest/page.tsx | 13 ++++++ .../app-router/app/config-redirect/page.tsx | 12 ++++++ examples/app-router/next.config.ts | 12 +++--- .../tests/appRouter/config.redirect.test.ts | 42 +++++++++++++++++++ 4 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 examples/app-router/app/config-redirect/dest/page.tsx diff --git a/examples/app-router/app/config-redirect/dest/page.tsx b/examples/app-router/app/config-redirect/dest/page.tsx new file mode 100644 index 00000000..e9ae5d05 --- /dev/null +++ b/examples/app-router/app/config-redirect/dest/page.tsx @@ -0,0 +1,13 @@ +export default async function Page({ + searchParams, +}: { + searchParams: Promise<{ [key: string]: string | string[] | undefined }>; +}) { + const q = (await searchParams).q; + + return ( + <> +
q: {q}
+ + ); +} diff --git a/examples/app-router/app/config-redirect/page.tsx b/examples/app-router/app/config-redirect/page.tsx index 6e51d3d5..c6628006 100644 --- a/examples/app-router/app/config-redirect/page.tsx +++ b/examples/app-router/app/config-redirect/page.tsx @@ -3,6 +3,18 @@ export default function RedirectDestination() {

I was redirected from next.config.js

/next-config-redirect => /config-redirect

+ + /next-config-redirect-encoding?q=äöå€ + + + /next-config-redirect-encoding?q=%C3%A4%C3%B6%C3%A5%E2%82%AC +
); } diff --git a/examples/app-router/next.config.ts b/examples/app-router/next.config.ts index d1356ef9..77bd5abf 100644 --- a/examples/app-router/next.config.ts +++ b/examples/app-router/next.config.ts @@ -6,13 +6,6 @@ const nextConfig: NextConfig = { transpilePackages: ["@example/shared"], output: "standalone", // outputFileTracingRoot: "../sst", - eslint: { - ignoreDuringBuilds: true, - }, - //TODO: remove this when i'll figure out why it fails locally - typescript: { - ignoreBuildErrors: true, - }, images: { remotePatterns: [ { @@ -60,6 +53,11 @@ const nextConfig: NextConfig = { basePath: false, locale: false, }, + { + source: "/next-config-redirect-encoding", + destination: "/config-redirect/dest", + permanent: false, + }, ]; }, async headers() { diff --git a/packages/tests-e2e/tests/appRouter/config.redirect.test.ts b/packages/tests-e2e/tests/appRouter/config.redirect.test.ts index d328d04e..218e8327 100644 --- a/packages/tests-e2e/tests/appRouter/config.redirect.test.ts +++ b/packages/tests-e2e/tests/appRouter/config.redirect.test.ts @@ -72,4 +72,46 @@ test.describe("Next Config Redirect", () => { }); await expect(el).toBeVisible(); }); + test("Should properly encode the Location header for redirects with query params", async ({ + page, + baseURL, + }) => { + await page.goto("/config-redirect"); + const responsePromise = page.waitForResponse((response) => { + return response.status() === 307; + }); + page.getByTestId("redirect-link").click(); + const res = await responsePromise; + await page.waitForURL("/config-redirect/dest?q=äöå€"); + + const locationHeader = res.headers().location; + expect(locationHeader).toBe( + `${baseURL}/config-redirect/dest?q=%C3%A4%C3%B6%C3%A5%E2%82%AC`, + ); + expect(res.status()).toBe(307); + + const searchParams = page.getByTestId("searchParams"); + await expect(searchParams).toHaveText("q: äöå€"); + }); + test("Should respect already encoded query params", async ({ + page, + baseURL, + }) => { + await page.goto("/config-redirect"); + const responsePromise = page.waitForResponse((response) => { + return response.status() === 307; + }); + page.getByTestId("redirect-link-already-encoded").click(); + const res = await responsePromise; + await page.waitForURL("/config-redirect/dest?q=äöå€"); + + const locationHeader = res.headers().location; + expect(locationHeader).toBe( + `${baseURL}/config-redirect/dest?q=%C3%A4%C3%B6%C3%A5%E2%82%AC`, + ); + expect(res.status()).toBe(307); + + const searchParams = page.getByTestId("searchParams"); + await expect(searchParams).toHaveText("q: äöå€"); + }); }); From 75c57280bc803b09c913bc770845b525e9937b92 Mon Sep 17 00:00:00 2001 From: magnus Date: Wed, 21 May 2025 12:42:39 +0200 Subject: [PATCH 3/5] changeset --- .changeset/proud-dogs-punch.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/proud-dogs-punch.md diff --git a/.changeset/proud-dogs-punch.md b/.changeset/proud-dogs-punch.md new file mode 100644 index 00000000..fb9ea931 --- /dev/null +++ b/.changeset/proud-dogs-punch.md @@ -0,0 +1,5 @@ +--- +"@opennextjs/aws": patch +--- + +fix: Ensure Location header is encoded in redirects from next config From c8c85287aa7e180367e2be1841a34d1c6f52f981 Mon Sep 17 00:00:00 2001 From: magnus Date: Wed, 21 May 2025 12:52:32 +0200 Subject: [PATCH 4/5] refactor comment --- packages/open-next/src/core/routingHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/open-next/src/core/routingHandler.ts b/packages/open-next/src/core/routingHandler.ts index 01fb43fb..834bf4f5 100644 --- a/packages/open-next/src/core/routingHandler.ts +++ b/packages/open-next/src/core/routingHandler.ts @@ -96,7 +96,7 @@ export default async function routingHandler( const redirect = handleRedirects(internalEvent, RoutesManifest.redirects); if (redirect) { - // We need to encode query params in the Location header to make sure it is valid according to RFC + // We need to encode the value in the Location header to make sure it is valid according to RFC // https://stackoverflow.com/a/7654605/16587222 redirect.headers.Location = new URL( redirect.headers.Location as string, From 63b94ee309de96bf695dc0f2b39b547ca96f2d53 Mon Sep 17 00:00:00 2001 From: magnus Date: Wed, 21 May 2025 13:06:46 +0200 Subject: [PATCH 5/5] refactor changeset --- .changeset/proud-dogs-punch.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/proud-dogs-punch.md b/.changeset/proud-dogs-punch.md index fb9ea931..ad987661 100644 --- a/.changeset/proud-dogs-punch.md +++ b/.changeset/proud-dogs-punch.md @@ -2,4 +2,4 @@ "@opennextjs/aws": patch --- -fix: Ensure Location header is encoded in redirects from next config +fix: Ensure Location header is properly encoded in redirects happening from next config