Merge tag '4.12.4'

This commit is contained in:
Douglas Christopher Wilson 2015-05-18 00:41:42 -04:00
commit f90e045334
23 changed files with 287 additions and 53 deletions

View File

@ -2,6 +2,9 @@ language: node_js
node_js: node_js:
- "0.10" - "0.10"
- "0.12" - "0.12"
- "1.0"
- "1.8"
sudo: false sudo: false
before_install: "npm rm --save-dev connect-redis"
script: "npm run-script test-ci" script: "npm run-script test-ci"
after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls" after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls"

View File

@ -1,7 +1,7 @@
5.x 5.x
=== ===
This incorporates all changes after 4.10.1 up to 4.12.0. This incorporates all changes after 4.10.1 up to 4.12.4.
5.0.0-alpha.1 / 2014-11-06 5.0.0-alpha.1 / 2014-11-06
========================== ==========================
@ -25,6 +25,75 @@ This is the first Express 5.0 alpha release, based off 4.10.1.
* add: * add:
- `app.router` is a reference to the base router - `app.router` is a reference to the base router
4.12.4 / 2015-05-17
===================
* deps: accepts@~1.2.7
- deps: mime-types@~2.0.11
- deps: negotiator@0.5.3
* deps: debug@~2.2.0
- deps: ms@0.7.1
* deps: depd@~1.0.1
* deps: etag@~1.6.0
- Improve support for JXcore
- Support "fake" stats objects in environments without `fs`
* deps: finalhandler@0.3.6
- deps: debug@~2.2.0
- deps: on-finished@~2.2.1
* deps: on-finished@~2.2.1
- Fix `isFinished(req)` when data buffered
* deps: proxy-addr@~1.0.8
- deps: ipaddr.js@1.0.1
* deps: qs@2.4.2
- Fix allowing parameters like `constructor`
* deps: send@0.12.3
- deps: debug@~2.2.0
- deps: depd@~1.0.1
- deps: etag@~1.6.0
- deps: ms@0.7.1
- deps: on-finished@~2.2.1
* deps: serve-static@~1.9.3
- deps: send@0.12.3
* deps: type-is@~1.6.2
- deps: mime-types@~2.0.11
4.12.3 / 2015-03-17
===================
* deps: accepts@~1.2.5
- deps: mime-types@~2.0.10
* deps: debug@~2.1.3
- Fix high intensity foreground color for bold
- deps: ms@0.7.0
* deps: finalhandler@0.3.4
- deps: debug@~2.1.3
* deps: proxy-addr@~1.0.7
- deps: ipaddr.js@0.1.9
* deps: qs@2.4.1
- Fix error when parameter `hasOwnProperty` is present
* deps: send@0.12.2
- Throw errors early for invalid `extensions` or `index` options
- deps: debug@~2.1.3
* deps: serve-static@~1.9.2
- deps: send@0.12.2
* deps: type-is@~1.6.1
- deps: mime-types@~2.0.10
4.12.2 / 2015-03-02
===================
* Fix regression where `"Request aborted"` is logged using `res.sendFile`
4.12.1 / 2015-03-01
===================
* Fix constructing application with non-configurable prototype properties
* Fix `ECONNRESET` errors from `res.sendFile` usage
* Fix `req.host` when using "trust proxy" hops count
* Fix `req.protocol`/`req.secure` when using "trust proxy" hops count
* Fix wrong `code` on aborted connections from `res.sendFile`
* deps: merge-descriptors@1.0.0
4.12.0 / 2015-02-23 4.12.0 / 2015-02-23
=================== ===================
@ -729,6 +798,70 @@ This is the first Express 5.0 alpha release, based off 4.10.1.
- `app.route()` - Proxy to the app's `Router#route()` method to create a new route - `app.route()` - Proxy to the app's `Router#route()` method to create a new route
- Router & Route - public API - Router & Route - public API
3.20.3 / 2015-05-17
===================
* deps: connect@2.29.2
- deps: body-parser@~1.12.4
- deps: compression@~1.4.4
- deps: connect-timeout@~1.6.2
- deps: debug@~2.2.0
- deps: depd@~1.0.1
- deps: errorhandler@~1.3.6
- deps: finalhandler@0.3.6
- deps: method-override@~2.3.3
- deps: morgan@~1.5.3
- deps: qs@2.4.2
- deps: response-time@~2.3.1
- deps: serve-favicon@~2.2.1
- deps: serve-index@~1.6.4
- deps: serve-static@~1.9.3
- deps: type-is@~1.6.2
* deps: debug@~2.2.0
- deps: ms@0.7.1
* deps: depd@~1.0.1
* deps: proxy-addr@~1.0.8
- deps: ipaddr.js@1.0.1
* deps: send@0.12.3
- deps: debug@~2.2.0
- deps: depd@~1.0.1
- deps: etag@~1.6.0
- deps: ms@0.7.1
- deps: on-finished@~2.2.1
3.20.2 / 2015-03-16
===================
* deps: connect@2.29.1
- deps: body-parser@~1.12.2
- deps: compression@~1.4.3
- deps: connect-timeout@~1.6.1
- deps: debug@~2.1.3
- deps: errorhandler@~1.3.5
- deps: express-session@~1.10.4
- deps: finalhandler@0.3.4
- deps: method-override@~2.3.2
- deps: morgan@~1.5.2
- deps: qs@2.4.1
- deps: serve-index@~1.6.3
- deps: serve-static@~1.9.2
- deps: type-is@~1.6.1
* deps: debug@~2.1.3
- Fix high intensity foreground color for bold
- deps: ms@0.7.0
* deps: merge-descriptors@1.0.0
* deps: proxy-addr@~1.0.7
- deps: ipaddr.js@0.1.9
* deps: send@0.12.2
- Throw errors early for invalid `extensions` or `index` options
- deps: debug@~2.1.3
3.20.1 / 2015-02-28
===================
* Fix `req.host` when using "trust proxy" hops count
* Fix `req.protocol`/`req.secure` when using "trust proxy" hops count
3.20.0 / 2015-02-18 3.20.0 / 2015-02-18
=================== ===================

