Compare commits

...

27 Commits

Author SHA1 Message Date
Douglas Christopher Wilson
011e5dc241 3.20.2 2015-03-17 01:03:53 -04:00
Douglas Christopher Wilson
389ab1b19f tests: add test for cookie-sessions example 2015-03-17 01:02:08 -04:00
Douglas Christopher Wilson
279c8bbec3 deps: proxy-addr@~1.0.7 2015-03-17 00:47:15 -04:00
Douglas Christopher Wilson
6744f811b4 deps: debug@~2.1.3 2015-03-17 00:25:00 -04:00
Douglas Christopher Wilson
d7a6d709af deps: merge-descriptors@1.0.0 2015-03-17 00:23:23 -04:00
Douglas Christopher Wilson
ff44e0f9ae deps: send@0.12.2 2015-03-17 00:21:58 -04:00
Douglas Christopher Wilson
100e50f23d deps: connect@2.29.1 2015-03-17 00:17:34 -04:00
Douglas Christopher Wilson
20c040db22 deps: istanbul@0.3.8 2015-03-17 00:15:07 -04:00
Douglas Christopher Wilson
5d8a7a610f deps: should@~5.2.0 2015-03-17 00:14:09 -04:00
Douglas Christopher Wilson
d34d60ce92 deps: mocha@~2.2.1 2015-03-17 00:13:14 -04:00
Douglas Christopher Wilson
b2311c7402 3.20.1 2015-02-28 23:16:27 -05:00
Douglas Christopher Wilson
9ca0c66e23 build: skip unnecessary dependency in Travis CI 2015-02-28 22:41:01 -05:00
Douglas Christopher Wilson
ef71373fa3 deps: istanbul@0.3.6 2015-02-28 22:39:55 -05:00
Douglas Christopher Wilson
5873d335bd deps: ejs@2.3.1 2015-02-28 22:39:06 -05:00
Douglas Christopher Wilson
2e0f5e7817 Fix req.host when using "trust proxy" hops count 2015-02-28 21:32:51 -05:00
Paul Serby
20aa12616a Fix req.protocol/req.secure when using "trust proxy" hops count
fixes #2569
closes #2570
2015-02-28 21:29:43 -05:00
Douglas Christopher Wilson
bb4703e199 deps: remove un-used devDependency 2015-02-28 21:06:03 -05:00
Douglas Christopher Wilson
85755e32d9 3.20.0 2015-02-18 21:25:55 -05:00
Douglas Christopher Wilson
b40e74d6b6 Fix "trust proxy" setting to inherit when app is mounted
fixes #2550
fixes #2551
2015-02-18 00:59:56 -05:00
Douglas Christopher Wilson
eaf3318dd3 Generate ETags for all request responses
closes #2546
2015-02-18 00:12:28 -05:00
Douglas Christopher Wilson
e1057bd7fd build: support Node.js 0.12
closes #2538
2015-02-17 22:52:23 -05:00
Douglas Christopher Wilson
f22937f3d1 Use content-type to parse Content-Type headers 2015-02-17 22:49:24 -05:00
Douglas Christopher Wilson
69a4869db0 deps: should@~5.0.0 2015-02-17 22:43:38 -05:00
Douglas Christopher Wilson
c2a6c8d338 deps: send@0.12.1 2015-02-17 22:42:02 -05:00
Douglas Christopher Wilson
2ce05047f8 deps: cookie-signature@1.0.6 2015-02-17 22:40:51 -05:00
Douglas Christopher Wilson
829fa34581 build: use Travis CI container infrastructure 2015-02-17 22:37:28 -05:00
Douglas Christopher Wilson
3610fdce36 deps: connect@2.29.0 2015-02-17 22:32:18 -05:00
16 changed files with 471 additions and 194 deletions

View File

@@ -2,10 +2,8 @@ language: node_js
node_js:
- "0.8"
- "0.10"
- "0.11"
matrix:
allow_failures:
- node_js: "0.11"
fast_finish: true
- "0.12"
sudo: false
before_install: "npm rm --save-dev connect-redis"
script: "npm run-script test-travis"
after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls"

View File

