Skip to content

deps: update undici to 7.1.0 #56179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 10, 2024
Merged
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
2 changes: 2 additions & 0 deletions deps/undici/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,8 @@ and `undici.Agent`) which will enable the family autoselection algorithm when es
* [__Matthew Aitken__](https://github.com/KhafraDev), <https://www.npmjs.com/~khaf>
* [__Robert Nagy__](https://github.com/ronag), <https://www.npmjs.com/~ronag>
* [__Szymon Marczak__](https://github.com/szmarczak), <https://www.npmjs.com/~szmarczak>

## Past Collaborators
* [__Tomas Della Vedova__](https://github.com/delvedor), <https://www.npmjs.com/~delvedor>

### Releasers
Expand Down
13 changes: 11 additions & 2 deletions deps/undici/src/docs/docs/api/Client.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ Returns: `Client`

### Parameter: `ClientOptions`

> ⚠️ Warning: The `H2` support is experimental.

* **bodyTimeout** `number | null` (optional) - Default: `300e3` - The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Defaults to 300 seconds. Please note the `timeout` will be reset if you keep writing data to the socket everytime.
* **headersTimeout** `number | null` (optional) - Default: `300e3` - The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers while not sending the request. Defaults to 300 seconds.
* **keepAliveMaxTimeout** `number | null` (optional) - Default: `600e3` - The maximum allowed `keepAliveTimeout`, in milliseconds, when overridden by *keep-alive* hints from the server. Defaults to 10 minutes.
Expand All @@ -34,6 +32,17 @@ Returns: `Client`
* **allowH2**: `boolean` - Default: `false`. Enables support for H2 if the server has assigned bigger priority to it through ALPN negotiation.
* **maxConcurrentStreams**: `number` - Default: `100`. Dictates the maximum number of concurrent streams for a single H2 session. It can be overridden by a SETTINGS remote frame.

> **Notes about HTTP/2**
> - It only works under TLS connections. h2c is not supported.
> - The server must support HTTP/2 and choose it as the protocol during the ALPN negotiation.
> - The server must not have a bigger priority for HTTP/1.1 than HTTP/2.
> - Pseudo headers are automatically attached to the request. If you try to set them, they will be overwritten.
> - The `:path` header is automatically set to the request path.
> - The `:method` header is automatically set to the request method.
> - The `:scheme` header is automatically set to the request scheme.
> - The `:authority` header is automatically set to the request `host[:port]`.
> - `PUSH` frames are yet not supported.

#### Parameter: `ConnectOptions`

Every Tls option, see [here](https://nodejs.org/api/tls.html#tls_tls_connect_options_callback).
Expand Down
88 changes: 88 additions & 0 deletions deps/undici/src/docs/docs/api/ProxyAgent.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,91 @@ Implements [`Agent.dispatch(options, handlers)`](/docs/docs/api/Agent.md#paramet
### `ProxyAgent.request(options[, callback])`

See [`Dispatcher.request(options [, callback])`](/docs/docs/api/Dispatcher.md#dispatcherrequestoptions-callback).


#### Example - ProxyAgent with Fetch

This example demonstrates how to use `fetch` with a proxy via `ProxyAgent`. It is particularly useful for scenarios requiring proxy tunneling.

```javascript
import { ProxyAgent, fetch } from 'undici';

// Define the ProxyAgent
const proxyAgent = new ProxyAgent('http://localhost:8000');

// Make a GET request through the proxy
const response = await fetch('http://localhost:3000/foo', {
dispatcher: proxyAgent,
method: 'GET',
});

console.log('Response status:', response.status);
console.log('Response data:', await response.text());
```

---

#### Example - ProxyAgent with a Custom Proxy Server

This example shows how to create a custom proxy server and use it with `ProxyAgent`.

```javascript
import * as http from 'node:http';
import { createProxy } from 'proxy';
import { ProxyAgent, fetch } from 'undici';

// Create a proxy server
const proxyServer = createProxy(http.createServer());
proxyServer.listen(8000, () => {
console.log('Proxy server running on port 8000');
});

// Define and use the ProxyAgent
const proxyAgent = new ProxyAgent('http://localhost:8000');

const response = await fetch('http://example.com', {
dispatcher: proxyAgent,
method: 'GET',
});

console.log('Response status:', response.status);
console.log('Response data:', await response.text());
```

---

#### Example - ProxyAgent with HTTPS Tunneling

This example demonstrates how to perform HTTPS tunneling using a proxy.

```javascript
import { ProxyAgent, fetch } from 'undici';

// Define a ProxyAgent for HTTPS proxy
const proxyAgent = new ProxyAgent('https://secure.proxy.server');

// Make a request to an HTTPS endpoint via the proxy
const response = await fetch('https://secure.endpoint.com/api/data', {
dispatcher: proxyAgent,
method: 'GET',
});

console.log('Response status:', response.status);
console.log('Response data:', await response.json());
```

#### Example - ProxyAgent as a Global Dispatcher

`ProxyAgent` can be configured as a global dispatcher, making it available for all requests without explicitly passing it. This simplifies code and is useful when a single proxy configuration applies to all requests.

```javascript
import { ProxyAgent, setGlobalDispatcher, fetch } from 'undici';

// Define and configure the ProxyAgent
const proxyAgent = new ProxyAgent('http://localhost:8000');
setGlobalDispatcher(proxyAgent);

// Make requests without specifying the dispatcher
const response = await fetch('http://example.com');
console.log('Response status:', response.status);
console.log('Response data:', await response.text());
7 changes: 4 additions & 3 deletions deps/undici/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ try {
const SqliteCacheStore = require('./lib/cache/sqlite-cache-store')
module.exports.cacheStores.SqliteCacheStore = SqliteCacheStore
} catch (err) {
if (err.code !== 'ERR_UNKNOWN_BUILTIN_MODULE') {
throw err
}
// Most likely node:sqlite was not present, since SqliteCacheStore is
// optional, don't throw. Don't check specific error codes here because while
// ERR_UNKNOWN_BUILTIN_MODULE is expected, users have seen other codes like
// MODULE_NOT_FOUND
}

module.exports.buildConnector = buildConnector
Expand Down
10 changes: 0 additions & 10 deletions deps/undici/src/lib/dispatcher/client-h2.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ const kOpenStreams = Symbol('open streams')

let extractBody

// Experimental
let h2ExperimentalWarned = false

/** @type {import('http2')} */
let http2
try {
Expand Down Expand Up @@ -82,13 +79,6 @@ function parseH2Headers (headers) {
async function connectH2 (client, socket) {
client[kSocket] = socket

if (!h2ExperimentalWarned) {
h2ExperimentalWarned = true
process.emitWarning('H2 support is experimental, expect them to change at any time.', {
code: 'UNDICI-H2'
})
}

const session = http2.connect(client[kUrl], {
createConnection: () => socket,
peerMaxConcurrentStreams: client[kMaxConcurrentStreams],
Expand Down
50 changes: 23 additions & 27 deletions deps/undici/src/lib/handler/decorator-handler.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'

const assert = require('node:assert')
const WrapHandler = require('./wrap-handler')

/**
* @deprecated
Expand All @@ -9,63 +10,58 @@ module.exports = class DecoratorHandler {
#handler
#onCompleteCalled = false
#onErrorCalled = false
#onResponseStartCalled = false

constructor (handler) {
if (typeof handler !== 'object' || handler === null) {
throw new TypeError('handler must be an object')
}
this.#handler = handler
this.#handler = WrapHandler.wrap(handler)
}

onConnect (...args) {
return this.#handler.onConnect?.(...args)
onRequestStart (...args) {
this.#handler.onRequestStart?.(...args)
}

onError (...args) {
this.#onErrorCalled = true
return this.#handler.onError?.(...args)
}

onUpgrade (...args) {
onRequestUpgrade (...args) {
assert(!this.#onCompleteCalled)
assert(!this.#onErrorCalled)

return this.#handler.onUpgrade?.(...args)
return this.#handler.onRequestUpgrade?.(...args)
}

onResponseStarted (...args) {
onResponseStart (...args) {
assert(!this.#onCompleteCalled)
assert(!this.#onErrorCalled)
assert(!this.#onResponseStartCalled)

return this.#handler.onResponseStarted?.(...args)
}

onHeaders (...args) {
assert(!this.#onCompleteCalled)
assert(!this.#onErrorCalled)
this.#onResponseStartCalled = true

return this.#handler.onHeaders?.(...args)
return this.#handler.onResponseStart?.(...args)
}

onData (...args) {
onResponseData (...args) {
assert(!this.#onCompleteCalled)
assert(!this.#onErrorCalled)

return this.#handler.onData?.(...args)
return this.#handler.onResponseData?.(...args)
}

onComplete (...args) {
onResponseEnd (...args) {
assert(!this.#onCompleteCalled)
assert(!this.#onErrorCalled)

this.#onCompleteCalled = true
return this.#handler.onComplete?.(...args)
return this.#handler.onResponseEnd?.(...args)
}

onBodySent (...args) {
assert(!this.#onCompleteCalled)
assert(!this.#onErrorCalled)

return this.#handler.onBodySent?.(...args)
onResponseError (...args) {
this.#onErrorCalled = true
return this.#handler.onResponseError?.(...args)
}

/**
* @deprecated
*/
onBodySent () {}
}
16 changes: 8 additions & 8 deletions deps/undici/src/lib/interceptor/dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,27 +222,27 @@ class DNSDispatchHandler extends DecoratorHandler {
#state = null
#opts = null
#dispatch = null
#handler = null
#origin = null
#controller = null

constructor (state, { origin, handler, dispatch }, opts) {
super(handler)
this.#origin = origin
this.#handler = handler
this.#opts = { ...opts }
this.#state = state
this.#dispatch = dispatch
}

onError (err) {
onResponseError (controller, err) {
switch (err.code) {
case 'ETIMEDOUT':
case 'ECONNREFUSED': {
if (this.#state.dualStack) {
// We delete the record and retry
this.#state.runLookup(this.#origin, this.#opts, (err, newOrigin) => {
if (err) {
return this.#handler.onError(err)
super.onResponseError(controller, err)
return
}

const dispatchOpts = {
Expand All @@ -253,18 +253,18 @@ class DNSDispatchHandler extends DecoratorHandler {
this.#dispatch(dispatchOpts, this)
})

// if dual-stack disabled, we error out
return
}

this.#handler.onError(err)
return
// if dual-stack disabled, we error out
super.onResponseError(controller, err)
break
}
case 'ENOTFOUND':
this.#state.deleteRecord(this.#origin)
// eslint-disable-next-line no-fallthrough
default:
this.#handler.onError(err)
super.onResponseError(controller, err)
break
}
}
Expand Down
Loading
Loading