123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- 'use strict';
- var debug = require('debug')('connect:dispatcher');
- var EventEmitter = require('events').EventEmitter;
- var finalhandler = require('finalhandler');
- var http = require('http');
- var merge = require('utils-merge');
- var parseUrl = require('parseurl');
- module.exports = createServer;
- var env = process.env.NODE_ENV || 'development';
- var proto = {};
- var defer = typeof setImmediate === 'function'
- ? setImmediate
- : function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
- function createServer() {
- function app(req, res, next){ app.handle(req, res, next); }
- merge(app, proto);
- merge(app, EventEmitter.prototype);
- app.route = '/';
- app.stack = [];
- return app;
- }
- proto.use = function use(route, fn) {
- var handle = fn;
- var path = route;
-
- if (typeof route !== 'string') {
- handle = route;
- path = '/';
- }
-
- if (typeof handle.handle === 'function') {
- var server = handle;
- server.route = path;
- handle = function (req, res, next) {
- server.handle(req, res, next);
- };
- }
-
- if (handle instanceof http.Server) {
- handle = handle.listeners('request')[0];
- }
-
- if (path[path.length - 1] === '/') {
- path = path.slice(0, -1);
- }
-
- debug('use %s %s', path || '/', handle.name || 'anonymous');
- this.stack.push({ route: path, handle: handle });
- return this;
- };
- proto.handle = function handle(req, res, out) {
- var index = 0;
- var protohost = getProtohost(req.url) || '';
- var removed = '';
- var slashAdded = false;
- var stack = this.stack;
-
- var done = out || finalhandler(req, res, {
- env: env,
- onerror: logerror
- });
-
- req.originalUrl = req.originalUrl || req.url;
- function next(err) {
- if (slashAdded) {
- req.url = req.url.substr(1);
- slashAdded = false;
- }
- if (removed.length !== 0) {
- req.url = protohost + removed + req.url.substr(protohost.length);
- removed = '';
- }
-
- var layer = stack[index++];
-
- if (!layer) {
- defer(done, err);
- return;
- }
-
- var path = parseUrl(req).pathname || '/';
- var route = layer.route;
-
- if (path.toLowerCase().substr(0, route.length) !== route.toLowerCase()) {
- return next(err);
- }
-
- var c = path.length > route.length && path[route.length];
- if (c && c !== '/' && c !== '.') {
- return next(err);
- }
-
- if (route.length !== 0 && route !== '/') {
- removed = route;
- req.url = protohost + req.url.substr(protohost.length + removed.length);
-
- if (!protohost && req.url[0] !== '/') {
- req.url = '/' + req.url;
- slashAdded = true;
- }
- }
-
- call(layer.handle, route, err, req, res, next);
- }
- next();
- };
- proto.listen = function listen() {
- var server = http.createServer(this);
- return server.listen.apply(server, arguments);
- };
- function call(handle, route, err, req, res, next) {
- var arity = handle.length;
- var error = err;
- var hasError = Boolean(err);
- debug('%s %s : %s', handle.name || '<anonymous>', route, req.originalUrl);
- try {
- if (hasError && arity === 4) {
-
- handle(err, req, res, next);
- return;
- } else if (!hasError && arity < 4) {
-
- handle(req, res, next);
- return;
- }
- } catch (e) {
-
- error = e;
- }
-
- next(error);
- }
- function logerror(err) {
- if (env !== 'test') console.error(err.stack || err.toString());
- }
- function getProtohost(url) {
- if (url.length === 0 || url[0] === '/') {
- return undefined;
- }
- var fqdnIndex = url.indexOf('://')
- return fqdnIndex !== -1 && url.lastIndexOf('?', fqdnIndex) === -1
- ? url.substr(0, url.indexOf('/', 3 + fqdnIndex))
- : undefined;
- }
|