Skip to content

Commit 1a7302b

Browse files
mcollinarvagg
authored andcommittedFeb 27, 2019
http: prevent slowloris with keepalive connections
Fixes: nodejs-private/security#214 PR-URL: nodejs-private/node-private#158 Reviewed-By: Rod Vagg <[email protected]> Reviewed-By: Sam Roberts <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
1 parent 7840f71 commit 1a7302b

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed
 

‎lib/_http_server.js

+15
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,10 @@ function resOnFinish(req, res, socket, state, server) {
606606
function parserOnIncoming(server, socket, state, req, keepAlive) {
607607
resetSocketTimeout(server, socket, state);
608608

609+
if (server.keepAliveTimeout > 0) {
610+
req.on('end', resetHeadersTimeoutOnReqEnd);
611+
}
612+
609613
// Set to zero to communicate that we have finished parsing.
610614
socket.parser.parsingHeadersStart = 0;
611615

@@ -730,6 +734,17 @@ function socketOnWrap(ev, fn) {
730734
return res;
731735
}
732736

737+
function resetHeadersTimeoutOnReqEnd() {
738+
debug('resetHeadersTimeoutOnReqEnd');
739+
740+
const parser = this.socket.parser;
741+
// Parser can be null if the socket was destroyed
742+
// in that case, there is nothing to do.
743+
if (parser !== null) {
744+
parser.parsingHeadersStart = nowDate();
745+
}
746+
}
747+
733748
module.exports = {
734749
STATUS_CODES,
735750
Server,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const http = require('http');
5+
const net = require('net');
6+
const { finished } = require('stream');
7+
8+
const headers =
9+
'GET / HTTP/1.1\r\n' +
10+
'Host: localhost\r\n' +
11+
'Connection: keep-alive' +
12+
'Agent: node\r\n';
13+
14+
let sendCharEvery = 1000;
15+
16+
const server = http.createServer(common.mustCall((req, res) => {
17+
res.writeHead(200);
18+
res.end();
19+
}));
20+
21+
// Pass a REAL env variable to shortening up the default
22+
// value which is 40s otherwise this is useful for manual
23+
// testing
24+
if (!process.env.REAL) {
25+
sendCharEvery = common.platformTimeout(10);
26+
server.headersTimeout = 2 * sendCharEvery;
27+
}
28+
29+
server.once('timeout', common.mustCall((socket) => {
30+
socket.destroy();
31+
}));
32+
33+
server.listen(0, () => {
34+
const client = net.connect(server.address().port);
35+
client.write(headers);
36+
// finish the first request
37+
client.write('\r\n');
38+
// second request
39+
client.write(headers);
40+
client.write('X-CRASH: ');
41+
42+
const interval = setInterval(() => {
43+
client.write('a');
44+
}, sendCharEvery);
45+
46+
client.resume();
47+
finished(client, common.mustCall((err) => {
48+
clearInterval(interval);
49+
server.close();
50+
}));
51+
});

0 commit comments

Comments
 (0)
Please sign in to comment.