Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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';
}
```

### DEP0202: `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
[DEP0202][].
* `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
[DEP0202][].
* `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
[DEP0202]: deprecations.md#dep0202-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