diff --git a/packages/next/server/next-server.ts b/packages/next/server/next-server.ts index 24a226a18a9b..887eb2455918 100644 --- a/packages/next/server/next-server.ts +++ b/packages/next/server/next-server.ts @@ -982,15 +982,25 @@ export default class Server { // we need to re-encode them here but still allow passing through // values from rewrites/redirects const stringifyQuery = (req: IncomingMessage, 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 = (queryVal: string | string[]) => + Array.isArray(queryVal) + ? queryVal.includes(value) + : queryVal === 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 0972067f0375..ac370167265c 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: {} })