@@ -1,3 +1,64 @@
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
===================
* Fix `"trust proxy"` setting to inherit when app is mounted
* Generate `ETag`s for all request responses
- No longer restricted to only responses for `GET` and `HEAD` requests
* Use `content-type` to parse `Content-Type` headers
* deps: connect@2.29.0
- Use `content-type` to parse `Content-Type` headers
- deps: body-parser@~1.12.0
- deps: compression@~1.4.1
- deps: connect-timeout@~1.6.0
- deps: cookie-parser@~1.3.4
- deps: cookie-signature@1.0.6
- deps: csurf@~1.7.0
- deps: errorhandler@~1.3.4
- deps: express-session@~1.10.3
- deps: http-errors@~1.3.1
- deps: response-time@~2.3.0
- deps: serve-index@~1.6.2
- deps: serve-static@~1.9.1
- deps: type-is@~1.6.0
* deps: cookie-signature@1.0.6
* deps: send@0.12.1
- Always read the stat size from the file
- Fix mutating passed-in `options`
- deps: mime@1.3.4
3.19.2 / 2015-02-01
===================

View File

@@ -1,6 +1,8 @@
(The MIT License)
Copyright (c) 2009-2013 TJ Holowaychuk <tj@vision-media.ca>
Copyright (c) 2013 Roman Shtylman <shtylman+expressjs@gmail.com>
Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@@ -1,5 +1,14 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module dependencies.
* @api private
*/
var connect = require('connect')
@@ -21,6 +30,13 @@ var merge = require('utils-merge');
var app = exports = module.exports = {};
/**
* Variable for trust proxy inheritance back-compat
* @api private
*/
var trustProxyDefaultSymbol = '@@symbol:trust_proxy_default';
/**
* Initialize the server.
*
@@ -53,14 +69,27 @@ app.defaultConfiguration = function(){
this.set('subdomain offset', 2);
this.set('trust proxy', false);
// trust proxy inherit back-compat
Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
configurable: true,
value: true
});
debug('booting in %s mode', env);
// implicit middleware
this.use(connect.query());
this.use(middleware.init(this));
// inherit protos
this.on('mount', function(parent){
this.on('mount', function onmount(parent) {
// inherit trust proxy
if (this.settings[trustProxyDefaultSymbol] === true
&& typeof parent.settings['trust proxy fn'] === 'function') {
delete this.settings['trust proxy'];
delete this.settings['trust proxy fn'];
}
// inherit protos
this.request.__proto__ = parent.request;
this.response.__proto__ = parent.response;
this.engines.__proto__ = parent.engines;
@@ -271,6 +300,13 @@ app.set = function(setting, val){
case 'trust proxy':
debug('compile trust proxy %s', val);
this.set('trust proxy fn', compileTrust(val));
// trust proxy inherit back-compat
Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
configurable: true,
value: false
});
break;
}

View File

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

View File

@@ -1,5 +1,13 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module dependencies.
* @api private
*/
var contentDisposition = require('content-disposition');
@@ -86,7 +94,6 @@ res.links = function(links){
res.send = function(body){
var req = this.req;
var head = 'HEAD' == req.method;
var type;
var encoding;
var len;
@@ -153,12 +160,12 @@ res.send = function(body){
this.set('Content-Length', len);
}
// ETag support
var etag = len !== undefined && app.get('etag fn');
if (etag && ('GET' === req.method || 'HEAD' === req.method)) {
if (!this.get('ETag')) {
etag = etag(body, encoding);
etag && this.set('ETag', etag);
// populate ETag
var etag;
var generateETag = len !== undefined && app.get('etag fn');
if (typeof generateETag === 'function' && !this.get('ETag')) {
if ((etag = generateETag(body, encoding))) {
this.set('ETag', etag);
}
}
@@ -173,8 +180,13 @@ res.send = function(body){
body = '';
}
// respond
this.end((head ? null : body), encoding);
if (req.method === 'HEAD') {
// skip body for HEAD
this.end();
} else {
// respond
this.end(body, encoding);
}
return this;
};

View File

@@ -1,12 +1,19 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module dependencies.
* @api private
*/
var contentType = require('content-type');
var etag = require('etag');
var mime = require('connect').mime;
var proxyaddr = require('proxy-addr');
var typer = require('media-typer');
/**
* toString ref.
@@ -393,15 +400,17 @@ exports.compileTrust = function(val) {
* @api private
*/
exports.setCharset = function(type, charset){
if (!type || !charset) return type;
exports.setCharset = function setCharset(type, charset) {
if (!type || !charset) {
return type;
}
// parse type
var parsed = typer.parse(type);
var parsed = contentType.parse(type);
// set charset
parsed.parameters.charset = charset;
// format type
return typer.format(parsed);
return contentType.format(parsed);
};

View File

@@ -1,7 +1,7 @@
{
"name": "express",
"description": "Sinatra inspired web development framework",
"version": "3.19.2",
"version": "3.20.2",
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [
"Aaron Heckmann <aaron.heckmann+github@gmail.com>",
@@ -27,36 +27,35 @@
],
"dependencies": {
"basic-auth": "1.0.0",
"connect": "2.28.3",
"connect": "2.29.1",
"content-disposition": "0.5.0",
"content-type": "~1.0.1",
"commander": "2.6.0",
"cookie-signature": "1.0.5",
"debug": "~2.1.1",
"cookie": "0.1.2",
"cookie-signature": "1.0.6",
"debug": "~2.1.3",
"depd": "~1.0.0",
"escape-html": "1.0.1",
"etag": "~1.5.1",
"fresh": "0.2.4",
"media-typer": "0.3.0",
"merge-descriptors": "1.0.0",
"methods": "~1.1.1",
"mkdirp": "0.5.0",
"parseurl": "~1.3.0",
"proxy-addr": "~1.0.6",
"proxy-addr": "~1.0.7",
"range-parser": "~1.0.2",
"send": "0.11.1",
"send": "0.12.2",
"utils-merge": "1.0.0",
"vary": "~1.0.0",
"cookie": "0.1.2",
"merge-descriptors": "0.0.2"
"vary": "~1.0.0"
},
"devDependencies": {
"connect-redis": "~1.5.0",
"ejs": "2.1.4",
"istanbul": "0.3.5",
"ejs": "2.3.1",
"istanbul": "0.3.8",
"marked": "0.3.3",
"mocha": "~2.1.0",
"should": "~4.6.2",
"supertest": "~0.15.0",
"hjs": "~0.0.6"
"mocha": "~2.2.1",
"should": "~5.2.0",
"supertest": "~0.15.0"
},
"engines": {
"node": ">= 0.8.0"

View File

@@ -0,0 +1,36 @@
var app = require('../../examples/cookie-sessions')
var request = require('supertest')
function getCookie(res) {
return res.headers['set-cookie'][0].split(';')[0]
}
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', /connect\.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', getCookie(res))
.expect(200, 'viewed 1 times\n', done)
})
})
})
})

