Commit f70a9fbb authored by Thorsten Alteholz's avatar Thorsten Alteholz

Imported Upstream version 3.4.1

parent 3fc37b7f
coverage/
.DS_Store
pids
logs
results
*.pid
*.gz
*.log
test/fixtures/foo.bar.baz.css
test/fixtures/style.css
test/fixtures/script.js
test.js
docs/*.html
docs/*.json
node_modules
.idea
*.iml
coverage/
docs/
test/
.travis.yml
language: node_js
node_js:
- "0.10"
- "0.11"
matrix:
allow_failures:
- node_js: "0.11"
fast_finish: true
script: "npm run-script test-travis"
after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls"
- "0.12"
- "1.8"
- "2.5"
- "3.3"
- "4.2"
- "5.5"
sudo: false
script:
- "npm run-script test-travis"
after_script:
- "npm install coveralls@2 && cat ./coverage/lcov.info | coveralls"
This diff is collapsed.
......@@ -3,6 +3,7 @@
Copyright (c) 2010 Sencha Inc.
Copyright (c) 2011 LearnBoost
Copyright (c) 2011-2014 TJ Holowaychuk
Copyright (c) 2015 Douglas Christopher Wilson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
......
......@@ -4,89 +4,158 @@
[![NPM Downloads][downloads-image]][downloads-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
[![Gittip][gittip-image]][gittip-url]
[![Gratipay][gratipay-image]][gratipay-url]
Connect is an extensible HTTP server framework for [node](http://nodejs.org) using "plugins" known as _middleware_.
```js
var connect = require('connect')
var http = require('http')
var connect = require('connect');
var http = require('http');
var app = connect()
var app = connect();
// gzip/deflate outgoing responses
var compression = require('compression')
app.use(compression())
var compression = require('compression');
app.use(compression());
// store session state in browser cookie
var cookieSession = require('cookie-session')
var cookieSession = require('cookie-session');
app.use(cookieSession({
keys: ['secret1', 'secret2']
}))
}));
// parse urlencoded request bodies into req.body
var bodyParser = require('body-parser')
app.use(bodyParser.urlencoded())
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded());
// respond to all requests
app.use(function(req, res){
res.end('Hello from Connect!\n');
})
});
//create node.js http server and listen on port
http.createServer(app).listen(3000)
http.createServer(app).listen(3000);
```
## Connect 3.0
## Getting Started
Connect 3.0 is in progress in the `master` branch. The main changes in Connect are:
Connect is a simple framework to glue together various "middleware" to handle requests.
- Middleware will be moved to their own repositories in the [expressjs](http://github.com/expressjs) organization
- All node patches will be removed - all middleware _should_ work without Connect and with similar frameworks like [restify](https://github.com/mcavage/node-restify)
- Node `0.8` is no longer supported
- The website documentation has been removed - view the markdown readmes instead
### Install Connect
If you would like to help maintain these middleware, please contact a [member of the expressjs team](https://github.com/orgs/expressjs/people).
```sh
$ npm install connect
```
### Create an app
The main component is a Connect "app". This will store all the middleware
added and is, itself, a function.
```js
var app = connect();
```
### Use middleware
The core of Connect is "using" middleware. Middleware are added as a "stack"
where incoming requests will execute each middleware one-by-one until a middleware
does not call `next()` within it.
```js
app.use(function middleware1(req, res, next) {
// middleware 1
next();
});
app.use(function middleware2(req, res, next) {
// middleware 2
next();
});
```
### Mount middleware
The `.use()` method also takes an optional path string that is matched against
the beginning of the incoming request URL. This allows for basic routing.
```js
app.use('/foo', function fooMiddleware(req, res, next) {
// req.url starts with "/foo"
next();
});
app.use('/bar', function barMiddleware(req, res, next) {
// req.url starts with "/bar"
next();
});
```
### Error middleware
There are special cases of "error-handling" middleware. There are middleware
where the function takes exactly 4 arguments. Errors that occur in the middleware
added before the error middleware will invoke this middleware when errors occur.
```js
app.use(function onerror(err, req, res, next) {
// an error occurred!
});
```
### Create a server from the app
The last step is to actually use the Connect app in a server. The `.listen()` method
is a convenience to start a HTTP server.
```js
var server = app.listen(port);
```
The app itself is really just a function with three arguments, so it can also be handed
to `.createServer()` in Node.js.
```js
var server = http.createServer(app);
```
## Middleware
These middleware and libraries are officially supported by the Connect/Express team:
- [body-parser](https://github.com/expressjs/body-parser) - previous `bodyParser`, `json`, and `urlencoded`. You may also be interested in:
- [body](https://github.com/raynos/body)
- [co-body](https://github.com/visionmedia/co-body)
- [raw-body](https://github.com/stream-utils/raw-body)
- [compression](https://github.com/expressjs/compression) - previously `compress`
- [connect-timeout](https://github.com/expressjs/timeout) - previously `timeout`
- [cookie-parser](https://github.com/expressjs/cookie-parser) - previously `cookieParser`
- [cookie-session](https://github.com/expressjs/cookie-session) - previously `cookieSession`
- [csurf](https://github.com/expressjs/csurf) - previously `csrf`
- [errorhandler](https://github.com/expressjs/errorhandler) - previously `error-handler`
- [express-session](https://github.com/expressjs/session) - previously `session`
- [method-override](https://github.com/expressjs/method-override) - previously `method-override`
- [morgan](https://github.com/expressjs/morgan) - previously `logger`
- [response-time](https://github.com/expressjs/response-time) - previously `response-time`
- [serve-favicon](https://github.com/expressjs/serve-favicon) - previously `favicon`
- [serve-index](https://github.com/expressjs/serve-index) - previously `directory`
- [serve-static](https://github.com/expressjs/serve-static) - previously `static`
- [vhost](https://github.com/expressjs/vhost) - previously `vhost`
- [body-parser](https://www.npmjs.com/package/body-parser) - previous `bodyParser`, `json`, and `urlencoded`. You may also be interested in:
- [body](https://www.npmjs.com/package/body)
- [co-body](https://www.npmjs.com/package/co-body)
- [raw-body](https://www.npmjs.com/package/raw-body)
- [compression](https://www.npmjs.com/package/compression) - previously `compress`
- [connect-timeout](https://www.npmjs.com/package/connect-timeout) - previously `timeout`
- [cookie-parser](https://www.npmjs.com/package/cookie-parser) - previously `cookieParser`
- [cookie-session](https://www.npmjs.com/package/cookie-session) - previously `cookieSession`
- [csurf](https://www.npmjs.com/package/csurf) - previously `csrf`
- [errorhandler](https://www.npmjs.com/package/errorhandler) - previously `error-handler`
- [express-session](https://www.npmjs.com/package/express-session) - previously `session`
- [method-override](https://www.npmjs.com/package/method-override) - previously `method-override`
- [morgan](https://www.npmjs.com/package/morgan) - previously `logger`
- [response-time](https://www.npmjs.com/package/response-time) - previously `response-time`
- [serve-favicon](https://www.npmjs.com/package/serve-favicon) - previously `favicon`
- [serve-index](https://www.npmjs.com/package/serve-index) - previously `directory`
- [serve-static](https://www.npmjs.com/package/serve-static) - previously `static`
- [vhost](https://www.npmjs.com/package/vhost) - previously `vhost`
Most of these are exact ports of their Connect 2.x equivalents. The primary exception is `cookie-session`.
Some middleware previously included with Connect are no longer supported by the Connect/Express team, are replaced by an alternative module, or should be superseded by a better module. Use one of these alternatives instead:
- `cookieParser`
- [cookies](https://github.com/jed/cookies) and [keygrip](https://github.com/jed/keygrip)
- [cookies](https://www.npmjs.com/package/cookies) and [keygrip](https://www.npmjs.com/package/keygrip)
- `limit`
- [raw-body](https://github.com/stream-utils/raw-body)
- [raw-body](https://www.npmjs.com/package/raw-body)
- `multipart`
- [connect-multiparty](https://github.com/superjoe30/connect-multiparty)
- [connect-busboy](https://github.com/mscdex/connect-busboy)
- [connect-multiparty](https://www.npmjs.com/package/connect-multiparty)
- [connect-busboy](https://www.npmjs.com/package/connect-busboy)
- `query`
- [qs](https://github.com/visionmedia/node-querystring)
- [qs](https://www.npmjs.com/package/qs)
- `staticCache`
- [st](https://github.com/isaacs/st)
- [connect-static](https://github.com/andrewrk/connect-static)
- [st](https://www.npmjs.com/package/st)
- [connect-static](https://www.npmjs.com/package/connect-static)
Checkout [http-framework](https://github.com/Raynos/http-framework/wiki/Modules) for many other compatible middleware!
......@@ -107,19 +176,19 @@ npm test
- Connect `1.x` - node `0.4`
- Connect `< 2.8` - node `0.6`
- Connect `>= 2.8 < 3` - node `0.8`
- Connect `>= 3` - node `0.10`
- Connect `>= 3` - node `0.10`, `0.12`; io.js `1.x`, `2.x`
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/connect.svg?style=flat
[npm-image]: https://img.shields.io/npm/v/connect.svg
[npm-url]: https://npmjs.org/package/connect
[travis-image]: https://img.shields.io/travis/senchalabs/connect.svg?style=flat
[travis-image]: https://img.shields.io/travis/senchalabs/connect/master.svg
[travis-url]: https://travis-ci.org/senchalabs/connect
[coveralls-image]: https://img.shields.io/coveralls/senchalabs/connect.svg?style=flat
[coveralls-image]: https://img.shields.io/coveralls/senchalabs/connect/master.svg
[coveralls-url]: https://coveralls.io/r/senchalabs/connect
[downloads-image]: https://img.shields.io/npm/dm/connect.svg?style=flat
[downloads-image]: https://img.shields.io/npm/dm/connect.svg
[downloads-url]: https://npmjs.org/package/connect
[gittip-image]: https://img.shields.io/gittip/dougwilson.svg?style=flat
[gittip-url]: https://www.gittip.com/dougwilson/
[gratipay-image]: https://img.shields.io/gratipay/dougwilson.svg
[gratipay-url]: https://www.gratipay.com/dougwilson/
/*!
* connect
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
module.exports = require('./lib/connect');
'use strict';
/**
* Module dependencies.
* @private
*/
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.
* @public
*/
module.exports = createServer;
/**
* Module variables.
* @private
*/
var env = process.env.NODE_ENV || 'development';
var proto = {};
/* istanbul ignore next */
var defer = typeof setImmediate === 'function'
? setImmediate
: function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
/**
* Create a new connect server.
*
* @return {function}
* @public
*/
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;
}
/**
* 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_.
*
* @param {String|Function|Server} route, callback or server
* @param {Function|Server} callback or server
* @return {Server} for chaining
* @public
*/
proto.use = function use(route, fn) {
var handle = fn;
var path = route;
// default route to '/'
if (typeof route !== 'string') {
handle = route;
path = '/';
}
// wrap sub-apps
if (typeof handle.handle === 'function') {
var server = handle;
server.route = path;
handle = function (req, res, next) {
server.handle(req, res, next);
};
}
// wrap vanilla http.Servers
if (handle instanceof http.Server) {
handle = handle.listeners('request')[0];
}
// strip trailing slash
if (path[path.length - 1] === '/') {
path = path.slice(0, -1);
}
// add the middleware
debug('use %s %s', path || '/', handle.name || 'anonymous');
this.stack.push({ route: path, handle: handle });
return this;
};
/**
* Handle server requests, punting them down
* the middleware stack.
*
* @private
*/
proto.handle = function handle(req, res, out) {
var index = 0;
var protohost = getProtohost(req.url) || '';
var removed = '';
var slashAdded = false;
var stack = this.stack;
// final function handler
var done = out || finalhandler(req, res, {
env: env,
onerror: logerror
});
// store the original URL
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 = '';
}
// next callback
var layer = stack[index++];
// all done
if (!layer) {
defer(done, err);
return;
}
// route data
var path = parseUrl(req).pathname || '/';
var route = layer.route;
// skip this layer if the route doesn't match
if (path.toLowerCase().substr(0, route.length) !== route.toLowerCase()) {
return next(err);
}
// skip if route match does not border "/", ".", or end
var c = path[route.length];
if (c !== undefined && '/' !== c && '.' !== c) {
return next(err);
}
// trim off the part of the url that matches the route
if (route.length !== 0 && route !== '/') {
removed = route;
req.url = protohost + req.url.substr(protohost.length + removed.length);
// ensure leading slash
if (!protohost && req.url[0] !== '/') {
req.url = '/' + req.url;
slashAdded = true;
}
}
// call the layer handle
call(layer.handle, route, err, req, res, next);
}
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
*/
proto.listen = function listen() {
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
/**
* Invoke a route handle.
* @private
*/
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) {
// error-handling middleware
handle(err, req, res, next);
return;
} else if (!hasError && arity < 4) {
// request-handling middleware
handle(req, res, next);
return;
}
} catch (e) {
// replace the error
error = e;
}
// continue
next(error);
}
/**
* Log error using console.error.
*
* @param {Error} err
* @private
*/
function logerror(err) {
if (env !== 'test') console.error(err.stack || err.toString());
}
/**
* Get get protocol + host for a URL.
*
* @param {string} url
* @private
*/
function getProtohost(url) {
if (url.length === 0 || url[0] === '/') {
return undefined;
}
var searchIndex = url.indexOf('?');
var pathLength = searchIndex !== -1
? searchIndex
: url.length;
var fqdnIndex = url.substr(0, pathLength).indexOf('://');
return fqdnIndex !== -1
? url.substr(0, url.indexOf('/', 3 + fqdnIndex))
: undefined;
}
/*!
* Connect
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var EventEmitter = require('events').EventEmitter;
var merge = require('utils-merge');
var proto = require('./proto');
// expose createServer() as the module
module.exports = createServer;
/**
* Create a new connect server.
*
* @return {Function}
* @api public
*/
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;
}
/*!
* 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';
/**
* 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_.
*
* @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;
server.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 = 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
});
// store the original URL
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 = '';
}
// next callback
var layer = stack[index++];
// all done
if (!layer) {
done(err);
return;
}
// route data
var path = parseUrl(req).pathname || '/';
var route = layer.route;
// skip this layer if the route doesn't match
if (path.toLowerCase().substr(0, route.length) !== route.toLowerCase()) {
return next(err);
}
// skip if route match does not border "/", ".", or end
var c = path[route.length];
if (c !== undefined && '/' !== c && '.' !== c) {
return next(err);
}
// trim off the part of the url that matches the route
if (route.length !== 0 && route !== '/') {
removed = 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;
}
}
// call the layer handle