Skip to content

Commit 588fd0c

Browse files
committed
http, http2: flag for overriding server timeout
Make it possible to override the default http server timeout. Ideally there should be no server timeout - as done on the master branch. This is a non-breaking way to enable platform providers to override the value. Ref: #27558 Ref: #27556 PR-URL: #27704 Refs: #27558 Refs: #27556 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Myles Borins <myles.borins@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
1 parent c0cf173 commit 588fd0c

File tree

10 files changed

+90
-5
lines changed

10 files changed

+90
-5
lines changed

doc/api/cli.md

+12
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,17 @@ This flag exists to aid in experimentation with the internal implementation of
264264
the Node.js http parser.
265265
This flag is likely to become a no-op and removed at some point in the future.
266266

267+
### `--http-server-default-timeout=milliseconds`
268+
<!-- YAML
269+
added: REPLACEME
270+
-->
271+
272+
Overrides the default value of `http`, `https` and `http2` server socket
273+
timeout. Setting the value to 0 disables server socket timeout. Unless
274+
provided, http server sockets timeout after 120s (2 minutes). Programmatic
275+
setting of the timeout takes precedence over the value set through this
276+
flag.
277+
267278
### `--icu-data-dir=file`
268279
<!-- YAML
269280
added: v0.11.15
@@ -917,6 +928,7 @@ Node.js options that are allowed are:
917928
- `--force-fips`
918929
- `--frozen-intrinsics`
919930
- `--heapsnapshot-signal`
931+
- `--http-server-default-timeout`
920932
- `--icu-data-dir`
921933
- `--inspect`
922934
- `--inspect-brk`

doc/api/http.md

+7
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,9 @@ By default, the Server's timeout value is 2 minutes, and sockets are
10301030
destroyed automatically if they time out. However, if a callback is assigned
10311031
to the Server's `'timeout'` event, timeouts must be handled explicitly.
10321032

1033+
To change the default timeout use the [`--http-server-default-timeout`][]
1034+
flag.
1035+
10331036
### server.timeout
10341037
<!-- YAML
10351038
added: v0.9.12
@@ -1045,6 +1048,9 @@ A value of `0` will disable the timeout behavior on incoming connections.
10451048
The socket timeout logic is set up on connection, so changing this
10461049
value only affects new connections to the server, not any existing connections.
10471050

1051+
To change the default timeout use the [`--http-server-default-timeout`][]
1052+
flag.
1053+
10481054
### server.keepAliveTimeout
10491055
<!-- YAML
10501056
added: v8.0.0
@@ -2150,6 +2156,7 @@ will be emitted in the following order:
21502156
Note that setting the `timeout` option or using the `setTimeout()` function will
21512157
not abort the request or do anything besides add a `'timeout'` event.
21522158

2159+
[`--http-server-default-timeout`]: cli.html#cli_http_server_default_timeout_milliseconds
21532160
[`--max-http-header-size`]: cli.html#cli_max_http_header_size_size
21542161
[`'checkContinue'`]: #http_event_checkcontinue
21552162
[`'request'`]: #http_event_request

doc/api/http2.md

+7
Original file line numberDiff line numberDiff line change
@@ -1728,6 +1728,9 @@ The `'timeout'` event is emitted when there is no activity on the Server for
17281728
a given number of milliseconds set using `http2server.setTimeout()`.
17291729
**Default:** 2 minutes.
17301730

1731+
To change the default timeout use the [`--http-server-default-timeout`][]
1732+
flag.
1733+
17311734
#### server.close([callback])
17321735
<!-- YAML
17331736
added: v8.4.0
@@ -1758,6 +1761,9 @@ The given callback is registered as a listener on the `'timeout'` event.
17581761
In case of no callback function were assigned, a new `ERR_INVALID_CALLBACK`
17591762
error will be thrown.
17601763

1764+
To change the default timeout use the [`--http-server-default-timeout`][]
1765+
flag.
1766+
17611767
### Class: Http2SecureServer
17621768
<!-- YAML
17631769
added: v8.4.0
@@ -3426,6 +3432,7 @@ following additional properties:
34263432
* `type` {string} Either `'server'` or `'client'` to identify the type of
34273433
`Http2Session`.
34283434

3435+
[`--http-server-default-timeout`]: cli.html#cli_http_server_default_timeout_milliseconds
34293436
[ALPN Protocol ID]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
34303437
[ALPN negotiation]: #http2_alpn_negotiation
34313438
[Compatibility API]: #http2_compatibility_api

doc/node.1

+3
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ Chooses an HTTP parser library. Available values are
145145
or
146146
.Sy legacy .
147147
.
148+
.It Fl -http-server-default-timeout Ns = Ns Ar milliseconds
149+
Overrides the default value for server socket timeout.
150+
.
148151
.It Fl -icu-data-dir Ns = Ns Ar file
149152
Specify ICU data load path.
150153
Overrides

lib/_http_server.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,11 @@ const {
5555
DTRACE_HTTP_SERVER_REQUEST,
5656
DTRACE_HTTP_SERVER_RESPONSE
5757
} = require('internal/dtrace');
58+
const { getOptionValue } = require('internal/options');
5859

5960
const kServerResponse = Symbol('ServerResponse');
61+
const kDefaultHttpServerTimeout =
62+
getOptionValue('--http-server-default-timeout');
6063

