Skip to content
38 changes: 38 additions & 0 deletions doc/api/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -4415,6 +4415,42 @@ import { opendir } from 'node:fs/promises';
}
```

### DEP0201: `Http1IncomingMessage` and `Http1ServerResponse` options of HTTP/2 servers

<!-- YAML
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/61713
description: Documentation-only deprecation.
-->

Type: Documentation-only

The `Http1IncomingMessage` and `Http1ServerResponse` options of
[`http2.createServer()`][] and [`http2.createSecureServer()`][] are
deprecated. Use `http1Options.IncomingMessage` and
`http1Options.ServerResponse` instead.

```cjs
// Deprecated
const server = http2.createSecureServer({
allowHTTP1: true,
Http1IncomingMessage: MyIncomingMessage,
Http1ServerResponse: MyServerResponse,
});
```

```cjs
// Use this instead
const server = http2.createSecureServer({
allowHTTP1: true,
http1Options: {
IncomingMessage: MyIncomingMessage,
ServerResponse: MyServerResponse,
},
});
```

[DEP0142]: #dep0142-repl_builtinlibs
[NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
[RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3
Expand Down Expand Up @@ -4493,6 +4529,8 @@ import { opendir } from 'node:fs/promises';
[`http.ServerResponse`]: http.md#class-httpserverresponse
[`http.get()`]: http.md#httpgetoptions-callback
[`http.request()`]: http.md#httprequestoptions-callback
[`http2.createSecureServer()`]: http2.md#http2createsecureserveroptions-onrequesthandler
[`http2.createServer()`]: http2.md#http2createserveroptions-onrequesthandler
[`https.get()`]: https.md#httpsgetoptions-callback
[`https.request()`]: https.md#httpsrequestoptions-callback
[`message.connection`]: http.md#messageconnection
Expand Down
41 changes: 41 additions & 0 deletions doc/api/http2.md
Original file line number Diff line number Diff line change
Expand Up @@ -2796,6 +2796,10 @@ Throws `ERR_INVALID_ARG_TYPE` for invalid `settings` argument.
<!-- YAML
added: v8.4.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/61713
description: Added `http1Options` option. The `Http1IncomingMessage`
and `Http1ServerResponse` options are now deprecated.
- version:
- v23.0.0
- v22.10.0
Expand Down Expand Up @@ -2914,9 +2918,27 @@ changes:
* `Http1IncomingMessage` {http.IncomingMessage} Specifies the
`IncomingMessage` class to used for HTTP/1 fallback. Useful for extending
the original `http.IncomingMessage`. **Default:** `http.IncomingMessage`.
**Deprecated.** Use `http1Options.IncomingMessage` instead. See
[DEP0201][].
* `Http1ServerResponse` {http.ServerResponse} Specifies the `ServerResponse`
class to used for HTTP/1 fallback. Useful for extending the original
`http.ServerResponse`. **Default:** `http.ServerResponse`.
**Deprecated.** Use `http1Options.ServerResponse` instead. See
[DEP0201][].
* `http1Options` {Object} An options object for configuring the HTTP/1
fallback when `allowHTTP1` is `true`. These options are passed to the
underlying HTTP/1 server. See [`http.createServer()`][] for available
options. Among others, the following are supported:
* `IncomingMessage` {http.IncomingMessage} Specifies the
`IncomingMessage` class to use for HTTP/1 fallback.
**Default:** `http.IncomingMessage`.
* `ServerResponse` {http.ServerResponse} Specifies the `ServerResponse`
class to use for HTTP/1 fallback.
**Default:** `http.ServerResponse`.
* `keepAliveTimeout` {number} The number of milliseconds of inactivity
a server needs to wait for additional incoming data, after it has
finished writing the last response, before a socket will be destroyed.
**Default:** `5000`.
* `Http2ServerRequest` {http2.Http2ServerRequest} Specifies the
`Http2ServerRequest` class to use.
Useful for extending the original `Http2ServerRequest`.
Expand Down Expand Up @@ -2990,6 +3012,9 @@ server.listen(8000);
<!-- YAML
added: v8.4.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/61713
description: Added `http1Options` option.
- version:
- v15.10.0
- v14.16.0
Expand Down Expand Up @@ -3108,6 +3133,20 @@ changes:
and trailing whitespace validation for HTTP/2 header field names and values
as per [RFC-9113](https://www.rfc-editor.org/rfc/rfc9113.html#section-8.2.1).
**Default:** `true`.
* `http1Options` {Object} An options object for configuring the HTTP/1
fallback when `allowHTTP1` is `true`. These options are passed to the
underlying HTTP/1 server. See [`http.createServer()`][] for available
options. Among others, the following are supported:
* `IncomingMessage` {http.IncomingMessage} Specifies the
`IncomingMessage` class to use for HTTP/1 fallback.
**Default:** `http.IncomingMessage`.
* `ServerResponse` {http.ServerResponse} Specifies the `ServerResponse`
class to use for HTTP/1 fallback.
**Default:** `http.ServerResponse`.
* `keepAliveTimeout` {number} The number of milliseconds of inactivity
a server needs to wait for additional incoming data, after it has
finished writing the last response, before a socket will be destroyed.
**Default:** `5000`.
* `onRequestHandler` {Function} See [Compatibility API][]
* Returns: {Http2SecureServer}

Expand Down Expand Up @@ -4937,6 +4976,7 @@ you need to implement any fall-back behavior yourself.
[ALPN Protocol ID]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
[ALPN negotiation]: #alpn-negotiation
[Compatibility API]: #compatibility-api
[DEP0201]: deprecations.md#dep0201-http1incomingmessage-and-http1serverresponse-options-of-http2-servers
[HTTP/1]: http.md
[HTTP/2]: https://tools.ietf.org/html/rfc7540
[HTTP/2 Headers Object]: #headers-object
Expand All @@ -4963,6 +5003,7 @@ you need to implement any fall-back behavior yourself.
[`Http2Stream`]: #class-http2stream
[`ServerHttp2Stream`]: #class-serverhttp2stream
[`TypeError`]: errors.md#class-typeerror
[`http.createServer()`]: http.md#httpcreateserveroptions-requestlistener
[`http2.SecureServer`]: #class-http2secureserver
[`http2.Server`]: #class-http2server
[`http2.createSecureServer()`]: #http2createsecureserveroptions-onrequesthandler
Expand Down
29 changes: 19 additions & 10 deletions lib/internal/http2/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,12 @@ const { Duplex } = require('stream');
const tls = require('tls');
const { setImmediate, setTimeout, clearTimeout } = require('timers');

const { kIncomingMessage } = require('_http_common');
const { kServerResponse, Server: HttpServer, httpServerPreClose, setupConnectionsTracking } = require('_http_server');
const {
Server: HttpServer,
httpServerPreClose,
setupConnectionsTracking,
storeHTTPOptions,
} = require('_http_server');
const JSStreamSocket = require('internal/js_stream_socket');

const {
Expand Down Expand Up @@ -3253,8 +3257,6 @@ function connectionListener(socket) {
if (socket.alpnProtocol === false || socket.alpnProtocol === 'http/1.1') {
// Fallback to HTTP/1.1
if (options.allowHTTP1 === true) {
socket.server[kIncomingMessage] = options.Http1IncomingMessage;
socket.server[kServerResponse] = options.Http1ServerResponse;
return httpConnectionListener.call(this, socket);
}
// Let event handler deal with the socket
Expand Down Expand Up @@ -3336,9 +3338,18 @@ function initializeOptions(options) {
options.unknownProtocolTimeout = 10000;


// Used only with allowHTTP1
options.Http1IncomingMessage ||= http.IncomingMessage;
options.Http1ServerResponse ||= http.ServerResponse;
// Initialize http1Options bag for HTTP/1 fallback when allowHTTP1 is true.
// This bag is passed to storeHTTPOptions() to configure HTTP/1 server
// behavior (timeouts, IncomingMessage/ServerResponse classes, etc.).
options.http1Options = { ...options.http1Options };

// Backward compat: migrate deprecated top-level Http1 options (DEP0201)
if (options.Http1IncomingMessage !== undefined) {
options.http1Options.IncomingMessage ??= options.Http1IncomingMessage;
}
if (options.Http1ServerResponse !== undefined) {
options.http1Options.ServerResponse ??= options.Http1ServerResponse;
}

options.Http2ServerRequest ||= Http2ServerRequest;
options.Http2ServerResponse ||= Http2ServerResponse;
Expand Down Expand Up @@ -3386,9 +3397,7 @@ class Http2SecureServer extends TLSServer {
this.timeout = 0;
this.on('newListener', setupCompat);
if (options.allowHTTP1 === true) {
this.headersTimeout = 60_000; // Minimum between 60 seconds or requestTimeout
this.requestTimeout = 300_000; // 5 minutes
this.connectionsCheckingInterval = 30_000; // 30 seconds
storeHTTPOptions.call(this, { ...options, ...options.http1Options });
this.shouldUpgradeCallback = function() {
return this.listenerCount('upgrade') > 0;
};
Expand Down
11 changes: 9 additions & 2 deletions test/parallel/test-http2-https-fallback-http-server-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ const ca = fixtures.readKey('fake-startcom-root-cert.pem');
function onRequest(request, response) {
const { socket: { alpnProtocol } } = request.httpVersion === '2.0' ?
request.stream.session : request;
// Verify that http1Options are applied when allowHTTP1 is true
if (request.httpVersion === '1.1') {
assert.strictEqual(request.socket.server.keepAliveTimeout, 10000);
}
response.status(200);
response.end(JSON.stringify({
alpnProtocol,
Expand All @@ -46,8 +50,11 @@ class MyServerResponse extends http.ServerResponse {
{
cert,
key, allowHTTP1: true,
Http1IncomingMessage: MyIncomingMessage,
Http1ServerResponse: MyServerResponse
http1Options: {
IncomingMessage: MyIncomingMessage,
ServerResponse: MyServerResponse,
keepAliveTimeout: 10000,
},
},
common.mustCall(onRequest, 1)
);
Expand Down
Loading