View File

@ -87,7 +87,7 @@ $ npm start
## Examples ## Examples
To view the examples, clone the Express repo and install the dependancies: To view the examples, clone the Express repo and install the dependencies:
```bash ```bash
$ git clone git://github.com/strongloop/express.git --depth 1 $ git clone git://github.com/strongloop/express.git --depth 1
@ -103,7 +103,7 @@ $ node examples/content-negotiation
## Tests ## Tests
To run the test suite, first install the dependancies, then run `npm test`: To run the test suite, first install the dependencies, then run `npm test`:
```bash ```bash
$ npm install $ npm install

View File

@ -2,8 +2,11 @@ environment:
matrix: matrix:
- nodejs_version: "0.10" - nodejs_version: "0.10"
- nodejs_version: "0.12" - nodejs_version: "0.12"
- nodejs_version: "1.0"
- nodejs_version: "1.8"
install: install:
- ps: Install-Product node $env:nodejs_version - ps: Install-Product node $env:nodejs_version
- npm rm --save-dev connect-redis
- npm install - npm install
build: off build: off
test_script: test_script:

View File

@ -2,6 +2,7 @@
* Module dependencies. * Module dependencies.
*/ */
var cookieSession = require('cookie-session');
var express = require('../../'); var express = require('../../');
var app = module.exports = express(); var app = module.exports = express();

View File

@ -1 +0,0 @@
한中日

View File

