@mila.solutions/express 5.2.1-mila.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +25 -0
- package/Readme.md +212 -0
- package/index.js +11 -0
- package/lib/application.js +694 -0
- package/lib/express.js +81 -0
- package/lib/request.js +527 -0
- package/lib/response.js +1186 -0
- package/lib/schema-serializer.js +102 -0
- package/lib/utils.js +271 -0
- package/lib/view.js +205 -0
- package/package.json +99 -0
|
@@ -0,0 +1,694 @@
|
|
|
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 finalhandler = require('finalhandler');
|
|
17
|
+
var debug = require('debug')('express:application');
|
|
18
|
+
var View = require('./view');
|
|
19
|
+
var http = require('node:http');
|
|
20
|
+
var methods = require('./utils').methods;
|
|
21
|
+
var compileETag = require('./utils').compileETag;
|
|
22
|
+
var compileQueryParser = require('./utils').compileQueryParser;
|
|
23
|
+
var compileTrust = require('./utils').compileTrust;
|
|
24
|
+
var resolve = require('node:path').resolve;
|
|
25
|
+
var once = require('once')
|
|
26
|
+
var Router = require('router');
|
|
27
|
+
var schemaSerializer = require('./schema-serializer');
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Module variables.
|
|
31
|
+
* @private
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
var slice = Array.prototype.slice;
|
|
35
|
+
var flatten = Array.prototype.flat;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Application prototype.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
var app = exports = module.exports = {};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Variable for trust proxy inheritance back-compat
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
var trustProxyDefaultSymbol = '@@symbol:trust_proxy_default';
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Initialize the server.
|
|
52
|
+
*
|
|
53
|
+
* - setup default configuration
|
|
54
|
+
* - setup default middleware
|
|
55
|
+
* - setup route reflection methods
|
|
56
|
+
*
|
|
57
|
+
* @private
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
app.init = function init() {
|
|
61
|
+
var router = null;
|
|
62
|
+
|
|
63
|
+
this.cache = Object.create(null);
|
|
64
|
+
this.engines = Object.create(null);
|
|
65
|
+
this.settings = Object.create(null);
|
|
66
|
+
this._jsonSettingsCache = null;
|
|
67
|
+
this._boundLogError = logerror.bind(this);
|
|
68
|
+
|
|
69
|
+
this.defaultConfiguration();
|
|
70
|
+
|
|
71
|
+
// Setup getting to lazily add base router
|
|
72
|
+
Object.defineProperty(this, 'router', {
|
|
73
|
+
configurable: true,
|
|
74
|
+
enumerable: true,
|
|
75
|
+
get: function getrouter() {
|
|
76
|
+
if (router === null) {
|
|
77
|
+
router = new Router({
|
|
78
|
+
caseSensitive: this.enabled('case sensitive routing'),
|
|
79
|
+
strict: this.enabled('strict routing')
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return router;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Initialize application configuration.
|
|
90
|
+
* @private
|
|
91
|
+
*/
|
|
92
|
+
|
|
93
|
+
app.defaultConfiguration = function defaultConfiguration() {
|
|
94
|
+
var env = process.env.NODE_ENV || 'development';
|
|
95
|
+
|
|
96
|
+
// default settings
|
|
97
|
+
this.enable('x-powered-by');
|
|
98
|
+
this.set('etag', 'weak');
|
|
99
|
+
this.set('env', env);
|
|
100
|
+
this.set('query parser', 'simple')
|
|
101
|
+
this.set('subdomain offset', 2);
|
|
102
|
+
this.set('trust proxy', false);
|
|
103
|
+
|
|
104
|
+
// trust proxy inherit back-compat
|
|
105
|
+
Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
|
|
106
|
+
configurable: true,
|
|
107
|
+
value: true
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
debug('booting in %s mode', env);
|
|
111
|
+
|
|
112
|
+
this.on('mount', function onmount(parent) {
|
|
113
|
+
// inherit trust proxy
|
|
114
|
+
if (this.settings[trustProxyDefaultSymbol] === true
|
|
115
|
+
&& typeof parent.settings['trust proxy fn'] === 'function') {
|
|
116
|
+
delete this.settings['trust proxy'];
|
|
117
|
+
delete this.settings['trust proxy fn'];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// inherit protos (for app.request/app.response config objects)
|
|
121
|
+
Object.setPrototypeOf(this.request, parent.request)
|
|
122
|
+
Object.setPrototypeOf(this.response, parent.response)
|
|
123
|
+
Object.setPrototypeOf(this.engines, parent.engines)
|
|
124
|
+
Object.setPrototypeOf(this.settings, parent.settings)
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// setup locals
|
|
128
|
+
this.locals = Object.create(null);
|
|
129
|
+
|
|
130
|
+
// top-most app is mounted at /
|
|
131
|
+
this.mountpath = '/';
|
|
132
|
+
|
|
133
|
+
// default locals
|
|
134
|
+
this.locals.settings = this.settings;
|
|
135
|
+
|
|
136
|
+
// default configuration
|
|
137
|
+
this.set('view', View);
|
|
138
|
+
this.set('views', resolve('views'));
|
|
139
|
+
this.set('jsonp callback name', 'callback');
|
|
140
|
+
|
|
141
|
+
if (env === 'production') {
|
|
142
|
+
this.enable('view cache');
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Dispatch a req, res pair into the application. Starts pipeline processing.
|
|
148
|
+
*
|
|
149
|
+
* If no callback is provided, then default error handlers will respond
|
|
150
|
+
* in the event of an error bubbling through the stack.
|
|
151
|
+
*
|
|
152
|
+
* @private
|
|
153
|
+
*/
|
|
154
|
+
|
|
155
|
+
app.handle = function handle(req, res, callback) {
|
|
156
|
+
// final handler
|
|
157
|
+
var done = callback || finalhandler(req, res, {
|
|
158
|
+
env: this.get('env'),
|
|
159
|
+
onerror: this._boundLogError
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// set powered by header
|
|
163
|
+
if (this.enabled('x-powered-by')) {
|
|
164
|
+
res.setHeader('X-Powered-By', 'Express');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// set circular references
|
|
168
|
+
req.res = res;
|
|
169
|
+
res.req = req;
|
|
170
|
+
|
|
171
|
+
// alter prototype of req and res objects to add Express methods
|
|
172
|
+
Object.setPrototypeOf(req, this.request);
|
|
173
|
+
Object.setPrototypeOf(res, this.response);
|
|
174
|
+
|
|
175
|
+
this.router.handle(req, res, done);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Proxy `Router#use()` to add middleware to the app router.
|
|
180
|
+
* See Router#use() documentation for details.
|
|
181
|
+
*
|
|
182
|
+
* If the _fn_ parameter is an express app, then it will be
|
|
183
|
+
* mounted at the _route_ specified.
|
|
184
|
+
*
|
|
185
|
+
* @public
|
|
186
|
+
*/
|
|
187
|
+
|
|
188
|
+
app.use = function use(fn) {
|
|
189
|
+
var offset = 0;
|
|
190
|
+
var path = '/';
|
|
191
|
+
|
|
192
|
+
// default path to '/'
|
|
193
|
+
// disambiguate app.use([fn])
|
|
194
|
+
if (typeof fn !== 'function') {
|
|
195
|
+
var arg = fn;
|
|
196
|
+
|
|
197
|
+
while (Array.isArray(arg) && arg.length !== 0) {
|
|
198
|
+
arg = arg[0];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// first arg is the path
|
|
202
|
+
if (typeof arg !== 'function') {
|
|
203
|
+
offset = 1;
|
|
204
|
+
path = fn;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
var fns = flatten.call(slice.call(arguments, offset), Infinity);
|
|
209
|
+
|
|
210
|
+
if (fns.length === 0) {
|
|
211
|
+
throw new TypeError('app.use() requires a middleware function')
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// get router
|
|
215
|
+
var router = this.router;
|
|
216
|
+
|
|
217
|
+
fns.forEach(function (fn) {
|
|
218
|
+
// non-express app
|
|
219
|
+
if (!fn || !fn.handle || !fn.set) {
|
|
220
|
+
return router.use(path, fn);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
debug('.use app under %s', path);
|
|
224
|
+
fn.mountpath = path;
|
|
225
|
+
fn.parent = this;
|
|
226
|
+
|
|
227
|
+
// restore parent app's req/res properties after sub-app
|
|
228
|
+
router.use(path, function mounted_app(req, res, next) {
|
|
229
|
+
var orig = req.app;
|
|
230
|
+
fn.handle(req, res, function (err) {
|
|
231
|
+
Object.setPrototypeOf(req, orig.request);
|
|
232
|
+
Object.setPrototypeOf(res, orig.response);
|
|
233
|
+
next(err);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// mounted an app
|
|
238
|
+
fn.emit('mount', this);
|
|
239
|
+
}, this);
|
|
240
|
+
|
|
241
|
+
return this;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Proxy to the app `Router#route()`
|
|
246
|
+
* Returns a new `Route` instance for the _path_.
|
|
247
|
+
*
|
|
248
|
+
* Routes are isolated middleware stacks for specific paths.
|
|
249
|
+
* See the Route api docs for details.
|
|
250
|
+
*
|
|
251
|
+
* @public
|
|
252
|
+
*/
|
|
253
|
+
|
|
254
|
+
app.route = function route(path) {
|
|
255
|
+
return this.router.route(path);
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Register the given template engine callback `fn`
|
|
260
|
+
* as `ext`.
|
|
261
|
+
*
|
|
262
|
+
* By default will `require()` the engine based on the
|
|
263
|
+
* file extension. For example if you try to render
|
|
264
|
+
* a "foo.ejs" file Express will invoke the following internally:
|
|
265
|
+
*
|
|
266
|
+
* app.engine('ejs', require('ejs').__express);
|
|
267
|
+
*
|
|
268
|
+
* For engines that do not provide `.__express` out of the box,
|
|
269
|
+
* or if you wish to "map" a different extension to the template engine
|
|
270
|
+
* you may use this method. For example mapping the EJS template engine to
|
|
271
|
+
* ".html" files:
|
|
272
|
+
*
|
|
273
|
+
* app.engine('html', require('ejs').renderFile);
|
|
274
|
+
*
|
|
275
|
+
* In this case EJS provides a `.renderFile()` method with
|
|
276
|
+
* the same signature that Express expects: `(path, options, callback)`,
|
|
277
|
+
* though note that it aliases this method as `ejs.__express` internally
|
|
278
|
+
* so if you're using ".ejs" extensions you don't need to do anything.
|
|
279
|
+
*
|
|
280
|
+
* Some template engines do not follow this convention, the
|
|
281
|
+
* [Consolidate.js](https://github.com/tj/consolidate.js)
|
|
282
|
+
* library was created to map all of node's popular template
|
|
283
|
+
* engines to follow this convention, thus allowing them to
|
|
284
|
+
* work seamlessly within Express.
|
|
285
|
+
*
|
|
286
|
+
* @param {String} ext
|
|
287
|
+
* @param {Function} fn
|
|
288
|
+
* @return {app} for chaining
|
|
289
|
+
* @public
|
|
290
|
+
*/
|
|
291
|
+
|
|
292
|
+
app.engine = function engine(ext, fn) {
|
|
293
|
+
if (typeof fn !== 'function') {
|
|
294
|
+
throw new Error('callback function required');
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// get file extension
|
|
298
|
+
var extension = ext[0] !== '.'
|
|
299
|
+
? '.' + ext
|
|
300
|
+
: ext;
|
|
301
|
+
|
|
302
|
+
// store engine
|
|
303
|
+
this.engines[extension] = fn;
|
|
304
|
+
|
|
305
|
+
return this;
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Proxy to `Router#param()` with one added api feature. The _name_ parameter
|
|
310
|
+
* can be an array of names.
|
|
311
|
+
*
|
|
312
|
+
* See the Router#param() docs for more details.
|
|
313
|
+
*
|
|
314
|
+
* @param {String|Array} name
|
|
315
|
+
* @param {Function} fn
|
|
316
|
+
* @return {app} for chaining
|
|
317
|
+
* @public
|
|
318
|
+
*/
|
|
319
|
+
|
|
320
|
+
app.param = function param(name, fn) {
|
|
321
|
+
if (Array.isArray(name)) {
|
|
322
|
+
for (var i = 0; i < name.length; i++) {
|
|
323
|
+
this.param(name[i], fn);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return this;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
this.router.param(name, fn);
|
|
330
|
+
|
|
331
|
+
return this;
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Assign `setting` to `val`, or return `setting`'s value.
|
|
336
|
+
*
|
|
337
|
+
* app.set('foo', 'bar');
|
|
338
|
+
* app.set('foo');
|
|
339
|
+
* // => "bar"
|
|
340
|
+
*
|
|
341
|
+
* Mounted servers inherit their parent server's settings.
|
|
342
|
+
*
|
|
343
|
+
* @param {String} setting
|
|
344
|
+
* @param {*} [val]
|
|
345
|
+
* @return {Server} for chaining
|
|
346
|
+
* @public
|
|
347
|
+
*/
|
|
348
|
+
|
|
349
|
+
app.set = function set(setting, val) {
|
|
350
|
+
if (arguments.length === 1) {
|
|
351
|
+
// app.get(setting)
|
|
352
|
+
return this.settings[setting];
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
debug('set "%s" to %o', setting, val);
|
|
356
|
+
|
|
357
|
+
// set value
|
|
358
|
+
this.settings[setting] = val;
|
|
359
|
+
|
|
360
|
+
// invalidate JSON settings cache
|
|
361
|
+
this._jsonSettingsCache = null;
|
|
362
|
+
|
|
363
|
+
// trigger matched settings
|
|
364
|
+
switch (setting) {
|
|
365
|
+
case 'etag':
|
|
366
|
+
this.set('etag fn', compileETag(val));
|
|
367
|
+
break;
|
|
368
|
+
case 'query parser':
|
|
369
|
+
this.set('query parser fn', compileQueryParser(val));
|
|
370
|
+
break;
|
|
371
|
+
case 'trust proxy':
|
|
372
|
+
this.set('trust proxy fn', compileTrust(val));
|
|
373
|
+
|
|
374
|
+
// trust proxy inherit back-compat
|
|
375
|
+
Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
|
|
376
|
+
configurable: true,
|
|
377
|
+
value: false
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
break;
|
|
381
|
+
case 'json schema':
|
|
382
|
+
this.set('json serializer', val ? schemaSerializer.compileSerializer(val) : null);
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return this;
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Get cached JSON-related settings to avoid per-request app.get() overhead.
|
|
391
|
+
* Cache is invalidated whenever app.set() is called.
|
|
392
|
+
*
|
|
393
|
+
* @return {Object}
|
|
394
|
+
* @private
|
|
395
|
+
*/
|
|
396
|
+
|
|
397
|
+
app._getJsonSettings = function _getJsonSettings() {
|
|
398
|
+
if (this._jsonSettingsCache) return this._jsonSettingsCache;
|
|
399
|
+
this._jsonSettingsCache = {
|
|
400
|
+
escape: this.settings['json escape'],
|
|
401
|
+
replacer: this.settings['json replacer'],
|
|
402
|
+
spaces: this.settings['json spaces'],
|
|
403
|
+
etagFn: this.settings['etag fn'],
|
|
404
|
+
jsonSerializer: this.settings['json serializer'],
|
|
405
|
+
jsonEtag: this.settings['json etag']
|
|
406
|
+
};
|
|
407
|
+
return this._jsonSettingsCache;
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Return the app's absolute pathname
|
|
412
|
+
* based on the parent(s) that have
|
|
413
|
+
* mounted it.
|
|
414
|
+
*
|
|
415
|
+
* For example if the application was
|
|
416
|
+
* mounted as "/admin", which itself
|
|
417
|
+
* was mounted as "/blog" then the
|
|
418
|
+
* return value would be "/blog/admin".
|
|
419
|
+
*
|
|
420
|
+
* @return {String}
|
|
421
|
+
* @private
|
|
422
|
+
*/
|
|
423
|
+
|
|
424
|
+
app.path = function path() {
|
|
425
|
+
return this.parent
|
|
426
|
+
? this.parent.path() + this.mountpath
|
|
427
|
+
: '';
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Check if `setting` is enabled (truthy).
|
|
432
|
+
*
|
|
433
|
+
* app.enabled('foo')
|
|
434
|
+
* // => false
|
|
435
|
+
*
|
|
436
|
+
* app.enable('foo')
|
|
437
|
+
* app.enabled('foo')
|
|
438
|
+
* // => true
|
|
439
|
+
*
|
|
440
|
+
* @param {String} setting
|
|
441
|
+
* @return {Boolean}
|
|
442
|
+
* @public
|
|
443
|
+
*/
|
|
444
|
+
|
|
445
|
+
app.enabled = function enabled(setting) {
|
|
446
|
+
return Boolean(this.set(setting));
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Check if `setting` is disabled.
|
|
451
|
+
*
|
|
452
|
+
* app.disabled('foo')
|
|
453
|
+
* // => true
|
|
454
|
+
*
|
|
455
|
+
* app.enable('foo')
|
|
456
|
+
* app.disabled('foo')
|
|
457
|
+
* // => false
|
|
458
|
+
*
|
|
459
|
+
* @param {String} setting
|
|
460
|
+
* @return {Boolean}
|
|
461
|
+
* @public
|
|
462
|
+
*/
|
|
463
|
+
|
|
464
|
+
app.disabled = function disabled(setting) {
|
|
465
|
+
return !this.set(setting);
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Enable `setting`.
|
|
470
|
+
*
|
|
471
|
+
* @param {String} setting
|
|
472
|
+
* @return {app} for chaining
|
|
473
|
+
* @public
|
|
474
|
+
*/
|
|
475
|
+
|
|
476
|
+
app.enable = function enable(setting) {
|
|
477
|
+
return this.set(setting, true);
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Disable `setting`.
|
|
482
|
+
*
|
|
483
|
+
* @param {String} setting
|
|
484
|
+
* @return {app} for chaining
|
|
485
|
+
* @public
|
|
486
|
+
*/
|
|
487
|
+
|
|
488
|
+
app.disable = function disable(setting) {
|
|
489
|
+
return this.set(setting, false);
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Delegate `.VERB(...)` calls to `router.VERB(...)`.
|
|
494
|
+
*/
|
|
495
|
+
|
|
496
|
+
methods.forEach(function (method) {
|
|
497
|
+
app[method] = function (path) {
|
|
498
|
+
if (method === 'get' && arguments.length === 1) {
|
|
499
|
+
// app.get(setting)
|
|
500
|
+
return this.set(path);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
var args = slice.call(arguments, 1);
|
|
504
|
+
|
|
505
|
+
// Check if first arg after path is a schema options object
|
|
506
|
+
var schemaOpts = null;
|
|
507
|
+
if (args.length > 1 && typeof args[0] === 'object' && args[0] !== null
|
|
508
|
+
&& !Array.isArray(args[0]) && typeof args[0] !== 'function'
|
|
509
|
+
&& args[0].schema) {
|
|
510
|
+
schemaOpts = args.shift();
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
var route = this.route(path);
|
|
514
|
+
|
|
515
|
+
// If schema options provided, inject serializer middleware
|
|
516
|
+
if (schemaOpts) {
|
|
517
|
+
var serializers = schemaSerializer.compileRouteSerializers(schemaOpts.schema);
|
|
518
|
+
route[method].call(route, function attachSerializer(req, res, next) {
|
|
519
|
+
res._routeSerializers = serializers;
|
|
520
|
+
next();
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
route[method].apply(route, args);
|
|
525
|
+
return this;
|
|
526
|
+
};
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Special-cased "all" method, applying the given route `path`,
|
|
531
|
+
* middleware, and callback to _every_ HTTP method.
|
|
532
|
+
*
|
|
533
|
+
* @param {String} path
|
|
534
|
+
* @param {Function} ...
|
|
535
|
+
* @return {app} for chaining
|
|
536
|
+
* @public
|
|
537
|
+
*/
|
|
538
|
+
|
|
539
|
+
app.all = function all(path) {
|
|
540
|
+
var args = slice.call(arguments, 1);
|
|
541
|
+
|
|
542
|
+
// Check if first arg after path is a schema options object
|
|
543
|
+
var schemaOpts = null;
|
|
544
|
+
if (args.length > 1 && typeof args[0] === 'object' && args[0] !== null
|
|
545
|
+
&& !Array.isArray(args[0]) && typeof args[0] !== 'function'
|
|
546
|
+
&& args[0].schema) {
|
|
547
|
+
schemaOpts = args.shift();
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
var route = this.route(path);
|
|
551
|
+
|
|
552
|
+
// If schema options provided, inject serializer middleware via 'all'
|
|
553
|
+
if (schemaOpts) {
|
|
554
|
+
var serializers = schemaSerializer.compileRouteSerializers(schemaOpts.schema);
|
|
555
|
+
route.all(function attachSerializer(req, res, next) {
|
|
556
|
+
res._routeSerializers = serializers;
|
|
557
|
+
next();
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
for (var i = 0; i < methods.length; i++) {
|
|
562
|
+
route[methods[i]].apply(route, args);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
return this;
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Render the given view `name` name with `options`
|
|
570
|
+
* and a callback accepting an error and the
|
|
571
|
+
* rendered template string.
|
|
572
|
+
*
|
|
573
|
+
* Example:
|
|
574
|
+
*
|
|
575
|
+
* app.render('email', { name: 'Tobi' }, function(err, html){
|
|
576
|
+
* // ...
|
|
577
|
+
* })
|
|
578
|
+
*
|
|
579
|
+
* @param {String} name
|
|
580
|
+
* @param {Object|Function} options or fn
|
|
581
|
+
* @param {Function} callback
|
|
582
|
+
* @public
|
|
583
|
+
*/
|
|
584
|
+
|
|
585
|
+
app.render = function render(name, options, callback) {
|
|
586
|
+
var cache = this.cache;
|
|
587
|
+
var done = callback;
|
|
588
|
+
var engines = this.engines;
|
|
589
|
+
var opts = options || {};
|
|
590
|
+
var view;
|
|
591
|
+
|
|
592
|
+
// support callback function as second arg
|
|
593
|
+
if (typeof options === 'function') {
|
|
594
|
+
done = options;
|
|
595
|
+
opts = {};
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// merge options
|
|
599
|
+
var renderOptions = { ...this.locals, ...opts._locals, ...opts };
|
|
600
|
+
|
|
601
|
+
// set .cache unless explicitly provided
|
|
602
|
+
if (renderOptions.cache == null) {
|
|
603
|
+
renderOptions.cache = this.enabled('view cache');
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// primed cache
|
|
607
|
+
if (renderOptions.cache) {
|
|
608
|
+
view = cache[name];
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// view
|
|
612
|
+
if (!view) {
|
|
613
|
+
var View = this.get('view');
|
|
614
|
+
|
|
615
|
+
view = new View(name, {
|
|
616
|
+
defaultEngine: this.get('view engine'),
|
|
617
|
+
root: this.get('views'),
|
|
618
|
+
engines: engines
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
if (!view.path) {
|
|
622
|
+
var dirs = Array.isArray(view.root) && view.root.length > 1
|
|
623
|
+
? 'directories "' + view.root.slice(0, -1).join('", "') + '" or "' + view.root[view.root.length - 1] + '"'
|
|
624
|
+
: 'directory "' + view.root + '"'
|
|
625
|
+
var err = new Error('Failed to lookup view "' + name + '" in views ' + dirs);
|
|
626
|
+
err.view = view;
|
|
627
|
+
return done(err);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// prime the cache
|
|
631
|
+
if (renderOptions.cache) {
|
|
632
|
+
cache[name] = view;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// render
|
|
637
|
+
tryRender(view, renderOptions, done);
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Listen for connections.
|
|
642
|
+
*
|
|
643
|
+
* A node `http.Server` is returned, with this
|
|
644
|
+
* application (which is a `Function`) as its
|
|
645
|
+
* callback. If you wish to create both an HTTP
|
|
646
|
+
* and HTTPS server you may do so with the "http"
|
|
647
|
+
* and "https" modules as shown here:
|
|
648
|
+
*
|
|
649
|
+
* var http = require('node:http')
|
|
650
|
+
* , https = require('node:https')
|
|
651
|
+
* , express = require('express')
|
|
652
|
+
* , app = express();
|
|
653
|
+
*
|
|
654
|
+
* http.createServer(app).listen(80);
|
|
655
|
+
* https.createServer({ ... }, app).listen(443);
|
|
656
|
+
*
|
|
657
|
+
* @return {http.Server}
|
|
658
|
+
* @public
|
|
659
|
+
*/
|
|
660
|
+
|
|
661
|
+
app.listen = function listen() {
|
|
662
|
+
var server = http.createServer(this)
|
|
663
|
+
var args = slice.call(arguments)
|
|
664
|
+
if (typeof args[args.length - 1] === 'function') {
|
|
665
|
+
var done = args[args.length - 1] = once(args[args.length - 1])
|
|
666
|
+
server.once('error', done)
|
|
667
|
+
}
|
|
668
|
+
return server.listen.apply(server, args)
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Log error using console.error.
|
|
673
|
+
*
|
|
674
|
+
* @param {Error} err
|
|
675
|
+
* @private
|
|
676
|
+
*/
|
|
677
|
+
|
|
678
|
+
function logerror(err) {
|
|
679
|
+
/* istanbul ignore next */
|
|
680
|
+
if (this.get('env') !== 'test') console.error(err.stack || err.toString());
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Try rendering a view.
|
|
685
|
+
* @private
|
|
686
|
+
*/
|
|
687
|
+
|
|
688
|
+
function tryRender(view, options, callback) {
|
|
689
|
+
try {
|
|
690
|
+
view.render(options, callback);
|
|
691
|
+
} catch (err) {
|
|
692
|
+
callback(err);
|
|
693
|
+
}
|
|
694
|
+
}
|