annotate node_modules/express/lib/application.js @ 101:52e44ee1c791 tip master

enabled all scores in autostart script
author Rob Canning <rc@kiben.net>
date Tue, 21 Apr 2015 16:20:57 +0100
parents 0c3a2942ddee
children
rev   line source
rc@73 1 /**
rc@73 2 * Module dependencies.
rc@73 3 */
rc@73 4
rc@73 5 var mixin = require('utils-merge');
rc@73 6 var escapeHtml = require('escape-html');
rc@73 7 var Router = require('./router');
rc@73 8 var methods = require('methods');
rc@73 9 var middleware = require('./middleware/init');
rc@73 10 var query = require('./middleware/query');
rc@73 11 var debug = require('debug')('express:application');
rc@73 12 var View = require('./view');
rc@73 13 var http = require('http');
rc@73 14 var compileETag = require('./utils').compileETag;
rc@73 15 var compileTrust = require('./utils').compileTrust;
rc@73 16 var deprecate = require('./utils').deprecate;
rc@73 17 var resolve = require('path').resolve;
rc@73 18
rc@73 19 /**
rc@73 20 * Application prototype.
rc@73 21 */
rc@73 22
rc@73 23 var app = exports = module.exports = {};
rc@73 24
rc@73 25 /**
rc@73 26 * Initialize the server.
rc@73 27 *
rc@73 28 * - setup default configuration
rc@73 29 * - setup default middleware
rc@73 30 * - setup route reflection methods
rc@73 31 *
rc@73 32 * @api private
rc@73 33 */
rc@73 34
rc@73 35 app.init = function(){
rc@73 36 this.cache = {};
rc@73 37 this.settings = {};
rc@73 38 this.engines = {};
rc@73 39 this.defaultConfiguration();
rc@73 40 };
rc@73 41
rc@73 42 /**
rc@73 43 * Initialize application configuration.
rc@73 44 *
rc@73 45 * @api private
rc@73 46 */
rc@73 47
rc@73 48 app.defaultConfiguration = function(){
rc@73 49 // default settings
rc@73 50 this.enable('x-powered-by');
rc@73 51 this.set('etag', 'weak');
rc@73 52 var env = process.env.NODE_ENV || 'development';
rc@73 53 this.set('env', env);
rc@73 54 this.set('subdomain offset', 2);
rc@73 55 this.set('trust proxy', false);
rc@73 56
rc@73 57 debug('booting in %s mode', env);
rc@73 58
rc@73 59 // inherit protos
rc@73 60 this.on('mount', function(parent){
rc@73 61 this.request.__proto__ = parent.request;
rc@73 62 this.response.__proto__ = parent.response;
rc@73 63 this.engines.__proto__ = parent.engines;
rc@73 64 this.settings.__proto__ = parent.settings;
rc@73 65 });
rc@73 66
rc@73 67 // setup locals
rc@73 68 this.locals = Object.create(null);
rc@73 69
rc@73 70 // top-most app is mounted at /
rc@73 71 this.mountpath = '/';
rc@73 72
rc@73 73 // default locals
rc@73 74 this.locals.settings = this.settings;
rc@73 75
rc@73 76 // default configuration
rc@73 77 this.set('view', View);
rc@73 78 this.set('views', resolve('views'));
rc@73 79 this.set('jsonp callback name', 'callback');
rc@73 80
rc@73 81 if (env === 'production') {
rc@73 82 this.enable('view cache');
rc@73 83 }
rc@73 84
rc@73 85 Object.defineProperty(this, 'router', {
rc@73 86 get: function() {
rc@73 87 throw new Error('\'app.router\' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app.');
rc@73 88 }
rc@73 89 });
rc@73 90 };
rc@73 91
rc@73 92 /**
rc@73 93 * lazily adds the base router if it has not yet been added.
rc@73 94 *
rc@73 95 * We cannot add the base router in the defaultConfiguration because
rc@73 96 * it reads app settings which might be set after that has run.
rc@73 97 *
rc@73 98 * @api private
rc@73 99 */
rc@73 100 app.lazyrouter = function() {
rc@73 101 if (!this._router) {
rc@73 102 this._router = new Router({
rc@73 103 caseSensitive: this.enabled('case sensitive routing'),
rc@73 104 strict: this.enabled('strict routing')
rc@73 105 });
rc@73 106
rc@73 107 this._router.use(query());
rc@73 108 this._router.use(middleware.init(this));
rc@73 109 }
rc@73 110 };
rc@73 111
rc@73 112 /**
rc@73 113 * Dispatch a req, res pair into the application. Starts pipeline processing.
rc@73 114 *
rc@73 115 * If no _done_ callback is provided, then default error handlers will respond
rc@73 116 * in the event of an error bubbling through the stack.
rc@73 117 *
rc@73 118 * @api private
rc@73 119 */
rc@73 120
rc@73 121 app.handle = function(req, res, done) {
rc@73 122 var env = this.get('env');
rc@73 123
rc@73 124 this._router.handle(req, res, function(err) {
rc@73 125 if (done) {
rc@73 126 return done(err);
rc@73 127 }
rc@73 128
rc@73 129 // unhandled error
rc@73 130 if (err) {
rc@73 131 // default to 500
rc@73 132 if (res.statusCode < 400) res.statusCode = 500;
rc@73 133 debug('default %s', res.statusCode);
rc@73 134
rc@73 135 // respect err.status
rc@73 136 if (err.status) res.statusCode = err.status;
rc@73 137
rc@73 138 // production gets a basic error message
rc@73 139 var msg = 'production' == env
rc@73 140 ? http.STATUS_CODES[res.statusCode]
rc@73 141 : err.stack || err.toString();
rc@73 142 msg = escapeHtml(msg);
rc@73 143
rc@73 144 // log to stderr in a non-test env
rc@73 145 if ('test' != env) console.error(err.stack || err.toString());
rc@73 146 if (res.headersSent) return req.socket.destroy();
rc@73 147 res.setHeader('Content-Type', 'text/html');
rc@73 148 res.setHeader('Content-Length', Buffer.byteLength(msg));
rc@73 149 if ('HEAD' == req.method) return res.end();
rc@73 150 res.end(msg);
rc@73 151 return;
rc@73 152 }
rc@73 153
rc@73 154 // 404
rc@73 155 debug('default 404');
rc@73 156 res.statusCode = 404;
rc@73 157 res.setHeader('Content-Type', 'text/html');
rc@73 158 if ('HEAD' == req.method) return res.end();
rc@73 159 res.end('Cannot ' + escapeHtml(req.method) + ' ' + escapeHtml(req.originalUrl) + '\n');
rc@73 160 });
rc@73 161 };
rc@73 162
rc@73 163 /**
rc@73 164 * Proxy `Router#use()` to add middleware to the app router.
rc@73 165 * See Router#use() documentation for details.
rc@73 166 *
rc@73 167 * If the _fn_ parameter is an express app, then it will be
rc@73 168 * mounted at the _route_ specified.
rc@73 169 *
rc@73 170 * @api public
rc@73 171 */
rc@73 172
rc@73 173 app.use = function(route, fn){
rc@73 174 var mount_app;
rc@73 175
rc@73 176 // default route to '/'
rc@73 177 if ('string' != typeof route) fn = route, route = '/';
rc@73 178
rc@73 179 // express app
rc@73 180 if (fn.handle && fn.set) mount_app = fn;
rc@73 181
rc@73 182 // restore .app property on req and res
rc@73 183 if (mount_app) {
rc@73 184 debug('.use app under %s', route);
rc@73 185 mount_app.mountpath = route;
rc@73 186 fn = function(req, res, next) {
rc@73 187 var orig = req.app;
rc@73 188 mount_app.handle(req, res, function(err) {
rc@73 189 req.__proto__ = orig.request;
rc@73 190 res.__proto__ = orig.response;
rc@73 191 next(err);
rc@73 192 });
rc@73 193 };
rc@73 194 }
rc@73 195
rc@73 196 this.lazyrouter();
rc@73 197 this._router.use(route, fn);
rc@73 198
rc@73 199 // mounted an app
rc@73 200 if (mount_app) {
rc@73 201 mount_app.parent = this;
rc@73 202 mount_app.emit('mount', this);
rc@73 203 }
rc@73 204
rc@73 205 return this;
rc@73 206 };
rc@73 207
rc@73 208 /**
rc@73 209 * Proxy to the app `Router#route()`
rc@73 210 * Returns a new `Route` instance for the _path_.
rc@73 211 *
rc@73 212 * Routes are isolated middleware stacks for specific paths.
rc@73 213 * See the Route api docs for details.
rc@73 214 *
rc@73 215 * @api public
rc@73 216 */
rc@73 217
rc@73 218 app.route = function(path){
rc@73 219 this.lazyrouter();
rc@73 220 return this._router.route(path);
rc@73 221 };
rc@73 222
rc@73 223 /**
rc@73 224 * Register the given template engine callback `fn`
rc@73 225 * as `ext`.
rc@73 226 *
rc@73 227 * By default will `require()` the engine based on the
rc@73 228 * file extension. For example if you try to render
rc@73 229 * a "foo.jade" file Express will invoke the following internally:
rc@73 230 *
rc@73 231 * app.engine('jade', require('jade').__express);
rc@73 232 *
rc@73 233 * For engines that do not provide `.__express` out of the box,
rc@73 234 * or if you wish to "map" a different extension to the template engine
rc@73 235 * you may use this method. For example mapping the EJS template engine to
rc@73 236 * ".html" files:
rc@73 237 *
rc@73 238 * app.engine('html', require('ejs').renderFile);
rc@73 239 *
rc@73 240 * In this case EJS provides a `.renderFile()` method with
rc@73 241 * the same signature that Express expects: `(path, options, callback)`,
rc@73 242 * though note that it aliases this method as `ejs.__express` internally
rc@73 243 * so if you're using ".ejs" extensions you dont need to do anything.
rc@73 244 *
rc@73 245 * Some template engines do not follow this convention, the
rc@73 246 * [Consolidate.js](https://github.com/visionmedia/consolidate.js)
rc@73 247 * library was created to map all of node's popular template
rc@73 248 * engines to follow this convention, thus allowing them to
rc@73 249 * work seamlessly within Express.
rc@73 250 *
rc@73 251 * @param {String} ext
rc@73 252 * @param {Function} fn
rc@73 253 * @return {app} for chaining
rc@73 254 * @api public
rc@73 255 */
rc@73 256
rc@73 257 app.engine = function(ext, fn){
rc@73 258 if ('function' != typeof fn) throw new Error('callback function required');
rc@73 259 if ('.' != ext[0]) ext = '.' + ext;
rc@73 260 this.engines[ext] = fn;
rc@73 261 return this;
rc@73 262 };
rc@73 263
rc@73 264 /**
rc@73 265 * Proxy to `Router#param()` with one added api feature. The _name_ parameter
rc@73 266 * can be an array of names.
rc@73 267 *
rc@73 268 * See the Router#param() docs for more details.
rc@73 269 *
rc@73 270 * @param {String|Array} name
rc@73 271 * @param {Function} fn
rc@73 272 * @return {app} for chaining
rc@73 273 * @api public
rc@73 274 */
rc@73 275
rc@73 276 app.param = function(name, fn){
rc@73 277 var self = this;
rc@73 278 self.lazyrouter();
rc@73 279
rc@73 280 if (Array.isArray(name)) {
rc@73 281 name.forEach(function(key) {
rc@73 282 self.param(key, fn);
rc@73 283 });
rc@73 284 return this;
rc@73 285 }
rc@73 286
rc@73 287 self._router.param(name, fn);
rc@73 288 return this;
rc@73 289 };
rc@73 290
rc@73 291 /**
rc@73 292 * Assign `setting` to `val`, or return `setting`'s value.
rc@73 293 *
rc@73 294 * app.set('foo', 'bar');
rc@73 295 * app.get('foo');
rc@73 296 * // => "bar"
rc@73 297 *
rc@73 298 * Mounted servers inherit their parent server's settings.
rc@73 299 *
rc@73 300 * @param {String} setting
rc@73 301 * @param {*} [val]
rc@73 302 * @return {Server} for chaining
rc@73 303 * @api public
rc@73 304 */
rc@73 305
rc@73 306 app.set = function(setting, val){
rc@73 307 if (arguments.length === 1) {
rc@73 308 // app.get(setting)
rc@73 309 return this.settings[setting];
rc@73 310 }
rc@73 311
rc@73 312 // set value
rc@73 313 this.settings[setting] = val;
rc@73 314
rc@73 315 // trigger matched settings
rc@73 316 switch (setting) {
rc@73 317 case 'etag':
rc@73 318 debug('compile etag %s', val);
rc@73 319 this.set('etag fn', compileETag(val));
rc@73 320 break;
rc@73 321 case 'trust proxy':
rc@73 322 debug('compile trust proxy %s', val);
rc@73 323 this.set('trust proxy fn', compileTrust(val));
rc@73 324 break;
rc@73 325 }
rc@73 326
rc@73 327 return this;
rc@73 328 };
rc@73 329
rc@73 330 /**
rc@73 331 * Return the app's absolute pathname
rc@73 332 * based on the parent(s) that have
rc@73 333 * mounted it.
rc@73 334 *
rc@73 335 * For example if the application was
rc@73 336 * mounted as "/admin", which itself
rc@73 337 * was mounted as "/blog" then the
rc@73 338 * return value would be "/blog/admin".
rc@73 339 *
rc@73 340 * @return {String}
rc@73 341 * @api private
rc@73 342 */
rc@73 343
rc@73 344 app.path = function(){
rc@73 345 return this.parent
rc@73 346 ? this.parent.path() + this.mountpath
rc@73 347 : '';
rc@73 348 };
rc@73 349
rc@73 350 /**
rc@73 351 * Check if `setting` is enabled (truthy).
rc@73 352 *
rc@73 353 * app.enabled('foo')
rc@73 354 * // => false
rc@73 355 *
rc@73 356 * app.enable('foo')
rc@73 357 * app.enabled('foo')
rc@73 358 * // => true
rc@73 359 *
rc@73 360 * @param {String} setting
rc@73 361 * @return {Boolean}
rc@73 362 * @api public
rc@73 363 */
rc@73 364
rc@73 365 app.enabled = function(setting){
rc@73 366 return !!this.set(setting);
rc@73 367 };
rc@73 368
rc@73 369 /**
rc@73 370 * Check if `setting` is disabled.
rc@73 371 *
rc@73 372 * app.disabled('foo')
rc@73 373 * // => true
rc@73 374 *
rc@73 375 * app.enable('foo')
rc@73 376 * app.disabled('foo')
rc@73 377 * // => false
rc@73 378 *
rc@73 379 * @param {String} setting
rc@73 380 * @return {Boolean}
rc@73 381 * @api public
rc@73 382 */
rc@73 383
rc@73 384 app.disabled = function(setting){
rc@73 385 return !this.set(setting);
rc@73 386 };
rc@73 387
rc@73 388 /**
rc@73 389 * Enable `setting`.
rc@73 390 *
rc@73 391 * @param {String} setting
rc@73 392 * @return {app} for chaining
rc@73 393 * @api public
rc@73 394 */
rc@73 395
rc@73 396 app.enable = function(setting){
rc@73 397 return this.set(setting, true);
rc@73 398 };
rc@73 399
rc@73 400 /**
rc@73 401 * Disable `setting`.
rc@73 402 *
rc@73 403 * @param {String} setting
rc@73 404 * @return {app} for chaining
rc@73 405 * @api public
rc@73 406 */
rc@73 407
rc@73 408 app.disable = function(setting){
rc@73 409 return this.set(setting, false);
rc@73 410 };
rc@73 411
rc@73 412 /**
rc@73 413 * Delegate `.VERB(...)` calls to `router.VERB(...)`.
rc@73 414 */
rc@73 415
rc@73 416 methods.forEach(function(method){
rc@73 417 app[method] = function(path){
rc@73 418 if ('get' == method && 1 == arguments.length) return this.set(path);
rc@73 419
rc@73 420 this.lazyrouter();
rc@73 421
rc@73 422 var route = this._router.route(path);
rc@73 423 route[method].apply(route, [].slice.call(arguments, 1));
rc@73 424 return this;
rc@73 425 };
rc@73 426 });
rc@73 427
rc@73 428 /**
rc@73 429 * Special-cased "all" method, applying the given route `path`,
rc@73 430 * middleware, and callback to _every_ HTTP method.
rc@73 431 *
rc@73 432 * @param {String} path
rc@73 433 * @param {Function} ...
rc@73 434 * @return {app} for chaining
rc@73 435 * @api public
rc@73 436 */
rc@73 437
rc@73 438 app.all = function(path){
rc@73 439 this.lazyrouter();
rc@73 440
rc@73 441 var route = this._router.route(path);
rc@73 442 var args = [].slice.call(arguments, 1);
rc@73 443 methods.forEach(function(method){
rc@73 444 route[method].apply(route, args);
rc@73 445 });
rc@73 446
rc@73 447 return this;
rc@73 448 };
rc@73 449
rc@73 450 // del -> delete alias
rc@73 451
rc@73 452 app.del = deprecate(app.delete, 'app.del: Use app.delete instead');
rc@73 453
rc@73 454 /**
rc@73 455 * Render the given view `name` name with `options`
rc@73 456 * and a callback accepting an error and the
rc@73 457 * rendered template string.
rc@73 458 *
rc@73 459 * Example:
rc@73 460 *
rc@73 461 * app.render('email', { name: 'Tobi' }, function(err, html){
rc@73 462 * // ...
rc@73 463 * })
rc@73 464 *
rc@73 465 * @param {String} name
rc@73 466 * @param {String|Function} options or fn
rc@73 467 * @param {Function} fn
rc@73 468 * @api public
rc@73 469 */
rc@73 470
rc@73 471 app.render = function(name, options, fn){
rc@73 472 var opts = {};
rc@73 473 var cache = this.cache;
rc@73 474 var engines = this.engines;
rc@73 475 var view;
rc@73 476
rc@73 477 // support callback function as second arg
rc@73 478 if ('function' == typeof options) {
rc@73 479 fn = options, options = {};
rc@73 480 }
rc@73 481
rc@73 482 // merge app.locals
rc@73 483 mixin(opts, this.locals);
rc@73 484
rc@73 485 // merge options._locals
rc@73 486 if (options._locals) mixin(opts, options._locals);
rc@73 487
rc@73 488 // merge options
rc@73 489 mixin(opts, options);
rc@73 490
rc@73 491 // set .cache unless explicitly provided
rc@73 492 opts.cache = null == opts.cache
rc@73 493 ? this.enabled('view cache')
rc@73 494 : opts.cache;
rc@73 495
rc@73 496 // primed cache
rc@73 497 if (opts.cache) view = cache[name];
rc@73 498
rc@73 499 // view
rc@73 500 if (!view) {
rc@73 501 view = new (this.get('view'))(name, {
rc@73 502 defaultEngine: this.get('view engine'),
rc@73 503 root: this.get('views'),
rc@73 504 engines: engines
rc@73 505 });
rc@73 506
rc@73 507 if (!view.path) {
rc@73 508 var err = new Error('Failed to lookup view "' + name + '" in views directory "' + view.root + '"');
rc@73 509 err.view = view;
rc@73 510 return fn(err);
rc@73 511 }
rc@73 512
rc@73 513 // prime the cache
rc@73 514 if (opts.cache) cache[name] = view;
rc@73 515 }
rc@73 516
rc@73 517 // render
rc@73 518 try {
rc@73 519 view.render(opts, fn);
rc@73 520 } catch (err) {
rc@73 521 fn(err);
rc@73 522 }
rc@73 523 };
rc@73 524
rc@73 525 /**
rc@73 526 * Listen for connections.
rc@73 527 *
rc@73 528 * A node `http.Server` is returned, with this
rc@73 529 * application (which is a `Function`) as its
rc@73 530 * callback. If you wish to create both an HTTP
rc@73 531 * and HTTPS server you may do so with the "http"
rc@73 532 * and "https" modules as shown here:
rc@73 533 *
rc@73 534 * var http = require('http')
rc@73 535 * , https = require('https')
rc@73 536 * , express = require('express')
rc@73 537 * , app = express();
rc@73 538 *
rc@73 539 * http.createServer(app).listen(80);
rc@73 540 * https.createServer({ ... }, app).listen(443);
rc@73 541 *
rc@73 542 * @return {http.Server}
rc@73 543 * @api public
rc@73 544 */
rc@73 545
rc@73 546 app.listen = function(){
rc@73 547 var server = http.createServer(this);
rc@73 548 return server.listen.apply(server, arguments);
rc@73 549 };