Skip to content
Permalink
Browse files

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>
  • Loading branch information...
mcollina authored and rvagg committed Dec 1, 2018
1 parent 852d25b commit 76d52c508a281fd09ef87b802d592e1645470e16
Showing with 73 additions and 0 deletions.
  1. +15 −0 lib/_http_server.js
  2. +58 −0 test/parallel/test-http-slow-headers-keepalive.js
@@ -596,6 +596,10 @@ function resOnFinish(req, res, socket, state, server) {
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;

@@ -714,6 +718,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) {

This comment has been minimized.

Copy link
@hyj1991

hyj1991 Mar 5, 2019

Is parser maybe undefined?

parser.parsingHeadersStart = nowDate();
}
}

module.exports = {
STATUS_CODES,
Server,
@@ -0,0 +1,58 @@
'use strict';

const common = require('../common');
const http = require('http');
const net = require('net');

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();

const onClose = common.mustCall(() => {
client.removeListener('close', onClose);
client.removeListener('error', onClose);
client.removeListener('end', onClose);
clearInterval(interval);
server.close();
});

client.on('error', onClose);
client.on('close', onClose);
client.on('end', onClose);
});

0 comments on commit 76d52c5

Please sign in to comment.
You can’t perform that action at this time.