http: prevent slowloris with keepalive connections
Fixes: https://github.com/nodejs-private/security/issues/214 PR-URL: https://github.com/nodejs-private/node-private/pull/158 Reviewed-By: Rod Vagg <rod@vagg.org> Reviewed-By: Sam Roberts <vieuxtech@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
This commit is contained in:
parent
04d5c1b8fd
commit
667b31be95
@ -622,6 +622,10 @@ function emitCloseNT(self) {
|
|||||||
function parserOnIncoming(server, socket, state, req, keepAlive) {
|
function parserOnIncoming(server, socket, state, req, keepAlive) {
|
||||||
resetSocketTimeout(server, socket, state);
|
resetSocketTimeout(server, socket, state);
|
||||||
|
|
||||||
|
if (server.keepAliveTimeout > 0) {
|
||||||
|
req.on('end', resetHeadersTimeoutOnReqEnd);
|
||||||
|
}
|
||||||
|
|
||||||
// Set to zero to communicate that we have finished parsing.
|
// Set to zero to communicate that we have finished parsing.
|
||||||
socket.parser.parsingHeadersStart = 0;
|
socket.parser.parsingHeadersStart = 0;
|
||||||
|
|
||||||
@ -745,6 +749,17 @@ function socketOnWrap(ev, fn) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resetHeadersTimeoutOnReqEnd() {
|
||||||
|
debug('resetHeadersTimeoutOnReqEnd');
|
||||||
|
|
||||||
|
const parser = this.socket.parser;
|
||||||
|
// Parser can be null if the socket was destroyed
|
||||||
|
// in that case, there is nothing to do.
|
||||||
|
if (parser !== null) {
|
||||||
|
parser.parsingHeadersStart = nowDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
STATUS_CODES,
|
STATUS_CODES,
|
||||||
Server,
|
Server,
|
||||||
|
51
test/parallel/test-http-slow-headers-keepalive.js
Normal file
51
test/parallel/test-http-slow-headers-keepalive.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const http = require('http');
|
||||||
|
const net = require('net');
|
||||||
|
const { finished } = require('stream');
|
||||||
|
|
||||||
|
const headers =
|
||||||
|
'GET / HTTP/1.1\r\n' +
|
||||||
|
'Host: localhost\r\n' +
|
||||||
|
'Connection: keep-alive' +
|
||||||
|
'Agent: node\r\n';
|
||||||
|
|
||||||
|
let sendCharEvery = 1000;
|
||||||
|
|
||||||
|
const server = http.createServer(common.mustCall((req, res) => {
|
||||||
|
res.writeHead(200);
|
||||||
|
res.end();
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Pass a REAL env variable to shortening up the default
|
||||||
|
// value which is 40s otherwise this is useful for manual
|
||||||
|
// testing
|
||||||
|
if (!process.env.REAL) {
|
||||||
|
sendCharEvery = common.platformTimeout(10);
|
||||||
|
server.headersTimeout = 2 * sendCharEvery;
|
||||||
|
}
|
||||||
|
|
||||||
|
server.once('timeout', common.mustCall((socket) => {
|
||||||
|
socket.destroy();
|
||||||
|
}));
|
||||||
|
|
||||||
|
server.listen(0, () => {
|
||||||
|
const client = net.connect(server.address().port);
|
||||||
|
client.write(headers);
|
||||||
|
// finish the first request
|
||||||
|
client.write('\r\n');
|
||||||
|
// second request
|
||||||
|
client.write(headers);
|
||||||
|
client.write('X-CRASH: ');
|
||||||
|
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
client.write('a');
|
||||||
|
}, sendCharEvery);
|
||||||
|
|
||||||
|
client.resume();
|
||||||
|
finished(client, common.mustCall((err) => {
|
||||||
|
clearInterval(interval);
|
||||||
|
server.close();
|
||||||
|
}));
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user