text: /*!
   * Connect - HTTPServer
   * Copyright(c) 2010 Sencha Inc.
   * Copyright(c) 2011 TJ Holowaychuk
   * MIT Licensed
   */
  
  /**
   * Module dependencies.
   */
  
  var http = require('http')
    , utils = require('./utils')
    , debug = require('debug')('connect:dispatcher');
  
  // prototype
  
  var app = module.exports = {};
  
  // environment
  
  var env = process.env.NODE_ENV || 'development';
  
  /**
   * 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_.
   *
   * Examples:
   *
   *      var app = connect();
   *      app.use(connect.favicon());
   *      app.use(connect.logger());
   *      app.use(connect.static(__dirname + '/public'));
   *
   * If we wanted to prefix static files with _/public_, we could
   * "mount" the `static()` middleware:
   *
   *      app.use('/public', connect.static(__dirname + '/public'));
   *
   * This api is chainable, so the following is valid:
   *
   *      connect()
   *        .use(connect.favicon())
   *        .use(connect.logger())
   *        .use(connect.static(__dirname + '/public'))
   *        .listen(3000);
   *
   * @param {String|Function|Server} route, callback or server
   * @param {Function|Server} callback or server
   * @return {Server} for chaining
   * @api public
   */
  
  app.use = function(route, fn){
    // default route to '/'
    if ('string' != typeof route) {
      fn = route;
      route = '/';
    }
  
    // wrap sub-apps
    if ('function' == typeof fn.handle) {
      var server = fn;
      fn.route = route;
      fn = function(req, res, next){
        server.handle(req, res, next);
      };
    }
  
    // wrap vanilla http.Servers
    if (fn instanceof http.Server) {
      fn = fn.listeners('request')[0];
    }
  
    // strip trailing slash
    if ('/' == route[route.length - 1]) {
      route = route.slice(0, -1);
    }
  
    // add the middleware
    debug('use %s %s', route || '/', fn.name || 'anonymous');
    this.stack.push({ route: route, handle: fn });
  
    return this;
  };
  
  /**
   * Handle server requests, punting them down
   * the middleware stack.
   *
   * @api private
   */
  
  app.handle = function(req, res, out) {
    var stack = this.stack
      , search = 1 + req.url.indexOf('?')
      , pathlength = search ? search - 1 : req.url.length
      , fqdn = 1 + req.url.substr(0, pathlength).indexOf('://')
      , protohost = fqdn ? req.url.substr(0, req.url.indexOf('/', 2 + fqdn)) : ''
      , removed = ''
      , slashAdded = false
      , index = 0;
  
    function next(err) {
      var layer, path, c;
  
      if (slashAdded) {
        req.url = req.url.substr(1);
        slashAdded = false;
      }
  
      req.url = protohost + removed + req.url.substr(protohost.length);
      req.originalUrl = req.originalUrl || req.url;
      removed = '';
  
      // next callback
      layer = stack[index++];
  
      // all done
      if (!layer || res.headerSent) {
        // delegate to parent
        if (out) return out(err);
  
        // unhandled error
        if (err) {
          // default to 500
          if (res.statusCode < 400) res.statusCode = 500;
          debug('default %s', res.statusCode);
  
          // respect err.status
          if (err.status) res.statusCode = err.status;
  
          // production gets a basic error message
          var msg = 'production' == env
            ? http.STATUS_CODES[res.statusCode]
            : err.stack || err.toString();
          msg = utils.escape(msg);
  
          // log to stderr in a non-test env
          if ('test' != env) console.error(err.stack || err.toString());
          if (res.headerSent) return req.socket.destroy();
          res.setHeader('Content-Type', 'text/html');
          res.setHeader('Content-Length', Buffer.byteLength(msg));
          if ('HEAD' == req.method) return res.end();
          res.end(msg);
        } else {
          debug('default 404');
          res.statusCode = 404;
          res.setHeader('Content-Type', 'text/html');
          if ('HEAD' == req.method) return res.end();
          res.end('Cannot ' + utils.escape(req.method) + ' ' + utils.escape(req.originalUrl));
        }
        return;
      }
  
      try {
        path = utils.parseUrl(req).pathname;
        if (undefined == path) path = '/';
  
        // skip this layer if the route doesn't match.
        if (0 != path.toLowerCase().indexOf(layer.route.toLowerCase())) 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 = protohost + req.url.substr(protohost.length + removed.length);
  
        // Ensure leading slash
        if (!fqdn && '/' != req.url[0]) {
          req.url = '/' + req.url;
          slashAdded = true;
        }
  
        debug('%s %s : %s', layer.handle.name || 'anonymous', layer.route, req.originalUrl);
        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) {
        next(e);
      }
    }
    next();
  };
  
  /**
   * Listen for connections.
   *
   * This method takes the same arguments
   * as node's `http.Server#listen()`.
   *
   * HTTP and HTTPS:
   *
   * If you run your application both as HTTP
   * and HTTPS you may wrap them individually,
   * since your Connect "server" is really just
   * a JavaScript `Function`.
   *
   *      var connect = require('connect')
   *        , http = require('http')
   *        , https = require('https');
   *
   *      var app = connect();
   *
   *      http.createServer(app).listen(80);
   *      https.createServer(options, app).listen(443);
   *
   * @return {http.Server}
   * @api public
   */
  
  app.listen = function(){
    var server = http.createServer(this);
    return server.listen.apply(server, arguments);
  };
  