| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673 | 
							- /*!
 
-  * express
 
-  * Copyright(c) 2009-2013 TJ Holowaychuk
 
-  * Copyright(c) 2013 Roman Shtylman
 
-  * Copyright(c) 2014-2015 Douglas Christopher Wilson
 
-  * MIT Licensed
 
-  */
 
- 'use strict';
 
- /**
 
-  * Module dependencies.
 
-  * @private
 
-  */
 
- var Route = require('./route');
 
- var Layer = require('./layer');
 
- var methods = require('methods');
 
- var mixin = require('utils-merge');
 
- var debug = require('debug')('express:router');
 
- var deprecate = require('depd')('express');
 
- var flatten = require('array-flatten');
 
- var parseUrl = require('parseurl');
 
- var setPrototypeOf = require('setprototypeof')
 
- /**
 
-  * Module variables.
 
-  * @private
 
-  */
 
- var objectRegExp = /^\[object (\S+)\]$/;
 
- var slice = Array.prototype.slice;
 
- var toString = Object.prototype.toString;
 
- /**
 
-  * Initialize a new `Router` with the given `options`.
 
-  *
 
-  * @param {Object} [options]
 
-  * @return {Router} which is a callable function
 
-  * @public
 
-  */
 
- var proto = module.exports = function(options) {
 
-   var opts = options || {};
 
-   function router(req, res, next) {
 
-     router.handle(req, res, next);
 
-   }
 
-   // mixin Router class functions
 
-   setPrototypeOf(router, proto)
 
-   router.params = {};
 
-   router._params = [];
 
-   router.caseSensitive = opts.caseSensitive;
 
-   router.mergeParams = opts.mergeParams;
 
-   router.strict = opts.strict;
 
-   router.stack = [];
 
-   return router;
 
- };
 
- /**
 
-  * Map the given param placeholder `name`(s) to the given callback.
 
-  *
 
-  * Parameter mapping is used to provide pre-conditions to routes
 
-  * which use normalized placeholders. For example a _:user_id_ parameter
 
-  * could automatically load a user's information from the database without
 
-  * any additional code,
 
-  *
 
-  * The callback uses the same signature as middleware, the only difference
 
-  * being that the value of the placeholder is passed, in this case the _id_
 
-  * of the user. Once the `next()` function is invoked, just like middleware
 
-  * it will continue on to execute the route, or subsequent parameter functions.
 
-  *
 
-  * Just like in middleware, you must either respond to the request or call next
 
-  * to avoid stalling the request.
 
-  *
 
-  *  app.param('user_id', function(req, res, next, id){
 
-  *    User.find(id, function(err, user){
 
-  *      if (err) {
 
-  *        return next(err);
 
-  *      } else if (!user) {
 
-  *        return next(new Error('failed to load user'));
 
-  *      }
 
-  *      req.user = user;
 
-  *      next();
 
-  *    });
 
-  *  });
 
-  *
 
-  * @param {String} name
 
-  * @param {Function} fn
 
-  * @return {app} for chaining
 
-  * @public
 
-  */
 
- proto.param = function param(name, fn) {
 
-   // param logic
 
-   if (typeof name === 'function') {
 
-     deprecate('router.param(fn): Refactor to use path params');
 
-     this._params.push(name);
 
-     return;
 
-   }
 
-   // apply param functions
 
-   var params = this._params;
 
-   var len = params.length;
 
-   var ret;
 
-   if (name[0] === ':') {
 
-     deprecate('router.param(' + JSON.stringify(name) + ', fn): Use router.param(' + JSON.stringify(name.slice(1)) + ', fn) instead')
 
-     name = name.slice(1)
 
-   }
 
-   for (var i = 0; i < len; ++i) {
 
-     if (ret = params[i](name, fn)) {
 
-       fn = ret;
 
-     }
 
-   }
 
-   // ensure we end up with a
 
-   // middleware function
 
-   if ('function' !== typeof fn) {
 
-     throw new Error('invalid param() call for ' + name + ', got ' + fn);
 
-   }
 
-   (this.params[name] = this.params[name] || []).push(fn);
 
-   return this;
 
- };
 
- /**
 
-  * Dispatch a req, res into the router.
 
-  * @private
 
-  */
 