View File

@@ -1,6 +1,7 @@
var express = require('../')
, request = require('supertest');
var assert = require('assert');
var express = require('..');
var request = require('supertest');
describe('app', function(){
it('should emit "mount" when mounted', function(done){

View File

@@ -1,30 +1,36 @@
var express = require('../')
, assert = require('assert');
var assert = require('assert');
var express = require('..');
describe('config', function(){
describe('.set()', function(){
it('should set a value', function(){
describe('config', function () {
describe('.set()', function () {
it('should set a value', function () {
var app = express();
app.set('foo', 'bar').should.equal(app);
app.set('foo', 'bar');
assert.equal(app.get('foo'), 'bar');
})
it('should return the app when undefined', function(){
it('should return the app', function () {
var app = express();
app.set('foo', undefined).should.equal(app);
assert.equal(app.set('foo', 'bar'), app);
})
it('should return the app when undefined', function () {
var app = express();
assert.equal(app.set('foo', undefined), app);
})
describe('"etag"', function(){
it('should throw on bad value', function(){
var app = express()
app.set.bind(app, 'etag', 42).should.throw(/unknown value/)
var app = express();
assert.throws(app.set.bind(app, 'etag', 42), /unknown value/);
})
it('should set "etag fn"', function(){
var app = express()
var fn = function(){}
app.set('etag', fn)
app.get('etag fn').should.equal(fn)
assert.equal(app.get('etag fn'), fn)
})
})
@@ -33,7 +39,7 @@ describe('config', function(){
var app = express()
var fn = function(){}
app.set('trust proxy', fn)
app.get('trust proxy fn').should.equal(fn)
assert.equal(app.get('trust proxy fn'), fn)
})
})
})
@@ -41,34 +47,73 @@ describe('config', function(){
describe('.get()', function(){
it('should return undefined when unset', function(){
var app = express();
assert(undefined === app.get('foo'));
assert.strictEqual(app.get('foo'), undefined);
})
it('should otherwise return the value', function(){
var app = express();
app.set('foo', 'bar');
app.get('foo').should.equal('bar');
assert.equal(app.get('foo'), 'bar');
})
describe('when mounted', function(){
it('should default to the parent app', function(){
var app = express()
, blog = express();
var app = express();
var blog = express();
app.set('title', 'Express');
app.use(blog);
blog.get('title').should.equal('Express');
assert.equal(blog.get('title'), 'Express');
})
it('should given precedence to the child', function(){
var app = express()
, blog = express();
var app = express();
var blog = express();
app.use(blog);
app.set('title', 'Express');
blog.set('title', 'Some Blog');
blog.get('title').should.equal('Some Blog');
assert.equal(blog.get('title'), 'Some Blog');
})
it('should inherit "trust proxy" setting', function () {
var app = express();
var blog = express();
function fn() { return false }
app.set('trust proxy', fn);
assert.equal(app.get('trust proxy'), fn);
assert.equal(app.get('trust proxy fn'), fn);
app.use(blog);
assert.equal(blog.get('trust proxy'), fn);
assert.equal(blog.get('trust proxy fn'), fn);
})
it('should prefer child "trust proxy" setting', function () {
var app = express();
var blog = express();
function fn1() { return false }
function fn2() { return true }
app.set('trust proxy', fn1);
assert.equal(app.get('trust proxy'), fn1);
assert.equal(app.get('trust proxy fn'), fn1);
blog.set('trust proxy', fn2);
assert.equal(blog.get('trust proxy'), fn2);
assert.equal(blog.get('trust proxy fn'), fn2);
app.use(blog);
assert.equal(app.get('trust proxy'), fn1);
assert.equal(app.get('trust proxy fn'), fn1);
assert.equal(blog.get('trust proxy'), fn2);
assert.equal(blog.get('trust proxy fn'), fn2);
})
})
})
@@ -76,42 +121,42 @@ describe('config', function(){
describe('.enable()', function(){
it('should set the value to true', function(){
var app = express();
app.enable('tobi').should.equal(app);
app.get('tobi').should.be.true;
assert.equal(app.enable('tobi'), app);
assert.strictEqual(app.get('tobi'), true);
})
})
describe('.disable()', function(){
it('should set the value to false', function(){
var app = express();
app.disable('tobi').should.equal(app);
app.get('tobi').should.be.false;
assert.equal(app.disable('tobi'), app);
assert.strictEqual(app.get('tobi'), false);
})
})
describe('.enabled()', function(){
it('should default to false', function(){
var app = express();
app.enabled('foo').should.be.false;
assert.strictEqual(app.enabled('foo'), false);
})
it('should return true when set', function(){
var app = express();
app.set('foo', 'bar');
app.enabled('foo').should.be.true;
assert.strictEqual(app.enabled('foo'), true);
})
})
describe('.disabled()', function(){
it('should default to true', function(){
var app = express();
app.disabled('foo').should.be.true;
assert.strictEqual(app.disabled('foo'), true);
})
it('should return false when set', function(){
var app = express();
app.set('foo', 'bar');
app.disabled('foo').should.be.false;
assert.strictEqual(app.disabled('foo'), false);
})
})
})

View File

@@ -117,6 +117,24 @@ describe('req', function(){
.set('Host', 'example.com')
.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(){

View File

@@ -35,6 +35,23 @@ describe('req', function(){
.set('X-Forwarded-For', 'client, p1, p2')
.expect('p1', done);
})
it('should return the addr after trusted proxy, from sub app', function (done) {
var app = express();
var sub = express();
app.set('trust proxy', 2);
app.use(sub);
sub.use(function (req, res, next) {
res.send(req.ip);
});
request(app)
.get('/')
.set('X-Forwarded-For', 'client, p1, p2')
.expect(200, 'p1', done);
})
})
describe('when "trust proxy" is disabled', function(){

View File

@@ -75,6 +75,23 @@ describe('req', function(){
.get('/')
.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(){

View File

@@ -78,6 +78,23 @@ describe('req', function(){
.set('X-Forwarded-Proto', 'https, http')
.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

@@ -1,7 +1,8 @@
var express = require('../')
, request = require('supertest')
, assert = require('assert');
var assert = require('assert');
var express = require('..');
var methods = require('methods');
var request = require('supertest');
describe('res', function(){
describe('.send(null)', function(){
@@ -110,10 +111,10 @@ describe('res', function(){
})
})
it('should set ETag', function(done){
it('should set ETag', function (done) {
var app = express();
app.use(function(req, res){
app.use(function (req, res) {
var str = Array(1024 * 2).join('-');
res.send(str);
});
@@ -121,24 +122,7 @@ describe('res', function(){
request(app)
.get('/')
.expect('ETag', 'W/"fz/jGo0ONwzb+aKy/rWipg=="')
.end(done);
})
it('should not set ETag for non-GET/HEAD', function(done){
var app = express();
app.use(function(req, res){
var str = Array(1024 * 2).join('-');
res.send(str);
});
request(app)
.post('/')
.end(function(err, res){
if (err) return done(err);
assert(!res.header.etag, 'has an ETag');
done();
});
.expect(200, done);
})
it('should not override Content-Type', function(done){
@@ -199,10 +183,10 @@ describe('res', function(){
})
})
it('should set ETag', function(done){
it('should set ETag', function (done) {
var app = express();
app.use(function(req, res){
app.use(function (req, res) {
var str = Array(1024 * 2).join('-');
res.send(new Buffer(str));
});
@@ -210,7 +194,7 @@ describe('res', function(){
request(app)
.get('/')
.expect('ETag', 'W/"fz/jGo0ONwzb+aKy/rWipg=="')
.end(done);
.expect(200, done);
})
it('should not override Content-Type', function(done){
@@ -358,12 +342,12 @@ describe('res', function(){
.expect('{"foo":"bar"}', done);
})
describe('"etag" setting', function(){
describe('when enabled', function(){
it('should send ETag', function(done){
describe('"etag" setting', function () {
describe('when enabled', function () {
it('should send ETag', function (done) {
var app = express();
app.use(function(req, res){
app.use(function (req, res) {
res.send('kajdslfkasdf');
});
@@ -371,76 +355,95 @@ describe('res', function(){
request(app)
.get('/')
.expect('etag', 'W/"c-5aee35d8"', done)
})
it('should send ETag for empty string response', function(done){
var app = express()
app.use(function(req, res){
res.send('')
});
app.enable('etag')
request(app)
.get('/')
.expect('etag', 'W/"0-0"', done)
})
it('should send ETag for long response', function(done){
var app = express();
app.use(function(req, res){
var str = Array(1024 * 2).join('-');
res.send(str);
});
app.enable('etag');
request(app)
.get('/')
.expect('etag', 'W/"fz/jGo0ONwzb+aKy/rWipg=="', done)
.expect('ETag', 'W/"c-5aee35d8"')
.expect(200, done);
});
it('should not override ETag when manually set', function(done){
var app = express();
methods.forEach(function (method) {
if (method === 'connect') return;
app.use(function(req, res){
res.set('etag', '"asdf"');
res.send(200);
});
it('should send ETag in response to ' + method.toUpperCase() + ' request', function (done) {
var app = express();
app.enable('etag');
app[method]('/', function (req, res) {
res.send('kajdslfkasdf');
});
request(app)
.get('/')
.expect('etag', '"asdf"', done)
});
it('should not send ETag for res.send()', function(done){
var app = express()
app.use(function(req, res){
res.send()
});
app.enable('etag')
request(app)
.get('/')
.end(function(err, res){
res.headers.should.not.have.property('etag');
done();
request(app)
[method]('/')
.expect('ETag', 'W/"c-5aee35d8"')
.expect(200, done);
})
});
it('should send ETag for empty string response', function (done) {
var app = express();
app.use(function (req, res) {
res.send('');
});
app.enable('etag');
request(app)
.get('/')
.expect('ETag', 'W/"0-0"')
.expect(200, done);
})
it('should send ETag for long response', function (done) {
var app = express();
app.use(function (req, res) {
var str = Array(1024 * 2).join('-');
res.send(str);
});
app.enable('etag');
request(app)
.get('/')
.expect('ETag', 'W/"fz/jGo0ONwzb+aKy/rWipg=="')
.expect(200, done);
});
it('should not override ETag when manually set', function (done) {
var app = express();
app.use(function (req, res) {
res.set('etag', '"asdf"');
res.send(200);
});
app.enable('etag');
request(app)
.get('/')
.expect('ETag', '"asdf"')
.expect(200, done);
});
it('should not send ETag for res.send()', function (done) {
var app = express();
app.use(function (req, res) {
res.send();
});
app.enable('etag');
request(app)
.get('/')
.expect(shouldNotHaveHeader('ETag'))
.expect(200, done);
})
});
describe('when disabled', function(){
it('should send no ETag', function(done){
describe('when disabled', function () {
it('should send no ETag', function (done) {
var app = express();
app.use(function(req, res){
app.use(function (req, res) {
var str = Array(1024 * 2).join('-');
res.send(str);
});
@@ -449,97 +452,103 @@ describe('res', function(){
request(app)
.get('/')
.end(function(err, res){
res.headers.should.not.have.property('etag');
done();
});
.expect(shouldNotHaveHeader('ETag'))
.expect(200, done);
});
it('should send ETag when manually set', function(done){
it('should send ETag when manually set', function (done) {
var app = express();
app.disable('etag');
app.use(function(req, res){
app.use(function (req, res) {
res.set('etag', '"asdf"');
res.send(200);
});
request(app)
.get('/')
.expect('etag', '"asdf"', done)
.expect('ETag', '"asdf"')
.expect(200, done);
});
});
describe('when "strong"', function(){
it('should send strong ETag', function(done){
var app = express()
describe('when "strong"', function () {
it('should send strong ETag', function (done) {
var app = express();
app.set('etag', 'strong');
app.use(function(req, res){
app.use(function (req, res) {
res.send('hello, world!');
});
request(app)
.get('/')
.expect('etag', '"Otu60XkfuuPskIiUxJY4cA=="', done)
.expect('ETag', '"Otu60XkfuuPskIiUxJY4cA=="')
.expect(200, done);
})
})
describe('when "weak"', function(){
it('should send weak ETag', function(done){
var app = express()
describe('when "weak"', function () {
it('should send weak ETag', function (done) {
var app = express();
app.set('etag', 'weak');
app.use(function(req, res){
app.use(function (req, res) {
res.send('hello, world!');
});
request(app)
.get('/')
.expect('etag', 'W/"d-58988d13"', done)
.expect('ETag', 'W/"d-58988d13"')
.expect(200, done)
})
})
describe('when a function', function(){
it('should send custom ETag', function(done){
var app = express()
describe('when a function', function () {
it('should send custom ETag', function (done) {
var app = express();
app.set('etag', function(body, encoding){
body.should.equal('hello, world!')
encoding.should.equal('utf8')
return '"custom"'
app.set('etag', function (body, encoding) {
body.should.equal('hello, world!');
encoding.should.equal('utf8');
return '"custom"';
});
app.use(function(req, res){
app.use(function (req, res) {
res.send('hello, world!');
});
request(app)
.get('/')
.expect('etag', '"custom"', done)
.expect('ETag', '"custom"')
.expect(200, done);
})
it('should not send falsy ETag', function(done){
var app = express()
it('should not send falsy ETag', function (done) {
var app = express();
app.set('etag', function(body, encoding){
return undefined
app.set('etag', function (body, encoding) {
return undefined;
});
app.use(function(req, res){
app.use(function (req, res) {
res.send('hello, world!');
});
request(app)
.get('/')
.end(function(err, res){
res.headers.should.not.have.property('etag')
done();
})
.expect(shouldNotHaveHeader('ETag'))
.expect(200, done);
})
})
})
})
function shouldNotHaveHeader(header) {
return function (res) {
assert.ok(!(header.toLowerCase() in res.headers), 'should not have header ' + header)
}
}