github.com/cloudcredo/cloudrocker@v0.0.0-20160108110610-1320f8cc2dfd/sample-apps/node/node_modules/express/lib/application.js (about)

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