- proto.handle = function handle(req, res, out) {
 
-   var self = this;
 
-   debug('dispatching %s %s', req.method, req.url);
 
-   var idx = 0;
 
-   var protohost = getProtohost(req.url) || ''
 
-   var removed = '';
 
-   var slashAdded = false;
 
-   var sync = 0
 
-   var paramcalled = {};
 
-   // store options for OPTIONS request
 
-   // only used if OPTIONS request
 
-   var options = [];
 
-   // middleware and routes
 
-   var stack = self.stack;
 
-   // manage inter-router variables
 
-   var parentParams = req.params;
 
-   var parentUrl = req.baseUrl || '';
 
-   var done = restore(out, req, 'baseUrl', 'next', 'params');
 
-   // setup next layer
 
-   req.next = next;
 
-   // for options requests, respond with a default if nothing else responds
 
-   if (req.method === 'OPTIONS') {
 
-     done = wrap(done, function(old, err) {
 
-       if (err || options.length === 0) return old(err);
 
-       sendOptionsResponse(res, options, old);
 
-     });
 
-   }
 
-   // setup basic req values
 
-   req.baseUrl = parentUrl;
 
-   req.originalUrl = req.originalUrl || req.url;
 
-   next();
 
-   function next(err) {
 
-     var layerError = err === 'route'
 
-       ? null
 
-       : err;
 
-     // remove added slash
 
-     if (slashAdded) {
 
-       req.url = req.url.slice(1)
 
-       slashAdded = false;
 
-     }
 
-     // restore altered req.url
 
-     if (removed.length !== 0) {
 
-       req.baseUrl = parentUrl;
 
-       req.url = protohost + removed + req.url.slice(protohost.length)
 
-       removed = '';
 
-     }
 
-     // signal to exit router
 
-     if (layerError === 'router') {
 
-       setImmediate(done, null)
 
-       return
 
-     }
 
-     // no more matching layers
 
-     if (idx >= stack.length) {
 
-       setImmediate(done, layerError);
 
-       return;
 
-     }
 
-     // max sync stack
 
-     if (++sync > 100) {
 
-       return setImmediate(next, err)
 
-     }
 
-     // get pathname of request
 
-     var path = getPathname(req);
 
-     if (path == null) {
 
-       return done(layerError);
 
-     }
 
-     // find next matching layer
 
-     var layer;
 
-     var match;
 
-     var route;
 
-     while (match !== true && idx < stack.length) {
 
-       layer = stack[idx++];
 
-       match = matchLayer(layer, path);
 
-       route = layer.route;
 
-       if (typeof match !== 'boolean') {
 
-         // hold on to layerError
 
-         layerError = layerError || match;
 
-       }
 
-       if (match !== true) {
 
-         continue;
 
-       }
 
-       if (!route) {
 
-         // process non-route handlers normally
 
-         continue;
 
-       }
 
-       if (layerError) {
 
-         // routes do not match with a pending error
 
-         match = false;
 
-         continue;
 
-       }
 
-       var method = req.method;
 
-       var has_method = route._handles_method(method);
 
-       // build up automatic options response
 
-       if (!has_method && method === 'OPTIONS') {
 
-         appendMethods(options, route._options());
 
-       }
 
-       // don't even bother matching route
 
-       if (!has_method && method !== 'HEAD') {
 
-         match = false;
 
-       }
 
-     }
 
-     // no match
 
-     if (match !== true) {
 
-       return done(layerError);
 
-     }
 
-     // store route for dispatch on change
 
-     if (route) {
 
-       req.route = route;
 
-     }
 
-     // Capture one-time layer values
 
-     req.params = self.mergeParams
 
-       ? mergeParams(layer.params, parentParams)
 
-       : layer.params;
 
-     var layerPath = layer.path;
 
-     // this should be done for the layer
 
-     self.process_params(layer, paramcalled, req, res, function (err) {
 
-       if (err) {
 
-         next(layerError || err)
 
-       } else if (route) {
 
-         layer.handle_request(req, res, next)
 
-       } else {
 
-         trim_prefix(layer, layerError, layerPath, path)
 
-       }
 
-       sync = 0
 
-     });
 
-   }
 
-   function trim_prefix(layer, layerError, layerPath, path) {
 
-     if (layerPath.length !== 0) {
 
-       // Validate path is a prefix match
 
-       if (layerPath !== path.slice(0, layerPath.length)) {
 
-         next(layerError)
 
-         return
 
-       }
 
-       // Validate path breaks on a path separator
 
-       var c = path[layerPath.length]
 
-       if (c && c !== '/' && c !== '.') return next(layerError)
 
-       // Trim off the part of the url that matches the route
 
-       // middleware (.use stuff) needs to have the path stripped
 
-       debug('trim prefix (%s) from url %s', layerPath, req.url);
 
-       removed = layerPath;
 
-       req.url = protohost + req.url.slice(protohost.length + removed.length)
 
-       // Ensure leading slash
 
-       if (!protohost && req.url[0] !== '/') {
 
-         req.url = '/' + req.url;
 
-         slashAdded = true;
 
-       }
 
-       // Setup base URL (no trailing slash)
 
-       req.baseUrl = parentUrl + (removed[removed.length - 1] === '/'
 
-         ? removed.substring(0, removed.length - 1)
 
-         : removed);
 
-     }
 
-     debug('%s %s : %s', layer.name, layerPath, req.originalUrl);
 
-     if (layerError) {
 
-       layer.handle_error(layerError, req, res, next);
 
-     } else {
 
-       layer.handle_request(req, res, next);
 
-     }
 
-   }
 
- };
 
