Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http: server check Host header in request, to meet RFC 7230 5.4 requirement #39322

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions lib/_http_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -904,8 +904,18 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
resOnFinish.bind(undefined,
req, res, socket, state, server));

if (req.headers.expect !== undefined &&
(req.httpVersionMajor === 1 && req.httpVersionMinor === 1)) {
const isHttp11 = (req.httpVersionMajor === 1 && req.httpVersionMinor === 1);

// From RFC 2730 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 (req.headers.host === undefined && isHttp11) {
res.writeHead(400);
res.end();
return 0;
}

if (req.headers.expect !== undefined && isHttp11) {
if (RegExpPrototypeTest(continueExpression, req.headers.expect)) {
res._expect_continue = true;

Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-http-chunked-304.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function test(statusCode) {
const conn = net.createConnection(
server.address().port,
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 = '';
conn.setEncoding('utf8');
Expand Down
17 changes: 13 additions & 4 deletions test/parallel/test-http-client-headers-array.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ function execute(options) {
const expectHeaders = {
'x-foo': 'boom',
'cookie': 'a=1; b=2; c=3',
'connection': 'close'
'connection': 'close',
'host': 'example.com',
};

// no Host header when you set headers an array
Expand Down Expand Up @@ -42,13 +43,20 @@ function execute(options) {
// 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' ]],
[ '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: [
[ '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
Expand All @@ -57,4 +65,5 @@ execute({ auth: 'foo:bar', headers:
execute({ auth: 'foo:bar', headers: [
[ 'x-foo', 'boom' ], [ 'cookie', 'a=1' ],
[ 'cookie', 'b=2' ], [ 'cookie', 'c=3'],
[ 'Host', 'example.com'],
] });
6 changes: 3 additions & 3 deletions test/parallel/test-http-content-length.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,18 @@ const server = http.createServer(function(req, res) {

switch (req.url.substr(1)) {
case 'multiple-writes':
delete req.headers.host;
assert.deepStrictEqual(req.headers, expectedHeadersMultipleWrites);
res.write('hello');
res.end('world');
break;
case 'end-with-data':
delete req.headers.host;
assert.deepStrictEqual(req.headers, expectedHeadersEndWithData);
res.end('hello world');
break;
case 'empty':
delete req.headers.host;
assert.deepStrictEqual(req.headers, expectedHeadersEndNoData);
res.end();
break;
Expand All @@ -55,7 +58,6 @@ server.listen(0, function() {
path: '/multiple-writes'
});
req.removeHeader('Date');
req.removeHeader('Host');
req.write('hello ');
req.end('world');
req.on('response', function(res) {
Expand All @@ -68,7 +70,6 @@ server.listen(0, function() {
path: '/end-with-data'
});
req.removeHeader('Date');
req.removeHeader('Host');
req.end('hello world');
req.on('response', function(res) {
assert.deepStrictEqual(res.headers, expectedHeadersEndWithData);
Expand All @@ -80,7 +81,6 @@ server.listen(0, function() {
path: '/empty'
});
req.removeHeader('Date');
req.removeHeader('Host');
req.end();
req.on('response', function(res) {
assert.deepStrictEqual(res.headers, expectedHeadersEndNoData);
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-http-header-badrequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ server.listen(0, mustCall(() => {
let received = '';

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) => {
received += data.toString();
Expand Down
4 changes: 4 additions & 0 deletions test/parallel/test-http-insecure-parser-per-stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const MakeDuplexPair = require('../common/duplexpair');

serverSide.resume(); // Dump the request
serverSide.end('HTTP/1.1 200 OK\r\n' +
'Host: example.com\r\n' +
'Hello: foo\x08foo\r\n' +
'Content-Length: 0\r\n' +
'\r\n\r\n');
Expand All @@ -39,6 +40,7 @@ const MakeDuplexPair = require('../common/duplexpair');

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

clientSide.write('GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Hello: foo\x08foo\r\n' +
'\r\n\r\n');
}
Expand All @@ -77,6 +80,7 @@ const MakeDuplexPair = require('../common/duplexpair');
server.emit('connection', serverSide);

clientSide.write('GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Hello: foo\x08foo\r\n' +
'\r\n\r\n');
}
Expand Down
1 change: 1 addition & 0 deletions test/parallel/test-http-insecure-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ server.listen(0, common.mustCall(function() {
client.write(
'GET / HTTP/1.1\r\n' +
'Content-Type: text/te\x08t\r\n' +
'Host: example.com' +
'Connection: close\r\n\r\n');
}
);
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-http-malformed-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ server.listen(0);
server.on('listening', function() {
const c = net.createConnection(this.address().port);
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();
});
});
1 change: 1 addition & 0 deletions test/parallel/test-http-max-header-size-per-stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const MakeDuplexPair = require('../common/duplexpair');
server.emit('connection', serverSide);

clientSide.write('GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Hello: ' + 'A'.repeat(http.maxHeaderSize * 3) + '\r\n' +
'\r\n\r\n');
}
Expand Down
8 changes: 5 additions & 3 deletions test/parallel/test-http-max-headers-count.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ const http = require('http');
let requests = 0;
let responses = 0;

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

Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-http-pipeline-assertionerror-finish.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const server = http
.listen(0, function() {
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.resume();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const server = http
});
})
.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.write(req);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const server = http
.listen(0, () => {
const s = net.connect(server.address().port);
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 = () => {
s.write(
Expand Down
1 change: 1 addition & 0 deletions test/parallel/test-http-req-close-robust-from-tampering.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ server.listen(0, common.mustCall(() => {

const req = [
'POST / HTTP/1.1',
'Host: example.com',
'Content-Length: 11',
'',
'hello world',
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-http-response-splitting.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const server = http.createServer((req, res) => {
res.end('ok');
});
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 }, () => {
client.write(`GET ${str} ${end}`);
client.write(`GET / ${end}`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ server.listen(0, common.mustCall(() => {

client.resume();
client.write('POST / HTTP/1.1\r\n');
client.write('Host: example.com\r\n');
client.write('Content-Length: 20\r\n');
client.write('Connection: close\r\n');
client.write('\r\n');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ server.listen(0, common.mustCall(() => {

client.resume();
client.write('POST / HTTP/1.1\r\n');
client.write('Host: example.com\r\n');
client.write('Content-Length: 20\r\n');
client.write('Connection: close\r\n');
client.write('\r\n');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const { connect } = require('net');

function performRequestWithDelay(client, firstDelay, secondDelay) {
client.resume();
client.write('GET / HTTP/1.1\r\n');
client.write('GET / HTTP/1.1\r\nHost: example.com\r\n');

firstDelay = common.platformTimeout(firstDelay);
secondDelay = common.platformTimeout(secondDelay);
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-http-server-unconsume.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const net = require('net');
server.close();
}).listen(0, 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.end('hello world');
Expand Down
13 changes: 9 additions & 4 deletions test/parallel/test-http-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,26 @@ server.on('listening', function() {
c.setEncoding('utf8');

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;
});

c.on('data', function(chunk) {
server_response += chunk;

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;
}

if (requests_sent === 2) {
c.write('GET / HTTP/1.1\r\nX-X: foo\r\n\r\n' +
'GET / HTTP/1.1\r\nX-X: bar\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\nHost: example.com\r\n\r\n');
// Note: we are making the connection half-closed here
// before we've gotten the response from the server. This
// is a pretty bad thing to do and not really supported
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-http-set-trailers.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function testHttp11(port, callback) {

let tid;
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.');
});

Expand Down
5 changes: 4 additions & 1 deletion test/parallel/test-http-status-message.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ function test() {
const client = net.connect(
this.address().port,
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) {
Expand Down
4 changes: 3 additions & 1 deletion test/parallel/test-http-upgrade-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ function test_upgrade_with_listener() {
conn.on('connect', function() {
writeReq(conn,
'GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Upgrade: WebSocket\r\n' +
'Connection: Upgrade\r\n' +
'\r\n' +
Expand Down Expand Up @@ -124,6 +125,7 @@ function test_upgrade_no_listener() {
conn.on('connect', function() {
writeReq(conn,
'GET / HTTP/1.1\r\n' +
'Host: example.com\r\n' +
'Upgrade: WebSocket\r\n' +
'Connection: Upgrade\r\n' +
'\r\n');
Expand All @@ -146,7 +148,7 @@ function test_standard_http() {
conn.setEncoding('utf8');

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) {
Expand Down
4 changes: 3 additions & 1 deletion test/parallel/test-http.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ server.on('listening', () => {
path: '/world',
headers: [ ['Cookie', 'abc=123'],
['Cookie', 'def=456'],
['Cookie', 'ghi=789'] ],
['Cookie', 'ghi=789'],
['Host', 'example.com'],
],
agent: agent
}, common.mustCall((res) => {
const cookieHeaders = req._header.match(/^Cookie: .+$/img);
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-https-agent-create-connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const expectCertError = /^Error: unable to verify the first certificate$/;
const checkRequest = (socket, server) => {
let result = '';
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.on('data', common.mustCall((chunk) => {
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-https-host-headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const httpsServer = https.createServer({
}
res.writeHead(200, {});
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}`);
assert.ifError(err);
https.get({
Expand Down
Loading