comunicationLeap/node_modules/express/lib/application.js
node_modules/express/lib/application.jsRaw
1/**
2 * Module dependencies.
3 */
4
5var connect = require('connect')
6 , Router = require('./router')
7 , methods = require('methods')
8 , middleware = require('./middleware')
9 , debug = require('debug')('express:application')
10 , locals = require('./utils').locals
11 , View = require('./view')
12 , utils = connect.utils
13 , path = require('path')
14 , http = require('http')
15 , join = path.join;
16
17/**
18 * Application prototype.
19 */
20
21var app = exports = module.exports = {};
22
23/**
24 * Initialize the server.
25 *
26 * - setup default configuration
27 * - setup default middleware
28 * - setup route reflection methods
29 *
30 * @api private
31 */
32
33app.init = function(){
34 this.cache = {};
35 this.settings = {};
36 this.engines = {};
37 this.defaultConfiguration();
38};
39
40/**
41 * Initialize application configuration.
42 *
43 * @api private
44 */
45
46app.defaultConfiguration = function(){
47 // default settings
48 this.enable('x-powered-by');
49 this.set('env', process.env.NODE_ENV || 'development');
50 this.set('subdomain offset', 2);
51 debug('booting in %s mode', this.get('env'));
52
53 // implicit middleware
54 this.use(connect.query());
55 this.use(middleware.init(this));
56
57 // inherit protos
58 this.on('mount', function(parent){
59 this.request.__proto__ = parent.request;
60 this.response.__proto__ = parent.response;
61 this.engines.__proto__ = parent.engines;
62 this.settings.__proto__ = parent.settings;
63 });
64
65 // router
66 this._router = new Router(this);
67 this.routes = this._router.map;
68 this.__defineGetter__('router', function(){
69 this._usedRouter = true;
70 this._router.caseSensitive = this.enabled('case sensitive routing');
71 this._router.strict = this.enabled('strict routing');
72 return this._router.middleware;
73 });
74
75 // setup locals
76 this.locals = locals(this);
77
78 // default locals
79 this.locals.settings = this.settings;
80
81 // default configuration
82 this.set('view', View);
83 this.set('views', process.cwd() + '/views');
84 this.set('jsonp callback name', 'callback');
85
86 this.configure('development', function(){
87 this.set('json spaces', 2);
88 });
89
90 this.configure('production', function(){
91 this.enable('view cache');
92 });
93};
94
95/**
96 * Proxy `connect#use()` to apply settings to
97 * mounted applications.
98 *
99 * @param {String|Function|Server} route
100 * @param {Function|Server} fn
101 * @return {app} for chaining
102 * @api public
103 */
104
105app.use = function(route, fn){
106 var app;
107
108 // default route to '/'
109 if ('string' != typeof route) fn = route, route = '/';
110
111 // express app
112 if (fn.handle && fn.set) app = fn;
113
114 // restore .app property on req and res
115 if (app) {
116 app.route = route;
117 fn = function(req, res, next) {
118 var orig = req.app;
119 app.handle(req, res, function(err){
120 req.app = res.app = orig;
121 req.__proto__ = orig.request;
122 res.__proto__ = orig.response;
123 next(err);
124 });
125 };
126 }
127
128 connect.proto.use.call(this, route, fn);
129
130 // mounted an app
131 if (app) {
132 app.parent = this;
133 app.emit('mount', this);
134 }
135
136 return this;
137};
138
139/**
140 * Register the given template engine callback `fn`
141 * as `ext`.
142 *
143 * By default will `require()` the engine based on the
144 * file extension. For example if you try to render
145 * a "foo.jade" file Express will invoke the following internally:
146 *
147 * app.engine('jade', require('jade').__express);
148 *
149 * For engines that do not provide `.__express` out of the box,
150 * or if you wish to "map" a different extension to the template engine
151 * you may use this method. For example mapping the EJS template engine to
152 * ".html" files:
153 *
154 * app.engine('html', require('ejs').renderFile);
155 *
156 * In this case EJS provides a `.renderFile()` method with
157 * the same signature that Express expects: `(path, options, callback)`,
158 * though note that it aliases this method as `ejs.__express` internally
159 * so if you're using ".ejs" extensions you dont need to do anything.
160 *
161 * Some template engines do not follow this convention, the
162 * [Consolidate.js](https://github.com/visionmedia/consolidate.js)
163 * library was created to map all of node's popular template
164 * engines to follow this convention, thus allowing them to
165 * work seamlessly within Express.
166 *
167 * @param {String} ext
168 * @param {Function} fn
169 * @return {app} for chaining
170 * @api public
171 */
172
173app.engine = function(ext, fn){
174 if ('function' != typeof fn) throw new Error('callback function required');
175 if ('.' != ext[0]) ext = '.' + ext;
176 this.engines[ext] = fn;
177 return this;
178};
179
180/**
181 * Map the given param placeholder `name`(s) to the given callback(s).
182 *
183 * Parameter mapping is used to provide pre-conditions to routes
184 * which use normalized placeholders. For example a _:user_id_ parameter
185 * could automatically load a user's information from the database without
186 * any additional code,
187 *
188 * The callback uses the samesignature as middleware, the only differencing
189 * being that the value of the placeholder is passed, in this case the _id_
190 * of the user. Once the `next()` function is invoked, just like middleware
191 * it will continue on to execute the route, or subsequent parameter functions.
192 *
193 * app.param('user_id', function(req, res, next, id){
194 * User.find(id, function(err, user){
195 * if (err) {
196 * next(err);
197 * } else if (user) {
198 * req.user = user;
199 * next();
200 * } else {
201 * next(new Error('failed to load user'));
202 * }
203 * });
204 * });
205 *
206 * @param {String|Array} name
207 * @param {Function} fn
208 * @return {app} for chaining
209 * @api public
210 */
211
212app.param = function(name, fn){
213 var self = this
214 , fns = [].slice.call(arguments, 1);
215
216 // array
217 if (Array.isArray(name)) {
218 name.forEach(function(name){
219 fns.forEach(function(fn){
220 self.param(name, fn);
221 });
222 });
223 // param logic
224 } else if ('function' == typeof name) {
225 this._router.param(name);
226 // single
227 } else {
228 if (':' == name[0]) name = name.substr(1);
229 fns.forEach(function(fn){
230 self._router.param(name, fn);
231 });
232 }
233
234 return this;
235};
236
237/**
238 * Assign `setting` to `val`, or return `setting`'s value.
239 *
240 * app.set('foo', 'bar');
241 * app.get('foo');
242 * // => "bar"
243 *
244 * Mounted servers inherit their parent server's settings.
245 *
246 * @param {String} setting
247 * @param {String} val
248 * @return {Server} for chaining
249 * @api public
250 */
251
252app.set = function(setting, val){
253 if (1 == arguments.length) {
254 return this.settings[setting];
255 } else {
256 this.settings[setting] = val;
257 return this;
258 }
259};
260
261/**
262 * Return the app's absolute pathname
263 * based on the parent(s) that have
264 * mounted it.
265 *
266 * For example if the application was
267 * mounted as "/admin", which itself
268 * was mounted as "/blog" then the
269 * return value would be "/blog/admin".
270 *
271 * @return {String}
272 * @api private
273 */
274
275app.path = function(){
276 return this.parent
277 ? this.parent.path() + this.route
278 : '';
279};
280
281/**
282 * Check if `setting` is enabled (truthy).
283 *
284 * app.enabled('foo')
285 * // => false
286 *
287 * app.enable('foo')
288 * app.enabled('foo')
289 * // => true
290 *
291 * @param {String} setting
292 * @return {Boolean}
293 * @api public
294 */
295
296app.enabled = function(setting){
297 return !!this.set(setting);
298};
299
300/**
301 * Check if `setting` is disabled.
302 *
303 * app.disabled('foo')
304 * // => true
305 *
306 * app.enable('foo')
307 * app.disabled('foo')
308 * // => false
309 *
310 * @param {String} setting
311 * @return {Boolean}
312 * @api public
313 */
314
315app.disabled = function(setting){
316 return !this.set(setting);
317};
318
319/**
320 * Enable `setting`.
321 *
322 * @param {String} setting
323 * @return {app} for chaining
324 * @api public
325 */
326
327app.enable = function(setting){
328 return this.set(setting, true);
329};
330
331/**
332 * Disable `setting`.
333 *
334 * @param {String} setting
335 * @return {app} for chaining
336 * @api public
337 */
338
339app.disable = function(setting){
340 return this.set(setting, false);
341};
342
343/**
344 * Configure callback for zero or more envs,
345 * when no `env` is specified that callback will
346 * be invoked for all environments. Any combination
347 * can be used multiple times, in any order desired.
348 *
349 * Examples:
350 *
351 * app.configure(function(){
352 * // executed for all envs
353 * });
354 *
355 * app.configure('stage', function(){
356 * // executed staging env
357 * });
358 *
359 * app.configure('stage', 'production', function(){
360 * // executed for stage and production
361 * });
362 *
363 * Note:
364 *
365 * These callbacks are invoked immediately, and
366 * are effectively sugar for the following:
367 *
368 * var env = process.env.NODE_ENV || 'development';
369 *
370 * switch (env) {
371 * case 'development':
372 * ...
373 * break;
374 * case 'stage':
375 * ...
376 * break;
377 * case 'production':
378 * ...
379 * break;
380 * }
381 *
382 * @param {String} env...
383 * @param {Function} fn
384 * @return {app} for chaining
385 * @api public
386 */
387
388app.configure = function(env, fn){
389 var envs = 'all'
390 , args = [].slice.call(arguments);
391 fn = args.pop();
392 if (args.length) envs = args;
393 if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this);
394 return this;
395};
396
397/**
398 * Delegate `.VERB(...)` calls to `router.VERB(...)`.
399 */
400
401methods.forEach(function(method){
402 app[method] = function(path){
403 if ('get' == method && 1 == arguments.length) return this.set(path);
404
405 // deprecated
406 if (Array.isArray(path)) {
407 console.trace('passing an array to app.VERB() is deprecated and will be removed in 4.0');
408 }
409
410 // if no router attached yet, attach the router
411 if (!this._usedRouter) this.use(this.router);
412
413 // setup route
414 this._router[method].apply(this._router, arguments);
415 return this;
416 };
417});
418
419/**
420 * Special-cased "all" method, applying the given route `path`,
421 * middleware, and callback to _every_ HTTP method.
422 *
423 * @param {String} path
424 * @param {Function} ...
425 * @return {app} for chaining
426 * @api public
427 */
428
429app.all = function(path){
430 var args = arguments;
431 methods.forEach(function(method){
432 app[method].apply(this, args);
433 }, this);
434 return this;
435};
436
437// del -> delete alias
438
439app.del = app.delete;
440
441/**
442 * Render the given view `name` name with `options`
443 * and a callback accepting an error and the
444 * rendered template string.
445 *
446 * Example:
447 *
448 * app.render('email', { name: 'Tobi' }, function(err, html){
449 * // ...
450 * })
451 *
452 * @param {String} name
453 * @param {String|Function} options or fn
454 * @param {Function} fn
455 * @api public
456 */
457
458app.render = function(name, options, fn){
459 var opts = {}
460 , cache = this.cache
461 , engines = this.engines
462 , view;
463
464 // support callback function as second arg
465 if ('function' == typeof options) {
466 fn = options, options = {};
467 }
468
469 // merge app.locals
470 utils.merge(opts, this.locals);
471
472 // merge options._locals
473 if (options._locals) utils.merge(opts, options._locals);
474
475 // merge options
476 utils.merge(opts, options);
477
478 // set .cache unless explicitly provided
479 opts.cache = null == opts.cache
480 ? this.enabled('view cache')
481 : opts.cache;
482
483 // primed cache
484 if (opts.cache) view = cache[name];
485
486 // view
487 if (!view) {
488 view = new (this.get('view'))(name, {
489 defaultEngine: this.get('view engine'),
490 root: this.get('views'),
491 engines: engines
492 });
493
494 if (!view.path) {
495 var err = new Error('Failed to lookup view "' + name + '"');
496 err.view = view;
497 return fn(err);
498 }
499
500 // prime the cache
501 if (opts.cache) cache[name] = view;
502 }
503
504 // render
505 try {
506 view.render(opts, fn);
507 } catch (err) {
508 fn(err);
509 }
510};
511
512/**
513 * Listen for connections.
514 *
515 * A node `http.Server` is returned, with this
516 * application (which is a `Function`) as its
517 * callback. If you wish to create both an HTTP
518 * and HTTPS server you may do so with the "http"
519 * and "https" modules as shown here:
520 *
521 * var http = require('http')
522 * , https = require('https')
523 * , express = require('express')
524 * , app = express();
525 *
526 * http.createServer(app).listen(80);
527 * https.createServer({ ... }, app).listen(443);
528 *
529 * @return {http.Server}
530 * @api public
531 */
532
533app.listen = function(){
534 var server = http.createServer(this);
535 return server.listen.apply(server, arguments);
536};