summaryrefslogtreecommitdiff
path: root/node_modules/express/lib/http.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/express/lib/http.js')
-rw-r--r--node_modules/express/lib/http.js582
1 files changed, 582 insertions, 0 deletions
diff --git a/node_modules/express/lib/http.js b/node_modules/express/lib/http.js
new file mode 100644
index 0000000..da2158f
--- /dev/null
+++ b/node_modules/express/lib/http.js
@@ -0,0 +1,582 @@
+/*!
+ * Express - HTTPServer
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var qs = require('qs')
+ , connect = require('connect')
+ , router = require('./router')
+ , Router = require('./router')
+ , view = require('./view')
+ , toArray = require('./utils').toArray
+ , methods = router.methods.concat('del', 'all')
+ , url = require('url')
+ , utils = connect.utils;
+
+/**
+ * Expose `HTTPServer`.
+ */
+
+exports = module.exports = HTTPServer;
+
+/**
+ * Server proto.
+ */
+
+var app = HTTPServer.prototype;
+
+/**
+ * Initialize a new `HTTPServer` with optional `middleware`.
+ *
+ * @param {Array} middleware
+ * @api public
+ */
+
+function HTTPServer(middleware){
+ connect.HTTPServer.call(this, []);
+ this.init(middleware);
+};
+
+/**
+ * Inherit from `connect.HTTPServer`.
+ */
+
+app.__proto__ = connect.HTTPServer.prototype;
+
+/**
+ * Initialize the server.
+ *
+ * @param {Array} middleware
+ * @api private
+ */
+
+app.init = function(middleware){
+ var self = this;
+ this.cache = {};
+ this.settings = {};
+ this.redirects = {};
+ this.isCallbacks = {};
+ this._locals = {};
+ this.dynamicViewHelpers = {};
+ this.errorHandlers = [];
+
+ this.set('env', process.env.NODE_ENV || 'development');
+
+ // expose objects to each other
+ this.use(function(req, res, next){
+ req.query = req.query || {};
+ res.setHeader('X-Powered-By', 'Express');
+ req.app = res.app = self;
+ req.res = res;
+ res.req = req;
+ req.next = next;
+ // assign req.query
+ if (req.url.indexOf('?') > 0) {
+ var query = url.parse(req.url).query;
+ req.query = qs.parse(query);
+ }
+ next();
+ });
+
+ // apply middleware
+ if (middleware) middleware.forEach(self.use.bind(self));
+
+ // router
+ this.routes = new Router(this);
+ this.__defineGetter__('router', function(){
+ this.__usedRouter = true;
+ return self.routes.middleware;
+ });
+
+ // default locals
+ this.locals({
+ settings: this.settings
+ , app: this
+ });
+
+ // default development configuration
+ this.configure('development', function(){
+ this.enable('hints');
+ });
+
+ // default production configuration
+ this.configure('production', function(){
+ this.enable('view cache');
+ });
+
+ // register error handlers on "listening"
+ // so that they disregard definition position.
+ this.on('listening', this.registerErrorHandlers.bind(this));
+
+ // route manipulation methods
+ methods.forEach(function(method){
+ self.lookup[method] = function(path){
+ return self.routes.lookup(method, path);
+ };
+
+ self.match[method] = function(path){
+ return self.routes.match(method, path);
+ };
+
+ self.remove[method] = function(path){
+ return self.routes.lookup(method, path).remove();
+ };
+ });
+
+ // del -> delete
+ self.lookup.del = self.lookup.delete;
+ self.match.del = self.match.delete;
+ self.remove.del = self.remove.delete;
+};
+
+/**
+ * Remove routes matching the given `path`.
+ *
+ * @param {Route} path
+ * @return {Boolean}
+ * @api public
+ */
+
+app.remove = function(path){
+ return this.routes.lookup('all', path).remove();
+};
+
+/**
+ * Lookup routes defined with a path
+ * equivalent to `path`.
+ *
+ * @param {Stirng} path
+ * @return {Array}
+ * @api public
+ */
+
+app.lookup = function(path){
+ return this.routes.lookup('all', path);
+};
+
+/**
+ * Lookup routes matching the given `url`.
+ *
+ * @param {Stirng} url
+ * @return {Array}
+ * @api public
+ */
+
+app.match = function(url){
+ return this.routes.match('all', url);
+};
+
+/**
+ * When using the vhost() middleware register error handlers.
+ */
+
+app.onvhost = function(){
+ this.registerErrorHandlers();
+};
+
+/**
+ * Register error handlers.
+ *
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.registerErrorHandlers = function(){
+ this.errorHandlers.forEach(function(fn){
+ this.use(function(err, req, res, next){
+ fn.apply(this, arguments);
+ });
+ }, this);
+ return this;
+};
+
+/**
+ * Proxy `connect.HTTPServer#use()` to apply settings to
+ * mounted applications.
+ *
+ * @param {String|Function|Server} route
+ * @param {Function|Server} middleware
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.use = function(route, middleware){
+ var app, base, handle;
+
+ if ('string' != typeof route) {
+ middleware = route, route = '/';
+ }
+
+ // express app
+ if (middleware.handle && middleware.set) app = middleware;
+
+ // restore .app property on req and res
+ if (app) {
+ app.route = route;
+ middleware = function(req, res, next) {
+ var orig = req.app;
+ app.handle(req, res, function(err){
+ req.app = res.app = orig;
+ next(err);
+ });
+ };
+ }
+
+ connect.HTTPServer.prototype.use.call(this, route, middleware);
+
+ // mounted an app, invoke the hook
+ // and adjust some settings
+ if (app) {
+ base = this.set('basepath') || this.route;
+ if ('/' == base) base = '';
+ base = base + (app.set('basepath') || app.route);
+ app.set('basepath', base);
+ app.parent = this;
+ if (app.__mounted) app.__mounted.call(app, this);
+ }
+
+ return this;
+};
+
+/**
+ * Assign a callback `fn` which is called
+ * when this `Server` is passed to `Server#use()`.
+ *
+ * Examples:
+ *
+ * var app = express.createServer()
+ * , blog = express.createServer();
+ *
+ * blog.mounted(function(parent){
+ * // parent is app
+ * // "this" is blog
+ * });
+ *
+ * app.use(blog);
+ *
+ * @param {Function} fn
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.mounted = function(fn){
+ this.__mounted = fn;
+ return this;
+};
+
+/**
+ * See: view.register.
+ *
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.register = function(){
+ view.register.apply(this, arguments);
+ return this;
+};
+
+/**
+ * Register the given view helpers `obj`. This method
+ * can be called several times to apply additional helpers.
+ *
+ * @param {Object} obj
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.helpers =
+app.locals = function(obj){
+ utils.merge(this._locals, obj);
+ return this;
+};
+
+/**
+ * Register the given dynamic view helpers `obj`. This method
+ * can be called several times to apply additional helpers.
+ *
+ * @param {Object} obj
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.dynamicHelpers = function(obj){
+ utils.merge(this.dynamicViewHelpers, obj);
+ return this;
+};
+
+/**
+ * Map the given param placeholder `name`(s) to the given callback(s).
+ *
+ * Param mapping is used to provide pre-conditions to routes
+ * which us normalized placeholders. This callback has the same
+ * signature as regular middleware, for example below when ":userId"
+ * is used this function will be invoked in an attempt to load the user.
+ *
+ * app.param('userId', 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'));
+ * }
+ * });
+ * });
+ *
+ * Passing a single function allows you to map logic
+ * to the values passed to `app.param()`, for example
+ * this is useful to provide coercion support in a concise manner.
+ *
+ * The following example maps regular expressions to param values
+ * ensuring that they match, otherwise passing control to the next
+ * route:
+ *
+ * app.param(function(name, regexp){
+ * if (regexp instanceof RegExp) {
+ * return function(req, res, next, val){
+ * var captures;
+ * if (captures = regexp.exec(String(val))) {
+ * req.params[name] = captures;
+ * next();
+ * } else {
+ * next('route');
+ * }
+ * }
+ * }
+ * });
+ *
+ * We can now use it as shown below, where "/commit/:commit" expects
+ * that the value for ":commit" is at 5 or more digits. The capture
+ * groups are then available as `req.params.commit` as we defined
+ * in the function above.
+ *
+ * app.param('commit', /^\d{5,}$/);
+ *
+ * For more of this useful functionality take a look
+ * at [express-params](http://github.com/visionmedia/express-params).
+ *
+ * @param {String|Array|Function} name
+ * @param {Function} fn
+ * @return {Server} 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.routes.param(name);
+ // single
+ } else {
+ if (':' == name[0]) name = name.substr(1);
+ fns.forEach(function(fn){
+ self.routes.param(name, fn);
+ });
+ }
+
+ return this;
+};
+
+/**
+ * Assign a custom exception handler callback `fn`.
+ * These handlers are always _last_ in the middleware stack.
+ *
+ * @param {Function} fn
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.error = function(fn){
+ this.errorHandlers.push(fn);
+ return this;
+};
+
+/**
+ * Register the given callback `fn` for the given `type`.
+ *
+ * @param {String} type
+ * @param {Function} fn
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.is = function(type, fn){
+ if (!fn) return this.isCallbacks[type];
+ this.isCallbacks[type] = fn;
+ return this;
+};
+
+/**
+ * Assign `setting` to `val`, or return `setting`'s value.
+ * Mounted servers inherit their parent server's settings.
+ *
+ * @param {String} setting
+ * @param {String} val
+ * @return {Server|Mixed} for chaining, or the setting value
+ * @api public
+ */
+
+app.set = function(setting, val){
+ if (val === undefined) {
+ if (this.settings.hasOwnProperty(setting)) {
+ return this.settings[setting];
+ } else if (this.parent) {
+ return this.parent.set(setting);
+ }
+ } else {
+ this.settings[setting] = val;
+ return this;
+ }
+};
+
+/**
+ * Check if `setting` is enabled.
+ *
+ * @param {String} setting
+ * @return {Boolean}
+ * @api public
+ */
+
+app.enabled = function(setting){
+ return !!this.set(setting);
+};
+
+/**
+ * Check if `setting` is disabled.
+ *
+ * @param {String} setting
+ * @return {Boolean}
+ * @api public
+ */
+
+app.disabled = function(setting){
+ return !this.set(setting);
+};
+
+/**
+ * Enable `setting`.
+ *
+ * @param {String} setting
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.enable = function(setting){
+ return this.set(setting, true);
+};
+
+/**
+ * Disable `setting`.
+ *
+ * @param {String} setting
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.disable = function(setting){
+ return this.set(setting, false);
+};
+
+/**
+ * Redirect `key` to `url`.
+ *
+ * @param {String} key
+ * @param {String} url
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.redirect = function(key, url){
+ this.redirects[key] = url;
+ return this;
+};
+
+/**
+ * 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
+ * });
+ *
+ * @param {String} env...
+ * @param {Function} fn
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.configure = function(env, fn){
+ var envs = 'all'
+ , args = toArray(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 `.route(VERB, ...)`.
+ */
+
+methods.forEach(function(method){
+ app[method] = function(path){
+ if (1 == arguments.length) return this.routes.lookup(method, path);
+ var args = [method].concat(toArray(arguments));
+ if (!this.__usedRouter) this.use(this.router);
+ return this.routes._route.apply(this.routes, args);
+ }
+});
+
+/**
+ * Special-cased "all" method, applying the given route `path`,
+ * middleware, and callback to _every_ HTTP method.
+ *
+ * @param {String} path
+ * @param {Function} ...
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.all = function(path){
+ var args = arguments;
+ if (1 == args.length) return this.routes.lookup('all', path);
+ methods.forEach(function(method){
+ if ('all' == method || 'del' == method) return;
+ app[method].apply(this, args);
+ }, this);
+ return this;
+};
+
+// del -> delete alias
+
+app.del = app.delete;
+