Skip to content

Commit def3bb2

Browse files
indutnyMyles Borins
authored and
Myles Borins
committed
http: do not emit upgrade on advertisement
Do not emit `upgrade` if the server is just advertising its protocols support as per RFC 7230 Section 6.7. A server MAY send an Upgrade header field in any other response to advertise that it implements support for upgrading to the listed protocols, in order of descending preference, when appropriate for a future request. Fix: #4334 PR-URL: #4337 Reviewed-By: Ben Noordhuis <[email protected]>
1 parent df1fb15 commit def3bb2

File tree

5 files changed

+82
-1
lines changed

5 files changed

+82
-1
lines changed

lib/_http_client.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ function tickOnSocket(req, socket) {
465465
parser.reinitialize(HTTPParser.RESPONSE);
466466
parser.socket = socket;
467467
parser.incoming = null;
468+
parser.outgoing = req;
468469
req.parser = parser;
469470

470471
socket.parser = parser;

lib/_http_common.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,20 @@ function parserOnHeadersComplete(versionMajor, versionMinor, headers, method,
7777
parser.incoming.statusMessage = statusMessage;
7878
}
7979

80+
// The client made non-upgrade request, and server is just advertising
81+
// supported protocols.
82+
//
83+
// See RFC7230 Section 6.7
84+
//
85+
// NOTE: RegExp below matches `upgrade` in `Connection: abc, upgrade, def`
86+
// header.
87+
if (upgrade &&
88+
parser.outgoing !== null &&
89+
(parser.outgoing._headers.upgrade === undefined ||
90+
!/(^|\W)upgrade(\W|$)/i.test(parser.outgoing._headers.connection))) {
91+
upgrade = false;
92+
}
93+
8094
parser.incoming.upgrade = upgrade;
8195

8296
var skipBody = false; // response to HEAD or CONNECT
@@ -142,6 +156,10 @@ var parsers = new FreeList('parsers', 1000, function() {
142156
parser._url = '';
143157
parser._consumed = false;
144158

159+
parser.socket = null;
160+
parser.incoming = null;
161+
parser.outgoing = null;
162+
145163
// Only called in the slow case where slow means
146164
// that the request headers were either fragmented
147165
// across multiple TCP packets or too large to be
@@ -175,6 +193,7 @@ function freeParser(parser, req, socket) {
175193
parser.socket.parser = null;
176194
parser.socket = null;
177195
parser.incoming = null;
196+
parser.outgoing = null;
178197
if (parsers.free(parser) === false)
179198
parser.close();
180199
parser = null;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const http = require('http');
6+
7+
const tests = [
8+
{ headers: {}, expected: 'regular' },
9+
{ headers: { upgrade: 'h2c' }, expected: 'regular' },
10+
{ headers: { connection: 'upgrade' }, expected: 'regular' },
11+
{ headers: { connection: 'upgrade', upgrade: 'h2c' }, expected: 'upgrade' }
12+
];
13+
14+
function fire() {
15+
if (tests.length === 0)
16+
return server.close();
17+
18+
const test = tests.shift();
19+
20+
const done = common.mustCall(function done(result) {
21+
assert.equal(result, test.expected);
22+
23+
fire();
24+
});
25+
26+
const req = http.request({
27+
port: common.PORT,
28+
path: '/',
29+
headers: test.headers
30+
}, function onResponse(res) {
31+
res.resume();
32+
done('regular');
33+
});
34+
35+
req.on('upgrade', function onUpgrade(res, socket) {
36+
socket.destroy();
37+
done('upgrade');
38+
});
39+
40+
req.end();
41+
}
42+
43+
const server = http.createServer(function(req, res) {
44+
res.writeHead(200, {
45+
Connection: 'upgrade, keep-alive',
46+
Upgrade: 'h2c'
47+
});
48+
res.end('hello world');
49+
}).on('upgrade', function(req, socket) {
50+
socket.end('HTTP/1.1 101 Switching protocols\r\n' +
51+
'Connection: upgrade\r\n' +
52+
'Upgrade: h2c\r\n\r\n' +
53+
'ohai');
54+
}).listen(common.PORT, fire);

test/parallel/test-http-upgrade-agent.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ srv.listen(common.PORT, '127.0.0.1', function() {
3636
port: common.PORT,
3737
host: '127.0.0.1',
3838
headers: {
39+
'connection': 'upgrade',
3940
'upgrade': 'websocket'
4041
}
4142
};

test/parallel/test-http-upgrade-client.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,13 @@ var gotUpgrade = false;
3232

3333
srv.listen(common.PORT, '127.0.0.1', function() {
3434

35-
var req = http.get({ port: common.PORT });
35+
var req = http.get({
36+
port: common.PORT,
37+
headers: {
38+
connection: 'upgrade',
39+
upgrade: 'websocket'
40+
}
41+
});
3642
req.on('upgrade', function(res, socket, upgradeHead) {
3743
var recvData = upgradeHead;
3844
socket.on('data', function(d) {

0 commit comments

Comments
 (0)