thoughts/node_modules/express/lib/router/layer.js
node_modules/express/lib/router/layer.jsRaw
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
16var pathRegexp = require('path-to-regexp');
17var debug = require('debug')('express:router:layer');
18
19/**
20 * Module variables.
21 * @private
22 */
23
24var hasOwnProperty = Object.prototype.hasOwnProperty;
25
26/**
27 * Module exports.
28 * @public
29 */
30
31module.exports = Layer;
32
33function Layer(path, options, fn) {
34 if (!(this instanceof Layer)) {
35 return new Layer(path, options, fn);
36 }
37
38 debug('new %s', 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 if (path === '/' && opts.end === false) {
48 this.regexp.fast_slash = true;
49 }
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
62Layer.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
86Layer.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
110Layer.prototype.match = function match(path) {
111 if (path == null) {
112 // no path, nothing matches
113 this.params = undefined;
114 this.path = undefined;
115 return false;
116 }
117
118 if (this.regexp.fast_slash) {
119 // fast path non-ending match for / (everything matches)
120 this.params = {};
121 this.path = '';
122 return true;
123 }
124
125 var m = this.regexp.exec(path);
126
127 if (!m) {
128 this.params = undefined;
129 this.path = undefined;
130 return false;
131 }
132
133 // store values
134 this.params = {};
135 this.path = m[0];
136
137 var keys = this.keys;
138 var params = this.params;
139
140 for (var i = 1; i < m.length; i++) {
141 var key = keys[i - 1];
142 var prop = key.name;
143 var val = decode_param(m[i]);
144
145 if (val !== undefined || !(hasOwnProperty.call(params, prop))) {
146 params[prop] = val;
147 }
148 }
149
150 return true;
151};
152
153/**
154 * Decode param value.
155 *
156 * @param {string} val
157 * @return {string}
158 * @private
159 */
160
161function decode_param(val) {
162 if (typeof val !== 'string' || val.length === 0) {
163 return val;
164 }
165
166 try {
167 return decodeURIComponent(val);
168 } catch (err) {
169 if (err instanceof URIError) {
170 err.message = 'Failed to decode param \'' + val + '\'';
171 err.status = err.statusCode = 400;
172 }
173
174 throw err;
175 }
176}