rc@73: /** rc@73: * Module dependencies. rc@73: */ rc@73: rc@73: var debug = require('debug')('express:router:route'); rc@73: var methods = require('methods'); rc@73: var utils = require('../utils'); rc@73: rc@73: /** rc@73: * Expose `Route`. rc@73: */ rc@73: rc@73: module.exports = Route; rc@73: rc@73: /** rc@73: * Initialize `Route` with the given `path`, rc@73: * rc@73: * @param {String} path rc@73: * @api private rc@73: */ rc@73: rc@73: function Route(path) { rc@73: debug('new %s', path); rc@73: this.path = path; rc@73: this.stack = undefined; rc@73: rc@73: // route handlers for various http methods rc@73: this.methods = {}; rc@73: } rc@73: rc@73: /** rc@73: * @return {Array} supported HTTP methods rc@73: * @api private rc@73: */ rc@73: rc@73: Route.prototype._options = function(){ rc@73: return Object.keys(this.methods).map(function(method) { rc@73: return method.toUpperCase(); rc@73: }); rc@73: }; rc@73: rc@73: /** rc@73: * dispatch req, res into this route rc@73: * rc@73: * @api private rc@73: */ rc@73: rc@73: Route.prototype.dispatch = function(req, res, done){ rc@73: var self = this; rc@73: var method = req.method.toLowerCase(); rc@73: rc@73: if (method === 'head' && !this.methods['head']) { rc@73: method = 'get'; rc@73: } rc@73: rc@73: req.route = self; rc@73: rc@73: // single middleware route case rc@73: if (typeof this.stack === 'function') { rc@73: this.stack(req, res, done); rc@73: return; rc@73: } rc@73: rc@73: var stack = self.stack; rc@73: if (!stack) { rc@73: return done(); rc@73: } rc@73: rc@73: var idx = 0; rc@73: (function next_layer(err) { rc@73: if (err && err === 'route') { rc@73: return done(); rc@73: } rc@73: rc@73: var layer = stack[idx++]; rc@73: if (!layer) { rc@73: return done(err); rc@73: } rc@73: rc@73: if (layer.method && layer.method !== method) { rc@73: return next_layer(err); rc@73: } rc@73: rc@73: var arity = layer.handle.length; rc@73: if (err) { rc@73: if (arity < 4) { rc@73: return next_layer(err); rc@73: } rc@73: rc@73: try { rc@73: layer.handle(err, req, res, next_layer); rc@73: } catch (err) { rc@73: next_layer(err); rc@73: } rc@73: return; rc@73: } rc@73: rc@73: if (arity > 3) { rc@73: return next_layer(); rc@73: } rc@73: rc@73: try { rc@73: layer.handle(req, res, next_layer); rc@73: } catch (err) { rc@73: next_layer(err); rc@73: } rc@73: })(); rc@73: }; rc@73: rc@73: /** rc@73: * Add a handler for all HTTP verbs to this route. rc@73: * rc@73: * Behaves just like middleware and can respond or call `next` rc@73: * to continue processing. rc@73: * rc@73: * You can use multiple `.all` call to add multiple handlers. rc@73: * rc@73: * function check_something(req, res, next){ rc@73: * next(); rc@73: * }; rc@73: * rc@73: * function validate_user(req, res, next){ rc@73: * next(); rc@73: * }; rc@73: * rc@73: * route rc@73: * .all(validate_user) rc@73: * .all(check_something) rc@73: * .get(function(req, res, next){ rc@73: * res.send('hello world'); rc@73: * }); rc@73: * rc@73: * @param {function} handler rc@73: * @return {Route} for chaining rc@73: * @api public rc@73: */ rc@73: rc@73: Route.prototype.all = function(){ rc@73: var self = this; rc@73: var callbacks = utils.flatten([].slice.call(arguments)); rc@73: callbacks.forEach(function(fn) { rc@73: if (typeof fn !== 'function') { rc@73: var type = {}.toString.call(fn); rc@73: var msg = 'Route.all() requires callback functions but got a ' + type; rc@73: throw new Error(msg); rc@73: } rc@73: rc@73: if (!self.stack) { rc@73: self.stack = fn; rc@73: } rc@73: else if (typeof self.stack === 'function') { rc@73: self.stack = [{ handle: self.stack }, { handle: fn }]; rc@73: } rc@73: else { rc@73: self.stack.push({ handle: fn }); rc@73: } rc@73: }); rc@73: rc@73: return self; rc@73: }; rc@73: rc@73: methods.forEach(function(method){ rc@73: Route.prototype[method] = function(){ rc@73: var self = this; rc@73: var callbacks = utils.flatten([].slice.call(arguments)); rc@73: rc@73: callbacks.forEach(function(fn) { rc@73: if (typeof fn !== 'function') { rc@73: var type = {}.toString.call(fn); rc@73: var msg = 'Route.' + method + '() requires callback functions but got a ' + type; rc@73: throw new Error(msg); rc@73: } rc@73: rc@73: debug('%s %s', method, self.path); rc@73: rc@73: if (!self.methods[method]) { rc@73: self.methods[method] = true; rc@73: } rc@73: rc@73: if (!self.stack) { rc@73: self.stack = []; rc@73: } rc@73: else if (typeof self.stack === 'function') { rc@73: self.stack = [{ handle: self.stack }]; rc@73: } rc@73: rc@73: self.stack.push({ method: method, handle: fn }); rc@73: }); rc@73: return self; rc@73: }; rc@73: });