You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					217 lines
				
				4.1 KiB
			
		
		
			
		
	
	
					217 lines
				
				4.1 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								/*!
							 | 
						||
| 
								 | 
							
								 * 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 debug = require('debug')('express:router:route');
							 | 
						||
| 
								 | 
							
								var flatten = require('array-flatten');
							 | 
						||
| 
								 | 
							
								var Layer = require('./layer');
							 | 
						||
| 
								 | 
							
								var methods = require('methods');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Module variables.
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var slice = Array.prototype.slice;
							 | 
						||
| 
								 | 
							
								var toString = Object.prototype.toString;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Module exports.
							 | 
						||
| 
								 | 
							
								 * @public
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = Route;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Initialize `Route` with the given `path`,
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {String} path
							 | 
						||
| 
								 | 
							
								 * @public
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function Route(path) {
							 | 
						||
| 
								 | 
							
								  this.path = path;
							 | 
						||
| 
								 | 
							
								  this.stack = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  debug('new %o', path)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // route handlers for various http methods
							 | 
						||
| 
								 | 
							
								  this.methods = {};
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Determine if the route handles a given method.
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Route.prototype._handles_method = function _handles_method(method) {
							 | 
						||
| 
								 | 
							
								  if (this.methods._all) {
							 | 
						||
| 
								 | 
							
								    return true;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var name = method.toLowerCase();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (name === 'head' && !this.methods['head']) {
							 | 
						||
| 
								 | 
							
								    name = 'get';
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return Boolean(this.methods[name]);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * @return {Array} supported HTTP methods
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Route.prototype._options = function _options() {
							 | 
						||
| 
								 | 
							
								  var methods = Object.keys(this.methods);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // append automatic head
							 | 
						||
| 
								 | 
							
								  if (this.methods.get && !this.methods.head) {
							 | 
						||
| 
								 | 
							
								    methods.push('head');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (var i = 0; i < methods.length; i++) {
							 | 
						||
| 
								 | 
							
								    // make upper case
							 | 
						||
| 
								 | 
							
								    methods[i] = methods[i].toUpperCase();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return methods;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * dispatch req, res into this route
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Route.prototype.dispatch = function dispatch(req, res, done) {
							 | 
						||
| 
								 | 
							
								  var idx = 0;
							 | 
						||
| 
								 | 
							
								  var stack = this.stack;
							 | 
						||
| 
								 | 
							
								  if (stack.length === 0) {
							 | 
						||
| 
								 | 
							
								    return done();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var method = req.method.toLowerCase();
							 | 
						||
| 
								 | 
							
								  if (method === 'head' && !this.methods['head']) {
							 | 
						||
| 
								 | 
							
								    method = 'get';
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  req.route = this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  next();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function next(err) {
							 | 
						||
| 
								 | 
							
								    // signal to exit route
							 | 
						||
| 
								 | 
							
								    if (err && err === 'route') {
							 | 
						||
| 
								 | 
							
								      return done();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // signal to exit router
							 | 
						||
| 
								 | 
							
								    if (err && err === 'router') {
							 | 
						||
| 
								 | 
							
								      return done(err)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var layer = stack[idx++];
							 | 
						||
| 
								 | 
							
								    if (!layer) {
							 | 
						||
| 
								 | 
							
								      return done(err);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (layer.method && layer.method !== method) {
							 | 
						||
| 
								 | 
							
								      return next(err);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (err) {
							 | 
						||
| 
								 | 
							
								      layer.handle_error(err, req, res, next);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      layer.handle_request(req, res, next);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Add a handler for all HTTP verbs to this route.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Behaves just like middleware and can respond or call `next`
							 | 
						||
| 
								 | 
							
								 * to continue processing.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * You can use multiple `.all` call to add multiple handlers.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *   function check_something(req, res, next){
							 | 
						||
| 
								 | 
							
								 *     next();
							 | 
						||
| 
								 | 
							
								 *   };
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *   function validate_user(req, res, next){
							 | 
						||
| 
								 | 
							
								 *     next();
							 | 
						||
| 
								 | 
							
								 *   };
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *   route
							 | 
						||
| 
								 | 
							
								 *   .all(validate_user)
							 | 
						||
| 
								 | 
							
								 *   .all(check_something)
							 | 
						||
| 
								 | 
							
								 *   .get(function(req, res, next){
							 | 
						||
| 
								 | 
							
								 *     res.send('hello world');
							 | 
						||
| 
								 | 
							
								 *   });
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {function} handler
							 | 
						||
| 
								 | 
							
								 * @return {Route} for chaining
							 | 
						||
| 
								 | 
							
								 * @api public
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Route.prototype.all = function all() {
							 | 
						||
| 
								 | 
							
								  var handles = flatten(slice.call(arguments));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (var i = 0; i < handles.length; i++) {
							 | 
						||
| 
								 | 
							
								    var handle = handles[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (typeof handle !== 'function') {
							 | 
						||
| 
								 | 
							
								      var type = toString.call(handle);
							 | 
						||
| 
								 | 
							
								      var msg = 'Route.all() requires a callback function but got a ' + type
							 | 
						||
| 
								 | 
							
								      throw new TypeError(msg);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var layer = Layer('/', {}, handle);
							 | 
						||
| 
								 | 
							
								    layer.method = undefined;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    this.methods._all = true;
							 | 
						||
| 
								 | 
							
								    this.stack.push(layer);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return this;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								methods.forEach(function(method){
							 | 
						||
| 
								 | 
							
								  Route.prototype[method] = function(){
							 | 
						||
| 
								 | 
							
								    var handles = flatten(slice.call(arguments));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (var i = 0; i < handles.length; i++) {
							 | 
						||
| 
								 | 
							
								      var handle = handles[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (typeof handle !== 'function') {
							 | 
						||
| 
								 | 
							
								        var type = toString.call(handle);
							 | 
						||
| 
								 | 
							
								        var msg = 'Route.' + method + '() requires a callback function but got a ' + type
							 | 
						||
| 
								 | 
							
								        throw new Error(msg);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      debug('%s %o', method, this.path)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      var layer = Layer('/', {}, handle);
							 | 
						||
| 
								 | 
							
								      layer.method = method;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      this.methods[method] = true;
							 | 
						||
| 
								 | 
							
								      this.stack.push(layer);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return this;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								});
							 |