Skip to content

Commit

Permalink
http: provide keep-alive timeout response header
Browse files Browse the repository at this point in the history
In http 1.1 persistent connection protocol there is a
timing race where the client sends the request and then
the server kills the connection (due to inactivity)
before receiving the client's request.

By providing a keep-alive header it is possible to provide
the client a hint of when idle timeout would occur and
avoid the race.

Fixes: #34560

PR-URL: #34561
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Zeyu Yang <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
Reviewed-By: Pranshu Srivastava <[email protected]>
  • Loading branch information
ronag authored and addaleax committed Sep 22, 2020
1 parent c0a961e commit 10815c4
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 0 deletions.
7 changes: 7 additions & 0 deletions lib/_http_outgoing.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const {
ObjectKeys,
ObjectPrototypeHasOwnProperty,
ObjectSetPrototypeOf,
MathFloor,
Symbol,
} = primordials;

Expand Down Expand Up @@ -117,6 +118,8 @@ function OutgoingMessage() {
this._header = null;
this[kOutHeaders] = null;

this._keepAliveTimeout = 0;

this._onPendingData = noopPendingOutput;
}
ObjectSetPrototypeOf(OutgoingMessage.prototype, Stream.prototype);
Expand Down Expand Up @@ -402,6 +405,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';
Expand Down
1 change: 1 addition & 0 deletions lib/_http_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,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;
Expand Down
28 changes: 28 additions & 0 deletions test/parallel/test-http-keep-alive-timeout.js
Original file line number Diff line number Diff line change
@@ -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();
}));
}));

0 comments on commit 10815c4

Please sign in to comment.