6164
const STATUS_CODES = {
6265
100: 'Continue',
@@ -315,7 +318,7 @@ function Server(options, requestListener) {
315318

316319
this.on('connection', connectionListener);
317320

318-
this.timeout = 2 * 60 * 1000;
321+
this.timeout = kDefaultHttpServerTimeout;
319322
this.keepAliveTimeout = 5000;
320323
this.maxHeadersCount = null;
321324
this.headersTimeout = 40 * 1000; // 40 seconds

lib/https.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ const debug = require('internal/util/debuglog').debuglog('https');
3838
const { URL, urlToOptions, searchParamsSymbol } = require('internal/url');
3939
const { IncomingMessage, ServerResponse } = require('http');
4040
const { kIncomingMessage } = require('_http_common');
41+
const { getOptionValue } = require('internal/options');
42+
43+
const kDefaultHttpServerTimeout =
44+
getOptionValue('--http-server-default-timeout');
4145

4246
function Server(opts, requestListener) {
4347
if (!(this instanceof Server)) return new Server(opts, requestListener);
@@ -71,7 +75,7 @@ function Server(opts, requestListener) {
7175
conn.destroy(err);
7276
});
7377

74-
this.timeout = 2 * 60 * 1000;
78+
this.timeout = kDefaultHttpServerTimeout;
7579
this.keepAliveTimeout = 5000;
7680
this.maxHeadersCount = null;
7781
this.headersTimeout = 40 * 1000; // 40 seconds

lib/internal/http2/core.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ const { UV_EOF } = internalBinding('uv');
137137
const { StreamPipe } = internalBinding('stream_pipe');
138138
const { _connectionListener: httpConnectionListener } = http;
139139
const debug = require('internal/util/debuglog').debuglog('http2');
140+
const { getOptionValue } = require('internal/options');
140141

141142
const kMaxFrameSize = (2 ** 24) - 1;
142143
const kMaxInt = (2 ** 32) - 1;
@@ -171,7 +172,8 @@ const kState = Symbol('state');
171172
const kType = Symbol('type');
172173
const kWriteGeneric = Symbol('write-generic');
173174

174-
const kDefaultSocketTimeout = 2 * 60 * 1000;
175+
const kDefaultHttpServerTimeout =
176+
getOptionValue('--http-server-default-timeout');
175177

176178
const {
177179
paddingBuffer,
@@ -2679,7 +2681,7 @@ class Http2SecureServer extends TLSServer {
26792681
options = initializeTLSOptions(options);
26802682
super(options, connectionListener);
26812683
this[kOptions] = options;
2682-
this.timeout = kDefaultSocketTimeout;
2684+
this.timeout = kDefaultHttpServerTimeout;
26832685
this.on('newListener', setupCompat);
26842686
if (typeof requestListener === 'function')
26852687
this.on('request', requestListener);
@@ -2701,7 +2703,7 @@ class Http2Server extends NETServer {
27012703
constructor(options, requestListener) {
27022704
super(connectionListener);
27032705
this[kOptions] = initializeOptions(options);
2704-
this.timeout = kDefaultSocketTimeout;
2706+
this.timeout = kDefaultHttpServerTimeout;
27052707
this.on('newListener', setupCompat);
27062708
if (typeof requestListener === 'function')
27072709
this.on('request', requestListener);

src/node_options.cc

+5
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,11 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
308308
"(default: llhttp).",
309309
&EnvironmentOptions::http_parser,
310310
kAllowedInEnvironment);
311+
AddOption("--http-server-default-timeout",
312+
"Default http server socket timeout in ms "
313+
"(default: 120000)",
314+
&EnvironmentOptions::http_server_default_timeout,
315+
kAllowedInEnvironment);
311316
AddOption("--input-type",
312317
"set module type for string input",
313318
&EnvironmentOptions::module_type,

src/node_options.h

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ class EnvironmentOptions : public Options {
102102
bool frozen_intrinsics = false;
103103
std::string heap_snapshot_signal;
104104
std::string http_parser = "llhttp";
105+
uint64_t http_server_default_timeout = 120000;
105106
bool no_deprecation = false;
106107
bool no_force_async_hooks_checks = false;
107108
bool no_warnings = false;
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
'use strict';
2+
const common = require('../common');
3+
4+
if (!common.hasCrypto)
5+
common.skip('missing crypto');
6+
7+
const fixtures = require('../common/fixtures');
8+
const http = require('http');
9+
const https = require('https');
10+
const http2 = require('http2');
11+
const assert = require('assert');
12+
const { spawnSync } = require('child_process');
13+
14+
// Make sure the defaults are correct.
15+
const servers = [
16+
http.createServer(),
17+
https.createServer({
18+
key: fixtures.readKey('agent1-key.pem'),
19+
cert: fixtures.readKey('agent1-cert.pem')
20+
}),
21+
http2.createServer()
22+
];
23+
24+
for (const server of servers) {
25+
assert.strictEqual(server.timeout, 120000);
26+
server.close();
27+
}
28+
29+
// Ensure that command line flag overrides the default timeout.
30+
const child1 = spawnSync(process.execPath, ['--http-server-default-timeout=10',
31+
'-p', 'http.createServer().timeout'
32+
]);
33+
assert.strictEqual(+child1.stdout.toString().trim(), 10);
34+
35+
// Ensure that the flag is whitelisted for NODE_OPTIONS.
36+
const env = Object.assign({}, process.env, {
37+
NODE_OPTIONS: '--http-server-default-timeout=10'
38+
});
39+
const child2 = spawnSync(process.execPath,
40+
[ '-p', 'http.createServer().timeout'], { env });
41+
assert.strictEqual(+child2.stdout.toString().trim(), 10);

0 commit comments

Comments
 (0)