Skip to content

Commit 097cd0c

Browse files
committed
Merge tag '3.7.0'
2 parents 31b2e2d + b91cd66 commit 097cd0c

19 files changed

+348
-111
lines changed

.gitignore

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
coverage.html
1+
coverage/
22
.DS_Store
3-
lib-cov
43
*.seed
54
*.log
65
*.csv
@@ -13,7 +12,5 @@ benchmarks/graphs
1312
testing
1413
node_modules/
1514
testing
16-
.coverage_data
17-
cover_html
1815
test.js
1916
.idea

.npmignore

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
.git*
22
benchmarks/
3+
coverage/
34
docs/
45
examples/
56
support/
67
test/
78
testing.js
89
.DS_Store
910
.travis.yml
10-
coverage.html
11-
lib-cov
1211
Contributing.md

.travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ matrix:
66
allow_failures:
77
- node_js: "0.11"
88
fast_finish: true
9+
script: "npm run-script test-travis"

History.md

+31
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@ unreleased
22
==========
33

44
* fix behavior of multiple `app.VERB` for the same path
5+
* proper proxy trust with `app.set('trust proxy', trust)`
6+
- `app.set('trust proxy', 1)` trust first hop
7+
- `app.set('trust proxy', 'loopback')` trust loopback addresses
8+
- `app.set('trust proxy', '10.0.0.1')` trust single IP
9+
- `app.set('trust proxy', '10.0.0.1/16')` trust subnet
10+
- `app.set('trust proxy', '10.0.0.1, 10.0.0.2')` trust list
11+
- `app.set('trust proxy', false)` turn off
12+
- `app.set('trust proxy', true)` trust everything
513
* update type-is to 1.2.0
614
- support suffix matching
715

@@ -101,6 +109,29 @@ unreleased
101109
- `app.route()` - Proxy to the app's `Router#route()` method to create a new route
102110
- Router & Route - public API
103111

112+
3.7.0 / 2014-05-18
113+
==================
114+
115+
* proper proxy trust with `app.set('trust proxy', trust)`
116+
- `app.set('trust proxy', 1)` trust first hop
117+
- `app.set('trust proxy', 'loopback')` trust loopback addresses
118+
- `app.set('trust proxy', '10.0.0.1')` trust single IP
119+
- `app.set('trust proxy', '10.0.0.1/16')` trust subnet
120+
- `app.set('trust proxy', '10.0.0.1, 10.0.0.2')` trust list
121+
- `app.set('trust proxy', false)` turn off
122+
- `app.set('trust proxy', true)` trust everything
123+
* update connect to 2.16.2
124+
- deprecate `res.headerSent` -- use `res.headersSent`
125+
- deprecate `res.on("header")` -- use on-headers module instead
126+
- fix edge-case in `res.appendHeader` that would append in wrong order
127+
- json: use body-parser
128+
- urlencoded: use body-parser
129+
130+
131+
132+
133+
134+
104135
3.6.0 / 2014-05-09
105136
==================
106137

Makefile

-34
This file was deleted.

Readme.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
44

