second
[josuexyz/.git] / node_modules / express / lib / router / layer.js
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 pathRegexp = require('path-to-regexp');
17 var debug = require('debug')('express:router:layer');
18
19 /**
20  * Module variables.
21  * @private
22  */
23
24 var hasOwnProperty = Object.prototype.hasOwnProperty;
25
26 /**
27  * Module exports.
28  * @public
29  */
30
31 module.exports = Layer;
32
33 function Layer(path, options, fn) {
34   if (!(this instanceof Layer)) {
35     return new Layer(path, options, fn);
36   }
37
38   debug('new %o', path)
39   var opts = options || {};
40
41   this.handle = fn;
42   this.name = fn.name || '<anonymous>';
43   this.params = undefined;
44   this.path = undefined;
45   this.regexp = pathRegexp(path, this.keys = [], opts);
46
47   // set fast path flags
48   this.regexp.fast_star = path === '*'
49   this.regexp.fast_slash = path === '/' && opts.end === false
50 }
51
52 /**
53  * Handle the error for the layer.
54  *
55  * @param {Error} error
56  * @param {Request} req
57  * @param {Response} res
58  * @param {function} next
59  * @api private
60  */
61
62 Layer.prototype.handle_error = function handle_error(error, req, res, next) {
63   var fn = this.handle;
64
65   if (fn.length !== 4) {
66     // not a standard error handler
67     return next(error);
68   }
69
70   try {
71     fn(error, req, res, next);
72   } catch (err) {
73     next(err);
74   }
75 };
76
77 /**
78  * Handle the request for the layer.
79  *
80  * @param {Request} req
81  * @param {Response} res
82  * @param {function} next
83  * @api private
84  */
85
86 Layer.prototype.handle_request = function handle(req, res, next) {
87   var fn = this.handle;
88
89   if (fn.length > 3) {
90     // not a standard request handler
91     return next();
92   }
93
94   try {
95     fn(req, res, next);
96   } catch (err) {
97     next(err);
98   }
99 };
100
101 /**
102  * Check if this route matches `path`, if so
103  * populate `.params`.
104  *
105  * @param {String} path
106  * @return {Boolean}
107  * @api private
108  */
109
110 Layer.prototype.match = function match(path) {
111   var match
112
113   if (path != null) {
114     // fast path non-ending match for / (any path matches)
115     if (this.regexp.fast_slash) {
116       this.params = {}
117       this.path = ''
118       return true
119     }
120
121     // fast path for * (everything matched in a param)
122     if (this.regexp.fast_star) {
123       this.params = {'0': decode_param(path)}
124       this.path = path
125       return true
126     }
127
128     // match the path
129     match = this.regexp.exec(path)
130   }
131
132   if (!match) {
133     this.params = undefined;
134     this.path = undefined;
135     return false;
136   }
137
138   // store values
139   this.params = {};
140   this.path = match[0]
141
142   var keys = this.keys;
143   var params = this.params;
144
145   for (var i = 1; i < match.length; i++) {
146     var key = keys[i - 1];
147     var prop = key.name;
148     var val = decode_param(match[i])
149
150     if (val !== undefined || !(hasOwnProperty.call(params, prop))) {
151       params[prop] = val;
152     }
153   }
154
155   return true;
156 };
157
158 /**
159  * Decode param value.
160  *
161  * @param {string} val
162  * @return {string}
163  * @private
164  */
165
166 function decode_param(val) {
167   if (typeof val !== 'string' || val.length === 0) {
168     return val;
169   }
170
171   try {
172     return decodeURIComponent(val);
173   } catch (err) {
174     if (err instanceof URIError) {
175       err.message = 'Failed to decode param \'' + val + '\'';
176       err.status = err.statusCode = 400;
177     }
178
179     throw err;
180   }
181 }