mirror of
https://github.com/nodejs/node.git
synced 2025-05-03 02:06:12 +00:00

This commits introduces a new http.Server option called requestTimeout with a default value in milliseconds of 0. If requestTimeout is set to a positive value, the server will start a new timer set to expire in requestTimeout milliseconds when a new connection is established. The timer is also set again if new requests after the first are received on the socket (this handles pipelining and keep-alive cases). The timer is cancelled when: 1. the request body is completely received by the server. 2. the response is completed. This handles the case where the application responds to the client without consuming the request body. 3. the connection is upgraded, like in the WebSocket case. If the timer expires, then the server responds with status code 408 and closes the connection. CVE-2020-8251 PR-URL: https://github.com/nodejs-private/node-private/pull/208 Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Mary Marchini <oss@mmarchini.me> Co-Authored-By: Paolo Insogna <paolo@cowtech.it> Co-Authored-By: Robert Nagy <ronagy@icloud.com>
95 lines
2.7 KiB
JavaScript
95 lines
2.7 KiB
JavaScript
'use strict';
|
|
|
|
const common = require('../common');
|
|
const assert = require('assert');
|
|
const { createServer } = require('http');
|
|
const { connect } = require('net');
|
|
|
|
// This test validates that the server returns 408
|
|
// after server.requestTimeout if the client
|
|
// does not complete a request, and that keep alive
|
|
// works properly
|
|
|
|
function performRequestWithDelay(client, firstDelay, secondDelay) {
|
|
client.resume();
|
|
client.write('GET / HTTP/1.1\r\n');
|
|
|
|
firstDelay = common.platformTimeout(firstDelay);
|
|
secondDelay = common.platformTimeout(secondDelay);
|
|
|
|
console.log('performRequestWithDelay', firstDelay, secondDelay);
|
|
|
|
setTimeout(() => {
|
|
client.write('Connection: ');
|
|
}, firstDelay).unref();
|
|
|
|
// Complete the request
|
|
setTimeout(() => {
|
|
client.write('keep-alive\r\n\r\n');
|
|
}, firstDelay + secondDelay).unref();
|
|
}
|
|
|
|
const server = createServer(common.mustCallAtLeast((req, res) => {
|
|
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
res.end();
|
|
}));
|
|
|
|
// 0 seconds is the default
|
|
assert.strictEqual(server.requestTimeout, 0);
|
|
const requestTimeout = common.platformTimeout(1000);
|
|
server.requestTimeout = requestTimeout;
|
|
assert.strictEqual(server.requestTimeout, requestTimeout);
|
|
|
|
// Make sure keepAliveTimeout is big enough for the requestTimeout.
|
|
server.keepAliveTimeout = 0;
|
|
|
|
server.listen(0, common.mustCall(() => {
|
|
const client = connect(server.address().port);
|
|
let second = false;
|
|
let response = '';
|
|
|
|
client.on('data', common.mustCallAtLeast((chunk) => {
|
|
response += chunk.toString('utf-8');
|
|
|
|
// First response has ended
|
|
if (!second && response.endsWith('\r\n\r\n')) {
|
|
assert.strictEqual(
|
|
response.split('\r\n')[0],
|
|
'HTTP/1.1 200 OK'
|
|
);
|
|
|
|
const defer = common.platformTimeout(server.requestTimeout * 1.5);
|
|
|
|
console.log('defer by', defer);
|
|
|
|
// Wait some time to make sure requestTimeout
|
|
// does not interfere with keep alive
|
|
setTimeout(() => {
|
|
response = '';
|
|
second = true;
|
|
|
|
// Perform a second request expected to finish after requestTimeout
|
|
performRequestWithDelay(client, 1000, 3000);
|
|
}, defer).unref();
|
|
}
|
|
}, 1));
|
|
|
|
const errOrEnd = common.mustCall(function(err) {
|
|
console.log(err);
|
|
assert.strictEqual(second, true);
|
|
assert.strictEqual(
|
|
response,
|
|
// Empty because of https://github.com/nodejs/node/commit/e8d7fedf7cad6e612e4f2e0456e359af57608ac7
|
|
// 'HTTP/1.1 408 Request Timeout\r\nConnection: close\r\n\r\n'
|
|
''
|
|
);
|
|
server.close();
|
|
});
|
|
|
|
client.on('error', errOrEnd);
|
|
client.on('end', errOrEnd);
|
|
|
|
// Perform a second request expected to finish before requestTimeout
|
|
performRequestWithDelay(client, 50, 500);
|
|
}));
|