GT2/GT2-Android/node_modules/connect/lib/proto.js

226 lines
5.3 KiB
JavaScript

/*!
* Connect - HTTPServer
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var finalhandler = require('finalhandler');
var http = require('http');
var debug = require('debug')('connect:dispatcher');
var parseUrl = require('parseurl');
// prototype
var app = module.exports = {};
// environment
var env = process.env.NODE_ENV || 'development';
/* istanbul ignore next */
var defer = typeof setImmediate === 'function'
? setImmediate
: function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
/**
* 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
, searchIndex = req.url.indexOf('?')
, pathlength = searchIndex !== -1 ? searchIndex : req.url.length
, fqdn = req.url[0] !== '/' && 1 + req.url.substr(0, pathlength).indexOf('://')
, protohost = fqdn ? req.url.substr(0, req.url.indexOf('/', 2 + fqdn)) : ''
, removed = ''
, slashAdded = false
, index = 0;
// final function handler
var done = out || finalhandler(req, res, {
env: env,
onerror: logerror
});
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) {
defer(done, err);
return;
}
try {
path = 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);
};
/**
* Log error using console.error.
*
* @param {Error} err
* @api public
*/
function logerror(err){
if (env !== 'test') console.error(err.stack || err.toString());
}