Skip to content

Commit 51bd1b4

Browse files
pgriessry
authored andcommitted
Only concatenate some incoming HTTP headers.
- Concatenate 'accept', 'accept-charset', 'accept-encoding', 'accept-language', 'connection', 'cookie', and 'x-*' headers. - For all others, drop duplicates.
1 parent 545e10f commit 51bd1b4

File tree

2 files changed

+63
-5
lines changed

2 files changed

+63
-5
lines changed

lib/http.js

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,13 +227,35 @@ IncomingMessage.prototype.resume = function () {
227227
this.socket.resume();
228228
};
229229

230+
// Add the given (field, value) pair to the message
231+
//
232+
// Per RFC2616, section 4.2 it is acceptable to join multiple instances of the
233+
// same header with a ', ' if the header in question supports specification of
234+
// multiple values this way. If not, we declare the first instance the winner
235+
// and drop the second. Extended header fields (those beginning with 'x-') are
236+
// always joined.
230237
IncomingMessage.prototype._addHeaderLine = function (field, value) {
231-
if (field in this.headers) {
232-
// TODO Certain headers like 'Content-Type' should not be concatinated.
233-
// See https://www.google.com/reader/view/?tab=my#overview-page
234-
this.headers[field] += ", " + value;
235-
} else {
238+
if (!(field in this.headers)) {
236239
this.headers[field] = value;
240+
return;
241+
}
242+
243+
// If this field already exists in the request, use duplicate-resolution
244+
// logic from RFC2616.
245+
switch (field) {
246+
case 'accept':
247+
case 'accept-charset':
248+
case 'accept-encoding':
249+
case 'accept-language':
250+
case 'connection':
251+
case 'cookie':
252+
this.headers[field] += ', ' + value;
253+
break;
254+
255+
default:
256+
if (field[0] !== 'x' || field[1] !== '-') break;
257+
this.headers[field] += ', ' + value;
258+
break;
237259
}
238260
};
239261

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Verify that the HTTP server implementation handles multiple instances
2+
// of the same header as per RFC2616: joining the handful of fields by ', '
3+
// that support it, and dropping duplicates for other fields.
4+
5+
require('../common');
6+
var http = require('http');
7+
8+
var srv = http.createServer(function(req, res) {
9+
assert.equal(req.headers.accept, 'abc, def, ghijklmnopqrst');
10+
assert.equal(req.headers.host, 'foo');
11+
assert.equal(req.headers['x-foo'], 'bingo');
12+
assert.equal(req.headers['x-bar'], 'banjo, bango');
13+
14+
res.writeHead(200, {'Content-Type' : 'text/plain'});
15+
res.end('EOF');
16+
17+
srv.close();
18+
});
19+
20+
srv.listen(PORT, function () {
21+
var hc = http.createClient(PORT, 'localhost');
22+
var hr = hc.request('/',
23+
[
24+
['accept', 'abc'],
25+
['accept', 'def'],
26+
['Accept', 'ghijklmnopqrst'],
27+
['host', 'foo'],
28+
['Host', 'bar'],
29+
['hOst', 'baz'],
30+
['x-foo', 'bingo'],
31+
['x-bar', 'banjo'],
32+
['x-bar', 'bango']
33+
]
34+
);
35+
hr.end();
36+
});

0 commit comments

Comments
 (0)