aboutsummaryrefslogtreecommitdiffstats
path: root/node_modules/express/lib/application.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/express/lib/application.js')
-rw-r--r--node_modules/express/lib/application.js531
1 files changed, 531 insertions, 0 deletions
diff --git a/node_modules/express/lib/application.js b/node_modules/express/lib/application.js
new file mode 100644
index 0000000..e841c12
--- /dev/null
+++ b/node_modules/express/lib/application.js
@@ -0,0 +1,531 @@
+/**
+ * Module dependencies.
+ */
+
+var connect = require('connect')
+ , Router = require('./router')
+ , methods = require('methods')
+ , middleware = require('./middleware')
+ , debug = require('debug')('express:application')
+ , locals = require('./utils').locals
+ , View = require('./view')
+ , utils = connect.utils
+ , path = require('path')
+ , http = require('http')
+ , join = path.join;
+
+/**
+ * Application prototype.
+ */
+
+var app = exports = module.exports = {};
+
+/**
+ * Initialize the server.
+ *
+ * - setup default configuration
+ * - setup default middleware
+ * - setup route reflection methods
+ *
+ * @api private
+ */
+
+app.init = function(){
+ this.cache = {};
+ this.settings = {};
+ this.engines = {};
+ this.defaultConfiguration();
+};
+
+/**
+ * Initialize application configuration.
+ *
+ * @api private
+ */
+
+app.defaultConfiguration = function(){
+ // default settings
+ this.enable('x-powered-by');
+ this.set('env', process.env.NODE_ENV || 'development');
+ this.set('subdomain offset', 2);
+ debug('booting in %s mode', this.get('env'));
+
+ // implicit middleware
+ this.use(connect.query());
+ this.use(middleware.init(this));
+
+ // inherit protos
+ this.on('mount', function(parent){
+ this.request.__proto__ = parent.request;
+ this.response.__proto__ = parent.response;
+ this.engines.__proto__ = parent.engines;
+ this.settings.__proto__ = parent.settings;
+ });
+
+ // router
+ this._router = new Router(this);
+ this.routes = this._router.map;
+ this.__defineGetter__('router', function(){
+ this._usedRouter = true;
+ this._router.caseSensitive = this.enabled('case sensitive routing');
+ this._router.strict = this.enabled('strict routing');
+ return this._router.middleware;
+ });
+
+ // setup locals
+ this.locals = locals(this);
+
+ // default locals
+ this.locals.settings = this.settings;
+
+ // default configuration
+ this.set('view', View);
+ this.set('views', process.cwd() + '/views');
+ this.set('jsonp callback name', 'callback');
+
+ this.configure('development', function(){
+ this.set('json spaces', 2);
+ });
+
+ this.configure('production', function(){
+ this.enable('view cache');
+ });
+};
+
+/**
+ * Proxy `connect#use()` to apply settings to
+ * mounted applications.
+ *
+ * @param {String|Function|Server} route
+ * @param {Function|Server} fn
+ * @return {app} for chaining
+ * @api public
+ */
+
+app.use = function(route, fn){
+ var app;
+
+ // default route to '/'
+ if ('string' != typeof route) fn = route, route = '/';
+
+ // express app
+ if (fn.handle && fn.set) app = fn;
+
+ // restore .app property on req and res
+ if (app) {
+ app.route = route;
+ fn = function(req, res, next) {
+ var orig = req.app;
+ app.handle(req, res, function(err){
+ req.app = res.app = orig;
+ req.__proto__ = orig.request;
+ res.__proto__ = orig.response;
+ next(err);
+ });
+ };
+ }
+
+ connect.proto.use.call(this, route, fn);
+
+ // mounted an app
+ if (app) {
+ app.parent = this;
+ app.emit('mount', this);
+ }
+
+ return this;
+};
+
+/**
+ * Register the given template engine callback `fn`
+ * as `ext`.
+ *
+ * By default will `require()` the engine based on the
+ * file extension. For example if you try to render
+ * a "foo.jade" file Express will invoke the following internally:
+ *
+ * app.engine('jade', require('jade').__express);
+ *
+ * For engines that do not provide `.__express` out of the box,
+ * or if you wish to "map" a different extension to the template engine
+ * you may use this method. For example mapping the EJS template engine to
+ * ".html" files:
+ *
+ * app.engine('html', require('ejs').renderFile);
+ *
+ * In this case EJS provides a `.renderFile()` method with
+ * the same signature that Express expects: `(path, options, callback)`,
+ * though note that it aliases this method as `ejs.__express` internally
+ * so if you're using ".ejs" extensions you dont need to do anything.
+ *
+ * Some template engines do not follow this convention, the
+ * [Consolidate.js](https://github.com/visionmedia/consolidate.js)
+ * library was created to map all of node's popular template
+ * engines to follow this convention, thus allowing them to
+ * work seamlessly within Express.
+ *
+ * @param {String} ext
+ * @param {Function} fn
+ * @return {app} for chaining
+ * @api public
+ */
+
+app.engine = function(ext, fn){
+ if ('function' != typeof fn) throw new Error('callback function required');
+ if ('.' != ext[0]) ext = '.' + ext;
+ this.engines[ext] = fn;
+ return this;
+};
+
+/**
+ * Map the given param placeholder `name`(s) to the given callback(s).
+ *
+ * Parameter mapping is used to provide pre-conditions to routes
+ * which use normalized placeholders. For example a _:user_id_ parameter
+ * could automatically load a user's information from the database without
+ * any additional code,
+ *
+ * The callback uses the samesignature as middleware, the only differencing
+ * being that the value of the placeholder is passed, in this case the _id_
+ * of the user. Once the `next()` function is invoked, just like middleware
+ * it will continue on to execute the route, or subsequent parameter functions.
+ *
+ * app.param('user_id', function(req, res, next, id){
+ * User.find(id, function(err, user){
+ * if (err) {
+ * next(err);
+ * } else if (user) {
+ * req.user = user;
+ * next();
+ * } else {
+ * next(new Error('failed to load user'));
+ * }
+ * });
+ * });
+ *
+ * @param {String|Array} name
+ * @param {Function} fn
+ * @return {app} for chaining
+ * @api public
+ */
+
+app.param = function(name, fn){
+ var self = this
+ , fns = [].slice.call(arguments, 1);
+
+ // array
+ if (Array.isArray(name)) {
+ name.forEach(function(name){
+ fns.forEach(function(fn){
+ self.param(name, fn);
+ });
+ });
+ // param logic
+ } else if ('function' == typeof name) {
+ this._router.param(name);
+ // single
+ } else {
+ if (':' == name[0]) name = name.substr(1);
+ fns.forEach(function(fn){
+ self._router.param(name, fn);
+ });
+ }
+
+ return this;
+};
+
+/**
+ * Assign `setting` to `val`, or return `setting`'s value.
+ *
+ * app.set('foo', 'bar');
+ * app.get('foo');
+ * // => "bar"
+ *
+ * Mounted servers inherit their parent server's settings.
+ *
+ * @param {String} setting
+ * @param {String} val
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.set = function(setting, val){
+ if (1 == arguments.length) {
+ return this.settings[setting];
+ } else {
+ this.settings[setting] = val;
+ return this;
+ }
+};
+
+/**
+ * Return the app's absolute pathname
+ * based on the parent(s) that have
+ * mounted it.
+ *
+ * For example if the application was
+ * mounted as "/admin", which itself
+ * was mounted as "/blog" then the
+ * return value would be "/blog/admin".
+ *
+ * @return {String}
+ * @api private
+ */
+
+app.path = function(){
+ return this.parent
+ ? this.parent.path() + this.route
+ : '';
+};
+
+/**
+ * Check if `setting` is enabled (truthy).
+ *
+ * app.enabled('foo')
+ * // => false
+ *
+ * app.enable('foo')
+ * app.enabled('foo')
+ * // => true
+ *
+ * @param {String} setting
+ * @return {Boolean}
+ * @api public
+ */
+
+app.enabled = function(setting){
+ return !!this.set(setting);
+};
+
+/**
+ * Check if `setting` is disabled.
+ *
+ * app.disabled('foo')
+ * // => true
+ *
+ * app.enable('foo')
+ * app.disabled('foo')
+ * // => false
+ *
+ * @param {String} setting
+ * @return {Boolean}
+ * @api public
+ */
+
+app.disabled = function(setting){
+ return !this.set(setting);
+};
+
+/**
+ * Enable `setting`.
+ *
+ * @param {String} setting
+ * @return {app} for chaining
+ * @api public
+ */
+
+app.enable = function(setting){
+ return this.set(setting, true);
+};
+
+/**
+ * Disable `setting`.
+ *
+ * @param {String} setting
+ * @return {app} for chaining
+ * @api public
+ */
+
+app.disable = function(setting){
+ return this.set(setting, false);
+};
+
+/**
+ * Configure callback for zero or more envs,
+ * when no `env` is specified that callback will
+ * be invoked for all environments. Any combination
+ * can be used multiple times, in any order desired.
+ *
+ * Examples:
+ *
+ * app.configure(function(){
+ * // executed for all envs
+ * });
+ *
+ * app.configure('stage', function(){
+ * // executed staging env
+ * });
+ *
+ * app.configure('stage', 'production', function(){
+ * // executed for stage and production
+ * });
+ *
+ * Note:
+ *
+ * These callbacks are invoked immediately, and
+ * are effectively sugar for the following:
+ *
+ * var env = process.env.NODE_ENV || 'development';
+ *
+ * switch (env) {
+ * case 'development':
+ * ...
+ * break;
+ * case 'stage':
+ * ...
+ * break;
+ * case 'production':
+ * ...
+ * break;
+ * }
+ *
+ * @param {String} env...
+ * @param {Function} fn
+ * @return {app} for chaining
+ * @api public
+ */
+
+app.configure = function(env, fn){
+ var envs = 'all'
+ , args = [].slice.call(arguments);
+ fn = args.pop();
+ if (args.length) envs = args;
+ if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this);
+ return this;
+};
+
+/**
+ * Delegate `.VERB(...)` calls to `router.VERB(...)`.
+ */
+
+methods.forEach(function(method){
+ app[method] = function(path){
+ if ('get' == method && 1 == arguments.length) return this.set(path);
+
+ // if no router attached yet, attach the router
+ if (!this._usedRouter) this.use(this.router);
+
+ // setup route
+ this._router[method].apply(this._router, arguments);
+ return this;
+ };
+});
+
+/**
+ * Special-cased "all" method, applying the given route `path`,
+ * middleware, and callback to _every_ HTTP method.
+ *
+ * @param {String} path
+ * @param {Function} ...
+ * @return {app} for chaining
+ * @api public
+ */
+
+app.all = function(path){
+ var args = arguments;
+ methods.forEach(function(method){
+ app[method].apply(this, args);
+ }, this);
+ return this;
+};
+
+// del -> delete alias
+
+app.del = app.delete;
+
+/**
+ * Render the given view `name` name with `options`
+ * and a callback accepting an error and the
+ * rendered template string.
+ *
+ * Example:
+ *
+ * app.render('email', { name: 'Tobi' }, function(err, html){
+ * // ...
+ * })
+ *
+ * @param {String} name
+ * @param {String|Function} options or fn
+ * @param {Function} fn
+ * @api public
+ */
+
+app.render = function(name, options, fn){
+ var opts = {}
+ , cache = this.cache
+ , engines = this.engines
+ , view;
+
+ // support callback function as second arg
+ if ('function' == typeof options) {
+ fn = options, options = {};
+ }
+
+ // merge app.locals
+ utils.merge(opts, this.locals);
+
+ // merge options._locals
+ if (options._locals) utils.merge(opts, options._locals);
+
+ // merge options
+ utils.merge(opts, options);
+
+ // set .cache unless explicitly provided
+ opts.cache = null == opts.cache
+ ? this.enabled('view cache')
+ : opts.cache;
+
+ // primed cache
+ if (opts.cache) view = cache[name];
+
+ // view
+ if (!view) {
+ view = new (this.get('view'))(name, {
+ defaultEngine: this.get('view engine'),
+ root: this.get('views'),
+ engines: engines
+ });
+
+ if (!view.path) {
+ var err = new Error('Failed to lookup view "' + name + '"');
+ err.view = view;
+ return fn(err);
+ }
+
+ // prime the cache
+ if (opts.cache) cache[name] = view;
+ }
+
+ // render
+ try {
+ view.render(opts, fn);
+ } catch (err) {
+ fn(err);
+ }
+};
+
+/**
+ * Listen for connections.
+ *
+ * A node `http.Server` is returned, with this
+ * application (which is a `Function`) as its
+ * callback. If you wish to create both an HTTP
+ * and HTTPS server you may do so with the "http"
+ * and "https" modules as shown here:
+ *
+ * var http = require('http')
+ * , https = require('https')
+ * , express = require('express')
+ * , app = express();
+ *
+ * http.createServer(app).listen(80);
+ * https.createServer({ ... }, app).listen(443);
+ *
+ * @return {http.Server}
+ * @api public
+ */
+
+app.listen = function(){
+ var server = http.createServer(this);
+ return server.listen.apply(server, arguments);
+};