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