Skip to content

Commit b13b4a9

Browse files
mcollinarvagg
authored andcommitted
http: prevent slowloris with keepalive connections
Fixes: nodejs-private/security#214 PR-URL: nodejs-private/node-private#162 Reviewed-By: Rod Vagg <rod@vagg.org> Reviewed-By: Sam Roberts <vieuxtech@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
1 parent 06a208d commit b13b4a9

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

lib/_http_server.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,10 @@ function connectionListener(socket) {
489489

490490
incoming.push(req);
491491

492+
if (self.keepAliveTimeout > 0) {
493+
req.on('end', resetHeadersTimeoutOnReqEnd);
494+
}
495+
492496
// Set to zero to communicate that we have finished parsing.
493497
socket.parser.parsingHeadersStart = 0;
494498

@@ -640,3 +644,14 @@ function socketOnWrap(ev, fn) {
640644

641645
return res;
642646
}
647+
648+
function resetHeadersTimeoutOnReqEnd() {
649+
debug('resetHeadersTimeoutOnReqEnd');
650+
651+
var parser = this.socket.parser;
652+
// Parser can be null if the socket was destroyed
653+
// in that case, there is nothing to do.
654+
if (parser !== null) {
655+
parser.parsingHeadersStart = nowDate();
656+
}
657+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const http = require('http');
5+
const net = require('net');
6+
7+
const headers =
8+
'GET / HTTP/1.1\r\n' +
9+
'Host: localhost\r\n' +
10+
'Connection: keep-alive' +
11+
'Agent: node\r\n';
12+
13+
let sendCharEvery = 1000;
14+
15+
const server = http.createServer(common.mustCall((req, res) => {
16+
res.writeHead(200);
17+
res.end();
18+
}));
19+
20+
// Pass a REAL env variable to shortening up the default
21+
// value which is 40s otherwise this is useful for manual
22+
// testing
23+
if (!process.env.REAL) {
24+
sendCharEvery = common.platformTimeout(10);
25+
server.headersTimeout = 2 * sendCharEvery;
26+
}
27+
28+
server.once('timeout', common.mustCall((socket) => {
29+
socket.destroy();
30+
}));
31+
32+
server.listen(0, () => {
33+
const client = net.connect(server.address().port);
34+
client.write(headers);
35+
// finish the first request
36+
client.write('\r\n');
37+
// second request
38+
client.write(headers);
39+
client.write('X-CRASH: ');
40+
41+
const interval = setInterval(() => {
42+
client.write('a');
43+
}, sendCharEvery);
44+
45+
client.resume();
46+
47+
const onClose = common.mustCall(() => {
48+
client.removeListener('close', onClose);
49+
client.removeListener('error', onClose);
50+
client.removeListener('end', onClose);
51+
clearInterval(interval);
52+
server.close();
53+
});
54+
55+
client.on('error', onClose);
56+
client.on('close', onClose);
57+
client.on('end', onClose);
58+
});

0 commit comments

Comments
 (0)