http: server check Host header, to meet RFC 7230 5.4 requirement

PR-URL: https://github.com/nodejs/node/pull/45597
Fixes: https://github.com/nodejs/node/issues/39033
Co-authored-by: Luigi Pinca <luigipinca@gmail.com>
Co-authored-by: mscdex <mscdex@users.noreply.github.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
wwwzbwcom 2021-07-09 15:59:35 +08:00 committed by Paolo Insogna
parent 71ff89f929
commit ed3604cd64
46 changed files with 156 additions and 42 deletions

View file

@ -3185,6 +3185,10 @@ changes:
* `uniqueHeaders` {Array} A list of response headers that should be sent only * `uniqueHeaders` {Array} A list of response headers that should be sent only
once. If the header's value is an array, the items will be joined once. If the header's value is an array, the items will be joined
using `; `. using `; `.
* `requireHostHeader` {boolean} It forces the server to respond with
a 400 (Bad Request) status code to any HTTP/1.1 request message
that lacks a Host header (as mandated by the specification).
**Default:** `true`.
* `requestListener` {Function} * `requestListener` {Function}

View file

@ -473,6 +473,14 @@ function storeHTTPOptions(options) {
} else { } else {
this.connectionsCheckingInterval = 30_000; // 30 seconds this.connectionsCheckingInterval = 30_000; // 30 seconds
} }
const requireHostHeader = options.requireHostHeader;
if (requireHostHeader !== undefined) {
validateBoolean(requireHostHeader, 'options.requireHostHeader');
this.requireHostHeader = requireHostHeader;
} else {
this.requireHostHeader = true;
}
} }
function setupConnectionsTracking(server) { function setupConnectionsTracking(server) {
@ -1022,7 +1030,18 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
let handled = false; let handled = false;
if (req.httpVersionMajor === 1 && req.httpVersionMinor === 1) { if (req.httpVersionMajor === 1 && req.httpVersionMinor === 1) {
// From RFC 7230 5.4 https://datatracker.ietf.org/doc/html/rfc7230#section-5.4
// A server MUST respond with a 400 (Bad Request) status code to any
// HTTP/1.1 request message that lacks a Host header field
if (server.requireHostHeader && req.headers.host === undefined) {
res.writeHead(400, ['Connection', 'close']);
res.end();
return 0;
}
const isRequestsLimitSet = ( const isRequestsLimitSet = (
typeof server.maxRequestsPerSocket === 'number' && typeof server.maxRequestsPerSocket === 'number' &&
server.maxRequestsPerSocket > 0 server.maxRequestsPerSocket > 0
@ -1045,7 +1064,6 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
if (RegExpPrototypeExec(continueExpression, req.headers.expect) !== null) { if (RegExpPrototypeExec(continueExpression, req.headers.expect) !== null) {
res._expect_continue = true; res._expect_continue = true;
if (server.listenerCount('checkContinue') > 0) { if (server.listenerCount('checkContinue') > 0) {
server.emit('checkContinue', req, res); server.emit('checkContinue', req, res);
} else { } else {

View file

@ -52,6 +52,7 @@ let maxHeaderSize;
* ServerResponse?: ServerResponse; * ServerResponse?: ServerResponse;
* insecureHTTPParser?: boolean; * insecureHTTPParser?: boolean;
* maxHeaderSize?: number; * maxHeaderSize?: number;
* requireHostHeader?: boolean
* }} [opts] * }} [opts]
* @param {Function} [requestListener] * @param {Function} [requestListener]
* @returns {Server} * @returns {Server}

View file

@ -47,7 +47,7 @@ function test(statusCode) {
const conn = net.createConnection( const conn = net.createConnection(
server.address().port, server.address().port,
common.mustCall(() => { common.mustCall(() => {
conn.write('GET / HTTP/1.1\r\n\r\n'); conn.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n');
let resp = ''; let resp = '';
conn.setEncoding('utf8'); conn.setEncoding('utf8');

View file

@ -10,7 +10,8 @@ function execute(options) {
const expectHeaders = { const expectHeaders = {
'x-foo': 'boom', 'x-foo': 'boom',
'cookie': 'a=1; b=2; c=3', 'cookie': 'a=1; b=2; c=3',
'connection': 'keep-alive' 'connection': 'keep-alive',
'host': 'example.com',
}; };
// no Host header when you set headers an array // no Host header when you set headers an array
@ -43,13 +44,20 @@ function execute(options) {
// Should be the same except for implicit Host header on the first two // Should be the same except for implicit Host header on the first two
execute({ headers: { 'x-foo': 'boom', 'cookie': 'a=1; b=2; c=3' } }); execute({ headers: { 'x-foo': 'boom', 'cookie': 'a=1; b=2; c=3' } });
execute({ headers: { 'x-foo': 'boom', 'cookie': [ 'a=1', 'b=2', 'c=3' ] } }); execute({ headers: { 'x-foo': 'boom', 'cookie': [ 'a=1', 'b=2', 'c=3' ] } });
execute({ headers: [[ 'x-foo', 'boom' ], [ 'cookie', 'a=1; b=2; c=3' ]] });
execute({ headers: [ execute({ headers: [
[ 'x-foo', 'boom' ], [ 'cookie', [ 'a=1', 'b=2', 'c=3' ]], [ 'x-foo', 'boom' ],
[ 'cookie', 'a=1; b=2; c=3' ],
[ 'Host', 'example.com' ],
] });
execute({ headers: [
[ 'x-foo', 'boom' ],
[ 'cookie', [ 'a=1', 'b=2', 'c=3' ]],
[ 'Host', 'example.com' ],
] }); ] });
execute({ headers: [ execute({ headers: [
[ 'x-foo', 'boom' ], [ 'cookie', 'a=1' ], [ 'x-foo', 'boom' ], [ 'cookie', 'a=1' ],
[ 'cookie', 'b=2' ], [ 'cookie', 'c=3'], [ 'cookie', 'b=2' ], [ 'cookie', 'c=3' ],
[ 'Host', 'example.com'],
] }); ] });
// Authorization and Host header both missing from the second // Authorization and Host header both missing from the second
@ -58,4 +66,5 @@ execute({ auth: 'foo:bar', headers:
execute({ auth: 'foo:bar', headers: [ execute({ auth: 'foo:bar', headers: [
[ 'x-foo', 'boom' ], [ 'cookie', 'a=1' ], [ 'x-foo', 'boom' ], [ 'cookie', 'a=1' ],
[ 'cookie', 'b=2' ], [ 'cookie', 'c=3'], [ 'cookie', 'b=2' ], [ 'cookie', 'c=3'],
[ 'Host', 'example.com'],
] }); ] });

View file

@ -28,15 +28,18 @@ const server = http.createServer(function(req, res) {
switch (req.url.substr(1)) { switch (req.url.substr(1)) {
case 'multiple-writes': case 'multiple-writes':
delete req.headers.host;
assert.deepStrictEqual(req.headers, expectedHeadersMultipleWrites); assert.deepStrictEqual(req.headers, expectedHeadersMultipleWrites);
res.write('hello'); res.write('hello');
res.end('world'); res.end('world');
break; break;
case 'end-with-data': case 'end-with-data':
delete req.headers.host;
assert.deepStrictEqual(req.headers, expectedHeadersEndWithData); assert.deepStrictEqual(req.headers, expectedHeadersEndWithData);
res.end('hello world'); res.end('hello world');
break; break;
case 'empty': case 'empty':
delete req.headers.host;
assert.deepStrictEqual(req.headers, expectedHeadersEndNoData); assert.deepStrictEqual(req.headers, expectedHeadersEndNoData);
res.end(); res.end();
break; break;
@ -56,7 +59,6 @@ server.listen(0, function() {
path: '/multiple-writes' path: '/multiple-writes'
}); });
req.removeHeader('Date'); req.removeHeader('Date');
req.removeHeader('Host');
req.write('hello '); req.write('hello ');
req.end('world'); req.end('world');
req.on('response', function(res) { req.on('response', function(res) {
@ -70,7 +72,6 @@ server.listen(0, function() {
path: '/end-with-data' path: '/end-with-data'
}); });
req.removeHeader('Date'); req.removeHeader('Date');
req.removeHeader('Host');
req.end('hello world'); req.end('hello world');
req.on('response', function(res) { req.on('response', function(res) {
assert.deepStrictEqual(res.headers, { ...expectedHeadersEndWithData, 'keep-alive': 'timeout=1' }); assert.deepStrictEqual(res.headers, { ...expectedHeadersEndWithData, 'keep-alive': 'timeout=1' });
@ -83,7 +84,6 @@ server.listen(0, function() {
path: '/empty' path: '/empty'
}); });
req.removeHeader('Date'); req.removeHeader('Date');
req.removeHeader('Host');
req.end(); req.end();
req.on('response', function(res) { req.on('response', function(res) {
assert.deepStrictEqual(res.headers, { ...expectedHeadersEndNoData, 'keep-alive': 'timeout=1' }); assert.deepStrictEqual(res.headers, { ...expectedHeadersEndNoData, 'keep-alive': 'timeout=1' });

View file

@ -17,7 +17,7 @@ server.listen(0, mustCall(() => {
let received = ''; let received = '';
c.on('connect', mustCall(() => { c.on('connect', mustCall(() => {
c.write('GET /blah HTTP/1.1\r\n\r\n'); c.write('GET /blah HTTP/1.1\r\nHost: example.com\r\n\r\n');
})); }));
c.on('data', mustCall((data) => { c.on('data', mustCall((data) => {
received += data.toString(); received += data.toString();

View file

@ -22,6 +22,7 @@ const MakeDuplexPair = require('../common/duplexpair');
serverSide.resume(); // Dump the request serverSide.resume(); // Dump the request
serverSide.end('HTTP/1.1 200 OK\r\n' + serverSide.end('HTTP/1.1 200 OK\r\n' +
'Host: example.com\r\n' +
'Hello: foo\x08foo\r\n' + 'Hello: foo\x08foo\r\n' +
'Content-Length: 0\r\n' + 'Content-Length: 0\r\n' +
'\r\n\r\n'); '\r\n\r\n');
@ -39,6 +40,7 @@ const MakeDuplexPair = require('../common/duplexpair');
serverSide.resume(); // Dump the request serverSide.resume(); // Dump the request
serverSide.end('HTTP/1.1 200 OK\r\n' + serverSide.end('HTTP/1.1 200 OK\r\n' +
'Host: example.com\r\n' +
'Hello: foo\x08foo\r\n' + 'Hello: foo\x08foo\r\n' +
'Content-Length: 0\r\n' + 'Content-Length: 0\r\n' +
'\r\n\r\n'); '\r\n\r\n');
@ -62,6 +64,7 @@ const MakeDuplexPair = require('../common/duplexpair');
server.emit('connection', serverSide); server.emit('connection', serverSide);
clientSide.write('GET / HTTP/1.1\r\n' + clientSide.write('GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Hello: foo\x08foo\r\n' + 'Hello: foo\x08foo\r\n' +
'\r\n\r\n'); '\r\n\r\n');
} }
@ -77,6 +80,7 @@ const MakeDuplexPair = require('../common/duplexpair');
server.emit('connection', serverSide); server.emit('connection', serverSide);
clientSide.write('GET / HTTP/1.1\r\n' + clientSide.write('GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Hello: foo\x08foo\r\n' + 'Hello: foo\x08foo\r\n' +
'\r\n\r\n'); '\r\n\r\n');
} }

View file

@ -19,6 +19,7 @@ server.listen(0, common.mustCall(function() {
client.write( client.write(
'GET / HTTP/1.1\r\n' + 'GET / HTTP/1.1\r\n' +
'Content-Type: text/te\x08t\r\n' + 'Content-Type: text/te\x08t\r\n' +
'Host: example.com' +
'Connection: close\r\n\r\n'); 'Connection: close\r\n\r\n');
} }
); );

View file

@ -8,6 +8,7 @@ const assert = require('assert');
function request(socket) { function request(socket) {
socket.write('GET / HTTP/1.1\r\n'); socket.write('GET / HTTP/1.1\r\n');
socket.write('Connection: keep-alive\r\n'); socket.write('Connection: keep-alive\r\n');
socket.write('Host: localhost\r\n');
socket.write('\r\n\r\n'); socket.write('\r\n\r\n');
} }

View file

@ -24,12 +24,14 @@ function writeRequest(socket, withBody) {
socket.write('POST / HTTP/1.1\r\n'); socket.write('POST / HTTP/1.1\r\n');
socket.write('Connection: keep-alive\r\n'); socket.write('Connection: keep-alive\r\n');
socket.write('Content-Type: text/plain\r\n'); socket.write('Content-Type: text/plain\r\n');
socket.write('Host: localhost\r\n');
socket.write(`Content-Length: ${bodySent.length}\r\n\r\n`); socket.write(`Content-Length: ${bodySent.length}\r\n\r\n`);
socket.write(`${bodySent}\r\n`); socket.write(`${bodySent}\r\n`);
socket.write('\r\n\r\n'); socket.write('\r\n\r\n');
} else { } else {
socket.write('GET / HTTP/1.1\r\n'); socket.write('GET / HTTP/1.1\r\n');
socket.write('Connection: keep-alive\r\n'); socket.write('Connection: keep-alive\r\n');
socket.write('Host: localhost\r\n');
socket.write('\r\n\r\n'); socket.write('\r\n\r\n');
} }
} }

View file

@ -21,6 +21,7 @@ function assertResponse(headers, body, expectClosed) {
function writeRequest(socket) { function writeRequest(socket) {
socket.write('POST / HTTP/1.1\r\n'); socket.write('POST / HTTP/1.1\r\n');
socket.write('Host: localhost\r\n');
socket.write('Connection: keep-alive\r\n'); socket.write('Connection: keep-alive\r\n');
socket.write('Content-Type: text/plain\r\n'); socket.write('Content-Type: text/plain\r\n');
socket.write(`Content-Length: ${bodySent.length}\r\n\r\n`); socket.write(`Content-Length: ${bodySent.length}\r\n\r\n`);

View file

@ -41,7 +41,7 @@ server.listen(0);
server.on('listening', function() { server.on('listening', function() {
const c = net.createConnection(this.address().port); const c = net.createConnection(this.address().port);
c.on('connect', function() { c.on('connect', function() {
c.write('GET /hello?foo=%99bar HTTP/1.1\r\n\r\n'); c.write('GET /hello?foo=%99bar HTTP/1.1\r\nHost: example.com\r\n\r\n');
c.end(); c.end();
}); });
}); });

View file

@ -62,6 +62,7 @@ const MakeDuplexPair = require('../common/duplexpair');
server.emit('connection', serverSide); server.emit('connection', serverSide);
clientSide.write('GET / HTTP/1.1\r\n' + clientSide.write('GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Hello: ' + 'A'.repeat(http.maxHeaderSize * 3) + '\r\n' + 'Hello: ' + 'A'.repeat(http.maxHeaderSize * 3) + '\r\n' +
'\r\n\r\n'); '\r\n\r\n');
} }

View file

@ -27,7 +27,9 @@ const http = require('http');
let requests = 0; let requests = 0;
let responses = 0; let responses = 0;
const headers = {}; const headers = {
host: 'example.com'
};
const N = 100; const N = 100;
for (let i = 0; i < N; ++i) { for (let i = 0; i < N; ++i) {
headers[`key${i}`] = i; headers[`key${i}`] = i;
@ -56,8 +58,8 @@ server.maxHeadersCount = max;
server.listen(0, function() { server.listen(0, function() {
const maxAndExpected = [ // for client const maxAndExpected = [ // for client
[20, 20], [20, 20],
[1200, 103], [1200, 104],
[0, N + 3], // Connection, Date and Transfer-Encoding [0, N + 4], // Host and Connection
]; ];
doRequest(); doRequest();

View file

@ -27,7 +27,7 @@ const server = http
.listen(0, function() { .listen(0, function() {
const s = net.connect(this.address().port); const s = net.connect(this.address().port);
const big = 'GET / HTTP/1.1\r\n\r\n'.repeat(COUNT); const big = 'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n'.repeat(COUNT);
s.write(big); s.write(big);
s.resume(); s.resume();

View file

@ -26,7 +26,7 @@ const server = http
}); });
}) })
.listen(0, function() { .listen(0, function() {
const req = 'GET / HTTP/1.1\r\n\r\n'.repeat(COUNT); const req = 'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n'.repeat(COUNT);
client = net.connect(this.address().port, function() { client = net.connect(this.address().port, function() {
client.write(req); client.write(req);
}); });

View file

@ -50,7 +50,7 @@ const server = http
.listen(0, () => { .listen(0, () => {
const s = net.connect(server.address().port); const s = net.connect(server.address().port);
more = () => { more = () => {
s.write('GET / HTTP/1.1\r\n\r\n'); s.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n');
}; };
done = () => { done = () => {
s.write( s.write(

View file

@ -17,6 +17,7 @@ server.listen(0, common.mustCall(() => {
const req = [ const req = [
'POST / HTTP/1.1', 'POST / HTTP/1.1',
'Host: example.com',
'Content-Length: 11', 'Content-Length: 11',
'', '',
'hello world', 'hello world',

View file

@ -0,0 +1,41 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const http = require('http');
{
const server = http.createServer(common.mustNotCall((req, res) => {
res.writeHead(200);
res.end();
}));
// From RFC 7230 5.4 https://datatracker.ietf.org/doc/html/rfc7230#section-5.4
// A server MUST respond with a 400 (Bad Request) status code to any
// HTTP/1.1 request message that lacks a Host header field
server.listen(0, common.mustCall(() => {
http.get({ port: server.address().port, headers: [] }, (res) => {
assert.strictEqual(res.statusCode, 400);
assert.strictEqual(res.headers.connection, 'close');
res.resume().on('end', common.mustCall(() => {
server.close();
}));
});
}));
}
{
const server = http.createServer({ requireHostHeader: false }, common.mustCall((req, res) => {
res.writeHead(200, ['test', '1']);
res.end();
}));
server.listen(0, common.mustCall(() => {
http.get({ port: server.address().port, headers: [] }, (res) => {
assert.strictEqual(res.statusCode, 200);
assert.strictEqual(res.headers.test, '1');
res.resume().on('end', common.mustCall(() => {
server.close();
}));
});
}));
}

View file

@ -53,7 +53,7 @@ const server = http.createServer((req, res) => {
res.end('ok'); res.end('ok');
}); });
server.listen(0, () => { server.listen(0, () => {
const end = 'HTTP/1.1\r\n\r\n'; const end = 'HTTP/1.1\r\nHost: example.com\r\n\r\n';
const client = net.connect({ port: server.address().port }, () => { const client = net.connect({ port: server.address().port }, () => {
client.write(`GET ${str} ${end}`); client.write(`GET ${str} ${end}`);
client.write(`GET / ${end}`); client.write(`GET / ${end}`);

View file

@ -50,7 +50,7 @@ server.listen(0, function() {
client2.on('close', common.mustCall()); client2.on('close', common.mustCall());
client2.write('GET / HTTP/1.1\r\n\r\n'); client2.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n');
})); }));
client1.on('close', common.mustCall()); client1.on('close', common.mustCall());

View file

@ -60,7 +60,7 @@ server.listen(0, function() {
client2Closed = true; client2Closed = true;
})); }));
client2.write('GET / HTTP/1.1\r\n\r\n'); client2.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n');
})); }));
client1.on('close', common.mustCall(() => { client1.on('close', common.mustCall(() => {

View file

@ -12,7 +12,7 @@ const { connect } = require('net');
function performRequestWithDelay(client, firstDelay, secondDelay, closeAfter) { function performRequestWithDelay(client, firstDelay, secondDelay, closeAfter) {
client.resume(); client.resume();
client.write('GET / HTTP/1.1\r\n'); client.write('GET / HTTP/1.1\r\nHost: example.com\r\n');
setTimeout(() => { setTimeout(() => {
client.write('Connection: '); client.write('Connection: ');

View file

@ -66,7 +66,8 @@ server.listen(0, common.mustCall(() => {
// Send two requests using pipelining. Delay before finishing the second one // Send two requests using pipelining. Delay before finishing the second one
client.resume(); client.resume();
client.write('GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\nGET / HTTP/1.1\r\nConnection: '); client.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n' +
'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: ');
// Complete the request // Complete the request
setTimeout(() => { setTimeout(() => {

View file

@ -16,6 +16,7 @@ function assertResponse(headers, body, expectClosed) {
function writeRequest(socket) { function writeRequest(socket) {
socket.write('POST / HTTP/1.1\r\n'); socket.write('POST / HTTP/1.1\r\n');
socket.write('Connection: keep-alive\r\n'); socket.write('Connection: keep-alive\r\n');
socket.write('Host: localhost\r\n');
socket.write('Content-Type: text/plain\r\n'); socket.write('Content-Type: text/plain\r\n');
socket.write(`Content-Length: ${bodySent.length}\r\n\r\n`); socket.write(`Content-Length: ${bodySent.length}\r\n\r\n`);
socket.write(`${bodySent}\r\n`); socket.write(`${bodySent}\r\n`);

View file

@ -16,6 +16,7 @@ function assertResponse(headers, body, expectClosed) {
function writeRequest(socket) { function writeRequest(socket) {
socket.write('POST / HTTP/1.1\r\n'); socket.write('POST / HTTP/1.1\r\n');
socket.write('Connection: keep-alive\r\n'); socket.write('Connection: keep-alive\r\n');
socket.write('Host: localhost\r\n');
socket.write('Content-Type: text/plain\r\n'); socket.write('Content-Type: text/plain\r\n');
socket.write(`Content-Length: ${bodySent.length}\r\n\r\n`); socket.write(`Content-Length: ${bodySent.length}\r\n\r\n`);
socket.write(`${bodySent}\r\n`); socket.write(`${bodySent}\r\n`);

View file

@ -47,6 +47,7 @@ server.listen(0, common.mustCall(() => {
client.resume(); client.resume();
client.write('POST / HTTP/1.1\r\n'); client.write('POST / HTTP/1.1\r\n');
client.write('Host: example.com\r\n');
client.write('Content-Length: 20\r\n'); client.write('Content-Length: 20\r\n');
client.write('Connection: close\r\n'); client.write('Connection: close\r\n');
client.write('\r\n'); client.write('\r\n');

View file

@ -58,6 +58,7 @@ server.listen(0, common.mustCall(() => {
client.resume(); client.resume();
client.write('POST / HTTP/1.1\r\n'); client.write('POST / HTTP/1.1\r\n');
client.write('Host: example.com\r\n');
client.write('Content-Length: 20\r\n'); client.write('Content-Length: 20\r\n');
client.write('Connection: close\r\n'); client.write('Connection: close\r\n');
client.write('\r\n'); client.write('\r\n');

View file

@ -12,7 +12,7 @@ const { connect } = require('net');
function performRequestWithDelay(client, firstDelay, secondDelay, closeAfter) { function performRequestWithDelay(client, firstDelay, secondDelay, closeAfter) {
client.resume(); client.resume();
client.write('GET / HTTP/1.1\r\n'); client.write('GET / HTTP/1.1\r\nHost: example.com\r\n');
setTimeout(() => { setTimeout(() => {
client.write('Connection: '); client.write('Connection: ');

View file

@ -60,7 +60,8 @@ server.listen(0, common.mustCall(() => {
// Send two requests using pipelining. Delay before finishing the second one // Send two requests using pipelining. Delay before finishing the second one
client.resume(); client.resume();
client.write('GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\nGET / HTTP/1.1\r\nConnection: '); client.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n' +
'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: ');
// Complete the request // Complete the request
setTimeout(() => { setTimeout(() => {

View file

@ -7,7 +7,7 @@ const { connect } = require('net');
// This test validates that request are correct checked for both requests and headers timeout in various situations. // This test validates that request are correct checked for both requests and headers timeout in various situations.
const requestBodyPart1 = 'POST / HTTP/1.1\r\nContent-Length: 20\r\n'; const requestBodyPart1 = 'POST / HTTP/1.1\r\nHost: localhost\r\nContent-Length: 20\r\n';
const requestBodyPart2 = 'Connection: close\r\n\r\n1234567890'; const requestBodyPart2 = 'Connection: close\r\n\r\n1234567890';
const requestBodyPart3 = '1234567890'; const requestBodyPart3 = '1234567890';

View file

@ -18,7 +18,7 @@ const net = require('net');
server.close(); server.close();
}).listen(0, function() { }).listen(0, function() {
const socket = net.connect(this.address().port, function() { const socket = net.connect(this.address().port, function() {
socket.write('PUT / HTTP/1.1\r\n\r\n'); socket.write('PUT / HTTP/1.1\r\nHost: example.com\r\n\r\n');
socket.once('data', function() { socket.once('data', function() {
socket.end('hello world'); socket.end('hello world');

View file

@ -89,7 +89,9 @@ server.on('listening', function() {
c.setEncoding('utf8'); c.setEncoding('utf8');
c.on('connect', function() { c.on('connect', function() {
c.write('GET /hello?hello=world&foo=b==ar HTTP/1.1\r\n\r\n'); c.write(
'GET /hello?hello=world&foo=b==ar HTTP/1.1\r\n' +
'Host: example.com\r\n\r\n');
requests_sent += 1; requests_sent += 1;
}); });
@ -97,13 +99,16 @@ server.on('listening', function() {
server_response += chunk; server_response += chunk;
if (requests_sent === 1) { if (requests_sent === 1) {
c.write('POST /quit HTTP/1.1\r\n\r\n'); c.write(
'POST /quit HTTP/1.1\r\n' +
'Host: example.com\r\n\r\n'
);
requests_sent += 1; requests_sent += 1;
} }
if (requests_sent === 2) { if (requests_sent === 2) {
c.write('GET / HTTP/1.1\r\nX-X: foo\r\n\r\n' + c.write('GET / HTTP/1.1\r\nX-X: foo\r\nHost: example.com\r\n\r\n' +
'GET / HTTP/1.1\r\nX-X: bar\r\n\r\n'); 'GET / HTTP/1.1\r\nX-X: bar\r\nHost: example.com\r\n\r\n');
// Note: we are making the connection half-closed here // Note: we are making the connection half-closed here
// before we've gotten the response from the server. This // before we've gotten the response from the server. This
// is a pretty bad thing to do and not really supported // is a pretty bad thing to do and not really supported

View file

@ -59,7 +59,7 @@ function testHttp11(port, callback) {
let tid; let tid;
c.on('connect', function() { c.on('connect', function() {
c.write('GET / HTTP/1.1\r\n\r\n'); c.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n');
tid = setTimeout(common.mustNotCall(), 2000, 'Couldn\'t find last chunk.'); tid = setTimeout(common.mustNotCall(), 2000, 'Couldn\'t find last chunk.');
}); });

View file

@ -38,7 +38,10 @@ function test() {
const client = net.connect( const client = net.connect(
this.address().port, this.address().port,
function() { function() {
client.write('GET / HTTP/1.1\r\nConnection: close\r\n\r\n'); client.write(
'GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Connection: close\r\n\r\n');
} }
); );
client.on('data', function(chunk) { client.on('data', function(chunk) {

View file

@ -87,6 +87,7 @@ function test_upgrade_with_listener() {
conn.on('connect', function() { conn.on('connect', function() {
writeReq(conn, writeReq(conn,
'GET / HTTP/1.1\r\n' + 'GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Upgrade: WebSocket\r\n' + 'Upgrade: WebSocket\r\n' +
'Connection: Upgrade\r\n' + 'Connection: Upgrade\r\n' +
'\r\n' + '\r\n' +
@ -124,6 +125,7 @@ function test_upgrade_no_listener() {
conn.on('connect', function() { conn.on('connect', function() {
writeReq(conn, writeReq(conn,
'GET / HTTP/1.1\r\n' + 'GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Upgrade: WebSocket\r\n' + 'Upgrade: WebSocket\r\n' +
'Connection: Upgrade\r\n' + 'Connection: Upgrade\r\n' +
'\r\n'); '\r\n');
@ -146,7 +148,7 @@ function test_standard_http() {
conn.setEncoding('utf8'); conn.setEncoding('utf8');
conn.on('connect', function() { conn.on('connect', function() {
writeReq(conn, 'GET / HTTP/1.1\r\n\r\n'); writeReq(conn, 'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n');
}); });
conn.once('data', function(data) { conn.once('data', function(data) {

View file

@ -113,7 +113,9 @@ server.on('listening', () => {
path: '/world', path: '/world',
headers: [ ['Cookie', 'abc=123'], headers: [ ['Cookie', 'abc=123'],
['Cookie', 'def=456'], ['Cookie', 'def=456'],
['Cookie', 'ghi=789'] ], ['Cookie', 'ghi=789'],
['Host', 'example.com'],
],
agent: agent agent: agent
}, common.mustCall((res) => { }, common.mustCall((res) => {
const cookieHeaders = req._header.match(/^Cookie: .+$/img); const cookieHeaders = req._header.match(/^Cookie: .+$/img);

View file

@ -22,7 +22,7 @@ const expectCertError = /^Error: unable to verify the first certificate$/;
const checkRequest = (socket, server) => { const checkRequest = (socket, server) => {
let result = ''; let result = '';
socket.on('connect', common.mustCall((data) => { socket.on('connect', common.mustCall((data) => {
socket.write('GET / HTTP/1.1\r\n\r\n'); socket.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n');
socket.end(); socket.end();
})); }));
socket.on('data', common.mustCall((chunk) => { socket.on('data', common.mustCall((chunk) => {

View file

@ -25,7 +25,7 @@ const httpsServer = https.createServer({
} }
res.writeHead(200, {}); res.writeHead(200, {});
res.end('ok'); res.end('ok');
}, 9)).listen(0, common.mustCall(function(err) { }, 6)).listen(0, common.mustCall(function(err) {
debug(`test https server listening on port ${this.address().port}`); debug(`test https server listening on port ${this.address().port}`);
assert.ifError(err); assert.ifError(err);
https.get({ https.get({

View file

@ -37,6 +37,7 @@ const certFixture = {
serverSide.resume(); // Dump the request serverSide.resume(); // Dump the request
serverSide.end('HTTP/1.1 200 OK\r\n' + serverSide.end('HTTP/1.1 200 OK\r\n' +
'Host: example.com\r\n' +
'Hello: foo\x08foo\r\n' + 'Hello: foo\x08foo\r\n' +
'Content-Length: 0\r\n' + 'Content-Length: 0\r\n' +
'\r\n\r\n'); '\r\n\r\n');
@ -55,6 +56,7 @@ const certFixture = {
serverSide.resume(); // Dump the request serverSide.resume(); // Dump the request
serverSide.end('HTTP/1.1 200 OK\r\n' + serverSide.end('HTTP/1.1 200 OK\r\n' +
'Host: example.com\r\n' +
'Hello: foo\x08foo\r\n' + 'Hello: foo\x08foo\r\n' +
'Content-Length: 0\r\n' + 'Content-Length: 0\r\n' +
'\r\n\r\n'); '\r\n\r\n');
@ -81,6 +83,7 @@ const certFixture = {
}); });
client.write( client.write(
'GET / HTTP/1.1\r\n' + 'GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Hello: foo\x08foo\r\n' + 'Hello: foo\x08foo\r\n' +
'\r\n\r\n'); '\r\n\r\n');
client.end(); client.end();
@ -107,6 +110,7 @@ const certFixture = {
}); });
client.write( client.write(
'GET / HTTP/1.1\r\n' + 'GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Hello: foo\x08foo\r\n' + 'Hello: foo\x08foo\r\n' +
'\r\n\r\n'); '\r\n\r\n');
client.end(); client.end();

View file

@ -13,7 +13,7 @@ const tls = require('tls');
const { readKey } = require('../common/fixtures'); const { readKey } = require('../common/fixtures');
function request(socket) { function request(socket) {
socket.write('GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n\r\n'); socket.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n\r\n');
} }
// https options // https options

View file

@ -38,6 +38,7 @@ const certFixture = {
serverSide.resume(); // Dump the request serverSide.resume(); // Dump the request
serverSide.end('HTTP/1.1 200 OK\r\n' + serverSide.end('HTTP/1.1 200 OK\r\n' +
'Host: example.com\r\n' +
'Hello: ' + 'A'.repeat(http.maxHeaderSize * 3) + '\r\n' + 'Hello: ' + 'A'.repeat(http.maxHeaderSize * 3) + '\r\n' +
'Content-Length: 0\r\n' + 'Content-Length: 0\r\n' +
'\r\n\r\n'); '\r\n\r\n');
@ -55,6 +56,7 @@ const certFixture = {
serverSide.resume(); // Dump the request serverSide.resume(); // Dump the request
serverSide.end('HTTP/1.1 200 OK\r\n' + serverSide.end('HTTP/1.1 200 OK\r\n' +
'Host: example.com\r\n' +
'Hello: ' + 'A'.repeat(http.maxHeaderSize * 3) + '\r\n' + 'Hello: ' + 'A'.repeat(http.maxHeaderSize * 3) + '\r\n' +
'Content-Length: 0\r\n' + 'Content-Length: 0\r\n' +
'\r\n\r\n'); '\r\n\r\n');
@ -81,6 +83,7 @@ const certFixture = {
}); });
client.write( client.write(
'GET / HTTP/1.1\r\n' + 'GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Hello: ' + 'A'.repeat(http.maxHeaderSize * 3) + '\r\n' + 'Hello: ' + 'A'.repeat(http.maxHeaderSize * 3) + '\r\n' +
'\r\n\r\n'); '\r\n\r\n');
client.end(); client.end();
@ -107,6 +110,7 @@ const certFixture = {
}); });
client.write( client.write(
'GET / HTTP/1.1\r\n' + 'GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Hello: ' + 'A'.repeat(http.maxHeaderSize * 3) + '\r\n' + 'Hello: ' + 'A'.repeat(http.maxHeaderSize * 3) + '\r\n' +
'\r\n\r\n'); '\r\n\r\n');
client.end(); client.end();

View file

@ -16,7 +16,9 @@ const serverOptions = {
let requests = 0; let requests = 0;
let responses = 0; let responses = 0;
const headers = {}; const headers = {
host: 'example.com'
};
const N = 100; const N = 100;
for (let i = 0; i < N; ++i) { for (let i = 0; i < N; ++i) {
headers[`key${i}`] = i; headers[`key${i}`] = i;
@ -45,8 +47,8 @@ server.maxHeadersCount = max;
server.listen(0, common.mustCall(() => { server.listen(0, common.mustCall(() => {
const maxAndExpected = [ // for client const maxAndExpected = [ // for client
[20, 20], [20, 20],
[1200, 103], [1200, 104],
[0, N + 3], // Connection, Date and Transfer-Encoding [0, N + 4], // Host and Connection
]; ];
const doRequest = common.mustCall(() => { const doRequest = common.mustCall(() => {
const max = maxAndExpected[responses][0]; const max = maxAndExpected[responses][0];

View file

@ -60,7 +60,7 @@ server.listen(0, function() {
client2.on('close', common.mustCall()); client2.on('close', common.mustCall());
client2.write('GET / HTTP/1.1\r\n\r\n'); client2.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n');
})); }));
client1.on('close', common.mustCall()); client1.on('close', common.mustCall());

View file

@ -70,7 +70,7 @@ server.listen(0, function() {
client2Closed = true; client2Closed = true;
})); }));
client2.write('GET / HTTP/1.1\r\n\r\n'); client2.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n');
})); }));
client1.on('close', common.mustCall(() => { client1.on('close', common.mustCall(() => {