- /**
 
-  * Process any parameters for the layer.
 
-  * @private
 
-  */
 
- 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;
 
-   // fast track
 
-   if (!keys || keys.length === 0) {
 
-     return done();
 
-   }
 
-   var i = 0;
 
-   var name;
 
-   var paramIndex = 0;
 
-   var key;
 
-   var paramVal;
 
-   var paramCallbacks;
 
-   var paramCalled;
 
-   // process params in order
 
-   // param callbacks can be async
 
-   function param(err) {
 
-     if (err) {
 
-       return done(err);
 
-     }
 
-     if (i >= keys.length ) {
 
-       return done();
 
-     }
 
-     paramIndex = 0;
 
-     key = keys[i++];
 
-     name = key.name;
 
-     paramVal = req.params[name];
 
-     paramCallbacks = params[name];
 
-     paramCalled = called[name];
 
-     if (paramVal === undefined || !paramCallbacks) {
 
-       return param();
 
-     }
 
-     // param previously called with same value or error occurred
 
-     if (paramCalled && (paramCalled.match === paramVal
 
-       || (paramCalled.error && paramCalled.error !== 'route'))) {
 
-       // restore value
 
-       req.params[name] = paramCalled.value;
 
-       // next param
 
-       return param(paramCalled.error);
 
-     }
 
-     called[name] = paramCalled = {
 
-       error: null,
 
-       match: paramVal,
 
-       value: paramVal
 
-     };
 
-     paramCallback();
 
-   }
 
-   // single param callbacks
 
-   function paramCallback(err) {
 
-     var fn = paramCallbacks[paramIndex++];
 
-     // store updated value
 
-     paramCalled.value = req.params[key.name];
 
-     if (err) {
 
-       // store error
 
-       paramCalled.error = err;
 
-       param(err);
 
-       return;
 
-     }
 
-     if (!fn) return param();
 
-     try {
 
-       fn(req, res, paramCallback, paramVal, key.name);
 
-     } catch (e) {
 
-       paramCallback(e);
 
-     }
 
-   }
 
-   param();
 
- };
 
- /**
 
-  * Use the given middleware function, with optional path, defaulting to "/".
 
-  *
 
-  * Use (like `.all`) will run for any http METHOD, but it will not add
 
-  * handlers for those methods so OPTIONS requests will not consider `.use`
 
-  * functions even if they could respond.
 
-  *
 
-  * The other difference is that _route_ path is stripped and not visible
 
-  * to the handler function. The main effect of this feature is that mounted
 
-  * handlers can operate without any code changes regardless of the "prefix"
 
-  * pathname.
 
-  *
 
-  * @public
 
-  */
 
- proto.use = function use(fn) {
 
-   var offset = 0;
 
-   var path = '/';
 
-   // default path to '/'
 
-   // disambiguate router.use([fn])
 
-   if (typeof fn !== 'function') {
 
-     var arg = fn;
 
-     while (Array.isArray(arg) && arg.length !== 0) {
 
-       arg = arg[0];
 
-     }
 
-     // first arg is the path
 
-     if (typeof arg !== 'function') {
 
-       offset = 1;
 
-       path = fn;
 
-     }
 
-   }
 
-   var callbacks = flatten(slice.call(arguments, offset));
 
-   if (callbacks.length === 0) {
 
-     throw new TypeError('Router.use() requires a middleware function')
 
-   }
 
-   for (var i = 0; i < callbacks.length; i++) {
 
-     var fn = callbacks[i];
 
-     if (typeof fn !== 'function') {
 
-       throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))
 
-     }
 
-     // add the middleware
 
-     debug('use %o %s', path, fn.name || '<anonymous>')
 
-     var layer = new Layer(path, {
 
-       sensitive: this.caseSensitive,
 
-       strict: false,
 
-       end: false
 
-     }, fn);
 
-     layer.route = undefined;
 
-     this.stack.push(layer);
 
-   }
 
-   return this;
 
- };
 
- /**
 
-  * Create a new Route for the given path.
 
-  *
 
-  * Each route contains a separate middleware stack and VERB handlers.
 
-  *
 
-  * See the Route api documentation for details on adding handlers
 
-  * and middleware to routes.
 
-  *
 
-  * @param {String} path
 
-  * @return {Route}
 
-  * @public
 
-  */
 