@ -8,7 +8,6 @@ var app = module.exports = express();
app.get('/', function(req, res){ app.get('/', function(req, res){
res.send('<ul>' res.send('<ul>'
+ '<li>Download <a href="/files/amazing.txt">amazing.txt</a>.</li>' + '<li>Download <a href="/files/amazing.txt">amazing.txt</a>.</li>'
+ '<li>Download <a href="/files/utf-8 한中日.txt">utf-8 한中日.txt</a>.</li>'
+ '<li>Download <a href="/files/missing.txt">missing.txt</a>.</li>' + '<li>Download <a href="/files/missing.txt">missing.txt</a>.</li>'
+ '<li>Download <a href="/files/CCTV大赛上海分赛区.txt">CCTV大赛上海分赛区.txt</a>.</li>' + '<li>Download <a href="/files/CCTV大赛上海分赛区.txt">CCTV大赛上海分赛区.txt</a>.</li>'
+ '</ul>'); + '</ul>');

View File

@ -15,12 +15,20 @@ var users = [
, { name: 'bandit' } , { name: 'bandit' }
]; ];
// Create HTTP error
function createError(status, message) {
var err = new Error(message);
err.status = status;
return err;
}
// Convert :to and :from to integers // Convert :to and :from to integers
app.param(['to', 'from'], function(req, res, next, num, name){ app.param(['to', 'from'], function(req, res, next, num, name){
req.params[name] = parseInt(num, 10); req.params[name] = parseInt(num, 10);
if( isNaN(req.params[name]) ){ if( isNaN(req.params[name]) ){
next(new Error('failed to parseInt '+num)); next(createError(400, 'failed to parseInt '+num));
} else { } else {
next(); next();
} }
@ -32,7 +40,7 @@ app.param('user', function(req, res, next, id){
if (req.user = users[id]) { if (req.user = users[id]) {
next(); next();
} else { } else {
next(new Error('failed to find user')); next(createError(404, 'failed to find user'));
} }
}); });

View File

@ -21,7 +21,7 @@ app.set('views', __dirname + '/views');
/* istanbul ignore next */ /* istanbul ignore next */
if (!module.parent) { if (!module.parent) {
app.use(express.logger('dev')); app.use(logger('dev'));
} }
app.use(methodOverride('_method')); app.use(methodOverride('_method'));

View File

@ -28,8 +28,8 @@ function createApplication() {
app.handle(req, res, next); app.handle(req, res, next);
}; };
mixin(app, proto); mixin(app, EventEmitter.prototype, false);
mixin(app, EventEmitter.prototype); mixin(app, proto, false);
app.request = { __proto__: req, app: app }; app.request = { __proto__: req, app: app };
app.response = { __proto__: res, app: app }; app.response = { __proto__: res, app: app };

View File

@ -282,7 +282,7 @@ defineGetter(req, 'protocol', function protocol(){
: 'http'; : 'http';
var trust = this.app.get('trust proxy fn'); var trust = this.app.get('trust proxy fn');
if (!trust(this.connection.remoteAddress)) { if (!trust(this.connection.remoteAddress, 0)) {
return proto; return proto;
} }
@ -392,7 +392,7 @@ defineGetter(req, 'host', function host(){
var trust = this.app.get('trust proxy fn'); var trust = this.app.get('trust proxy fn');
var val = this.get('X-Forwarded-Host'); var val = this.get('X-Forwarded-Host');
if (!val || !trust(this.connection.remoteAddress)) { if (!val || !trust(this.connection.remoteAddress, 0)) {
val = this.get('Host'); val = this.get('Host');
} }

View File

@ -374,7 +374,7 @@ res.sendFile = function sendFile(path, options, fn) {
if (err && err.code === 'EISDIR') return next(); if (err && err.code === 'EISDIR') return next();
// next() all but write errors // next() all but write errors
if (err && err.code !== 'ECONNABORT' && err.syscall !== 'write') { if (err && err.code !== 'ECONNABORTED' && err.syscall !== 'write') {
next(err); next(err);
} }
}); });
@ -847,7 +847,7 @@ function sendfile(res, file, options, callback) {
done = true; done = true;
var err = new Error('Request aborted'); var err = new Error('Request aborted');
err.code = 'ECONNABORT'; err.code = 'ECONNABORTED';
callback(err); callback(err);
} }
@ -882,6 +882,7 @@ function sendfile(res, file, options, callback) {
// finished // finished
function onfinish(err) { function onfinish(err) {
if (err && err.code === 'ECONNRESET') return onaborted();
if (err) return onerror(err); if (err) return onerror(err);
if (done) return; if (done) return;

View File

@ -27,48 +27,48 @@
"api" "api"
], ],
"dependencies": { "dependencies": {
"accepts": "~1.2.4", "accepts": "~1.2.7",
"content-disposition": "0.5.0", "content-disposition": "0.5.0",
"content-type": "~1.0.1", "content-type": "~1.0.1",
"cookie": "0.1.2",
"cookie-signature": "1.0.6", "cookie-signature": "1.0.6",
"debug": "~2.1.1", "debug": "~2.2.0",
"depd": "~1.0.0", "depd": "~1.0.1",
"escape-html": "1.0.1", "escape-html": "1.0.1",
"etag": "~1.5.1", "etag": "~1.6.0",
"finalhandler": "0.3.3", "finalhandler": "0.3.6",
"fresh": "0.2.4", "fresh": "0.2.4",
"merge-descriptors": "1.0.0",
"methods": "~1.1.1", "methods": "~1.1.1",
"on-finished": "~2.2.0", "on-finished": "~2.2.1",
"parseurl": "~1.3.0", "parseurl": "~1.3.0",
"path-to-regexp": "0.1.3", "path-to-regexp": "0.1.3",
"proxy-addr": "~1.0.6", "proxy-addr": "~1.0.8",
"qs": "2.3.3", "qs": "2.4.2",
"range-parser": "~1.0.2", "range-parser": "~1.0.2",
"send": "0.12.1", "send": "0.12.3",
"serve-static": "~1.9.1", "serve-static": "~1.9.3",
"type-is": "~1.6.0", "type-is": "~1.6.2",
"vary": "~1.0.0", "vary": "~1.0.0",
"cookie": "0.1.2",
"merge-descriptors": "0.0.2",
"utils-merge": "1.0.0" "utils-merge": "1.0.0"
}, },
"devDependencies": { "devDependencies": {
"after": "0.8.1", "after": "0.8.1",
"ejs": "2.3.1", "ejs": "2.3.1",
"istanbul": "0.3.6", "istanbul": "0.3.9",
"marked": "0.3.3", "marked": "0.3.3",
"mocha": "~2.1.0", "mocha": "2.2.5",
"should": "~5.0.1", "should": "6.0.1",
"supertest": "~0.15.0", "supertest": "1.0.1",
"hjs": "~0.0.6", "body-parser": "~1.12.4",
"body-parser": "~1.12.0", "connect-redis": "~2.3.0",
"connect-redis": "~2.2.0",
"cookie-parser": "~1.3.4", "cookie-parser": "~1.3.4",
"express-session": "~1.10.3", "cookie-session": "~1.1.0",
"express-session": "~1.11.2",
"jade": "~1.9.2", "jade": "~1.9.2",
"method-override": "~2.3.1", "method-override": "~2.3.3",
"morgan": "~1.5.1", "morgan": "~1.5.3",
"multiparty": "~4.1.1", "multiparty": "~4.1.2",
"vhost": "~3.0.0" "vhost": "~3.0.0"
}, },
"engines": { "engines": {

View File

@ -0,0 +1,38 @@
var app = require('../../examples/cookie-sessions')
var request = require('supertest')
describe('cookie-sessions', function () {
describe('GET /', function () {
it('should display no views', function (done) {
request(app)
.get('/')
.expect(200, 'viewed 0 times\n', done)
})
it('should set a session cookie', function (done) {
request(app)
.get('/')
.expect('Set-Cookie', /express:sess=/)
.expect(200, done)
})
it('should display 1 view on revisit', function (done) {
request(app)
.get('/')
.expect(200, 'viewed 0 times\n', function (err, res) {
if (err) return done(err)
request(app)
.get('/')
.set('Cookie', getCookies(res))
.expect(200, 'viewed 1 times\n', done)
})
})
})
})
function getCookies(res) {
return res.headers['set-cookie'].map(function (val) {
return val.split(';')[0]
}).join('; ');
}

View File

@ -35,7 +35,7 @@ describe('mvc', function(){
.put('/pet/3') .put('/pet/3')
.set('Content-Type', 'application/x-www-form-urlencoded') .set('Content-Type', 'application/x-www-form-urlencoded')
.send({ pet: { name: 'Boots' } }) .send({ pet: { name: 'Boots' } })
.end(function(err, res){ .expect(302, function (err, res) {
if (err) return done(err); if (err) return done(err);
request(app) request(app)
.get('/pet/3/edit') .get('/pet/3/edit')
@ -105,7 +105,7 @@ describe('mvc', function(){
.put('/user/1') .put('/user/1')
.set('Content-Type', 'application/x-www-form-urlencoded') .set('Content-Type', 'application/x-www-form-urlencoded')
.send({ user: { name: 'Tobo' }}) .send({ user: { name: 'Tobo' }})
.end(function(err, res){ .expect(302, function (err, res) {
if (err) return done(err); if (err) return done(err);
request(app) request(app)
.get('/user/1/edit') .get('/user/1/edit')

View File

@ -21,8 +21,8 @@ describe('params', function(){
describe('GET /user/9', function(){ describe('GET /user/9', function(){
it('should fail to find user', function(done){ it('should fail to find user', function(done){
request(app) request(app)
.get('/user/9') .get('/user/9')
.expect(/failed to find user/,done) .expect(404, /failed to find user/, done)
}) })
}) })
@ -37,8 +37,8 @@ describe('params', function(){
describe('GET /users/foo-bar', function(){ describe('GET /users/foo-bar', function(){
it('should fail integer parsing', function(done){ it('should fail integer parsing', function(done){
request(app) request(app)
.get('/users/foo-bar') .get('/users/foo-bar')
.expect(/failed to parseInt foo/,done) .expect(400, /failed to parseInt foo/, done)
}) })
}) })
}) })

View File

@ -19,7 +19,7 @@ describe('app.all()', function(){
}); });
}) })
it('should ', function(done){ it('should run the callback for a method just once', function(done){
var app = express() var app = express()
, n = 0; , n = 0;

View File

@ -12,7 +12,7 @@ describe('app', function(){
it('should be callable', function(){ it('should be callable', function(){
var app = express(); var app = express();
assert(typeof app, 'function'); assert.equal(typeof app, 'function');
}) })
it('should 404 without routes', function(done){ it('should 404 without routes', function(done){

View File

@ -117,6 +117,24 @@ describe('req', function(){
.set('Host', 'example.com') .set('Host', 'example.com')
.expect('example.com', done); .expect('example.com', done);
}) })
describe('when trusting hop count', function () {
it('should respect X-Forwarded-Host', function (done) {
var app = express();
app.set('trust proxy', 1);
app.use(function (req, res) {
res.end(req.host);
});
request(app)
.get('/')
.set('Host', 'localhost')
.set('X-Forwarded-Host', 'example.com')
.expect('example.com', done);
})
})
}) })
describe('when "trust proxy" is disabled', function(){ describe('when "trust proxy" is disabled', function(){

View File

@ -75,6 +75,23 @@ describe('req', function(){
.get('/') .get('/')
.expect('http', done); .expect('http', done);
}) })
describe('when trusting hop count', function () {
it('should respect X-Forwarded-Proto', function (done) {
var app = express();
app.set('trust proxy', 1);
app.use(function (req, res) {
res.end(req.protocol);
});
request(app)
.get('/')
.set('X-Forwarded-Proto', 'https')
.expect('https', done);
})
})
}) })
describe('when "trust proxy" is disabled', function(){ describe('when "trust proxy" is disabled', function(){

View File

@ -78,6 +78,23 @@ describe('req', function(){
.set('X-Forwarded-Proto', 'https, http') .set('X-Forwarded-Proto', 'https, http')
.expect('yes', done) .expect('yes', done)
}) })
describe('when "trust proxy" trusting hop count', function () {
it('should respect X-Forwarded-Proto', function (done) {
var app = express();
app.set('trust proxy', 1);
app.get('/', function (req, res) {
res.send(req.secure ? 'yes' : 'no');
});
request(app)
.get('/')
.set('X-Forwarded-Proto', 'https')
.expect('yes', done)
})
})
}) })
}) })
}) })

View File

@ -16,7 +16,7 @@ describe('res', function(){
request(app) request(app)
.get('/') .get('/')
.expect('Content-Length', '0') .expect('Content-Length', '0')
.expect('', done); .expect(200, '', done);
}) })
}) })
@ -30,10 +30,7 @@ describe('res', function(){
request(app) request(app)
.get('/') .get('/')
.expect('', function(req, res){ .expect(200, '', done);
res.header.should.not.have.property('content-length');
done();
});
}) })
}) })

View File

@ -207,7 +207,7 @@ describe('res', function(){
setImmediate(function () { setImmediate(function () {
res.sendFile(path.resolve(fixtures, 'name.txt'), function (err) { res.sendFile(path.resolve(fixtures, 'name.txt'), function (err) {
should(err).be.ok; should(err).be.ok;
err.code.should.equal('ECONNABORT'); err.code.should.equal('ECONNABORTED');
cb(); cb();
}); });
}); });
@ -226,7 +226,7 @@ describe('res', function(){
onFinished(res, function () { onFinished(res, function () {
res.sendFile(path.resolve(fixtures, 'name.txt'), function (err) { res.sendFile(path.resolve(fixtures, 'name.txt'), function (err) {
should(err).be.ok; should(err).be.ok;
err.code.should.equal('ECONNABORT'); err.code.should.equal('ECONNABORTED');
cb(); cb();
}); });
}); });