arnaucube
arnaucube/comunicationLeapPublic Self-hosted repository
comunicationLeap/node_modules/express/lib/router/index.js
node_modules/express/lib/router/index.jsRaw
  1/**
  2 * Module dependencies.
  3 */
  4
  5var Route = require('./route')
  6  , utils = require('../utils')
  7  , methods = require('methods')
  8  , debug = require('debug')('express:router')
  9  , parse = require('connect').utils.parseUrl;
 10
 11/**
 12 * Expose `Router` constructor.
 13 */
 14
 15exports = module.exports = Router;
 16
 17/**
 18 * Initialize a new `Router` with the given `options`.
 19 *
 20 * @param {Object} options
 21 * @api private
 22 */
 23
 24function Router(options) {
 25  options = options || {};
 26  var self = this;
 27  this.map = {};
 28  this.params = {};
 29  this._params = [];
 30  this.caseSensitive = options.caseSensitive;
 31  this.strict = options.strict;
 32  this.middleware = function router(req, res, next){
 33    self._dispatch(req, res, next);
 34  };
 35}
 36
 37/**
 38 * Register a param callback `fn` for the given `name`.
 39 *
 40 * @param {String|Function} name
 41 * @param {Function} fn
 42 * @return {Router} for chaining
 43 * @api public
 44 */
 45
 46Router.prototype.param = function(name, fn){
 47  // param logic
 48  if ('function' == typeof name) {
 49    this._params.push(name);
 50    return;
 51  }
 52
 53  // apply param functions
 54  var params = this._params
 55    , len = params.length
 56    , ret;
 57
 58  for (var i = 0; i < len; ++i) {
 59    if (ret = params[i](name, fn)) {
 60      fn = ret;
 61    }
 62  }
 63
 64  // ensure we end up with a
 65  // middleware function
 66  if ('function' != typeof fn) {
 67    throw new Error('invalid param() call for ' + name + ', got ' + fn);
 68  }
 69
 70  (this.params[name] = this.params[name] || []).push(fn);
 71  return this;
 72};
 73
 74/**
 75 * Route dispatcher aka the route "middleware".
 76 *
 77 * @param {IncomingMessage} req
 78 * @param {ServerResponse} res
 79 * @param {Function} next
 80 * @api private
 81 */
 82
 83Router.prototype._dispatch = function(req, res, next){
 84  var params = this.params
 85    , self = this;
 86
 87  debug('dispatching %s %s (%s)', req.method, req.url, req.originalUrl);
 88
 89  // route dispatch
 90  (function pass(i, err){
 91    var paramCallbacks
 92      , paramIndex = 0
 93      , paramVal
 94      , route
 95      , keys
 96      , key;
 97
 98    // match next route
 99    function nextRoute(err) {
100      pass(req._route_index + 1, err);
101    }
102
103    // match route
104    req.route = route = self.matchRequest(req, i);
105
106    // no route
107    if (!route) return next(err);
108    debug('matched %s %s', route.method, route.path);
109
110    // we have a route
111    // start at param 0
112    req.params = route.params;
113    keys = route.keys;
114    i = 0;
115
116    // param callbacks
117    function param(err) {
118      paramIndex = 0;
119      key = keys[i++];
120      paramVal = key && req.params[key.name];
121      paramCallbacks = key && params[key.name];
122
123      try {
124        if ('route' == err) {
125          nextRoute();
126        } else if (err) {
127          i = 0;
128          callbacks(err);
129        } else if (paramCallbacks && undefined !== paramVal) {
130          paramCallback();
131        } else if (key) {
132          param();
133        } else {
134          i = 0;
135          callbacks();
136        }
137      } catch (err) {
138        param(err);
139      }
140    };
141
142    param(err);
143
144    // single param callbacks
145    function paramCallback(err) {
146      var fn = paramCallbacks[paramIndex++];
147      if (err || !fn) return param(err);
148      fn(req, res, paramCallback, paramVal, key.name);
149    }
150
151    // invoke route callbacks
152    function callbacks(err) {
153      var fn = route.callbacks[i++];
154      try {
155        if ('route' == err) {
156          nextRoute();
157        } else if (err && fn) {
158          if (fn.length < 4) return callbacks(err);
159          fn(err, req, res, callbacks);
160        } else if (fn) {
161          if (fn.length < 4) return fn(req, res, callbacks);
162          callbacks();
163        } else {
164          nextRoute(err);
165        }
166      } catch (err) {
167        callbacks(err);
168      }
169    }
170  })(0);
171};
172
173/**
174 * Attempt to match a route for `req`
175 * with optional starting index of `i`
176 * defaulting to 0.
177 *
178 * @param {IncomingMessage} req
179 * @param {Number} i
180 * @return {Route}
181 * @api private
182 */
183
184Router.prototype.matchRequest = function(req, i, head){
185  var method = req.method.toLowerCase()
186    , url = parse(req)
187    , path = url.pathname
188    , routes = this.map
189    , i = i || 0
190    , route;
191
192  // HEAD support
193  if (!head && 'head' == method) {
194    route = this.matchRequest(req, i, true);
195    if (route) return route;
196     method = 'get';
197  }
198
199  // routes for this method
200  if (routes = routes[method]) {
201
202    // matching routes
203    for (var len = routes.length; i < len; ++i) {
204      route = routes[i];
205      if (route.match(path)) {
206        req._route_index = i;
207        return route;
208      }
209    }
210  }
211};
212
213/**
214 * Attempt to match a route for `method`
215 * and `url` with optional starting
216 * index of `i` defaulting to 0.
217 *
218 * @param {String} method
219 * @param {String} url
220 * @param {Number} i
221 * @return {Route}
222 * @api private
223 */
224
225Router.prototype.match = function(method, url, i, head){
226  var req = { method: method, url: url };
227  return  this.matchRequest(req, i, head);
228};
229
230/**
231 * Route `method`, `path`, and one or more callbacks.
232 *
233 * @param {String} method
234 * @param {String} path
235 * @param {Function} callback...
236 * @return {Router} for chaining
237 * @api private
238 */
239
240Router.prototype.route = function(method, path, callbacks){
241  var method = method.toLowerCase()
242    , callbacks = utils.flatten([].slice.call(arguments, 2));
243
244  // ensure path was given
245  if (!path) throw new Error('Router#' + method + '() requires a path');
246
247  // ensure all callbacks are functions
248  callbacks.forEach(function(fn, i){
249    if ('function' == typeof fn) return;
250    var type = {}.toString.call(fn);
251    var msg = '.' + method + '() requires callback functions but got a ' + type;
252    throw new Error(msg);
253  });
254
255  // create the route
256  debug('defined %s %s', method, path);
257  var route = new Route(method, path, callbacks, {
258    sensitive: this.caseSensitive,
259    strict: this.strict
260  });
261
262  // add it
263  (this.map[method] = this.map[method] || []).push(route);
264  return this;
265};
266
267methods.forEach(function(method){
268  Router.prototype[method] = function(path){
269    var args = [method].concat([].slice.call(arguments));
270    this.route.apply(this, args);
271    return this;
272  };
273});