From 9a88a4c37618d898fa88254e18ee1677fd360284 Mon Sep 17 00:00:00 2001 From: Robert Igl Date: Mon, 9 Apr 2018 17:03:53 +0200 Subject: [PATCH 1/2] Escaping routes containing asterisks --- lib/route.js | 5 +++-- test/test.js | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/route.js b/lib/route.js index 6acdb77..9775cc3 100644 --- a/lib/route.js +++ b/lib/route.js @@ -37,7 +37,7 @@ Route.prototype = Object.create(null); /** * Match a path against this route, returning the matched parameters if - * it matches, false if not. + * it matches, false if not. Escapes asterisks in route. * @example * var route = new Route('/this/is/my/route') * route.match('/this/is/my/route') // -> {} @@ -50,7 +50,8 @@ Route.prototype = Object.create(null); */ Route.prototype.match = function (path) { var re = RegexpVisitor.visit(this.ast); - var matched = re.match(path); + var escapedPath = path.replace(new RegExp('\\*', 'g'), '%2A'); + var matched = re.match(escapedPath); return matched !== null ? matched : false; }; diff --git a/test/test.js b/test/test.js index 446787e..7eca287 100644 --- a/test/test.js +++ b/test/test.js @@ -78,6 +78,16 @@ describe('Route', function () { var route = RouteParser('/*a/foo/*b'); assert.deepEqual(route.match('/zoo/woo/foo/bar/baz'), { a: 'zoo/woo', b: 'bar/baz' }); }); + + it('escapes asterisk in route', function () { + var route = RouteParser('/foo?bar=%2Atest&*a=splat'); + assert.deepEqual(route.match('/foo?bar=*test&marker=splat'), { a: 'marker' }); + }); + + it('escapes multiple asterisks', function () { + var route = RouteParser('/foo?bar=%2Atest&*a=splat&foo=%2Abar'); + assert.deepEqual(route.match('/foo?bar=*test&marker=splat&foo=*bar'), { a: 'marker' }); + }); }); describe('mixed', function () { From dd6f9c46bd91bdd1a10496bb46a07f869076502d Mon Sep 17 00:00:00 2001 From: Robert Igl Date: Mon, 9 Apr 2018 17:29:09 +0200 Subject: [PATCH 2/2] Added escaping of parantheses --- lib/route.js | 16 +++++++++++++++- test/test.js | 4 ++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/route.js b/lib/route.js index 9775cc3..a8a938f 100644 --- a/lib/route.js +++ b/lib/route.js @@ -35,6 +35,20 @@ function Route(spec) { Route.prototype = Object.create(null); +/** + * Escape asterisks, open parantheses and closed parantheses. + * This is necessary because they are valid parts of an URL + * but reserved characters in route-parser. + * @param {string} path the path to escape + * @return {string} The escaped path, containing %2A instead + * of *, %28 instead of ( and %29 instead of ) + */ +function escape(path) { + return path.replace(/\*/g, '%2A') + .replace(/\(/g, '%28') + .replace(/\)/g, '%29'); +} + /** * Match a path against this route, returning the matched parameters if * it matches, false if not. Escapes asterisks in route. @@ -50,7 +64,7 @@ Route.prototype = Object.create(null); */ Route.prototype.match = function (path) { var re = RegexpVisitor.visit(this.ast); - var escapedPath = path.replace(new RegExp('\\*', 'g'), '%2A'); + var escapedPath = escape(path); var matched = re.match(escapedPath); return matched !== null ? matched : false; diff --git a/test/test.js b/test/test.js index 7eca287..7b6fbd0 100644 --- a/test/test.js +++ b/test/test.js @@ -115,6 +115,10 @@ describe('Route', function () { var route = RouteParser('/things/(option/:first)'); assert.deepEqual(route.match('/things/option/bar'), { first: 'bar' }); }); + it('escapes parantheses in route', function () { + var route = RouteParser('/foo/(option/:first)'); + assert.deepEqual(route.match('/foo/option/bar()'), { first: 'bar()' }); + }); describe('nested', function () { it('allows nested', function () {