Skip to content

Commit 17cd6c6

Browse files
committed
http: make TCP keep-alive and TCP noDelay enabled by default
1 parent b3723fa commit 17cd6c6

29 files changed

+131
-30
lines changed

doc/api/http.md

+15-5
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ http.get({
117117
<!-- YAML
118118
added: v0.3.4
119119
changes:
120+
- version:
121+
- CHANGEME
122+
pr-url: https://github.com/nodejs/node/pull/42163/files
123+
description: Changed the default value of `keepAlive` to `true`.
120124
- version:
121125
- v15.6.0
122126
- v14.17.0
@@ -144,11 +148,11 @@ changes:
144148
header is always sent when using an agent except when the `Connection`
145149
header is explicitly specified or when the `keepAlive` and `maxSockets`
146150
options are respectively set to `false` and `Infinity`, in which case
147-
`Connection: close` will be used. **Default:** `false`.
151+
`Connection: close` will be used. **Default:** `true`.
148152
* `keepAliveMsecs` {number} When using the `keepAlive` option, specifies
149153
the [initial delay][]
150154
for TCP Keep-Alive packets. Ignored when the
151-
`keepAlive` option is `false` or `undefined`. **Default:** `1000`.
155+
`keepAlive` option is `false`. **Default:** `1000`.
152156
* `maxSockets` {number} Maximum number of sockets to allow per host.
153157
If the same host opens multiple concurrent connections, each request
154158
will use new socket until the `maxSockets` value is reached.
@@ -2838,6 +2842,12 @@ Found'`.
28382842
<!-- YAML
28392843
added: v0.1.13
28402844
changes:
2845+
- version:
2846+
- CHANGEME
2847+
pr-url: https://github.com/nodejs/node/pull/42163/files
2848+
description: Changed the default value of `noDelay` and `keepAlive`
2849+
to `true`. Changed the default value of `keepAliveInitialDelay`
2850+
to `1000`.
28412851
- version:
28422852
- v13.8.0
28432853
- v12.15.0
@@ -2871,14 +2881,14 @@ changes:
28712881
**Default:** 16384 (16 KB).
28722882
* `noDelay` {boolean} If set to `true`, it disables the use of Nagle's
28732883
algorithm immediately after a new incoming connection is received.
2874-
**Default:** `false`.
2884+
**Default:** `true`.
28752885
* `keepAlive` {boolean} If set to `true`, it enables keep-alive functionality
28762886
on the socket immediately after a new incoming connection is received,
28772887
similarly on what is done in \[`socket.setKeepAlive([enable][, initialDelay])`]\[`socket.setKeepAlive(enable, initialDelay)`].
2878-
**Default:** `false`.
2888+
**Default:** `true`.
28792889
* `keepAliveInitialDelay` {number} If set to a positive number, it sets the
28802890
initial delay before the first keepalive probe is sent on an idle socket.
2881-
**Default:** `0`.
2891+
**Default:** `1000`.
28822892

28832893
* `requestListener` {Function}
28842894

lib/_http_agent.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,21 @@ function Agent(options) {
101101

102102
this.options = { __proto__: null, ...options };
103103

104+
if (this.options.noDelay === undefined)
105+
this.options.noDelay = true;
106+
if (this.options.keepAlive === undefined)
107+
this.options.keepAlive = true;
108+
if (this.options.keepAliveInitialDelay === undefined)
109+
this.options.keepAliveInitialDelay = 1000;
110+
104111
// Don't confuse net and make it think that we're connecting to a pipe
105112
this.options.path = null;
106113
this.requests = ObjectCreate(null);
107114
this.sockets = ObjectCreate(null);
108115
this.freeSockets = ObjectCreate(null);
109-
this.keepAliveMsecs = this.options.keepAliveMsecs || 1000;
110-
this.keepAlive = this.options.keepAlive || false;
116+
this.keepAliveMsecs =
117+
this.options.keepAliveMsecs || this.options.keepAliveInitialDelay || 1000;
118+
this.keepAlive = this.options.keepAlive;
111119
this.maxSockets = this.options.maxSockets || Agent.defaultMaxSockets;
112120
this.maxFreeSockets = this.options.maxFreeSockets || 256;
113121
this.scheduling = this.options.scheduling || 'lifo';

lib/_http_server.js

+7
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,13 @@ function storeHTTPOptions(options) {
363363
if (insecureHTTPParser !== undefined)
364364
validateBoolean(insecureHTTPParser, 'options.insecureHTTPParser');
365365
this.insecureHTTPParser = insecureHTTPParser;
366+
367+
if (options.noDelay === undefined)
368+
options.noDelay = true;
369+
if (options.keepAlive === undefined)
370+
options.keepAlive = true;
371+
if (options.keepAliveInitialDelay === undefined)
372+
options.keepAliveInitialDelay = 1000;
366373
}
367374

368375
function Server(options, requestListener) {

test/async-hooks/test-graph.http.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ server.listen(0, common.mustCall(() => {
1919
http.get({
2020
host: '::1',
2121
family: 6,
22-
port: server.address().port
23-
}, common.mustCall());
22+
port: server.address().port,
23+
headers: { connection: 'close' }
24+
}, common.mustCall(() => {}));
2425
}));
2526

2627
process.on('exit', () => {

test/parallel/test-child-process-http-socket-leak.js

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ server.listen(0, common.mustCall(() => {
4949
assert.strictEqual(socket[kTimeout], null);
5050
assert.strictEqual(socket.parser, null);
5151
assert.strictEqual(socket._httpMessage, null);
52+
res.req.socket.end();
5253
}));
5354
}));
5455

test/parallel/test-http-client-agent.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ const max = 3;
3131
const server = http.Server(common.mustCall((req, res) => {
3232
if (req.url === '/0') {
3333
setTimeout(common.mustCall(() => {
34-
res.writeHead(200);
34+
res.writeHead(200, { connection: 'close' });
3535
res.end('Hello, World!');
3636
}), 100);
3737
} else {
38-
res.writeHead(200);
38+
res.writeHead(200, { connection: 'close' });
3939
res.end('Hello, World!');
4040
}
4141
}, max));

test/parallel/test-http-client-headers-array.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ function execute(options) {
1010
const expectHeaders = {
1111
'x-foo': 'boom',
1212
'cookie': 'a=1; b=2; c=3',
13-
'connection': 'close'
13+
'connection': 'keep-alive'
1414
};
1515

1616
// no Host header when you set headers an array

test/parallel/test-http-client-readable.js

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class FakeAgent extends http.Agent {
5353

5454
return s;
5555
}
56+
57+
keepSocketAlive() {}
5658
}
5759

5860
let received = '';

test/parallel/test-http-client-spurious-aborted.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ function download() {
4040
req.on('error', common.mustNotCall());
4141
req.on('response', (res) => {
4242
assert.strictEqual(res.statusCode, 200);
43-
assert.strictEqual(res.headers.connection, 'close');
43+
assert.strictEqual(res.headers.connection, 'keep-alive');
4444
let aborted = false;
4545
const writable = new Writable({
4646
write(chunk, encoding, callback) {

test/parallel/test-http-content-length.js

+13-3
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,29 @@ const countdown = new Countdown(3, () => server.close());
2424

2525
const server = http.createServer(function(req, res) {
2626
res.removeHeader('Date');
27+
res.setHeader('connection', 'close');
2728

2829
switch (req.url.substr(1)) {
2930
case 'multiple-writes':
30-
assert.deepStrictEqual(req.headers, expectedHeadersMultipleWrites);
31+
assert.deepStrictEqual(
32+
req.headers,
33+
{ ...expectedHeadersMultipleWrites, 'connection': 'keep-alive' }
34+
);
3135
res.write('hello');
3236
res.end('world');
3337
break;
3438
case 'end-with-data':
35-
assert.deepStrictEqual(req.headers, expectedHeadersEndWithData);
39+
assert.deepStrictEqual(
40+
req.headers,
41+
{ ...expectedHeadersEndWithData, 'connection': 'keep-alive' }
42+
);
3643
res.end('hello world');
3744
break;
3845
case 'empty':
39-
assert.deepStrictEqual(req.headers, expectedHeadersEndNoData);
46+
assert.deepStrictEqual(
47+
req.headers,
48+
{ ...expectedHeadersEndNoData, 'connection': 'keep-alive' }
49+
);
4050
res.end();
4151
break;
4252
default:

test/parallel/test-http-dump-req-when-res-ends.js

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ server.listen(0, mustCall(function() {
5555
// invalidate the test.
5656
res.on('close', function() {
5757
server.close();
58+
res.req.socket.end();
5859
});
5960
}));
6061

test/parallel/test-http-max-headers-count.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ server.listen(0, function() {
6666
const expected = maxAndExpected[responses][1];
6767
const req = http.request({
6868
port: server.address().port,
69-
headers: headers
69+
headers: { connection: 'close', ...headers }
7070
}, function(res) {
7171
assert.strictEqual(Object.keys(res.headers).length, expected);
7272
res.on('end', function() {

test/parallel/test-http-nodelay.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const http = require('http');
6+
const net = require('net');
7+
8+
const originalConnect = net.Socket.prototype.connect;
9+
10+
net.Socket.prototype.connect = common.mustCall(function(args) {
11+
assert.strictEqual(args[0].noDelay, true);
12+
assert.strictEqual(args[0].keepAlive, true);
13+
assert.strictEqual(args[0].keepAliveInitialDelay, 1000);
14+
return originalConnect.call(this, args);
15+
});
16+
17+
const server = http.createServer(common.mustCall((req, res) => {
18+
res.writeHead(200);
19+
res.end();
20+
server.close();
21+
}));
22+
23+
server.listen(0, common.mustCall(() => {
24+
assert.strictEqual(server.noDelay, true);
25+
assert.strictEqual(server.keepAlive, true);
26+
// Value is converted to second from net.Server
27+
assert.strictEqual(server.keepAliveInitialDelay, 1);
28+
29+
const req = http.request({
30+
method: 'GET',
31+
port: server.address().port
32+
}, common.mustCall((res) => {
33+
res.on('end', () => {
34+
server.close();
35+
res.req.socket.end();
36+
});
37+
38+
res.resume();
39+
}));
40+
41+
req.end();
42+
}));

test/parallel/test-http-pause-no-dump.js

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ server.on('listening', common.mustCall(function() {
2626
res.resume();
2727
res.on('end', common.mustCall(() => {
2828
server.close();
29+
res.req.socket.end();
2930
}));
3031
}));
3132

test/parallel/test-http-raw-headers.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ http.createServer(function(req, res) {
3434
'x-BaR',
3535
'yoyoyo',
3636
'Connection',
37-
'close',
37+
'keep-alive',
3838
];
3939
const expectHeaders = {
4040
'host': `localhost:${this.address().port}`,
4141
'transfer-encoding': 'CHUNKED',
4242
'x-bar': 'yoyoyo',
43-
'connection': 'close'
43+
'connection': 'keep-alive'
4444
};
4545
const expectRawTrailers = [
4646
'x-bAr',
@@ -91,14 +91,17 @@ http.createServer(function(req, res) {
9191
'Date',
9292
null,
9393
'Connection',
94-
'close',
94+
'keep-alive',
95+
'Keep-Alive',
96+
'timeout=5',
9597
'Transfer-Encoding',
9698
'chunked',
9799
];
98100
const expectHeaders = {
99101
'trailer': 'x-foo',
100102
'date': null,
101-
'connection': 'close',
103+
'connection': 'keep-alive',
104+
'keep-alive': 'timeout=5',
102105
'transfer-encoding': 'chunked'
103106
};
104107
res.rawHeaders[3] = null;
@@ -121,6 +124,7 @@ http.createServer(function(req, res) {
121124
assert.deepStrictEqual(res.rawTrailers, expectRawTrailers);
122125
assert.deepStrictEqual(res.trailers, expectTrailers);
123126
console.log('ok');
127+
req.socket.end();
124128
});
125129
res.resume();
126130
});

test/parallel/test-http-request-large-payload.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require('../common');
88
const http = require('http');
99

1010
const server = http.createServer(function(req, res) {
11-
res.writeHead(200);
11+
res.writeHead(200, { connection: 'close' });
1212
res.end();
1313

1414
server.close();

test/parallel/test-http-should-keep-alive.js

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const getCountdownIndex = () => SERVER_RESPONSES.length - countdown.remaining;
5050

5151
const server = net.createServer(function(socket) {
5252
socket.write(SERVER_RESPONSES[getCountdownIndex()]);
53+
socket.end();
5354
}).listen(0, function() {
5455
function makeRequest() {
5556
const req = http.get({ port: server.address().port }, function(res) {

test/parallel/test-http-unix-socket-keep-alive.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ tmpdir.refresh();
1111
server.listen(common.PIPE, common.mustCall(() =>
1212
asyncLoop(makeKeepAliveRequest, 10, common.mustCall(() =>
1313
server.getConnections(common.mustSucceed((conns) => {
14-
assert.strictEqual(conns, 1);
14+
assert.strictEqual(conns, 2);
1515
server.close();
1616
}))
1717
))

test/parallel/test-http2-https-fallback-http-server-options.js

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ class MyServerResponse extends http.ServerResponse {
8282
assert.strictEqual(userAgent, 'node-test');
8383

8484
server.close();
85+
response.req.socket.end();
8586
}));
8687
})
8788
);

test/parallel/test-http2-https-fallback.js

+1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ function onSession(session, next) {
100100
strictEqual(alpnProtocol, false);
101101
strictEqual(httpVersion, '1.1');
102102

103+
response.req.socket.end();
103104
cleanup();
104105
}));
105106
})

test/parallel/test-https-agent-session-eviction.js

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const options = {
1919

2020
// Create TLS1.2 server
2121
https.createServer(options, function(req, res) {
22+
res.writeHead(200, { connection: 'close' });
2223
res.end('ohai');
2324
}).listen(0, function() {
2425
first(this);

test/parallel/test-https-agent-session-reuse.js

+2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ const server = https.createServer(options, function(req, res) {
9696
function request() {
9797
const options = queue.shift();
9898
options.agent = agent;
99+
options.headers = { ...options.headers, connection: 'close' };
100+
99101
https.request(options, function(res) {
100102
clientSessions[options.name] = res.socket.getSession();
101103

test/parallel/test-https-agent-sockets-leak.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ server.listen(0, common.mustCall(() => {
2727
https.get({
2828
host: server.address().host,
2929
port: server.address().port,
30-
headers: { host: 'agent1' },
30+
headers: { host: 'agent1', connection: 'close' },
3131
rejectUnauthorized: true,
3232
ca: options.ca,
3333
agent: agent

test/parallel/test-https-max-headers-count.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ server.listen(0, common.mustCall(() => {
5353
const expected = maxAndExpected[responses][1];
5454
const req = https.request({
5555
port: server.address().port,
56-
headers: headers,
56+
headers: { connection: 'close', ...headers },
5757
rejectUnauthorized: false
5858
}, (res) => {
5959
assert.strictEqual(Object.keys(res.headers).length, expected);

0 commit comments

Comments
 (0)