Skip to content

Commit df8b9f2

Browse files
mcollinaRafaelGSS
authored andcommittedJan 19, 2025
deps: update undici to v6.21.1
Signed-off-by: Matteo Collina <hello@matteocollina.com> PR-URL: nodejs-private/node-private#663 Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> CVE-ID: CVE-2025-22150
1 parent 389f239 commit df8b9f2

38 files changed

+944
-10485
lines changed
 

‎deps/undici/src/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ The `body` mixins are the most common way to format the request/response body. M
8484

8585
- [`.arrayBuffer()`](https://fetch.spec.whatwg.org/#dom-body-arraybuffer)
8686
- [`.blob()`](https://fetch.spec.whatwg.org/#dom-body-blob)
87+
- [`.bytes()`](https://fetch.spec.whatwg.org/#dom-body-bytes)
8788
- [`.json()`](https://fetch.spec.whatwg.org/#dom-body-json)
8889
- [`.text()`](https://fetch.spec.whatwg.org/#dom-body-text)
8990

‎deps/undici/src/docs/docs/api/Dispatcher.md

+58-5
Original file line numberDiff line numberDiff line change
@@ -488,11 +488,13 @@ The `RequestOptions.method` property should not be value `'CONNECT'`.
488488

489489
`body` contains the following additional [body mixin](https://fetch.spec.whatwg.org/#body-mixin) methods and properties:
490490

491-
- `text()`
492-
- `json()`
493-
- `arrayBuffer()`
494-
- `body`
495-
- `bodyUsed`
491+
* [`.arrayBuffer()`](https://fetch.spec.whatwg.org/#dom-body-arraybuffer)
492+
* [`.blob()`](https://fetch.spec.whatwg.org/#dom-body-blob)
493+
* [`.bytes()`](https://fetch.spec.whatwg.org/#dom-body-bytes)
494+
* [`.json()`](https://fetch.spec.whatwg.org/#dom-body-json)
495+
* [`.text()`](https://fetch.spec.whatwg.org/#dom-body-text)
496+
* `body`
497+
* `bodyUsed`
496498

497499
`body` can not be consumed twice. For example, calling `text()` after `json()` throws `TypeError`.
498500

@@ -984,6 +986,57 @@ client.dispatch(
984986
);
985987
```
986988

989+
##### `dns`
990+
991+
The `dns` interceptor enables you to cache DNS lookups for a given duration, per origin.
992+
993+
>It is well suited for scenarios where you want to cache DNS lookups to avoid the overhead of resolving the same domain multiple times
994+
995+
**Options**
996+
- `maxTTL` - The maximum time-to-live (in milliseconds) of the DNS cache. It should be a positive integer. Default: `10000`.
997+
- Set `0` to disable TTL.
998+
- `maxItems` - The maximum number of items to cache. It should be a positive integer. Default: `Infinity`.
999+
- `dualStack` - Whether to resolve both IPv4 and IPv6 addresses. Default: `true`.
1000+
- It will also attempt a happy-eyeballs-like approach to connect to the available addresses in case of a connection failure.
1001+
- `affinity` - Whether to use IPv4 or IPv6 addresses. Default: `4`.
1002+
- It can be either `'4` or `6`.
1003+
- It will only take effect if `dualStack` is `false`.
1004+
- `lookup: (hostname: string, options: LookupOptions, callback: (err: NodeJS.ErrnoException | null, addresses: DNSInterceptorRecord[]) => void) => void` - Custom lookup function. Default: `dns.lookup`.
1005+
- For more info see [dns.lookup](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback).
1006+
- `pick: (origin: URL, records: DNSInterceptorRecords, affinity: 4 | 6) => DNSInterceptorRecord` - Custom pick function. Default: `RoundRobin`.
1007+
- The function should return a single record from the records array.
1008+
- By default a simplified version of Round Robin is used.
1009+
- The `records` property can be mutated to store the state of the balancing algorithm.
1010+
1011+
> The `Dispatcher#options` also gets extended with the options `dns.affinity`, `dns.dualStack`, `dns.lookup` and `dns.pick` which can be used to configure the interceptor at a request-per-request basis.
1012+
1013+
1014+
**DNSInterceptorRecord**
1015+
It represents a DNS record.
1016+
- `family` - (`number`) The IP family of the address. It can be either `4` or `6`.
1017+
- `address` - (`string`) The IP address.
1018+
1019+
**DNSInterceptorOriginRecords**
1020+
It represents a map of DNS IP addresses records for a single origin.
1021+
- `4.ips` - (`DNSInterceptorRecord[] | null`) The IPv4 addresses.
1022+
- `6.ips` - (`DNSInterceptorRecord[] | null`) The IPv6 addresses.
1023+
1024+
**Example - Basic DNS Interceptor**
1025+
1026+
```js
1027+
const { Client, interceptors } = require("undici");
1028+
const { dns } = interceptors;
1029+
1030+
const client = new Agent().compose([
1031+
dns({ ...opts })
1032+
])
1033+
1034+
const response = await client.request({
1035+
origin: `http://localhost:3030`,
1036+
...requestOpts
1037+
})
1038+
```
1039+
9871040
##### `Response Error Interceptor`
9881041

9891042
**Introduction**

‎deps/undici/src/docs/docs/api/Fetch.md

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ This API is implemented as per the standard, you can find documentation on [MDN]
2828

2929
- [`.arrayBuffer()`](https://fetch.spec.whatwg.org/#dom-body-arraybuffer)
3030
- [`.blob()`](https://fetch.spec.whatwg.org/#dom-body-blob)
31+
- [`.bytes()`](https://fetch.spec.whatwg.org/#dom-body-bytes)
3132
- [`.formData()`](https://fetch.spec.whatwg.org/#dom-body-formdata)
3233
- [`.json()`](https://fetch.spec.whatwg.org/#dom-body-json)
3334
- [`.text()`](https://fetch.spec.whatwg.org/#dom-body-text)

‎deps/undici/src/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ module.exports.createRedirectInterceptor = createRedirectInterceptor
4141
module.exports.interceptors = {
4242
redirect: require('./lib/interceptor/redirect'),
4343
retry: require('./lib/interceptor/retry'),
44-
dump: require('./lib/interceptor/dump')
44+
dump: require('./lib/interceptor/dump'),
45+
dns: require('./lib/interceptor/dns')
4546
}
4647

4748
module.exports.buildConnector = buildConnector

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class RequestHandler extends AsyncResource {
7373
this.removeAbortListener = util.addAbortListener(this.signal, () => {
7474
this.reason = this.signal.reason ?? new RequestAbortedError()
7575
if (this.res) {
76-
util.destroy(this.res, this.reason)
76+
util.destroy(this.res.on('error', util.nop), this.reason)
7777
} else if (this.abort) {
7878
this.abort(this.reason)
7979
}

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

+33-9
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ class BodyReadable extends Readable {
121121
return consume(this, 'blob')
122122
}
123123

124+
// https://fetch.spec.whatwg.org/#dom-body-bytes
125+
async bytes () {
126+
return consume(this, 'bytes')
127+
}
128+
124129
// https://fetch.spec.whatwg.org/#dom-body-arraybuffer
125130
async arrayBuffer () {
126131
return consume(this, 'arrayBuffer')
@@ -306,6 +311,31 @@ function chunksDecode (chunks, length) {
306311
return buffer.utf8Slice(start, bufferLength)
307312
}
308313

314+
/**
315+
* @param {Buffer[]} chunks
316+
* @param {number} length
317+
* @returns {Uint8Array}
318+
*/
319+
function chunksConcat (chunks, length) {
320+
if (chunks.length === 0 || length === 0) {
321+
return new Uint8Array(0)
322+
}
323+
if (chunks.length === 1) {
324+
// fast-path
325+
return new Uint8Array(chunks[0])
326+
}
327+
const buffer = new Uint8Array(Buffer.allocUnsafeSlow(length).buffer)
328+
329+
let offset = 0
330+
for (let i = 0; i < chunks.length; ++i) {
331+
const chunk = chunks[i]
332+
buffer.set(chunk, offset)
333+
offset += chunk.length
334+
}
335+
336+
return buffer
337+
}
338+
309339
function consumeEnd (consume) {
310340
const { type, body, resolve, stream, length } = consume
311341

@@ -315,17 +345,11 @@ function consumeEnd (consume) {
315345
} else if (type === 'json') {
316346
resolve(JSON.parse(chunksDecode(body, length)))
317347
} else if (type === 'arrayBuffer') {
318-
const dst = new Uint8Array(length)
319-
320-
let pos = 0
321-
for (const buf of body) {
322-
dst.set(buf, pos)
323-
pos += buf.byteLength
324-
}
325-
326-
resolve(dst.buffer)
348+
resolve(chunksConcat(body, length).buffer)
327349
} else if (type === 'blob') {
328350
resolve(new Blob(body, { type: stream[kContentType] }))
351+
} else if (type === 'bytes') {
352+
resolve(chunksConcat(body, length))
329353
}
330354

331355
consumeFinish(consume)

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

+5
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,11 @@ const setupConnectTimeout = process.platform === 'win32'
220220
* @param {number} opts.port
221221
*/
222222
function onConnectTimeout (socket, opts) {
223+
// The socket could be already garbage collected
224+
if (socket == null) {
225+
return
226+
}
227+
223228
let message = 'Connect Timeout Error'
224229
if (Array.isArray(socket.autoSelectFamilyAttemptedAddresses)) {
225230
message += ` (attempted addresses: ${socket.autoSelectFamilyAttemptedAddresses.join(', ')},`

‎deps/undici/src/lib/dispatcher/client-h1.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,10 @@ function writeH1 (client, request) {
860860
const expectsPayload = (
861861
method === 'PUT' ||
862862
method === 'POST' ||
863-
method === 'PATCH'
863+
method === 'PATCH' ||
864+
method === 'QUERY' ||
865+
method === 'PROPFIND' ||
866+
method === 'PROPPATCH'
864867
)
865868

866869
if (util.isFormDataLike(body)) {
@@ -1139,7 +1142,7 @@ function writeBuffer (abort, body, client, request, socket, contentLength, heade
11391142
socket.uncork()
11401143
request.onBodySent(body)
11411144

1142-
if (!expectsPayload) {
1145+
if (!expectsPayload && request.reset !== false) {
11431146
socket[kReset] = true
11441147
}
11451148
}
@@ -1169,7 +1172,7 @@ async function writeBlob (abort, body, client, request, socket, contentLength, h
11691172
request.onBodySent(buffer)
11701173
request.onRequestSent()
11711174

1172-
if (!expectsPayload) {
1175+
if (!expectsPayload && request.reset !== false) {
11731176
socket[kReset] = true
11741177
}
11751178

@@ -1270,7 +1273,7 @@ class AsyncWriter {
12701273
socket.cork()
12711274

12721275
if (bytesWritten === 0) {
1273-
if (!expectsPayload) {
1276+
if (!expectsPayload && request.reset !== false) {
12741277
socket[kReset] = true
12751278
}
12761279

0 commit comments

Comments
 (0)
Please sign in to comment.