twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

route.js (4149B)


      1 /*!
      2  * express
      3  * Copyright(c) 2009-2013 TJ Holowaychuk
      4  * Copyright(c) 2013 Roman Shtylman
      5  * Copyright(c) 2014-2015 Douglas Christopher Wilson
      6  * MIT Licensed
      7  */
      8 
      9 'use strict';
     10 
     11 /**
     12  * Module dependencies.
     13  * @private
     14  */
     15 
     16 var debug = require('debug')('express:router:route');
     17 var flatten = require('array-flatten');
     18 var Layer = require('./layer');
     19 var methods = require('methods');
     20 
     21 /**
     22  * Module variables.
     23  * @private
     24  */
     25 
     26 var slice = Array.prototype.slice;
     27 var toString = Object.prototype.toString;
     28 
     29 /**
     30  * Module exports.
     31  * @public
     32  */
     33 
     34 module.exports = Route;
     35 
     36 /**
     37  * Initialize `Route` with the given `path`,
     38  *
     39  * @param {String} path
     40  * @public
     41  */
     42 
     43 function Route(path) {
     44   this.path = path;
     45   this.stack = [];
     46 
     47   debug('new %o', path)
     48 
     49   // route handlers for various http methods
     50   this.methods = {};
     51 }
     52 
     53 /**
     54  * Determine if the route handles a given method.
     55  * @private
     56  */
     57 
     58 Route.prototype._handles_method = function _handles_method(method) {
     59   if (this.methods._all) {
     60     return true;
     61   }
     62 
     63   var name = method.toLowerCase();
     64 
     65   if (name === 'head' && !this.methods['head']) {
     66     name = 'get';
     67   }
     68 
     69   return Boolean(this.methods[name]);
     70 };
     71 
     72 /**
     73  * @return {Array} supported HTTP methods
     74  * @private
     75  */
     76 
     77 Route.prototype._options = function _options() {
     78   var methods = Object.keys(this.methods);
     79 
     80   // append automatic head
     81   if (this.methods.get && !this.methods.head) {
     82     methods.push('head');
     83   }
     84 
     85   for (var i = 0; i < methods.length; i++) {
     86     // make upper case
     87     methods[i] = methods[i].toUpperCase();
     88   }
     89 
     90   return methods;
     91 };
     92 
     93 /**
     94  * dispatch req, res into this route
     95  * @private
     96  */
     97 
     98 Route.prototype.dispatch = function dispatch(req, res, done) {
     99   var idx = 0;
    100   var stack = this.stack;
    101   if (stack.length === 0) {
    102     return done();
    103   }
    104 
    105   var method = req.method.toLowerCase();
    106   if (method === 'head' && !this.methods['head']) {
    107     method = 'get';
    108   }
    109 
    110   req.route = this;
    111 
    112   next();
    113 
    114   function next(err) {
    115     // signal to exit route
    116     if (err && err === 'route') {
    117       return done();
    118     }
    119 
    120     // signal to exit router
    121     if (err && err === 'router') {
    122       return done(err)
    123     }
    124 
    125     var layer = stack[idx++];
    126     if (!layer) {
    127       return done(err);
    128     }
    129 
    130     if (layer.method && layer.method !== method) {
    131       return next(err);
    132     }
    133 
    134     if (err) {
    135       layer.handle_error(err, req, res, next);
    136     } else {
    137       layer.handle_request(req, res, next);
    138     }
    139   }
    140 };
    141 
    142 /**
    143  * Add a handler for all HTTP verbs to this route.
    144  *
    145  * Behaves just like middleware and can respond or call `next`
    146  * to continue processing.
    147  *
    148  * You can use multiple `.all` call to add multiple handlers.
    149  *
    150  *   function check_something(req, res, next){
    151  *     next();
    152  *   };
    153  *
    154  *   function validate_user(req, res, next){
    155  *     next();
    156  *   };
    157  *
    158  *   route
    159  *   .all(validate_user)
    160  *   .all(check_something)
    161  *   .get(function(req, res, next){
    162  *     res.send('hello world');
    163  *   });
    164  *
    165  * @param {function} handler
    166  * @return {Route} for chaining
    167  * @api public
    168  */
    169 
    170 Route.prototype.all = function all() {
    171   var handles = flatten(slice.call(arguments));
    172 
    173   for (var i = 0; i < handles.length; i++) {
    174     var handle = handles[i];
    175 
    176     if (typeof handle !== 'function') {
    177       var type = toString.call(handle);
    178       var msg = 'Route.all() requires a callback function but got a ' + type
    179       throw new TypeError(msg);
    180     }
    181 
    182     var layer = Layer('/', {}, handle);
    183     layer.method = undefined;
    184 
    185     this.methods._all = true;
    186     this.stack.push(layer);
    187   }
    188 
    189   return this;
    190 };
    191 
    192 methods.forEach(function(method){
    193   Route.prototype[method] = function(){
    194     var handles = flatten(slice.call(arguments));
    195 
    196     for (var i = 0; i < handles.length; i++) {
    197       var handle = handles[i];
    198 
    199       if (typeof handle !== 'function') {
    200         var type = toString.call(handle);
    201         var msg = 'Route.' + method + '() requires a callback function but got a ' + type
    202         throw new Error(msg);
    203       }
    204 
    205       debug('%s %o', method, this.path)
    206 
    207       var layer = Layer('/', {}, handle);
    208       layer.method = method;
    209 
    210       this.methods[method] = true;
    211       this.stack.push(layer);
    212     }
    213 
    214     return this;
    215   };
    216 });