5-
[![Build Status](https://travis-ci.org/visionmedia/express.svg?branch=master)](https://travis-ci.org/visionmedia/express) [![Gittip](http://img.shields.io/gittip/visionmedia.svg)](https://www.gittip.com/visionmedia/) [![NPM version](https://badge.fury.io/js/express.svg)](http://badge.fury.io/js/express)
5+
[![NPM version](https://badge.fury.io/js/express.svg)](http://badge.fury.io/js/express) [![Build Status](https://travis-ci.org/visionmedia/express.svg?branch=master)](https://travis-ci.org/visionmedia/express) [![Coverage Status](https://img.shields.io/coveralls/visionmedia/express.svg)](https://coveralls.io/r/visionmedia/express) [![Gittip](http://img.shields.io/gittip/visionmedia.svg)](https://www.gittip.com/visionmedia/)
66

77
```js
88
var express = require('express');
@@ -95,7 +95,9 @@ To run the test suite, first invoke the following command within the repo, insta
9595

9696
Then run the tests:
9797

98-
$ make test
98+
```sh
99+
$ npm test
100+
```
99101

100102
## Contributors
101103

examples/auth/app.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ function restrict(req, res, next) {
7878
}
7979

8080
app.get('/', function(req, res){
81-
res.redirect('login');
81+
res.redirect('/login');
8282
});
8383

8484
app.get('/restricted', restrict, function(req, res){
@@ -116,7 +116,7 @@ app.post('/login', function(req, res){
116116
req.session.error = 'Authentication failed, please check your '
117117
+ ' username and password.'
118118
+ ' (use "tj" and "foobar")';
119-
res.redirect('login');
119+
res.redirect('/login');
120120
}
121121
});
122122
});

index.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
11

2-
module.exports = process.env.EXPRESS_COV
3-
? require('./lib-cov/express')
4-
: require('./lib/express');
2+
module.exports = require('./lib/express');

lib/application.js

+8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ var query = require('./middleware/query');
1111
var debug = require('debug')('express:application');
1212
var View = require('./view');
1313
var http = require('http');
14+
var compileTrust = require('./utils').compileTrust;
1415
var deprecate = require('./utils').deprecate;
1516

1617
/**
@@ -50,6 +51,7 @@ app.defaultConfiguration = function(){
5051
var env = process.env.NODE_ENV || 'development';
5152
this.set('env', env);
5253
this.set('subdomain offset', 2);
54+
this.set('trust proxy', false);
5355

5456
debug('booting in %s mode', env);
5557

@@ -308,6 +310,12 @@ app.set = function(setting, val){
308310
return this.settings[setting];
309311
} else {
310312
this.settings[setting] = val;
313+
314+
if (setting === 'trust proxy') {
315+
debug('compile trust proxy %j', val);
316+
this.set('trust proxy fn', compileTrust(val));
317+
}
318+
311319
return this;
312320
}
313321
};

lib/request.js

+41-22
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ var http = require('http');
88
var fresh = require('fresh');
99
var parseRange = require('range-parser');
1010
var parse = require('parseurl');
11+
var proxyaddr = require('proxy-addr');
1112

1213
/**
1314
* Request prototype.
@@ -239,19 +240,26 @@ req.is = function(types){
239240
/**
240241
* Return the protocol string "http" or "https"
241242
* when requested with TLS. When the "trust proxy"
242-
* setting is enabled the "X-Forwarded-Proto" header
243-
* field will be trusted. If you're running behind
244-
* a reverse proxy that supplies https for you this
245-
* may be enabled.
243+
* setting trusts the socket address, the
244+
* "X-Forwarded-Proto" header field will be trusted.
245+
* If you're running behind a reverse proxy that
246+
* supplies https for you this may be enabled.
246247
*
247248
* @return {String}
248249
* @api public
249250
*/
250251

251252
req.__defineGetter__('protocol', function(){
252-
var trustProxy = this.app.get('trust proxy');
253-
if (this.connection.encrypted) return 'https';
254-
if (!trustProxy) return 'http';
253+
var trust = this.app.get('trust proxy fn');
254+
255+
if (!trust(this.connection.remoteAddress)) {
256+
return this.connection.encrypted
257+
? 'https'
258+
: 'http';
259+
}
260+
261+
// Note: X-Forwarded-Proto is normally only ever a
262+
// single value, but this is to be safe.
255263
var proto = this.get('X-Forwarded-Proto') || 'http';
256264
return proto.split(/\s*,\s*/)[0];
257265
});
@@ -270,36 +278,36 @@ req.__defineGetter__('secure', function(){
270278
});
271279

272280
/**
273-
* Return the remote address, or when
274-
* "trust proxy" is `true` return
275-
* the upstream addr.
281+
* Return the remote address from the trusted proxy.
282+
*
283+
* The is the remote address on the socket unless
284+
* "trust proxy" is set.
276285
*
277286
* @return {String}
278287
* @api public
279288
*/
280289

281290
req.__defineGetter__('ip', function(){
282-
return this.ips[0] || this.connection.remoteAddress;
291+
var trust = this.app.get('trust proxy fn');
292+
return proxyaddr(this, trust);
283293
});
284294

285295
/**
286-
* When "trust proxy" is `true`, parse
287-
* the "X-Forwarded-For" ip address list.
296+
* When "trust proxy" is set, trusted proxy addresses + client.
288297
*
289298
* For example if the value were "client, proxy1, proxy2"
290299
* you would receive the array `["client", "proxy1", "proxy2"]`
291-
* where "proxy2" is the furthest down-stream.
300+
* where "proxy2" is the furthest down-stream and "proxy1" and
301+
* "proxy2" were trusted.
292302
*
293303
* @return {Array}
294304
* @api public
295305
*/
296306

297307
req.__defineGetter__('ips', function(){
298-
var trustProxy = this.app.get('trust proxy');
299-
var val = this.get('X-Forwarded-For');
300-
return trustProxy && val
301-
? val.split(/ *, */)
302-
: [];
308+
var trust = this.app.get('trust proxy fn');
309+
var addrs = proxyaddr.all(this, trust);
310+
return addrs.slice(1).reverse();
303311
});
304312

305313
/**
@@ -339,19 +347,30 @@ req.__defineGetter__('path', function(){
339347
/**
340348
* Parse the "Host" header field hostname.
341349
*
350+
* When the "trust proxy" setting trusts the socket
351+
* address, the "X-Forwarded-Host" header field will
352+
* be trusted.
353+
*
342354
* @return {String}
343355
* @api public
344356
*/
345357

346358
req.__defineGetter__('host', function(){
347-
var trustProxy = this.app.get('trust proxy');
348-
var host = trustProxy && this.get('X-Forwarded-Host');
349-
host = host || this.get('Host');
359+
var trust = this.app.get('trust proxy fn');
360+
var host = this.get('X-Forwarded-Host');
361+
362+
if (!host || !trust(this.connection.remoteAddress)) {
363+
host = this.get('Host');
364+
}
365+
350366
if (!host) return;
367+
368+
// IPv6 literal support
351369
var offset = host[0] === '['
352370
? host.indexOf(']') + 1
353371
: 0;
354372
var index = host.indexOf(':', offset);
373+
355374
return ~index
356375
? host.substring(0, index)
357376
: host;

lib/utils.js

+43-4
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ var mime = require('send').mime;
66
var crc32 = require('buffer-crc32');
77
var basename = require('path').basename;
88
var deprecate = require('util').deprecate;
9+
var proxyaddr = require('proxy-addr');
910

1011
/**
11-
* Deprecate function, like core `util.deprecate`
12+
* Deprecate function, like core `util.deprecate`,
13+
* but with NODE_ENV and color support.
1214
*
1315
* @param {Function} fn
1416
* @param {String} msg
@@ -17,9 +19,17 @@ var deprecate = require('util').deprecate;
1719
*/
1820

1921
exports.deprecate = function(fn, msg){
20-
return 'test' !== process.env.NODE_ENV
21-
? deprecate(fn, 'express: ' + msg)
22-
: fn;
22+
if (process.env.NODE_ENV === 'test') return fn;
23+
24+
// prepend module name
25+
msg = 'express: ' + msg;
26+
27+
if (process.stderr.isTTY) {
28+
// colorize
29+
msg = '\x1b[31;1m' + msg + '\x1b[0m';
30+
}
31+
32+
return deprecate(fn, msg);
2333
};
2434

2535
/**
@@ -148,3 +158,32 @@ function acceptParams(str, index) {
148158

149159
return ret;
150160
}
161+
162+
/**
163+
* Compile "proxy trust" value to function.
164+
*
165+
* @param {Boolean|String|Number|Array|Function} val
166+
* @return {Function}
167+
* @api private
168+
*/
169+
170+
exports.compileTrust = function(val) {
171+
if (typeof val === 'function') return val;
172+
173+
if (val === true) {
174+
// Support plain true/false
175+
return function(){ return true };
176+
}
177+
178+
if (typeof val === 'number') {
179+
// Support trusting hop count
180+
return function(a, i){ return i < val };
181+
}
182+
183+
if (typeof val === 'string') {
184+
// Support comma-separated values
185+
val = val.split(/ *, */);
186+
}
187+
188+
return proxyaddr.compile(val || []);
189+
}

0 commit comments

Comments
 (0)