Skip to content

Commit 5cdcba1

Browse files
amyssnippetaduh95
authored andcommitted
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 6cda3d3 commit 5cdcba1

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
@@ -4335,6 +4335,42 @@ Passing the `type` option to [`Duplex.toWeb()`][] is deprecated. To specify the
43354335
type of the readable half of the constructed readable-writable pair, use the
43364336
`readableType` option instead.
43374337
4338+
### DEP0202: `Http1IncomingMessage` and `Http1ServerResponse` options of HTTP/2 servers
4339+
4340+
<!-- YAML
4341+
changes:
4342+
- version: REPLACEME
4343+
pr-url: https://github.com/nodejs/node/pull/61713
4344+
description: Documentation-only deprecation.
4345+
-->
4346+
4347+
Type: Documentation-only
4348+
4349+
The `Http1IncomingMessage` and `Http1ServerResponse` options of
4350+
[`http2.createServer()`][] and [`http2.createSecureServer()`][] are
4351+
deprecated. Use `http1Options.IncomingMessage` and
4352+
`http1Options.ServerResponse` instead.
4353+
4354+
```cjs
4355+
// Deprecated
4356+
const server = http2.createSecureServer({
4357+
allowHTTP1: true,
4358+
Http1IncomingMessage: MyIncomingMessage,
4359+
Http1ServerResponse: MyServerResponse,
4360+
});
4361+
```
4362+
4363+
```cjs
4364+
// Use this instead
4365+
const server = http2.createSecureServer({
4366+
allowHTTP1: true,
4367+
http1Options: {
4368+
IncomingMessage: MyIncomingMessage,
4369+
ServerResponse: MyServerResponse,
4370+
},
4371+
});
4372+
```
4373+
43384374
[DEP0142]: #dep0142-repl_builtinlibs
43394375
[NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
43404376
[RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3
@@ -4416,6 +4452,8 @@ type of the readable half of the constructed readable-writable pair, use the
44164452
[`http.ServerResponse`]: http.md#class-httpserverresponse
44174453
[`http.get()`]: http.md#httpgetoptions-callback
44184454
[`http.request()`]: http.md#httprequestoptions-callback
4455+
[`http2.createSecureServer()`]: http2.md#http2createsecureserveroptions-onrequesthandler
4456+
[`http2.createServer()`]: http2.md#http2createserveroptions-onrequesthandler
44194457
[`https.get()`]: https.md#httpsgetoptions-callback
44204458
[`https.request()`]: https.md#httpsrequestoptions-callback
44214459
[`message.connection`]: http.md#messageconnection

doc/api/http2.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2786,6 +2786,10 @@ Throws `ERR_INVALID_ARG_TYPE` for invalid `settings` argument.
27862786
<!-- YAML
27872787
added: v8.4.0
27882788
changes:
2789+
- version: REPLACEME
2790+
pr-url: https://github.com/nodejs/node/pull/61713
2791+
description: Added `http1Options` option. The `Http1IncomingMessage`
2792+
and `Http1ServerResponse` options are now deprecated.
27892793
- version:
27902794
- v23.0.0
27912795
- v22.10.0
@@ -2904,9 +2908,27 @@ changes:
29042908
* `Http1IncomingMessage` {http.IncomingMessage} Specifies the
29052909
`IncomingMessage` class to used for HTTP/1 fallback. Useful for extending
29062910
the original `http.IncomingMessage`. **Default:** `http.IncomingMessage`.
2911+
**Deprecated.** Use `http1Options.IncomingMessage` instead. See
2912+
[DEP0202][].
29072913
* `Http1ServerResponse` {http.ServerResponse} Specifies the `ServerResponse`
29082914
class to used for HTTP/1 fallback. Useful for extending the original
29092915
`http.ServerResponse`. **Default:** `http.ServerResponse`.
2916+
**Deprecated.** Use `http1Options.ServerResponse` instead. See
2917+
[DEP0202][].
2918+
* `http1Options` {Object} An options object for configuring the HTTP/1
2919+
fallback when `allowHTTP1` is `true`. These options are passed to the
2920+
underlying HTTP/1 server. See [`http.createServer()`][] for available
2921+
options. Among others, the following are supported:
2922+
* `IncomingMessage` {http.IncomingMessage} Specifies the
2923+
`IncomingMessage` class to use for HTTP/1 fallback.
2924+
**Default:** `http.IncomingMessage`.
2925+
* `ServerResponse` {http.ServerResponse} Specifies the `ServerResponse`
2926+
class to use for HTTP/1 fallback.
2927+
**Default:** `http.ServerResponse`.
2928+
* `keepAliveTimeout` {number} The number of milliseconds of inactivity
2929+
a server needs to wait for additional incoming data, after it has
2930+
finished writing the last response, before a socket will be destroyed.
2931+
**Default:** `5000`.
29102932
* `Http2ServerRequest` {http2.Http2ServerRequest} Specifies the
29112933
`Http2ServerRequest` class to use.
29122934
Useful for extending the original `Http2ServerRequest`.
@@ -2980,6 +3002,9 @@ server.listen(8000);
29803002
<!-- YAML
29813003
added: v8.4.0
29823004
changes:
3005+
- version: REPLACEME
3006+
pr-url: https://github.com/nodejs/node/pull/61713
3007+
description: Added `http1Options` option.
29833008
- version:
29843009
- v15.10.0
29853010
- v14.16.0
@@ -3098,6 +3123,20 @@ changes:
30983123
and trailing whitespace validation for HTTP/2 header field names and values
30993124
as per [RFC-9113](https://www.rfc-editor.org/rfc/rfc9113.html#section-8.2.1).
31003125
**Default:** `true`.
3126+
* `http1Options` {Object} An options object for configuring the HTTP/1
3127+
fallback when `allowHTTP1` is `true`. These options are passed to the
3128+
underlying HTTP/1 server. See [`http.createServer()`][] for available
3129+
options. Among others, the following are supported:
3130+
* `IncomingMessage` {http.IncomingMessage} Specifies the
3131+
`IncomingMessage` class to use for HTTP/1 fallback.
3132+
**Default:** `http.IncomingMessage`.
3133+
* `ServerResponse` {http.ServerResponse} Specifies the `ServerResponse`
3134+
class to use for HTTP/1 fallback.
3135+
**Default:** `http.ServerResponse`.
3136+
* `keepAliveTimeout` {number} The number of milliseconds of inactivity
3137+
a server needs to wait for additional incoming data, after it has
3138+
finished writing the last response, before a socket will be destroyed.
3139+
**Default:** `5000`.
31013140
* `onRequestHandler` {Function} See [Compatibility API][]
31023141
* Returns: {Http2SecureServer}
31033142

@@ -4927,6 +4966,7 @@ you need to implement any fall-back behavior yourself.
49274966
[ALPN Protocol ID]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
49284967
[ALPN negotiation]: #alpn-negotiation
49294968
[Compatibility API]: #compatibility-api
4969+
[DEP0202]: deprecations.md#dep0202-http1incomingmessage-and-http1serverresponse-options-of-http2-servers
49304970
[HTTP/1]: http.md
49314971
[HTTP/2]: https://tools.ietf.org/html/rfc7540
49324972
[HTTP/2 Headers Object]: #headers-object
@@ -4953,6 +4993,7 @@ you need to implement any fall-back behavior yourself.
49534993
[`Http2Stream`]: #class-http2stream
49544994
[`ServerHttp2Stream`]: #class-serverhttp2stream
49554995
[`TypeError`]: errors.md#class-typeerror
4996+
[`http.createServer()`]: http.md#httpcreateserveroptions-requestlistener
49564997
[`http2.SecureServer`]: #class-http2secureserver
49574998
[`http2.Server`]: #class-http2server
49584999
[`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)