/node_modules/express/node_modules/connect/lib/http.js
https://gitlab.com/nhanvu/cyber-duck · JavaScript · 218 lines · 98 code · 32 blank · 88 comment · 43 complexity · 2bcfc3b1b3c6548cfbd236b3c4178031 MD5 · raw file
- /*!
- * Connect - HTTPServer
- * Copyright(c) 2010 Sencha Inc.
- * Copyright(c) 2011 TJ Holowaychuk
- * MIT Licensed
- */
-
- /**
- * Module dependencies.
- */
-
- var http = require('http')
- , parse = require('url').parse
- , assert = require('assert')
- , utils = require('./utils');
-
- // environment
-
- var env = process.env.NODE_ENV || 'development';
-
- /**
- * Initialize a new `Server` with the given `middleware`.
- *
- * Examples:
- *
- * var server = connect.createServer(
- * connect.favicon()
- * , connect.logger()
- * , connect.static(__dirname + '/public')
- * );
- *
- * @params {Array} middleware
- * @return {Server}
- * @api public
- */
-
- var Server = exports.Server = function HTTPServer(middleware) {
- this.stack = [];
- middleware.forEach(function(fn){
- this.use(fn);
- }, this);
- http.Server.call(this, this.handle);
- };
-
- /**
- * Inherit from `http.Server.prototype`.
- */
-
- Server.prototype.__proto__ = http.Server.prototype;
-
- /**
- * Utilize the given middleware `handle` to the given `route`,
- * defaulting to _/_. This "route" is the mount-point for the
- * middleware, when given a value other than _/_ the middleware
- * is only effective when that segment is present in the request's
- * pathname.
- *
- * For example if we were to mount a function at _/admin_, it would
- * be invoked on _/admin_, and _/admin/settings_, however it would
- * not be invoked for _/_, or _/posts_.
- *
- * This is effectively the same as passing middleware to `connect.createServer()`,
- * however provides a progressive api.
- *
- * Examples:
- *
- * var server = connect.createServer();
- * server.use(connect.favicon());
- * server.use(connect.logger());
- * server.use(connect.static(__dirname + '/public'));
- *
- * If we wanted to prefix static files with _/public_, we could
- * "mount" the `static()` middleware:
- *
- * server.use('/public', connect.static(__dirname + '/public'));
- *
- * This api is chainable, meaning the following is valid:
- *
- * connect.createServer()
- * .use(connect.favicon())
- * .use(connect.logger())
- * .use(connect.static(__dirname + '/public'))
- * .listen(3000);
- *
- * @param {String|Function} route or handle
- * @param {Function} handle
- * @return {Server}
- * @api public
- */
-
- Server.prototype.use = function(route, handle){
- this.route = '/';
-
- // default route to '/'
- if ('string' != typeof route) {
- handle = route;
- route = '/';
- }
-
- // wrap sub-apps
- if ('function' == typeof handle.handle) {
- var server = handle;
- server.route = route;
- handle = function(req, res, next) {
- server.handle(req, res, next);
- };
- }
-
- // wrap vanilla http.Servers
- if (handle instanceof http.Server) {
- handle = handle.listeners('request')[0];
- }
-
- // normalize route to not trail with slash
- if ('/' == route[route.length - 1]) {
- route = route.substr(0, route.length - 1);
- }
-
- // add the middleware
- this.stack.push({ route: route, handle: handle });
-
- // allow chaining
- return this;
- };
-
- /**
- * Handle server requests, punting them down
- * the middleware stack.
- *
- * @api private
- */
-
- Server.prototype.handle = function(req, res, out) {
- var writeHead = res.writeHead
- , stack = this.stack
- , removed = ''
- , index = 0;
-
- function next(err) {
- var layer, path, c;
- req.url = removed + req.url;
- req.originalUrl = req.originalUrl || req.url;
- removed = '';
-
- layer = stack[index++];
-
- // all done
- if (!layer || res.headerSent) {
- // but wait! we have a parent
- if (out) return out(err);
-
- // error
- if (err) {
- var msg = 'production' == env
- ? 'Internal Server Error'
- : err.stack || err.toString();
-
- // output to stderr in a non-test env
- if ('test' != env) console.error(err.stack || err.toString());
-
- // unable to respond
- if (res.headerSent) return req.socket.destroy();
-
- res.statusCode = 500;
- res.setHeader('Content-Type', 'text/plain');
- if ('HEAD' == req.method) return res.end();
- res.end(msg);
- } else {
- res.statusCode = 404;
- res.setHeader('Content-Type', 'text/plain');
- if ('HEAD' == req.method) return res.end();
- res.end('Cannot ' + req.method + ' ' + utils.escape(req.originalUrl));
- }
- return;
- }
-
- try {
- path = parse(req.url).pathname;
- if (undefined == path) path = '/';
-
- // skip this layer if the route doesn't match.
- if (0 != path.indexOf(layer.route)) return next(err);
-
- c = path[layer.route.length];
- if (c && '/' != c && '.' != c) return next(err);
-
- // Call the layer handler
- // Trim off the part of the url that matches the route
- removed = layer.route;
- req.url = req.url.substr(removed.length);
-
- // Ensure leading slash
- if ('/' != req.url[0]) req.url = '/' + req.url;
-
- var arity = layer.handle.length;
- if (err) {
- if (arity === 4) {
- layer.handle(err, req, res, next);
- } else {
- next(err);
- }
- } else if (arity < 4) {
- layer.handle(req, res, next);
- } else {
- next();
- }
- } catch (e) {
- if (e instanceof assert.AssertionError) {
- console.error(e.stack + '\n');
- next(e);
- } else {
- next(e);
- }
- }
- }
- next();
- };