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) {
|
||||
resetSocketTimeout(server, socket, state);
|
||||
|
||||
if (server.keepAliveTimeout > 0) {
|
||||
req.on('end', resetHeadersTimeoutOnReqEnd);
|
||||
}
|
||||
|
||||
// Set to zero to communicate that we have finished parsing.
|
||||
socket.parser.parsingHeadersStart = 0;
|
||||
|
||||
@ -745,6 +749,17 @@ function socketOnWrap(ev, fn) {
|
||||
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 = {
|
||||
STATUS_CODES,
|
||||
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