From 30966ee7f21e0f51cba6191c025a95ab9ce8839f Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 3 Sep 2018 18:36:07 -0400 Subject: [PATCH 1/2] decode req.params - fixes #417 --- src/core/create_manifests.ts | 10 +++++--- test/app/app/client.js | 5 ++-- test/app/routes/echo/page/[slug].html | 11 +++++++++ test/app/routes/echo/server-route/[slug].js | 15 ++++++++++++ test/app/routes/index.html | 1 + test/common/test.js | 26 +++++++++++++++++++++ 6 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 test/app/routes/echo/page/[slug].html create mode 100644 test/app/routes/echo/server-route/[slug].js diff --git a/src/core/create_manifests.ts b/src/core/create_manifests.ts index 3c904c9..3d260e6 100644 --- a/src/core/create_manifests.ts +++ b/src/core/create_manifests.ts @@ -63,6 +63,8 @@ function generate_client( import root from '${get_file(path_to_routes, manifest_data.root)}'; import error from '${posixify(`${path_to_routes}/_error.html`)}'; + const d = decodeURIComponent; + ${manifest_data.components.map(component => { const annotation = bundler === 'webpack' ? `/* webpackChunkName: "${component.name}" */ ` @@ -88,7 +90,7 @@ function generate_client( if (part === null) return 'null'; if (part.params.length > 0) { - const props = part.params.map((param, i) => `${param}: match[${i + 1}]`); + const props = part.params.map((param, i) => `${param}: d(match[${i + 1}])`); return `{ component: ${part.component.name}, params: match => ({ ${props.join(', ')} }) }`; } @@ -138,6 +140,8 @@ function generate_server( // This file is generated by Sapper — do not edit it! ${imports.join('\n')} + const d = decodeURIComponent; + export const manifest = { server_routes: [ ${manifest_data.server_routes.map(route => `{ @@ -145,7 +149,7 @@ function generate_server( pattern: ${route.pattern}, handlers: ${route.name}, params: ${route.params.length > 0 - ? `match => ({ ${route.params.map((param, i) => `${param}: match[${i + 1}]`).join(', ')} })` + ? `match => ({ ${route.params.map((param, i) => `${param}: d(match[${i + 1}])`).join(', ')} })` : `() => ({})`} }`).join(',\n\n\t\t\t\t')} ], @@ -165,7 +169,7 @@ function generate_server( ]; if (part.params.length > 0) { - const params = part.params.map((param, i) => `${param}: match[${i + 1}]`); + const params = part.params.map((param, i) => `${param}: d(match[${i + 1}])`); props.push(`params: match => ({ ${params.join(', ')} })`); } diff --git a/test/app/app/client.js b/test/app/app/client.js index 2ca0ebe..d1c2e96 100644 --- a/test/app/app/client.js +++ b/test/app/app/client.js @@ -1,4 +1,4 @@ -import { init, prefetchRoutes } from '../../../runtime.js'; +import { init, goto, prefetchRoutes } from '../../../runtime.js'; import { Store } from 'svelte/store.js'; import { manifest } from './manifest/client.js'; @@ -10,4 +10,5 @@ window.init = () => { }); }; -window.prefetchRoutes = prefetchRoutes; \ No newline at end of file +window.prefetchRoutes = prefetchRoutes; +window.goto = goto; \ No newline at end of file diff --git a/test/app/routes/echo/page/[slug].html b/test/app/routes/echo/page/[slug].html new file mode 100644 index 0000000..f393c6a --- /dev/null +++ b/test/app/routes/echo/page/[slug].html @@ -0,0 +1,11 @@ +

{slug}

+ + \ No newline at end of file diff --git a/test/app/routes/echo/server-route/[slug].js b/test/app/routes/echo/server-route/[slug].js new file mode 100644 index 0000000..e0e9ef7 --- /dev/null +++ b/test/app/routes/echo/server-route/[slug].js @@ -0,0 +1,15 @@ +export function get(req, res) { + res.writeHead(200, { + 'Content-Type': 'text/html' + }); + + res.end(` + + + + +

${req.params.slug}

+ + + `); +} \ No newline at end of file diff --git a/test/app/routes/index.html b/test/app/routes/index.html index 4678fbd..9ecc6a7 100644 --- a/test/app/routes/index.html +++ b/test/app/routes/index.html @@ -15,6 +15,7 @@ credentials blog const +echo/page/encöding
diff --git a/test/common/test.js b/test/common/test.js index d192fea..91240c3 100644 --- a/test/common/test.js +++ b/test/common/test.js @@ -751,6 +751,32 @@ function run({ mode, basepath = '' }) { assert.equal(title, 'reserved words are okay as routes'); }); }); + + it('encodes req.params for server-rendered pages', () => { + return nightmare.goto(`${base}/echo/page/encöded`) + .page.title() + .then(title => { + assert.equal(title, 'encöded'); + }); + }); + + it('encodes req.params for client-rendered pages', () => { + return nightmare.goto(base).init() + .click('a[href="echo/page/encöding"]') + .wait(100) + .page.title() + .then(title => { + assert.equal(title, 'encöding'); + }); + }); + + it('encodes req.params for server routes', () => { + return nightmare.goto(`${base}/echo/server-route/encöded`) + .page.title() + .then(title => { + assert.equal(title, 'encöded'); + }); + }); }); describe('headers', () => { From 9ef4f33e3853d25a3627703a987fc73605e787df Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 3 Sep 2018 20:09:25 -0400 Subject: [PATCH 2/2] decode query params --- src/runtime/index.ts | 2 +- test/app/routes/echo/page/[slug].html | 7 ++++--- test/app/routes/index.html | 2 +- test/common/test.js | 12 ++++++------ 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/runtime/index.ts b/src/runtime/index.ts index 83c0a76..9530604 100644 --- a/src/runtime/index.ts +++ b/src/runtime/index.ts @@ -67,7 +67,7 @@ function select_route(url: URL): Target { if (url.search.length > 0) { url.search.slice(1).split('&').forEach(searchParam => { const [, key, value] = /([^=]+)=(.*)/.exec(searchParam); - query[key] = value || true; + query[key] = value ? decodeURIComponent(value.replace(/\+/g, ' ')) : true; }); } return { url, path, page, match, query }; diff --git a/test/app/routes/echo/page/[slug].html b/test/app/routes/echo/page/[slug].html index f393c6a..7b2f0a8 100644 --- a/test/app/routes/echo/page/[slug].html +++ b/test/app/routes/echo/page/[slug].html @@ -1,10 +1,11 @@ -

{slug}

+

{slug} ({message})