| /*! |
| * 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 callback functions 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 callback functions 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; |
| }; |
| }); |