From 8ff41936ca27804f5582db149ee23aad297edb06 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 2 Jun 2021 13:53:15 -0500 Subject: [PATCH 1/2] Ensure has query encoding is normalized --- .../lib/router/utils/prepare-destination.ts | 16 ++++++ test/integration/custom-routes/next.config.js | 10 ++++ .../custom-routes/pages/blog/[post]/index.js | 14 ++++-- .../custom-routes/test/index.test.js | 49 ++++++++++++++++++- test/lib/next-test-utils.js | 2 +- 5 files changed, 84 insertions(+), 7 deletions(-) diff --git a/packages/next/next-server/lib/router/utils/prepare-destination.ts b/packages/next/next-server/lib/router/utils/prepare-destination.ts index 1cf7272ca9a03..b79fb8f0293cd 100644 --- a/packages/next/next-server/lib/router/utils/prepare-destination.ts +++ b/packages/next/next-server/lib/router/utils/prepare-destination.ts @@ -31,6 +31,17 @@ export function matchHas( query: Params ): false | Params { const params: Params = {} + let initialQueryValues: string[] = [] + + if (typeof window === 'undefined') { + initialQueryValues = Object.values((req as any).__NEXT_INIT_QUERY) + } + if (typeof window !== 'undefined') { + initialQueryValues = Array.from( + new URLSearchParams(location.search).values() + ) + } + const allMatch = has.every((hasItem) => { let value: undefined | string let key = hasItem.key @@ -46,7 +57,12 @@ export function matchHas( break } case 'query': { + // preserve initial encoding of query values value = query[key!] + + if (initialQueryValues.includes(value)) { + value = encodeURIComponent(value!) + } break } case 'host': { diff --git a/test/integration/custom-routes/next.config.js b/test/integration/custom-routes/next.config.js index f22c4c3bac9ce..9e3a33cf34608 100644 --- a/test/integration/custom-routes/next.config.js +++ b/test/integration/custom-routes/next.config.js @@ -190,6 +190,16 @@ module.exports = { ], destination: '/with-params?idk=:idk', }, + { + source: '/has-rewrite-8', + has: [ + { + type: 'query', + key: 'post', + }, + ], + destination: '/blog/:post', + }, { source: '/blog/about', destination: '/hello', diff --git a/test/integration/custom-routes/pages/blog/[post]/index.js b/test/integration/custom-routes/pages/blog/[post]/index.js index 221a7b0d40bc2..5f15a4fc62417 100644 --- a/test/integration/custom-routes/pages/blog/[post]/index.js +++ b/test/integration/custom-routes/pages/blog/[post]/index.js @@ -1,10 +1,14 @@ import { useRouter } from 'next/router' -const Page = () => ( - <> -

post: {useRouter().query.post}

- -) +const Page = () => { + const { query } = useRouter() + return ( + <> +

post: {query.post}

+
{JSON.stringify(query)}
+ + ) +} Page.getInitialProps = () => ({ hello: 'world' }) diff --git a/test/integration/custom-routes/test/index.test.js b/test/integration/custom-routes/test/index.test.js index 9453a19eb5fd5..ae25dae1cbc41 100644 --- a/test/integration/custom-routes/test/index.test.js +++ b/test/integration/custom-routes/test/index.test.js @@ -39,7 +39,43 @@ let appPort let app const runTests = (isDev = false) => { - it('should resolveHref correctly navigating through history', async () => { + it('should handle has query encoding correctly', async () => { + for (const expected of [ + { + post: 'first', + }, + { + post: 'hello%20world', + }, + { + post: 'hello/world', + }, + { + post: 'hello%2fworld', + }, + ]) { + const { status = 200, post } = expected + const res = await fetchViaHTTP( + appPort, + '/has-rewrite-8', + `?post=${post}`, + { + redirect: 'manual', + } + ) + + expect(res.status).toBe(status) + + if (status === 200) { + const $ = cheerio.load(await res.text()) + expect(JSON.parse($('#query').text())).toEqual({ + post: decodeURIComponent(post), + }) + } + } + }) + + it('should resolve href correctly navigating through history', async () => { const browser = await webdriver(appPort, '/') await browser.eval('window.beforeNav = 1') @@ -1707,6 +1743,17 @@ const runTests = (isDev = false) => { regex: normalizeRegEx('^\\/has-rewrite-7$'), source: '/has-rewrite-7', }, + { + destination: '/blog/:post', + has: [ + { + key: 'post', + type: 'query', + }, + ], + regex: normalizeRegEx('^\\/has-rewrite-8$'), + source: '/has-rewrite-8', + }, { destination: '/hello', regex: normalizeRegEx('^\\/blog\\/about$'), diff --git a/test/lib/next-test-utils.js b/test/lib/next-test-utils.js index 193cc3b176717..083d84f6dc40d 100644 --- a/test/lib/next-test-utils.js +++ b/test/lib/next-test-utils.js @@ -83,7 +83,7 @@ export function renderViaHTTP(appPort, pathname, query, opts) { export function fetchViaHTTP(appPort, pathname, query, opts) { const url = `http://localhost:${appPort}${pathname}${ - query ? `?${qs.stringify(query)}` : '' + typeof query === 'string' ? query : query ? `?${qs.stringify(query)}` : '' }` return fetch(url, opts) } From 976bafca1282499d6f9ea0cedef8255958c3f5bc Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 2 Jun 2021 14:03:23 -0500 Subject: [PATCH 2/2] fix type error --- .../next/next-server/lib/router/utils/prepare-destination.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/next-server/lib/router/utils/prepare-destination.ts b/packages/next/next-server/lib/router/utils/prepare-destination.ts index b79fb8f0293cd..4fbb4430eea69 100644 --- a/packages/next/next-server/lib/router/utils/prepare-destination.ts +++ b/packages/next/next-server/lib/router/utils/prepare-destination.ts @@ -60,7 +60,7 @@ export function matchHas( // preserve initial encoding of query values value = query[key!] - if (initialQueryValues.includes(value)) { + if (initialQueryValues.includes(value || '')) { value = encodeURIComponent(value!) } break