Skip to content

Commit 8df6332

Browse files
authored
http2: add http1Options for HTTP/1 fallback configuration
PR-URL: #61713 Fixes: #59783 Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Tim Perry <pimterry@gmail.com>
1 parent ad945c5 commit 8df6332

File tree

4 files changed

+107
-12
lines changed

4 files changed

+107
-12
lines changed

doc/api/deprecations.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4430,6 +4430,42 @@ Passing the `type` option to [`Duplex.toWeb()`][] is deprecated. To specify the
44304430
type of the readable half of the constructed readable-writable pair, use the
44314431
`readableType` option instead.
44324432
4433+
### DEP0202: `Http1IncomingMessage` and `Http1ServerResponse` options of HTTP/2 servers
4434+
4435+
<!-- YAML
4436+
changes:
4437+
- version: REPLACEME
4438+
pr-url: https://github.com/nodejs/node/pull/61713
4439+
description: Documentation-only deprecation.
4440+
-->
4441+
4442+
Type: Documentation-only
4443+
4444+
The `Http1IncomingMessage` and `Http1ServerResponse` options of
4445+
[`http2.createServer()`][] and [`http2.createSecureServer()`][] are
4446+
deprecated. Use `http1Options.IncomingMessage` and
4447+
`http1Options.ServerResponse` instead.
4448+
4449+
```cjs
4450+
// Deprecated
4451+
const server = http2.createSecureServer({
4452+
allowHTTP1: true,
4453+
Http1IncomingMessage: MyIncomingMessage,
4454+
Http1ServerResponse: MyServerResponse,
4455+
});
4456+
```
4457+
4458+
```cjs
4459+
// Use this instead
4460+
const server = http2.createSecureServer({
4461+
allowHTTP1: true,
4462+
http1Options: {
4463+
IncomingMessage: MyIncomingMessage,
4464+
ServerResponse: MyServerResponse,
4465+
},
4466+
});
4467+
```
4468+
44334469
[DEP0142]: #dep0142-repl_builtinlibs
44344470
[NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
44354471
[RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3
@@ -4509,6 +4545,8 @@ type of the readable half of the constructed readable-writable pair, use the
45094545
[`http.ServerResponse`]: http.md#class-httpserverresponse
45104546
[`http.get()`]: http.md#httpgetoptions-callback
45114547
[`http.request()`]: http.md#httprequestoptions-callback
4548+
[`http2.createSecureServer()`]: http2.md#http2createsecureserveroptions-onrequesthandler
4549+
[`http2.createServer()`]: http2.md#http2createserveroptions-onrequesthandler
45124550
[`https.get()`]: https.md#httpsgetoptions-callback
45134551
[`https.request()`]: https.md#httpsrequestoptions-callback
45144552
[`message.connection`]: http.md#messageconnection

doc/api/http2.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2796,6 +2796,10 @@ Throws `ERR_INVALID_ARG_TYPE` for invalid `settings` argument.
27962796
<!-- YAML
27972797
added: v8.4.0
27982798
changes:
2799+
- version: REPLACEME
2800+
pr-url: https://github.com/nodejs/node/pull/61713
2801+
description: Added `http1Options` option. The `Http1IncomingMessage`
2802+
and `Http1ServerResponse` options are now deprecated.
27992803
- version:
28002804
- v23.0.0
28012805
- v22.10.0
@@ -2914,9 +2918,27 @@ changes:
29142918
* `Http1IncomingMessage` {http.IncomingMessage} Specifies the
29152919
`IncomingMessage` class to used for HTTP/1 fallback. Useful for extending
29162920
the original `http.IncomingMessage`. **Default:** `http.IncomingMessage`.
2921+
**Deprecated.** Use `http1Options.IncomingMessage` instead. See
2922+
[DEP0202][].
29172923
* `Http1ServerResponse` {http.ServerResponse} Specifies the `ServerResponse`
29182924
class to used for HTTP/1 fallback. Useful for extending the original
29192925
`http.ServerResponse`. **Default:** `http.ServerResponse`.
2926+
**Deprecated.** Use `http1Options.ServerResponse` instead. See
2927+
[DEP0202][].
2928+
* `http1Options` {Object} An options object for configuring the HTTP/1
2929+
fallback when `allowHTTP1` is `true`. These options are passed to the
2930+
underlying HTTP/1 server. See [`http.createServer()`][] for available
2931+
options. Among others, the following are supported:
2932+
* `IncomingMessage` {http.IncomingMessage} Specifies the
2933+
`IncomingMessage` class to use for HTTP/1 fallback.
2934+
**Default:** `http.IncomingMessage`.
2935+
* `ServerResponse` {http.ServerResponse} Specifies the `ServerResponse`
2936+
class to use for HTTP/1 fallback.
2937+
**Default:** `http.ServerResponse`.
2938+
* `keepAliveTimeout` {number} The number of milliseconds of inactivity
2939+
a server needs to wait for additional incoming data, after it has
2940+
finished writing the last response, before a socket will be destroyed.
2941+
**Default:** `5000`.
29202942
* `Http2ServerRequest` {http2.Http2ServerRequest} Specifies the
29212943
`Http2ServerRequest` class to use.
29222944
Useful for extending the original `Http2ServerRequest`.
@@ -2990,6 +3012,9 @@ server.listen(8000);
29903012
<!-- YAML
29913013
added: v8.4.0
29923014
changes:
3015+
- version: REPLACEME
3016+
pr-url: https://github.com/nodejs/node/pull/61713
3017+
description: Added `http1Options` option.
29933018
- version:
29943019
- v15.10.0
29953020
- v14.16.0
@@ -3108,6 +3133,20 @@ changes:
31083133
and trailing whitespace validation for HTTP/2 header field names and values
31093134
as per [RFC-9113](https://www.rfc-editor.org/rfc/rfc9113.html#section-8.2.1).
31103135
**Default:** `true`.
3136+
* `http1Options` {Object} An options object for configuring the HTTP/1
3137+
fallback when `allowHTTP1` is `true`. These options are passed to the
3138+
underlying HTTP/1 server. See [`http.createServer()`][] for available
3139+
options. Among others, the following are supported:
3140+
* `IncomingMessage` {http.IncomingMessage} Specifies the
3141+
`IncomingMessage` class to use for HTTP/1 fallback.
3142+
**Default:** `http.IncomingMessage`.
3143+
* `ServerResponse` {http.ServerResponse} Specifies the `ServerResponse`
3144+
class to use for HTTP/1 fallback.
3145+
**Default:** `http.ServerResponse`.
3146+
* `keepAliveTimeout` {number} The number of milliseconds of inactivity
3147+
a server needs to wait for additional incoming data, after it has
3148+
finished writing the last response, before a socket will be destroyed.
3149+
**Default:** `5000`.
31113150
* `onRequestHandler` {Function} See [Compatibility API][]
31123151
* Returns: {Http2SecureServer}
31133152

@@ -4937,6 +4976,7 @@ you need to implement any fall-back behavior yourself.
49374976
[ALPN Protocol ID]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
49384977
[ALPN negotiation]: #alpn-negotiation
49394978
[Compatibility API]: #compatibility-api
4979+
[DEP0202]: deprecations.md#dep0202-http1incomingmessage-and-http1serverresponse-options-of-http2-servers
49404980
[HTTP/1]: http.md
49414981
[HTTP/2]: https://tools.ietf.org/html/rfc7540
49424982
[HTTP/2 Headers Object]: #headers-object
@@ -4963,6 +5003,7 @@ you need to implement any fall-back behavior yourself.
49635003
[`Http2Stream`]: #class-http2stream
49645004
[`ServerHttp2Stream`]: #class-serverhttp2stream
49655005
[`TypeError`]: errors.md#class-typeerror
5006+
[`http.createServer()`]: http.md#httpcreateserveroptions-requestlistener
49665007
[`http2.SecureServer`]: #class-http2secureserver
49675008
[`http2.Server`]: #class-http2server
49685009
[`http2.createSecureServer()`]: #http2createsecureserveroptions-onrequesthandler

lib/internal/http2/core.js

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,12 @@ const { Duplex } = require('stream');
4848
const tls = require('tls');
4949
const { setImmediate, setTimeout, clearTimeout } = require('timers');
5050

51-
const { kIncomingMessage } = require('_http_common');
52-
const { kServerResponse, Server: HttpServer, httpServerPreClose, setupConnectionsTracking } = require('_http_server');
51+
const {
52+
Server: HttpServer,
53+
httpServerPreClose,
54+
setupConnectionsTracking,
55+
storeHTTPOptions,
56+
} = require('_http_server');
5357
const JSStreamSocket = require('internal/js_stream_socket');
5458

5559
const {
@@ -3257,8 +3261,6 @@ function connectionListener(socket) {
32573261
if (socket.alpnProtocol === false || socket.alpnProtocol === 'http/1.1') {
32583262
// Fallback to HTTP/1.1
32593263
if (options.allowHTTP1 === true) {
3260-
socket.server[kIncomingMessage] = options.Http1IncomingMessage;
3261-
socket.server[kServerResponse] = options.Http1ServerResponse;
32623264
return httpConnectionListener.call(this, socket);
32633265
}
32643266
// Let event handler deal with the socket
@@ -3340,9 +3342,18 @@ function initializeOptions(options) {
33403342
options.unknownProtocolTimeout = 10000;
33413343

33423344

3343-
// Used only with allowHTTP1
3344-
options.Http1IncomingMessage ||= http.IncomingMessage;
3345-
options.Http1ServerResponse ||= http.ServerResponse;
3345+
// Initialize http1Options bag for HTTP/1 fallback when allowHTTP1 is true.
3346+
// This bag is passed to storeHTTPOptions() to configure HTTP/1 server
3347+
// behavior (timeouts, IncomingMessage/ServerResponse classes, etc.).
3348+
options.http1Options = { ...options.http1Options };
3349+
3350+
// Backward compat: migrate deprecated top-level Http1 options (DEP0201)
3351+
if (options.Http1IncomingMessage !== undefined) {
3352+
options.http1Options.IncomingMessage ??= options.Http1IncomingMessage;
3353+
}
3354+
if (options.Http1ServerResponse !== undefined) {
3355+
options.http1Options.ServerResponse ??= options.Http1ServerResponse;
3356+
}
33463357

33473358
options.Http2ServerRequest ||= Http2ServerRequest;
33483359
options.Http2ServerResponse ||= Http2ServerResponse;
@@ -3390,9 +3401,7 @@ class Http2SecureServer extends TLSServer {
33903401
this.timeout = 0;
33913402
this.on('newListener', setupCompat);
33923403
if (options.allowHTTP1 === true) {
3393-
this.headersTimeout = 60_000; // Minimum between 60 seconds or requestTimeout
3394-
this.requestTimeout = 300_000; // 5 minutes
3395-
this.connectionsCheckingInterval = 30_000; // 30 seconds
3404+
storeHTTPOptions.call(this, { ...options, ...options.http1Options });
33963405
this.shouldUpgradeCallback = function() {
33973406
return this.listenerCount('upgrade') > 0;
33983407
};

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ const ca = fixtures.readKey('fake-startcom-root-cert.pem');
2020
function onRequest(request, response) {
2121
const { socket: { alpnProtocol } } = request.httpVersion === '2.0' ?
2222
request.stream.session : request;
23+
// Verify that http1Options are applied when allowHTTP1 is true
24+
if (request.httpVersion === '1.1') {
25+
assert.strictEqual(request.socket.server.keepAliveTimeout, 10000);
26+
}
2327
response.status(200);
2428
response.end(JSON.stringify({
2529
alpnProtocol,
@@ -46,8 +50,11 @@ class MyServerResponse extends http.ServerResponse {
4650
{
4751
cert,
4852
key, allowHTTP1: true,
49-
Http1IncomingMessage: MyIncomingMessage,
50-
Http1ServerResponse: MyServerResponse
53+
http1Options: {
54+
IncomingMessage: MyIncomingMessage,
55+
ServerResponse: MyServerResponse,
56+
keepAliveTimeout: 10000,
57+
},
5158
},
5259
common.mustCall(onRequest, 1)
5360
);

0 commit comments

Comments
 (0)