diff --git a/lib/router/index.js b/lib/router/index.js index 504ed9ce0ee..49d388f9fba 100644 --- a/lib/router/index.js +++ b/lib/router/index.js @@ -273,6 +273,11 @@ proto.handle = function handle(req, res, out) { return next(layerError || err); } + // store matched routes + if (layer.path) { + req.matchedRoutes = (req.matchedRoutes || []).concat(layer.matchedPath.path); + } + if (route) { return layer.handle_request(req, res, next); } @@ -323,7 +328,7 @@ proto.process_params = function process_params(layer, called, req, res, done) { var params = this.params; // captured parameters from the layer, keys and values - var keys = layer.keys; + var keys = layer.matchedPath ? layer.matchedPath.keys : []; // fast track if (!keys || keys.length === 0) { diff --git a/lib/router/layer.js b/lib/router/layer.js index fe9210cb9de..f8c89cfd57a 100644 --- a/lib/router/layer.js +++ b/lib/router/layer.js @@ -30,23 +30,32 @@ var hasOwnProperty = Object.prototype.hasOwnProperty; module.exports = Layer; -function Layer(path, options, fn) { +function Layer(paths, options, fn) { if (!(this instanceof Layer)) { - return new Layer(path, options, fn); + return new Layer(paths, options, fn); } - debug('new %s', path); + debug('new %s', paths); var opts = options || {}; this.handle = fn; this.name = fn.name || ''; this.params = undefined; this.path = undefined; - this.regexp = pathRegexp(path, this.keys = [], opts); - if (path === '/' && opts.end === false) { - this.regexp.fast_slash = true; + if (paths === '/' && opts.end === false) { + this.fastSlash = true; } + + this.paths = !Array.isArray(paths) ? [paths] : paths; + this.paths = this.paths.map(function (path) { + var pathObj = { + path: path, + keys: [] + }; + pathObj.regexp = pathRegexp(path, pathObj.keys, opts); + return pathObj; + }); } /** @@ -115,14 +124,23 @@ Layer.prototype.match = function match(path) { return false; } - if (this.regexp.fast_slash) { + if (this.fastSlash) { // fast path non-ending match for / (everything matches) this.params = {}; this.path = ''; + this.matchedPath = this.paths[0]; return true; } - var m = this.regexp.exec(path); + var checkPath, m; + + for (var i = 0; i < this.paths.length; i++) { + checkPath = this.paths[i]; + if (m = checkPath.regexp.exec(path)) { + this.matchedPath = checkPath; + break; + } + } if (!m) { this.params = undefined; @@ -138,7 +156,7 @@ Layer.prototype.match = function match(path) { var params = this.params; for (var i = 1; i < m.length; i++) { - var key = keys[i - 1]; + var key = this.matchedPath.keys[i - 1]; var prop = key.name; var val = decode_param(m[i]); diff --git a/test/Router.js b/test/Router.js index 21cdff2c6c0..f965a873429 100644 --- a/test/Router.js +++ b/test/Router.js @@ -502,4 +502,25 @@ describe('Router', function(){ }); }); }); + + describe('matchedRoutes', function() { + it('should store matchedRoutes in request', function(done) { + var req = { url: '/foo/10/bar/baz/30', method: 'get' }; + var fooRouter = new Router(); + var barRouter = new Router(); + var bazRouter = new Router(); + + bazRouter.get(['/bez', '/baz/:subId'], function(req, res, next) { + next(); + }); + + fooRouter.use(['/foo/:id', '/foe'], barRouter); + barRouter.use(['/bar'], bazRouter); + + fooRouter.handle(req, {}, function(err) { + assert.deepEqual(req.matchedRoutes, ['/foo/:id', '/bar', '/baz/:subId']); + done(); + }); + }); + }); })