From ca7bee0def73c0623c1645c65430d836d03cdcd6 Mon Sep 17 00:00:00 2001 From: James Ide Date: Thu, 4 Mar 2021 14:24:39 -0800 Subject: [PATCH] URL-encode path parameters for Router.url The main breaking change from v8.x to v9.x was an upgrade to `path-to-regex`. [That PR](https://github.com/koajs/router/pull/71) alluded to a breaking change in encoding. Namely, parameters were not URL-encoded: parameters with safe special characters (like spaces) were not percent-encoded, and parameters with special characters that mean something in a URL, such as slashes (path separators) and question marks (query string delimiter). The motivation for this PR is to make URL-encoding be the default since typically the parameters provided to `Router.url` are plain, unencoded values. Should someone need an escape hatch, they could pass in `{ encode: null }` (I think) to disable the automatic encoding. Updated tests, docs, and the changelog. --- API.md | 2 +- history.md | 7 +++++++ lib/layer.js | 2 +- test/lib/layer.js | 9 +++------ test/lib/router.js | 8 ++++++++ 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/API.md b/API.md index 03417a6..c254623 100644 --- a/API.md +++ b/API.md @@ -382,7 +382,7 @@ router #### Router.url(path, params) ⇒ String -Generate URL from url pattern and given `params`. +Generate URL from the given URL pattern and `params`. This method URL-encodes the parameters before including them in the URL. **Kind**: static method of [Router](#exp_module_koa-router--Router) diff --git a/history.md b/history.md index cb85e77..5e7cd60 100644 --- a/history.md +++ b/history.md @@ -1,3 +1,10 @@ +Next +================== + +- [Breaking] URL-encode parameters passed to `Router.url` with `encodeURIComponent`. + - Previously, the parameters to insert in a URL were not encoded: `Router.url('/:x', { x: 'hello world' })` produced `"/hello world"` and `Router.url('/:x', { x: 'a/test?param#' })` would throw an error. + - Now, all parameters are safely URL-encoded by default: `Router.url('/:x', { x: 'hello world' })` produces `"/hello%20world"` and `Router.url('/:x', { x: 'a/test?param#' })` produces `"/a%2Ftest%3Fparam%23"`. + 9.0.0 / 2020-04-09 ================== diff --git a/lib/layer.js b/lib/layer.js index 0f39035..9ab208d 100644 --- a/lib/layer.js +++ b/lib/layer.js @@ -118,7 +118,7 @@ Layer.prototype.url = function (params, options) { } } - const toPath = compile(url, options); + const toPath = compile(url, Object.assign({ encode: encodeURIComponent }, options)); let replaced; const tokens = parse(url); diff --git a/test/lib/layer.js b/test/lib/layer.js index fe1ef24..64ac5cc 100644 --- a/test/lib/layer.js +++ b/test/lib/layer.js @@ -239,11 +239,8 @@ describe('Layer', function() { it('escapes using encodeURIComponent()', function() { const route = new Layer('/:category/:title', ['get'], [function () {}], {name: 'books'}); - const url = route.url( - { category: 'programming', title: 'how to node' }, - { encode: encodeURIComponent } - ); - url.should.equal('/programming/how%20to%20node'); + const url = route.url({ category: 'programming', title: 'how to node & js/ts' }); + url.should.equal('/programming/how%20to%20node%20%26%20js%2Fts'); }); it('setPrefix method checks Layer for path', function () { @@ -269,4 +266,4 @@ describe('Layer', function() { prefix.path.should.equal(false) }); }); -}); \ No newline at end of file +}); diff --git a/test/lib/router.js b/test/lib/router.js index 1344f52..f9f8a8f 100644 --- a/test/lib/router.js +++ b/test/lib/router.js @@ -1501,6 +1501,14 @@ describe('Router', function () { .url("Picard", "Enterprise") .should.Error(); }); + + it('escapes using encodeURIComponent()', function() { + const url = Router.url( + '/:category/:title', + { category: 'programming', title: 'how to node & js/ts' } + ); + url.should.equal('/programming/how%20to%20node%20%26%20js%2Fts'); + }); }); describe('Router#param()', function () {