Advertisement
YarikHrom

Untitled

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