diff --git a/packages/next/src/client/components/redirect.ts b/packages/next/src/client/components/redirect.ts index 162bea53944b8..f75c2cd08588b 100644 --- a/packages/next/src/client/components/redirect.ts +++ b/packages/next/src/client/components/redirect.ts @@ -106,7 +106,10 @@ export function isRedirectError( return false } - const [errorCode, type, destination, status] = error.digest.split(';', 4) + const digest = error.digest.split(';') + const [errorCode, type] = digest + const destination = digest.slice(2, -2).join(';') + const status = digest.at(-2) const statusCode = Number(status) @@ -134,7 +137,7 @@ export function getURLFromRedirectError(error: unknown): string | null { // Slices off the beginning of the digest that contains the code and the // separating ';'. - return error.digest.split(';', 3)[2] + return error.digest.split(';').slice(2, -2).join(';') } export function getRedirectTypeFromError( @@ -154,5 +157,5 @@ export function getRedirectStatusCodeFromError( throw new Error('Not a redirect error') } - return Number(error.digest.split(';', 4)[3]) + return Number(error.digest.split(';').at(-2)) } diff --git a/test/e2e/app-dir/navigation/app/redirect/semicolon/page.js b/test/e2e/app-dir/navigation/app/redirect/semicolon/page.js new file mode 100644 index 0000000000000..e6219c56c7a19 --- /dev/null +++ b/test/e2e/app-dir/navigation/app/redirect/semicolon/page.js @@ -0,0 +1,7 @@ +import { redirect } from 'next/navigation' + +export const dynamic = 'force-dynamic' + +export default function Page() { + return redirect('/?a=b;c') +} diff --git a/test/e2e/app-dir/navigation/navigation.test.ts b/test/e2e/app-dir/navigation/navigation.test.ts index a8188f840d10c..a285f7ecb0227 100644 --- a/test/e2e/app-dir/navigation/navigation.test.ts +++ b/test/e2e/app-dir/navigation/navigation.test.ts @@ -24,6 +24,17 @@ describe('app dir - navigation', () => { expect(url.searchParams.toString()).toMatchInlineSnapshot(`"a=b&c=d"`) }) + it('should set query with semicolon correctly', async () => { + const browser = await next.browser('/redirect/semicolon') + + await retry(() => + expect(browser.elementById('query').text()).resolves.toEqual('a=b%3Bc') + ) + + const url = new URL(await browser.url()) + expect(url.searchParams.toString()).toBe('a=b%3Bc') + }) + it('should handle unicode search params', async () => { const requests: Array<{ pathname: string