diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index 868c74d3518cc0..f444be8687db34 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -28,6 +28,7 @@ const { ObjectKeys, ObjectPrototypeHasOwnProperty, ObjectSetPrototypeOf, + MathFloor, Symbol, } = primordials; @@ -123,6 +124,8 @@ function OutgoingMessage() { this._header = null; this[kOutHeaders] = null; + this._keepAliveTimeout = 0; + this._onPendingData = noopPendingOutput; } ObjectSetPrototypeOf(OutgoingMessage.prototype, Stream.prototype); @@ -424,6 +427,10 @@ function _storeHeader(firstLine, headers) { (state.contLen || this.useChunkedEncodingByDefault || this.agent); if (shouldSendKeepAlive) { header += 'Connection: keep-alive\r\n'; + if (this._keepAliveTimeout) { + const timeoutSeconds = MathFloor(this._keepAliveTimeout) / 1000; + header += `Keep-Alive: timeout=${timeoutSeconds}\r\n`; + } } else { this._last = true; header += 'Connection: close\r\n'; diff --git a/lib/_http_server.js b/lib/_http_server.js index 084b67b6b3a6fe..0da43c3e3a8159 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -766,6 +766,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) { } const res = new server[kServerResponse](req); + res._keepAliveTimeout = server.keepAliveTimeout; res._onPendingData = updateOutgoingData.bind(undefined, socket, state); res.shouldKeepAlive = keepAlive; diff --git a/test/parallel/test-http-keep-alive-timeout.js b/test/parallel/test-http-keep-alive-timeout.js new file mode 100644 index 00000000000000..fccb267b8e9ee2 --- /dev/null +++ b/test/parallel/test-http-keep-alive-timeout.js @@ -0,0 +1,28 @@ +'use strict'; + +const common = require('../common'); +const http = require('http'); +const assert = require('assert'); + +const server = http.createServer(common.mustCall((req, res) => { + const body = 'hello world\n'; + + res.writeHead(200, { 'Content-Length': body.length }); + res.write(body); + res.end(); +})); +server.keepAliveTimeout = 12000; + +const agent = new http.Agent({ maxSockets: 1, keepAlive: true }); + +server.listen(0, common.mustCall(function() { + http.get({ + path: '/', port: this.address().port, agent: agent + }, common.mustCall((response) => { + response.resume(); + assert.strictEqual( + response.headers['keep-alive'], 'timeout=12'); + server.close(); + agent.destroy(); + })); +}));