From 8ff428b95c93b34045aeb2972bc0e6a7b31d5d67 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Fri, 28 Jan 2022 12:01:59 +0100 Subject: [PATCH 1/2] Fix encoding error with location and refresh headers Fixes the merge conflicts in #27003 Fixes #24977 Fixes #24047 Closes #27003 Co-Authored-By: Jamie <5964236+jamsinclair@users.noreply.github.com> --- packages/next/server/server-route-utils.ts | 20 +++++++++++++++---- .../custom-routes/test/index.test.js | 20 +++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/packages/next/server/server-route-utils.ts b/packages/next/server/server-route-utils.ts index 5917470c2c1a4af..2c43d7d6555a08f 100644 --- a/packages/next/server/server-route-utils.ts +++ b/packages/next/server/server-route-utils.ts @@ -140,15 +140,27 @@ export const createRedirectRoute = ({ // we need to re-encode them here but still allow passing through // values from rewrites/redirects export const stringifyQuery = (req: BaseNextRequest, query: ParsedUrlQuery) => { - const initialQueryValues = Object.values( - getRequestMeta(req, '__NEXT_INIT_QUERY') || {} - ) + const initialQuery = getRequestMeta(req, '__NEXT_INIT_QUERY') || {} + const initialQueryValues: Array = + Object.values(initialQuery) return stringifyQs(query, undefined, undefined, { encodeURIComponent(value) { - if (initialQueryValues.some((val) => val === value)) { + const queryContainsValue = (initialQueryVal: string | string[]) => { + // `value` always refers to a query value, even if it's nested in an array + return Array.isArray(initialQueryVal) + ? initialQueryVal.includes(value) + : initialQueryVal === value + } + + if ( + value in initialQuery || + initialQueryValues.some(queryContainsValue) + ) { + // Encode keys and values from initial query return encodeURIComponent(value) } + return value }, }) diff --git a/test/integration/custom-routes/test/index.test.js b/test/integration/custom-routes/test/index.test.js index 0972067f0375857..ac370167265cc75 100644 --- a/test/integration/custom-routes/test/index.test.js +++ b/test/integration/custom-routes/test/index.test.js @@ -690,6 +690,26 @@ const runTests = (isDev = false) => { expect(res.headers.get('refresh')).toBe(`0;url=/`) }) + it('should have correctly encoded query in location and refresh headers', async () => { + const res = await fetchViaHTTP( + appPort, + // Query unencoded is ?ใƒ†ใ‚นใƒˆ=ใ‚ + '/redirect4?%E3%83%86%E3%82%B9%E3%83%88=%E3%81%82', + undefined, + { + redirect: 'manual', + } + ) + expect(res.status).toBe(308) + + expect(res.headers.get('location').split('?')[1]).toBe( + '%E3%83%86%E3%82%B9%E3%83%88=%E3%81%82' + ) + expect(res.headers.get('refresh')).toBe( + '0;url=/?%E3%83%86%E3%82%B9%E3%83%88=%E3%81%82' + ) + }) + it('should handle basic api rewrite successfully', async () => { const data = await renderViaHTTP(appPort, '/api-hello') expect(JSON.parse(data)).toEqual({ query: {} }) From 95b9a4c8ffc79a7bec69f4295b55f46b62838734 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Fri, 28 Jan 2022 12:39:56 +0100 Subject: [PATCH 2/2] Remove extra variable --- packages/next/server/server-route-utils.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/next/server/server-route-utils.ts b/packages/next/server/server-route-utils.ts index 2c43d7d6555a08f..9c17bc3c2cb1fb2 100644 --- a/packages/next/server/server-route-utils.ts +++ b/packages/next/server/server-route-utils.ts @@ -146,16 +146,14 @@ export const stringifyQuery = (req: BaseNextRequest, query: ParsedUrlQuery) => { return stringifyQs(query, undefined, undefined, { encodeURIComponent(value) { - const queryContainsValue = (initialQueryVal: string | string[]) => { - // `value` always refers to a query value, even if it's nested in an array - return Array.isArray(initialQueryVal) - ? initialQueryVal.includes(value) - : initialQueryVal === value - } - if ( value in initialQuery || - initialQueryValues.some(queryContainsValue) + initialQueryValues.some((initialQueryVal: string | string[]) => { + // `value` always refers to a query value, even if it's nested in an array + return Array.isArray(initialQueryVal) + ? initialQueryVal.includes(value) + : initialQueryVal === value + }) ) { // Encode keys and values from initial query return encodeURIComponent(value)