Skip to content

Commit c9c6bf8

Browse files
nodejs-github-botmarco-ippolito
authored andcommitted
deps: update undici to 6.16.1
PR-URL: #52948 Reviewed-By: Marco Ippolito <[email protected]> Reviewed-By: Rafael Gonzaga <[email protected]>
1 parent b32b62d commit c9c6bf8

29 files changed

+1028
-589
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Class: EnvHttpProxyAgent
2+
3+
Stability: Experimental.
4+
5+
Extends: `undici.Dispatcher`
6+
7+
EnvHttpProxyAgent automatically reads the proxy configuration from the environment variables `http_proxy`, `https_proxy`, and `no_proxy` and sets up the proxy agents accordingly. When `http_proxy` and `https_proxy` are set, `http_proxy` is used for HTTP requests and `https_proxy` is used for HTTPS requests. If only `http_proxy` is set, `http_proxy` is used for both HTTP and HTTPS requests. If only `https_proxy` is set, it is only used for HTTPS requests.
8+
9+
`no_proxy` is a comma or space-separated list of hostnames that should not be proxied. The list may contain leading wildcard characters (`*`). If `no_proxy` is set, the EnvHttpProxyAgent will bypass the proxy for requests to hosts that match the list. If `no_proxy` is set to `"*"`, the EnvHttpProxyAgent will bypass the proxy for all requests.
10+
11+
Uppercase environment variables are also supported: `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY`. However, if both the lowercase and uppercase environment variables are set, the uppercase environment variables will be ignored.
12+
13+
## `new EnvHttpProxyAgent([options])`
14+
15+
Arguments:
16+
17+
* **options** `EnvHttpProxyAgentOptions` (optional) - extends the `Agent` options.
18+
19+
Returns: `EnvHttpProxyAgent`
20+
21+
### Parameter: `EnvHttpProxyAgentOptions`
22+
23+
Extends: [`AgentOptions`](Agent.md#parameter-agentoptions)
24+
25+
* **httpProxy** `string` (optional) - When set, it will override the `HTTP_PROXY` environment variable.
26+
* **httpsProxy** `string` (optional) - When set, it will override the `HTTPS_PROXY` environment variable.
27+
* **noProxy** `string` (optional) - When set, it will override the `NO_PROXY` environment variable.
28+
29+
Examples:
30+
31+
```js
32+
import { EnvHttpProxyAgent } from 'undici'
33+
34+
const envHttpProxyAgent = new EnvHttpProxyAgent()
35+
// or
36+
const envHttpProxyAgent = new EnvHttpProxyAgent({ httpProxy: 'my.proxy.server:8080', httpsProxy: 'my.proxy.server:8443', noProxy: 'localhost' })
37+
```
38+
39+
#### Example - EnvHttpProxyAgent instantiation
40+
41+
This will instantiate the EnvHttpProxyAgent. It will not do anything until registered as the agent to use with requests.
42+
43+
```js
44+
import { EnvHttpProxyAgent } from 'undici'
45+
46+
const envHttpProxyAgent = new EnvHttpProxyAgent()
47+
```
48+
49+
#### Example - Basic Proxy Fetch with global agent dispatcher
50+
51+
```js
52+
import { setGlobalDispatcher, fetch, EnvHttpProxyAgent } from 'undici'
53+
54+
const envHttpProxyAgent = new EnvHttpProxyAgent()
55+
setGlobalDispatcher(envHttpProxyAgent)
56+
57+
const { status, json } = await fetch('http://localhost:3000/foo')
58+
59+
console.log('response received', status) // response received 200
60+
61+
const data = await json() // data { foo: "bar" }
62+
```
63+
64+
#### Example - Basic Proxy Request with global agent dispatcher
65+
66+
```js
67+
import { setGlobalDispatcher, request, EnvHttpProxyAgent } from 'undici'
68+
69+
const envHttpProxyAgent = new EnvHttpProxyAgent()
70+
setGlobalDispatcher(envHttpProxyAgent)
71+
72+
const { statusCode, body } = await request('http://localhost:3000/foo')
73+
74+
console.log('response received', statusCode) // response received 200
75+
76+
for await (const data of body) {
77+
console.log('data', data.toString('utf8')) // data foo
78+
}
79+
```
80+
81+
#### Example - Basic Proxy Request with local agent dispatcher
82+
83+
```js
84+
import { EnvHttpProxyAgent, request } from 'undici'
85+
86+
const envHttpProxyAgent = new EnvHttpProxyAgent()
87+
88+
const {
89+
statusCode,
90+
body
91+
} = await request('http://localhost:3000/foo', { dispatcher: envHttpProxyAgent })
92+
93+
console.log('response received', statusCode) // response received 200
94+
95+
for await (const data of body) {
96+
console.log('data', data.toString('utf8')) // data foo
97+
}
98+
```
99+
100+
#### Example - Basic Proxy Fetch with local agent dispatcher
101+
102+
```js
103+
import { EnvHttpProxyAgent, fetch } from 'undici'
104+
105+
const envHttpProxyAgent = new EnvHttpProxyAgent()
106+
107+
const {
108+
status,
109+
json
110+
} = await fetch('http://localhost:3000/foo', { dispatcher: envHttpProxyAgent })
111+
112+
console.log('response received', status) // response received 200
113+
114+
const data = await json() // data { foo: "bar" }
115+
```
116+
117+
## Instance Methods
118+
119+
### `EnvHttpProxyAgent.close([callback])`
120+
121+
Implements [`Dispatcher.close([callback])`](Dispatcher.md#dispatcherclosecallback-promise).
122+
123+
### `EnvHttpProxyAgent.destroy([error, callback])`
124+
125+
Implements [`Dispatcher.destroy([error, callback])`](Dispatcher.md#dispatcherdestroyerror-callback-promise).
126+
127+
### `EnvHttpProxyAgent.dispatch(options, handler: AgentDispatchOptions)`
128+
129+
Implements [`Dispatcher.dispatch(options, handler)`](Dispatcher.md#dispatcherdispatchoptions-handler).
130+
131+
#### Parameter: `AgentDispatchOptions`
132+
133+
Extends: [`DispatchOptions`](Dispatcher.md#parameter-dispatchoptions)
134+
135+
* **origin** `string | URL`
136+
* **maxRedirections** `Integer`.
137+
138+
Implements [`Dispatcher.destroy([error, callback])`](Dispatcher.md#dispatcherdestroyerror-callback-promise).
139+
140+
### `EnvHttpProxyAgent.connect(options[, callback])`
141+
142+
See [`Dispatcher.connect(options[, callback])`](Dispatcher.md#dispatcherconnectoptions-callback).
143+
144+
### `EnvHttpProxyAgent.dispatch(options, handler)`
145+
146+
Implements [`Dispatcher.dispatch(options, handler)`](Dispatcher.md#dispatcherdispatchoptions-handler).
147+
148+
### `EnvHttpProxyAgent.pipeline(options, handler)`
149+
150+
See [`Dispatcher.pipeline(options, handler)`](Dispatcher.md#dispatcherpipelineoptions-handler).
151+
152+
### `EnvHttpProxyAgent.request(options[, callback])`
153+
154+
See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
155+
156+
### `EnvHttpProxyAgent.stream(options, factory[, callback])`
157+
158+
See [`Dispatcher.stream(options, factory[, callback])`](Dispatcher.md#dispatcherstreamoptions-factory-callback).
159+
160+
### `EnvHttpProxyAgent.upgrade(options[, callback])`
161+
162+
See [`Dispatcher.upgrade(options[, callback])`](Dispatcher.md#dispatcherupgradeoptions-callback).

deps/undici/src/docs/docs/api/Util.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ Receives a header object and returns the parsed value.
88

99
Arguments:
1010

11-
- **headers** `Record<string, string | string[]> | (Buffer | string | (Buffer | string)[])[]` (required) - Header object.
11+
- **headers** `(Buffer | string | (Buffer | string)[])[]` (required) - Header object.
1212

1313
- **obj** `Record<string, string | string[]>` (optional) - Object to specify a proxy object. The parsed value is assigned to this object. But, if **headers** is an object, it is not used.
1414

15-
Returns: `Record<string, string | string[]>` If **headers** is an object, it is **headers**. Otherwise, if **obj** is specified, it is equivalent to **obj**.
15+
Returns: `Record<string, string | string[]>` If **obj** is specified, it is equivalent to **obj**.
1616

1717
## `headerNameToString(value)`
1818

deps/undici/src/docs/docs/best-practices/proxy.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Connecting through a proxy is possible by:
44

5-
- Using [AgentProxy](../api/ProxyAgent.md).
5+
- Using [ProxyAgent](../api/ProxyAgent.md).
66
- Configuring `Client` or `Pool` constructor.
77

88
The proxy url should be passed to the `Client` or `Pool` constructor, while the upstream server url

deps/undici/src/lib/api/api-request.js

+49-17
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22

33
const assert = require('node:assert')
44
const { Readable } = require('./readable')
5-
const { InvalidArgumentError } = require('../core/errors')
5+
const { InvalidArgumentError, RequestAbortedError } = require('../core/errors')
66
const util = require('../core/util')
77
const { getResolveErrorBodyCallback } = require('./util')
88
const { AsyncResource } = require('node:async_hooks')
9-
const { addSignal, removeSignal } = require('./abort-signal')
109

1110
class RequestHandler extends AsyncResource {
1211
constructor (opts, callback) {
@@ -45,6 +44,7 @@ class RequestHandler extends AsyncResource {
4544
throw err
4645
}
4746

47+
this.method = method
4848
this.responseHeaders = responseHeaders || null
4949
this.opaque = opaque || null
5050
this.callback = callback
@@ -56,14 +56,36 @@ class RequestHandler extends AsyncResource {
5656
this.onInfo = onInfo || null
5757
this.throwOnError = throwOnError
5858
this.highWaterMark = highWaterMark
59+
this.signal = signal
60+
this.reason = null
61+
this.removeAbortListener = null
5962

6063
if (util.isStream(body)) {
6164
body.on('error', (err) => {
6265
this.onError(err)
6366
})
6467
}
6568

66-
addSignal(this, signal)
69+
if (this.signal) {
70+
if (this.signal.aborted) {
71+
this.reason = this.signal.reason ?? new RequestAbortedError()
72+
} else {
73+
this.removeAbortListener = util.addAbortListener(this.signal, () => {
74+
this.reason = this.signal.reason ?? new RequestAbortedError()
75+
if (this.res) {
76+
util.destroy(this.res, this.reason)
77+
} else if (this.abort) {
78+
this.abort(this.reason)
79+
}
80+
81+
if (this.removeAbortListener) {
82+
this.res?.off('close', this.removeAbortListener)
83+
this.removeAbortListener()
84+
this.removeAbortListener = null
85+
}
86+
})
87+
}
88+
}
6789
}
6890

6991
onConnect (abort, context) {
@@ -93,48 +115,52 @@ class RequestHandler extends AsyncResource {
93115
const parsedHeaders = responseHeaders === 'raw' ? util.parseHeaders(rawHeaders) : headers
94116
const contentType = parsedHeaders['content-type']
95117
const contentLength = parsedHeaders['content-length']
96-
const body = new Readable({ resume, abort, contentType, contentLength, highWaterMark })
118+
const res = new Readable({
119+
resume,
120+
abort,
121+
contentType,
122+
contentLength: this.method !== 'HEAD' && contentLength
123+
? Number(contentLength)
124+
: null,
125+
highWaterMark
126+
})
127+
128+
if (this.removeAbortListener) {
129+
res.on('close', this.removeAbortListener)
130+
}
97131

98132
this.callback = null
99-
this.res = body
133+
this.res = res
100134
if (callback !== null) {
101135
if (this.throwOnError && statusCode >= 400) {
102136
this.runInAsyncScope(getResolveErrorBodyCallback, null,
103-
{ callback, body, contentType, statusCode, statusMessage, headers }
137+
{ callback, body: res, contentType, statusCode, statusMessage, headers }
104138
)
105139
} else {
106140
this.runInAsyncScope(callback, null, null, {
107141
statusCode,
108142
headers,
109143
trailers: this.trailers,
110144
opaque,
111-
body,
145+
body: res,
112146
context
113147
})
114148
}
115149
}
116150
}
117151

118152
onData (chunk) {
119-
const { res } = this
120-
return res.push(chunk)
153+
return this.res.push(chunk)
121154
}
122155

123156
onComplete (trailers) {
124-
const { res } = this
125-
126-
removeSignal(this)
127-
128157
util.parseHeaders(trailers, this.trailers)
129-
130-
res.push(null)
158+
this.res.push(null)
131159
}
132160

133161
onError (err) {
134162
const { res, callback, body, opaque } = this
135163

136-
removeSignal(this)
137-
138164
if (callback) {
139165
// TODO: Does this need queueMicrotask?
140166
this.callback = null
@@ -155,6 +181,12 @@ class RequestHandler extends AsyncResource {
155181
this.body = null
156182
util.destroy(body, err)
157183
}
184+
185+
if (this.removeAbortListener) {
186+
res?.off('close', this.removeAbortListener)
187+
this.removeAbortListener()
188+
this.removeAbortListener = null
189+
}
158190
}
159191
}
160192

deps/undici/src/lib/api/readable.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,13 @@ class BodyReadable extends Readable {
6363
// tick as it is created, then a user who is waiting for a
6464
// promise (i.e micro tick) for installing a 'error' listener will
6565
// never get a chance and will always encounter an unhandled exception.
66-
setImmediate(() => {
66+
if (!this[kReading]) {
67+
setImmediate(() => {
68+
callback(err)
69+
})
70+
} else {
6771
callback(err)
68-
})
72+
}
6973
}
7074

7175
on (ev, ...args) {

deps/undici/src/lib/core/connect.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ function setupTimeout (onConnectTimeout, timeout) {
165165
let s1 = null
166166
let s2 = null
167167
const timeoutId = setTimeout(() => {
168-
// setImmediate is added to make sure that we priotorise socket error events over timeouts
168+
// setImmediate is added to make sure that we prioritize socket error events over timeouts
169169
s1 = setImmediate(() => {
170170
if (process.platform === 'win32') {
171171
// Windows needs an extra setImmediate probably due to implementation differences in the socket logic

deps/undici/src/lib/dispatcher/client-h2.js

+2
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,7 @@ function writeH2 (client, request) {
524524
}
525525
} else if (util.isStream(body)) {
526526
writeStream({
527+
abort,
527528
body,
528529
client,
529530
request,
@@ -535,6 +536,7 @@ function writeH2 (client, request) {
535536
})
536537
} else if (util.isIterable(body)) {
537538
writeIterable({
539+
abort,
538540
body,
539541
client,
540542
request,

0 commit comments

Comments
 (0)