Skip to content

Commit b0a79b1

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 f14ff14 commit b0a79b1

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
@@ -4415,6 +4415,42 @@ Passing the `type` option to [`Duplex.toWeb()`][] is deprecated. To specify the
44154415
type of the readable half of the constructed readable-writable pair, use the
44164416
`readableType` option instead.
44174417
4418+
### DEP0202: `Http1IncomingMessage` and `Http1ServerResponse` options of HTTP/2 servers
4419+
4420+
<!-- YAML
4421+
changes:
4422+
- version: REPLACEME
4423+
pr-url: https://github.com/nodejs/node/pull/61713
4424+
description: Documentation-only deprecation.
4425+
-->
4426+
4427+
Type: Documentation-only
4428+
4429+
The `Http1IncomingMessage` and `Http1ServerResponse` options of
4430+
[`http2.createServer()`][] and [`http2.createSecureServer()`][] are
4431+
deprecated. Use `http1Options.IncomingMessage` and
4432+
`http1Options.ServerResponse` instead.
4433+
4434+
```cjs
4435+
// Deprecated
4436+
const server = http2.createSecureServer({
4437+
allowHTTP1: true,
4438+
Http1IncomingMessage: MyIncomingMessage,
4439+
Http1ServerResponse: MyServerResponse,
4440+
});
4441+
```
4442+
4443+
```cjs
4444+
// Use this instead
4445+
const server = http2.createSecureServer({
4446+
allowHTTP1: true,
4447+
http1Options: {
4448+
IncomingMessage: MyIncomingMessage,
4449+
ServerResponse: MyServerResponse,
4450+
},
4451+
});
4452+
```
4453+
44184454
[DEP0142]: #dep0142-repl_builtinlibs
44194455
[NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
44204456
[RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3
@@ -4494,6 +4530,8 @@ type of the readable half of the constructed readable-writable pair, use the
44944530
[`http.ServerResponse`]: http.md#class-httpserverresponse
44954531
[`http.get()`]: http.md#httpgetoptions-callback
44964532
[`http.request()`]: http.md#httprequestoptions-callback
4533+
[`http2.createSecureServer()`]: http2.md#http2createsecureserveroptions-onrequesthandler
4534+
[`http2.createServer()`]: http2.md#http2createserveroptions-onrequesthandler
44974535
[`https.get()`]: https.md#httpsgetoptions-callback
44984536
[`https.request()`]: https.md#httpsrequestoptions-callback
44994537
[`message.connection`]: http.md#messageconnection

doc/api/http2.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2793,6 +2793,10 @@ Throws `ERR_INVALID_ARG_TYPE` for invalid `settings` argument.
27932793
<!-- YAML
27942794
added: v8.4.0
27952795
changes:
2796+
- version: REPLACEME
2797+
pr-url: https://github.com/nodejs/node/pull/61713
2798+
description: Added `http1Options` option. The `Http1IncomingMessage`
2799+
and `Http1ServerResponse` options are now deprecated.
27962800
- version:
27972801
- v23.0.0
27982802
- v22.10.0
@@ -2911,9 +2915,27 @@ changes:
29112915
* `Http1IncomingMessage` {http.IncomingMessage} Specifies the
29122916
`IncomingMessage` class to used for HTTP/1 fallback. Useful for extending
29132917
the original `http.IncomingMessage`. **Default:** `http.IncomingMessage`.
2918+
**Deprecated.** Use `http1Options.IncomingMessage` instead. See
2919+
[DEP0202][].
29142920
* `Http1ServerResponse` {http.ServerResponse} Specifies the `ServerResponse`
29152921
class to used for HTTP/1 fallback. Useful for extending the original
29162922
`http.ServerResponse`. **Default:** `http.ServerResponse`.
2923+
**Deprecated.** Use `http1Options.ServerResponse` instead. See
2924+
[DEP0202][].
2925+
* `http1Options` {Object} An options object for configuring the HTTP/1
2926+
fallback when `allowHTTP1` is `true`. These options are passed to the
2927+
underlying HTTP/1 server. See [`http.createServer()`][] for available
2928+
options. Among others, the following are supported:
2929+
* `IncomingMessage` {http.IncomingMessage} Specifies the
2930+
`IncomingMessage` class to use for HTTP/1 fallback.
2931+
**Default:** `http.IncomingMessage`.
2932+
* `ServerResponse` {http.ServerResponse} Specifies the `ServerResponse`
2933+
class to use for HTTP/1 fallback.
2934+
**Default:** `http.ServerResponse`.
2935+
* `keepAliveTimeout` {number} The number of milliseconds of inactivity
2936+
a server needs to wait for additional incoming data, after it has
2937+
finished writing the last response, before a socket will be destroyed.
2938+
**Default:** `5000`.
29172939
* `Http2ServerRequest` {http2.Http2ServerRequest} Specifies the
29182940
`Http2ServerRequest` class to use.
29192941
Useful for extending the original `Http2ServerRequest`.
@@ -2987,6 +3009,9 @@ server.listen(8000);
29873009
<!-- YAML
29883010
added: v8.4.0
29893011
changes:
3012+
- version: REPLACEME
3013+
pr-url: https://github.com/nodejs/node/pull/61713
3014+
description: Added `http1Options` option.
29903015
- version:
29913016
- v15.10.0
29923017
- v14.16.0
@@ -3105,6 +3130,20 @@ changes:
31053130
and trailing whitespace validation for HTTP/2 header field names and values
31063131
as per [RFC-9113](https://www.rfc-editor.org/rfc/rfc9113.html#section-8.2.1).
31073132
**Default:** `true`.
3133+
* `http1Options` {Object} An options object for configuring the HTTP/1
3134+
fallback when `allowHTTP1` is `true`. These options are passed to the
3135+
underlying HTTP/1 server. See [`http.createServer()`][] for available
3136+
options. Among others, the following are supported:
3137+
* `IncomingMessage` {http.IncomingMessage} Specifies the
3138+
`IncomingMessage` class to use for HTTP/1 fallback.
3139+
**Default:** `http.IncomingMessage`.
3140+
* `ServerResponse` {http.ServerResponse} Specifies the `ServerResponse`
3141+
class to use for HTTP/1 fallback.
3142+
**Default:** `http.ServerResponse`.
3143+
* `keepAliveTimeout` {number} The number of milliseconds of inactivity
3144+
a server needs to wait for additional incoming data, after it has
3145+
finished writing the last response, before a socket will be destroyed.
3146+
**Default:** `5000`.
31083147
* `onRequestHandler` {Function} See [Compatibility API][]
31093148
* Returns: {Http2SecureServer}
31103149

@@ -4934,6 +4973,7 @@ you need to implement any fall-back behavior yourself.
49344973
[ALPN Protocol ID]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
49354974
[ALPN negotiation]: #alpn-negotiation
49364975
[Compatibility API]: #compatibility-api
4976+
[DEP0202]: deprecations.md#dep0202-http1incomingmessage-and-http1serverresponse-options-of-http2-servers
49374977
[HTTP/1]: http.md
49384978
[HTTP/2]: https://tools.ietf.org/html/rfc7540
49394979
[HTTP/2 Headers Object]: #headers-object
@@ -4960,6 +5000,7 @@ you need to implement any fall-back behavior yourself.
49605000
[`Http2Stream`]: #class-http2stream
49615001
[`ServerHttp2Stream`]: #class-serverhttp2stream
49625002
[`TypeError`]: errors.md#class-typeerror
5003+
[`http.createServer()`]: http.md#httpcreateserveroptions-requestlistener
49635004
[`http2.SecureServer`]: #class-http2secureserver
49645005
[`http2.Server`]: #class-http2server
49655006
[`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)