node/test/parallel/test-http2-compat-serverrequest-host.js
Alba Mendez f5c0e282cc http2: allow Host in HTTP/2 requests
The HTTP/2 spec allows Host to be used instead of :authority in
requests, and this is in fact *preferred* when converting from HTTP/1.

We erroneously treated Host as a connection header, thus disallowing
it in requests. The patch corrects this, aligning Node.js behaviour
with the HTTP/2 spec and with nghttp2:

 - Treat Host as a single-value header instead of a connection header.
 - Don't autofill :authority if Host is present.
 - The compatibility API (request.authority) falls back to using Host
   if :authority is not present.

This is semver-major because requests are no longer guaranteed to
have :authority set. An explanatory note was added to the docs.

Fixes: https://github.com/nodejs/node/issues/29858

PR-URL: https://github.com/nodejs/node/pull/34664
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
Reviewed-By: Yongsheng Zhang <zyszys98@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Ricky Zhou <0x19951125@gmail.com>
2020-08-17 13:49:59 +02:00

64 lines
1.8 KiB
JavaScript

'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const h2 = require('http2');
// Requests using host instead of :authority should be allowed
// and Http2ServerRequest.authority should fall back to host
// :authority should NOT be auto-filled if host is present
const server = h2.createServer();
server.listen(0, common.mustCall(function() {
const port = server.address().port;
server.once('request', common.mustCall(function(request, response) {
const expected = {
':path': '/foobar',
':method': 'GET',
':scheme': 'http',
'host': `localhost:${port}`
};
assert.strictEqual(request.authority, expected.host);
const headers = request.headers;
for (const [name, value] of Object.entries(expected)) {
assert.strictEqual(headers[name], value);
}
const rawHeaders = request.rawHeaders;
for (const [name, value] of Object.entries(expected)) {
const position = rawHeaders.indexOf(name);
assert.notStrictEqual(position, -1);
assert.strictEqual(rawHeaders[position + 1], value);
}
assert(!Object.hasOwnProperty.call(headers, ':authority'));
assert(!Object.hasOwnProperty.call(rawHeaders, ':authority'));
response.on('finish', common.mustCall(function() {
server.close();
}));
response.end();
}));
const url = `http://localhost:${port}`;
const client = h2.connect(url, common.mustCall(function() {
const headers = {
':path': '/foobar',
':method': 'GET',
':scheme': 'http',
'host': `localhost:${port}`
};
const request = client.request(headers);
request.on('end', common.mustCall(function() {
client.close();
}));
request.end();
request.resume();
}));
}));