github.com/emc-advanced-dev/unik@v0.0.0-20190717152701-a58d3e8e33b7/docs/examples/example-nodejs-fileserver/node_modules/express/lib/application.js (about)

     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 Router = require('./router');
    18  var methods = require('methods');
    19  var middleware = require('./middleware/init');
    20  var query = require('./middleware/query');
    21  var debug = require('debug')('express:application');
    22  var View = require('./view');
    23  var http = require('http');
    24  var compileETag = require('./utils').compileETag;
    25  var compileQueryParser = require('./utils').compileQueryParser;
    26  var compileTrust = require('./utils').compileTrust;
    27  var deprecate = require('depd')('express');
    28  var flatten = require('array-flatten');
    29  var merge = require('utils-merge');
    30  var resolve = require('path').resolve;
    31  var slice = Array.prototype.slice;
    32  
    33  /**
    34   * Application prototype.
    35   */
    36  
    37  var app = exports = module.exports = {};
    38  
    39  /**
    40   * Variable for trust proxy inheritance back-compat
    41   * @private
    42   */
    43  
    44  var trustProxyDefaultSymbol = '@@symbol:trust_proxy_default';
    45  
    46  /**
    47   * Initialize the server.
    48   *
    49   *   - setup default configuration
    50   *   - setup default middleware
    51   *   - setup route reflection methods
    52   *
    53   * @private
    54   */
    55  
    56  app.init = function init() {
    57    this.cache = {};
    58    this.engines = {};
    59    this.settings = {};
    60  
    61    this.defaultConfiguration();
    62  };
    63  
    64  /**
    65   * Initialize application configuration.
    66   * @private
    67   */
    68  
    69  app.defaultConfiguration = function defaultConfiguration() {
    70    var env = process.env.NODE_ENV || 'development';
    71  
    72    // default settings
    73    this.enable('x-powered-by');
    74    this.set('etag', 'weak');
    75    this.set('env', env);
    76    this.set('query parser', 'extended');
    77    this.set('subdomain offset', 2);
    78    this.set('trust proxy', false);
    79  
    80    // trust proxy inherit back-compat
    81    Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
    82      configurable: true,
    83      value: true
    84    });
    85  
    86    debug('booting in %s mode', env);
    87  
    88    this.on('mount', function onmount(parent) {
    89      // inherit trust proxy
    90      if (this.settings[trustProxyDefaultSymbol] === true
    91        && typeof parent.settings['trust proxy fn'] === 'function') {
    92        delete this.settings['trust proxy'];
    93        delete this.settings['trust proxy fn'];
    94      }
    95  
    96      // inherit protos
    97      this.request.__proto__ = parent.request;
    98      this.response.__proto__ = parent.response;
    99      this.engines.__proto__ = parent.engines;
   100      this.settings.__proto__ = parent.settings;
   101    });
   102  
   103    // setup locals
   104    this.locals = Object.create(null);
   105  
   106    // top-most app is mounted at /
   107    this.mountpath = '/';
   108  
   109    // default locals
   110    this.locals.settings = this.settings;
   111  
   112    // default configuration
   113    this.set('view', View);
   114    this.set('views', resolve('views'));
   115    this.set('jsonp callback name', 'callback');
   116  
   117    if (env === 'production') {
   118      this.enable('view cache');
   119    }
   120  
   121    Object.defineProperty(this, 'router', {
   122      get: function() {
   123        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.');
   124      }
   125    });
   126  };
   127  
   128  /**
   129   * lazily adds the base router if it has not yet been added.
   130   *
   131   * We cannot add the base router in the defaultConfiguration because
   132   * it reads app settings which might be set after that has run.
   133   *
   134   * @private
   135   */
   136  app.lazyrouter = function lazyrouter() {
   137    if (!this._router) {
   138      this._router = new Router({
   139        caseSensitive: this.enabled('case sensitive routing'),
   140        strict: this.enabled('strict routing')
   141      });
   142  
   143      this._router.use(query(this.get('query parser fn')));
   144      this._router.use(middleware.init(this));
   145    }
   146  };
   147  
   148  /**
   149   * Dispatch a req, res pair into the application. Starts pipeline processing.
   150   *
   151   * If no callback is provided, then default error handlers will respond
   152   * in the event of an error bubbling through the stack.
   153   *
   154   * @private
   155   */
   156  
   157  app.handle = function handle(req, res, callback) {
   158    var router = this._router;
   159  
   160    // final handler
   161    var done = callback || finalhandler(req, res, {
   162      env: this.get('env'),
   163      onerror: logerror.bind(this)
   164    });
   165  
   166    // no routes
   167    if (!router) {
   168      debug('no routes defined on app');
   169      done();
   170      return;
   171    }
   172  
   173    router.handle(req, res, done);
   174  };
   175  
   176  /**
   177   * Proxy `Router#use()` to add middleware to the app router.
   178   * See Router#use() documentation for details.
   179   *
   180   * If the _fn_ parameter is an express app, then it will be
   181   * mounted at the _route_ specified.
   182   *
   183   * @public
   184   */
   185  
   186  app.use = function use(fn) {
   187    var offset = 0;
   188    var path = '/';
   189  
   190    // default path to '/'
   191    // disambiguate app.use([fn])
   192    if (typeof fn !== 'function') {
   193      var arg = fn;
   194  
   195      while (Array.isArray(arg) && arg.length !== 0) {
   196        arg = arg[0];
   197      }
   198  
   199      // first arg is the path
   200      if (typeof arg !== 'function') {
   201        offset = 1;
   202        path = fn;
   203      }
   204    }
   205  
   206    var fns = flatten(slice.call(arguments, offset));
   207  
   208    if (fns.length === 0) {
   209      throw new TypeError('app.use() requires middleware functions');
   210    }
   211  
   212    // setup router
   213    this.lazyrouter();
   214    var router = this._router;
   215  
   216    fns.forEach(function (fn) {
   217      // non-express app
   218      if (!fn || !fn.handle || !fn.set) {
   219        return router.use(path, fn);
   220      }
   221  
   222      debug('.use app under %s', path);
   223      fn.mountpath = path;
   224      fn.parent = this;
   225  
   226      // restore .app property on req and res
   227      router.use(path, function mounted_app(req, res, next) {
   228        var orig = req.app;
   229        fn.handle(req, res, function (err) {
   230          req.__proto__ = orig.request;
   231          res.__proto__ = orig.response;
   232          next(err);
   233        });
   234      });
   235  
   236      // mounted an app
   237      fn.emit('mount', this);
   238    }, this);
   239  
   240    return this;
   241  };
   242  
   243  /**
   244   * Proxy to the app `Router#route()`
   245   * Returns a new `Route` instance for the _path_.
   246   *
   247   * Routes are isolated middleware stacks for specific paths.
   248   * See the Route api docs for details.
   249   *
   250   * @public
   251   */
   252  
   253  app.route = function route(path) {
   254    this.lazyrouter();
   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.jade" file Express will invoke the following internally:
   265   *
   266   *     app.engine('jade', require('jade').__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 dont 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    this.lazyrouter();
   322  
   323    if (Array.isArray(name)) {
   324      for (var i = 0; i < name.length; i++) {
   325        this.param(name[i], fn);
   326      }
   327  
   328      return this;
   329    }
   330  
   331    this._router.param(name, fn);
   332  
   333    return this;
   334  };
   335  
   336  /**
   337   * Assign `setting` to `val`, or return `setting`'s value.
   338   *
   339   *    app.set('foo', 'bar');
   340   *    app.get('foo');
   341   *    // => "bar"
   342   *
   343   * Mounted servers inherit their parent server's settings.
   344   *
   345   * @param {String} setting
   346   * @param {*} [val]
   347   * @return {Server} for chaining
   348   * @public
   349   */
   350  
   351  app.set = function set(setting, val) {
   352    if (arguments.length === 1) {
   353      // app.get(setting)
   354      return this.settings[setting];
   355    }
   356  
   357    debug('set "%s" to %o', setting, val);
   358  
   359    // set value
   360    this.settings[setting] = val;
   361  
   362    // trigger matched settings
   363    switch (setting) {
   364      case 'etag':
   365        this.set('etag fn', compileETag(val));
   366        break;
   367      case 'query parser':
   368        this.set('query parser fn', compileQueryParser(val));
   369        break;
   370      case 'trust proxy':
   371        this.set('trust proxy fn', compileTrust(val));
   372  
   373        // trust proxy inherit back-compat
   374        Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
   375          configurable: true,
   376          value: false
   377        });
   378  
   379        break;
   380    }
   381  
   382    return this;
   383  };
   384  
   385  /**
   386   * Return the app's absolute pathname
   387   * based on the parent(s) that have
   388   * mounted it.
   389   *
   390   * For example if the application was
   391   * mounted as "/admin", which itself
   392   * was mounted as "/blog" then the
   393   * return value would be "/blog/admin".
   394   *
   395   * @return {String}
   396   * @private
   397   */
   398  
   399  app.path = function path() {
   400    return this.parent
   401      ? this.parent.path() + this.mountpath
   402      : '';
   403  };
   404  
   405  /**
   406   * Check if `setting` is enabled (truthy).
   407   *
   408   *    app.enabled('foo')
   409   *    // => false
   410   *
   411   *    app.enable('foo')
   412   *    app.enabled('foo')
   413   *    // => true
   414   *
   415   * @param {String} setting
   416   * @return {Boolean}
   417   * @public
   418   */
   419  
   420  app.enabled = function enabled(setting) {
   421    return Boolean(this.set(setting));
   422  };
   423  
   424  /**
   425   * Check if `setting` is disabled.
   426   *
   427   *    app.disabled('foo')
   428   *    // => true
   429   *
   430   *    app.enable('foo')
   431   *    app.disabled('foo')
   432   *    // => false
   433   *
   434   * @param {String} setting
   435   * @return {Boolean}
   436   * @public
   437   */
   438  
   439  app.disabled = function disabled(setting) {
   440    return !this.set(setting);
   441  };
   442  
   443  /**
   444   * Enable `setting`.
   445   *
   446   * @param {String} setting
   447   * @return {app} for chaining
   448   * @public
   449   */
   450  
   451  app.enable = function enable(setting) {
   452    return this.set(setting, true);
   453  };
   454  
   455  /**
   456   * Disable `setting`.
   457   *
   458   * @param {String} setting
   459   * @return {app} for chaining
   460   * @public
   461   */
   462  
   463  app.disable = function disable(setting) {
   464    return this.set(setting, false);
   465  };
   466  
   467  /**
   468   * Delegate `.VERB(...)` calls to `router.VERB(...)`.
   469   */
   470  
   471  methods.forEach(function(method){
   472    app[method] = function(path){
   473      if (method === 'get' && arguments.length === 1) {
   474        // app.get(setting)
   475        return this.set(path);
   476      }
   477  
   478      this.lazyrouter();
   479  
   480      var route = this._router.route(path);
   481      route[method].apply(route, slice.call(arguments, 1));
   482      return this;
   483    };
   484  });
   485  
   486  /**
   487   * Special-cased "all" method, applying the given route `path`,
   488   * middleware, and callback to _every_ HTTP method.
   489   *
   490   * @param {String} path
   491   * @param {Function} ...
   492   * @return {app} for chaining
   493   * @public
   494   */
   495  
   496  app.all = function all(path) {
   497    this.lazyrouter();
   498  
   499    var route = this._router.route(path);
   500    var args = slice.call(arguments, 1);
   501  
   502    for (var i = 0; i < methods.length; i++) {
   503      route[methods[i]].apply(route, args);
   504    }
   505  
   506    return this;
   507  };
   508  
   509  // del -> delete alias
   510  
   511  app.del = deprecate.function(app.delete, 'app.del: Use app.delete instead');
   512  
   513  /**
   514   * Render the given view `name` name with `options`
   515   * and a callback accepting an error and the
   516   * rendered template string.
   517   *
   518   * Example:
   519   *
   520   *    app.render('email', { name: 'Tobi' }, function(err, html){
   521   *      // ...
   522   *    })
   523   *
   524   * @param {String} name
   525   * @param {Object|Function} options or fn
   526   * @param {Function} callback
   527   * @public
   528   */
   529  
   530  app.render = function render(name, options, callback) {
   531    var cache = this.cache;
   532    var done = callback;
   533    var engines = this.engines;
   534    var opts = options;
   535    var renderOptions = {};
   536    var view;
   537  
   538    // support callback function as second arg
   539    if (typeof options === 'function') {
   540      done = options;
   541      opts = {};
   542    }
   543  
   544    // merge app.locals
   545    merge(renderOptions, this.locals);
   546  
   547    // merge options._locals
   548    if (opts._locals) {
   549      merge(renderOptions, opts._locals);
   550    }
   551  
   552    // merge options
   553    merge(renderOptions, opts);
   554  
   555    // set .cache unless explicitly provided
   556    if (renderOptions.cache == null) {
   557      renderOptions.cache = this.enabled('view cache');
   558    }
   559  
   560    // primed cache
   561    if (renderOptions.cache) {
   562      view = cache[name];
   563    }
   564  
   565    // view
   566    if (!view) {
   567      var View = this.get('view');
   568  
   569      view = new View(name, {
   570        defaultEngine: this.get('view engine'),
   571        root: this.get('views'),
   572        engines: engines
   573      });
   574  
   575      if (!view.path) {
   576        var dirs = Array.isArray(view.root) && view.root.length > 1
   577          ? 'directories "' + view.root.slice(0, -1).join('", "') + '" or "' + view.root[view.root.length - 1] + '"'
   578          : 'directory "' + view.root + '"'
   579        var err = new Error('Failed to lookup view "' + name + '" in views ' + dirs);
   580        err.view = view;
   581        return done(err);
   582      }
   583  
   584      // prime the cache
   585      if (renderOptions.cache) {
   586        cache[name] = view;
   587      }
   588    }
   589  
   590    // render
   591    tryRender(view, renderOptions, done);
   592  };
   593  
   594  /**
   595   * Listen for connections.
   596   *
   597   * A node `http.Server` is returned, with this
   598   * application (which is a `Function`) as its
   599   * callback. If you wish to create both an HTTP
   600   * and HTTPS server you may do so with the "http"
   601   * and "https" modules as shown here:
   602   *
   603   *    var http = require('http')
   604   *      , https = require('https')
   605   *      , express = require('express')
   606   *      , app = express();
   607   *
   608   *    http.createServer(app).listen(80);
   609   *    https.createServer({ ... }, app).listen(443);
   610   *
   611   * @return {http.Server}
   612   * @public
   613   */
   614  
   615  app.listen = function listen() {
   616    var server = http.createServer(this);
   617    return server.listen.apply(server, arguments);
   618  };
   619  
   620  /**
   621   * Log error using console.error.
   622   *
   623   * @param {Error} err
   624   * @private
   625   */
   626  
   627  function logerror(err) {
   628    /* istanbul ignore next */
   629    if (this.get('env') !== 'test') console.error(err.stack || err.toString());
   630  }
   631  
   632  /**
   633   * Try rendering a view.
   634   * @private
   635   */
   636  
   637  function tryRender(view, options, callback) {
   638    try {
   639      view.render(options, callback);
   640    } catch (err) {
   641      callback(err);
   642    }
   643  }