diff --git a/lib/_http_server.js b/lib/_http_server.js index a899f651be3..02cd7a81a9c 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -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, diff --git a/test/parallel/test-http-slow-headers-keepalive.js b/test/parallel/test-http-slow-headers-keepalive.js new file mode 100644 index 00000000000..5552f33f77e --- /dev/null +++ b/test/parallel/test-http-slow-headers-keepalive.js @@ -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(); + })); +});