http: fix connection upgrade checks
This commit fixes connection upgrade checks, specifically when headers are passed as an array instead of a plain object to http.request() Fixes: https://github.com/nodejs/node/issues/8235 PR-URL: https://github.com/nodejs/node/pull/8238 Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Родитель
7053922c1a
Коммит
1050594c86
|
@ -80,17 +80,11 @@ function parserOnHeadersComplete(versionMajor, versionMinor, headers, method,
|
|||
parser.incoming.statusMessage = statusMessage;
|
||||
}
|
||||
|
||||
if (upgrade && parser.outgoing !== null && !parser.outgoing.upgrading) {
|
||||
// The client made non-upgrade request, and server is just advertising
|
||||
// supported protocols.
|
||||
//
|
||||
// See RFC7230 Section 6.7
|
||||
//
|
||||
// NOTE: RegExp below matches `upgrade` in `Connection: abc, upgrade, def`
|
||||
// header.
|
||||
if (upgrade &&
|
||||
parser.outgoing !== null &&
|
||||
(parser.outgoing._headers.upgrade === undefined ||
|
||||
!/(^|\W)upgrade(\W|$)/i.test(parser.outgoing._headers.connection))) {
|
||||
upgrade = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,16 +9,18 @@ const Buffer = require('buffer').Buffer;
|
|||
const common = require('_http_common');
|
||||
|
||||
const CRLF = common.CRLF;
|
||||
const chunkExpression = common.chunkExpression;
|
||||
const trfrEncChunkExpression = common.chunkExpression;
|
||||
const debug = common.debug;
|
||||
|
||||
const connectionExpression = /^Connection$/i;
|
||||
const upgradeExpression = /^Upgrade$/i;
|
||||
const transferEncodingExpression = /^Transfer-Encoding$/i;
|
||||
const closeExpression = /close/i;
|
||||
const contentLengthExpression = /^Content-Length$/i;
|
||||
const dateExpression = /^Date$/i;
|
||||
const expectExpression = /^Expect$/i;
|
||||
const trailerExpression = /^Trailer$/i;
|
||||
const connectionExpression = /^Connection$/i;
|
||||
const connCloseExpression = /(^|\W)close(\W|$)/i;
|
||||
const connUpgradeExpression = /(^|\W)upgrade(\W|$)/i;
|
||||
|
||||
const automaticHeaders = {
|
||||
connection: true,
|
||||
|
@ -61,6 +63,7 @@ function OutgoingMessage() {
|
|||
this.writable = true;
|
||||
|
||||
this._last = false;
|
||||
this.upgrading = false;
|
||||
this.chunkedEncoding = false;
|
||||
this.shouldKeepAlive = true;
|
||||
this.useChunkedEncodingByDefault = true;
|
||||
|
@ -192,11 +195,13 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) {
|
|||
// in the case of response it is: 'HTTP/1.1 200 OK\r\n'
|
||||
var state = {
|
||||
sentConnectionHeader: false,
|
||||
sentConnectionUpgrade: false,
|
||||
sentContentLengthHeader: false,
|
||||
sentTransferEncodingHeader: false,
|
||||
sentDateHeader: false,
|
||||
sentExpect: false,
|
||||
sentTrailer: false,
|
||||
sentUpgrade: false,
|
||||
messageHeader: firstLine
|
||||
};
|
||||
|
||||
|
@ -225,6 +230,10 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) {
|
|||
}
|
||||
}
|
||||
|
||||
// Are we upgrading the connection?
|
||||
if (state.sentConnectionUpgrade && state.sentUpgrade)
|
||||
this.upgrading = true;
|
||||
|
||||
// Date header
|
||||
if (this.sendDate === true && state.sentDateHeader === false) {
|
||||
state.messageHeader += 'Date: ' + utcDate() + CRLF;
|
||||
|
@ -312,15 +321,16 @@ function storeHeader(self, state, field, value) {
|
|||
|
||||
if (connectionExpression.test(field)) {
|
||||
state.sentConnectionHeader = true;
|
||||
if (closeExpression.test(value)) {
|
||||
if (connCloseExpression.test(value)) {
|
||||
self._last = true;
|
||||
} else {
|
||||
self.shouldKeepAlive = true;
|
||||
}
|
||||
|
||||
if (connUpgradeExpression.test(value))
|
||||
state.sentConnectionUpgrade = true;
|
||||
} else if (transferEncodingExpression.test(field)) {
|
||||
state.sentTransferEncodingHeader = true;
|
||||
if (chunkExpression.test(value)) self.chunkedEncoding = true;
|
||||
if (trfrEncChunkExpression.test(value)) self.chunkedEncoding = true;
|
||||
|
||||
} else if (contentLengthExpression.test(field)) {
|
||||
state.sentContentLengthHeader = true;
|
||||
|
@ -330,6 +340,8 @@ function storeHeader(self, state, field, value) {
|
|||
state.sentExpect = true;
|
||||
} else if (trailerExpression.test(field)) {
|
||||
state.sentTrailer = true;
|
||||
} else if (upgradeExpression.test(field)) {
|
||||
state.sentUpgrade = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,15 +26,28 @@ var srv = net.createServer(function(c) {
|
|||
});
|
||||
|
||||
srv.listen(0, '127.0.0.1', common.mustCall(function() {
|
||||
|
||||
var req = http.get({
|
||||
port: this.address().port,
|
||||
headers: {
|
||||
var port = this.address().port;
|
||||
var headers = [
|
||||
{
|
||||
connection: 'upgrade',
|
||||
upgrade: 'websocket'
|
||||
}
|
||||
},
|
||||
[
|
||||
['Host', 'echo.websocket.org'],
|
||||
['Connection', 'Upgrade'],
|
||||
['Upgrade', 'websocket'],
|
||||
['Origin', 'http://www.websocket.org']
|
||||
]
|
||||
];
|
||||
var left = headers.length;
|
||||
headers.forEach(function(h) {
|
||||
var req = http.get({
|
||||
port: port,
|
||||
headers: h
|
||||
});
|
||||
var sawUpgrade = false;
|
||||
req.on('upgrade', common.mustCall(function(res, socket, upgradeHead) {
|
||||
sawUpgrade = true;
|
||||
var recvData = upgradeHead;
|
||||
socket.on('data', function(d) {
|
||||
recvData += d;
|
||||
|
@ -45,12 +58,19 @@ srv.listen(0, '127.0.0.1', common.mustCall(function() {
|
|||
}));
|
||||
|
||||
console.log(res.headers);
|
||||
var expectedHeaders = {'hello': 'world',
|
||||
'connection': 'upgrade',
|
||||
'upgrade': 'websocket' };
|
||||
var expectedHeaders = {
|
||||
hello: 'world',
|
||||
connection: 'upgrade',
|
||||
upgrade: 'websocket'
|
||||
};
|
||||
assert.deepStrictEqual(expectedHeaders, res.headers);
|
||||
|
||||
socket.end();
|
||||
if (--left == 0)
|
||||
srv.close();
|
||||
}));
|
||||
req.on('close', common.mustCall(function() {
|
||||
assert.strictEqual(sawUpgrade, true);
|
||||
}));
|
||||
});
|
||||
}));
|
||||
|
|
Загрузка…
Ссылка в новой задаче