Skip to content

Commit 849d9e7

Browse files
committed
http: provide keep-alive timeout response header
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]>
1 parent 770a02d commit 849d9e7

File tree

3 files changed

+36
-0
lines changed

3 files changed

+36
-0
lines changed

lib/_http_outgoing.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const {
2828
ObjectKeys,
2929
ObjectPrototypeHasOwnProperty,
3030
ObjectSetPrototypeOf,
31+
MathFloor,
3132
Symbol,
3233
} = primordials;
3334

@@ -123,6 +124,8 @@ function OutgoingMessage() {
123124
this._header = null;
124125
this[kOutHeaders] = null;
125126

127+
this._keepAliveTimeout = 0;
128+
126129
this._onPendingData = noopPendingOutput;
127130
}
128131
ObjectSetPrototypeOf(OutgoingMessage.prototype, Stream.prototype);
@@ -424,6 +427,10 @@ function _storeHeader(firstLine, headers) {
424427
(state.contLen || this.useChunkedEncodingByDefault || this.agent);
425428
if (shouldSendKeepAlive) {
426429
header += 'Connection: keep-alive\r\n';
430+
if (this._keepAliveTimeout) {
431+
const timeoutSeconds = MathFloor(this._keepAliveTimeout) / 1000;
432+
header += `Keep-Alive: timeout=${timeoutSeconds}\r\n`;
433+
}
427434
} else {
428435
this._last = true;
429436
header += 'Connection: close\r\n';

lib/_http_server.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
766766
}
767767

768768
const res = new server[kServerResponse](req);
769+
res._keepAliveTimeout = server.keepAliveTimeout;
769770
res._onPendingData = updateOutgoingData.bind(undefined, socket, state);
770771

771772
res.shouldKeepAlive = keepAlive;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const http = require('http');
5+
const assert = require('assert');
6+
7+
const server = http.createServer(common.mustCall((req, res) => {
8+
const body = 'hello world\n';
9+
10+
res.writeHead(200, { 'Content-Length': body.length });
11+
res.write(body);
12+
res.end();
13+
}));
14+
server.keepAliveTimeout = 12000;
15+
16+
const agent = new http.Agent({ maxSockets: 1, keepAlive: true });
17+
18+
server.listen(0, common.mustCall(function() {
19+
http.get({
20+
path: '/', port: this.address().port, agent: agent
21+
}, common.mustCall((response) => {
22+
response.resume();
23+
assert.strictEqual(
24+
response.headers['keep-alive'], 'timeout=12');
25+
server.close();
26+
agent.destroy();
27+
}));
28+
}));

0 commit comments

Comments
 (0)