- proto.route = function route(path) {
 
-   var route = new Route(path);
 
-   var layer = new Layer(path, {
 
-     sensitive: this.caseSensitive,
 
-     strict: this.strict,
 
-     end: true
 
-   }, route.dispatch.bind(route));
 
-   layer.route = route;
 
-   this.stack.push(layer);
 
-   return route;
 
- };
 
- // create Router#VERB functions
 
- methods.concat('all').forEach(function(method){
 
-   proto[method] = function(path){
 
-     var route = this.route(path)
 
-     route[method].apply(route, slice.call(arguments, 1));
 
-     return this;
 
-   };
 
- });
 
- // append methods to a list of methods
 
- function appendMethods(list, addition) {
 
-   for (var i = 0; i < addition.length; i++) {
 
-     var method = addition[i];
 
-     if (list.indexOf(method) === -1) {
 
-       list.push(method);
 
-     }
 
-   }
 
- }
 
- // get pathname of request
 
- function getPathname(req) {
 
-   try {
 
-     return parseUrl(req).pathname;
 
-   } catch (err) {
 
-     return undefined;
 
-   }
 
- }
 
- // Get get protocol + host for a URL
 
- function getProtohost(url) {
 
-   if (typeof url !== 'string' || url.length === 0 || url[0] === '/') {
 
-     return undefined
 
-   }
 
-   var searchIndex = url.indexOf('?')
 
-   var pathLength = searchIndex !== -1
 
-     ? searchIndex
 
-     : url.length
 
-   var fqdnIndex = url.slice(0, pathLength).indexOf('://')
 
-   return fqdnIndex !== -1
 
-     ? url.substring(0, url.indexOf('/', 3 + fqdnIndex))
 
-     : undefined
 
- }
 
- // get type for error message
 
- function gettype(obj) {
 
-   var type = typeof obj;
 
-   if (type !== 'object') {
 
-     return type;
 
-   }
 
-   // inspect [[Class]] for objects
 
-   return toString.call(obj)
 
-     .replace(objectRegExp, '$1');
 
- }
 
- /**
 
-  * Match path to a layer.
 
-  *
 
-  * @param {Layer} layer
 
-  * @param {string} path
 
-  * @private
 
-  */
 
- function matchLayer(layer, path) {
 
-   try {
 
-     return layer.match(path);
 
-   } catch (err) {
 
-     return err;
 
-   }
 
- }
 
- // merge params with parent params
 
- function mergeParams(params, parent) {
 
-   if (typeof parent !== 'object' || !parent) {
 
-     return params;
 
-   }
 
-   // make copy of parent for base
 
-   var obj = mixin({}, parent);
 
-   // simple non-numeric merging
 
-   if (!(0 in params) || !(0 in parent)) {
 
-     return mixin(obj, params);
 
-   }
 
-   var i = 0;
 
-   var o = 0;
 
-   // determine numeric gaps
 
-   while (i in params) {
 
-     i++;
 
-   }
 
-   while (o in parent) {
 
-     o++;
 
-   }
 
-   // offset numeric indices in params before merge
 
-   for (i--; i >= 0; i--) {
 
-     params[i + o] = params[i];
 
-     // create holes for the merge when necessary
 
-     if (i < o) {
 
-       delete params[i];
 
-     }
 
-   }
 
-   return mixin(obj, params);
 
- }
 
- // restore obj props after function
 
- function restore(fn, obj) {
 
-   var props = new Array(arguments.length - 2);
 
-   var vals = new Array(arguments.length - 2);
 
-   for (var i = 0; i < props.length; i++) {
 
-     props[i] = arguments[i + 2];
 
-     vals[i] = obj[props[i]];
 
-   }
 
-   return function () {
 
-     // restore vals
 
-     for (var i = 0; i < props.length; i++) {
 
-       obj[props[i]] = vals[i];
 
-     }
 
-     return fn.apply(this, arguments);
 
-   };
 
- }
 
- // send an OPTIONS response
 
- function sendOptionsResponse(res, options, next) {
 
-   try {
 
-     var body = options.join(',');
 
-     res.set('Allow', body);
 
-     res.send(body);
 
-   } catch (err) {
 
-     next(err);
 
-   }
 
- }
 
- // wrap a function
 
- function wrap(old, fn) {
 
-   return function proxy() {
 
-     var args = new Array(arguments.length + 1);
 
-     args[0] = old;
 
-     for (var i = 0, len = arguments.length; i < len; i++) {
 
-       args[i + 1] = arguments[i];
 
-     }
 
-     fn.apply(this, args);
 
-   };
 
- }
 
 
  |