Skip to content

Commit 60b74b0

Browse files
nodejs-github-botaduh95
authored andcommitted
deps: update undici to 8.10.0
PR-URL: #65155 Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
1 parent 766731e commit 60b74b0

21 files changed

Lines changed: 916 additions & 212 deletions

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

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,22 +111,35 @@ added: v1.0.0
111111
`autoSelectFamily` is enabled. **Default:** `250`.
112112
* `allowH2` {boolean} Enables HTTP/2 support when the server assigns it a
113113
higher priority through ALPN negotiation. **Default:** `true`.
114-
* `useH2c` {boolean} Enforces h2c (HTTP/2 cleartext) for non-HTTPS
115-
connections. **Default:** `false`.
116-
* `maxConcurrentStreams` {number} The maximum number of concurrent HTTP/2
114+
* `useH2c` {boolean} _Deprecated: use h2Options.useH2c instead_ Enforces h2c (HTTP/2 cleartext) for non-HTTPS
115+
connections. **Default:** `false`.
116+
* `maxConcurrentStreams` {number} _Deprecated: use h2Options.useH2c instead_ The maximum number of concurrent HTTP/2
117117
streams for a single session. Once h2 is negotiated this — not `pipelining`,
118118
which is HTTP/1.1 only — is the ceiling used to dispatch in-flight requests.
119119
It may be overridden by the server's `SETTINGS_MAX_CONCURRENT_STREAMS`
120120
frame. **Default:** `100`.
121-
* `initialWindowSize` {number} The HTTP/2 stream-level flow-control window
122-
size (`SETTINGS_INITIAL_WINDOW_SIZE`). Must be a positive integer.
123-
**Default:** `262144`.
124-
* `connectionWindowSize` {number} The HTTP/2 connection-level flow-control
121+
* `connectionWindowSize` {number} _Deprecated: use h2Options.connectionWindowSize instead_ The HTTP/2 connection-level flow-control
125122
window size set via `ClientHttp2Session.setLocalWindowSize()`. Must be a
126123
positive integer. **Default:** `524288`.
127-
* `pingInterval` {number} The time interval, in milliseconds, between HTTP/2
124+
* `pingInterval` {number} _Deprecated: use h2Options.pingInterval instead_ The time interval, in milliseconds, between HTTP/2
128125
PING frames. Set to `0` to disable PING frames. Applies only to HTTP/2
129126
connections and emits a `ping` event on the client. **Default:** `60e3`.
127+
* `h2Options` {object} Set of options for HTTP/2 sessions
128+
* `useH2c` {boolean} Enforces h2c (HTTP/2 cleartext) for non-HTTPS
129+
connections. **Default:** `false`.
130+
* `maxConcurrentStreams` {number} The maximum number of concurrent HTTP/2
131+
streams for a single session. Once h2 is negotiated this — not `pipelining`,
132+
which is HTTP/1.1 only — is the ceiling used to dispatch in-flight requests.
133+
It may be overridden by the server's `SETTINGS_MAX_CONCURRENT_STREAMS`
134+
frame. **Default:** `100`.
135+
* `connectionWindowSize` {number} The HTTP/2 connection-level flow-control
136+
window size set via `ClientHttp2Session.setLocalWindowSize()`. Must be a
137+
positive integer. **Default:** `524288`.
138+
* `pingInterval` {number} The time interval, in milliseconds, between HTTP/2
139+
PING frames. Set to `0` to disable PING frames. Applies only to HTTP/2
140+
connections and emits a `ping` event on the client. **Default:** `60e3`.
141+
* `settings` {object} `SETTINGS` frame options. For full reference, take a
142+
look to [HTTP/2#Settings Object](https://nodejs.org/api/http2.html#settings-object)
130143
* `webSocket` {Object} (optional) WebSocket-specific configuration.
131144
* `maxFragments` {number} The maximum number of fragments in a message. Set
132145
to `0` to disable the limit. **Default:** `131072`.

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

Lines changed: 33 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ const kContentType = Symbol('kContentType')
1515
const kContentLength = Symbol('kContentLength')
1616
const kUsed = Symbol('kUsed')
1717
const kBytesRead = Symbol('kBytesRead')
18-
const kPreservedBuffer = Symbol('kPreservedBuffer')
1918

2019
const noop = () => {}
2120

@@ -326,36 +325,14 @@ class BodyReadable extends Readable {
326325
*/
327326
setEncoding (encoding) {
328327
if (Buffer.isEncoding(encoding)) {
329-
// Preserve raw Buffer chunks for the consume path (body.text(),
330-
// body.json(), etc.) before super.setEncoding() replaces them
331-
// with decoded strings. Without this, the consume path would
332-
// lose access to the original bytes — some of which may be held
333-
// by the decoder for incomplete multi-byte sequences, and the
334-
// rest converted to strings that can't be safely concatenated
335-
// byte-wise.
336-
const state = this._readableState
337-
const buffer = state.buffer
338-
if (buffer && state.length > 0) {
339-
const bufferIndex = state.bufferIndex ?? 0
340-
const preserved = []
341-
const source = typeof buffer.slice === 'function'
342-
? buffer.slice(bufferIndex)
343-
: buffer
344-
for (const data of source) {
345-
if (Buffer.isBuffer(data)) {
346-
preserved.push(data)
347-
}
348-
}
349-
if (preserved.length > 0) {
350-
this[kPreservedBuffer] = (this[kPreservedBuffer] || []).concat(preserved)
351-
}
352-
}
353-
354328
// Delegate to Node.js Readable.setEncoding() which initializes a
355329
// StringDecoder and re-encodes already-buffered chunks. This properly
356330
// handles multi-byte sequences split at chunk boundaries for the
357331
// for-await / on('data') paths. Without this, Node.js uses
358332
// buf.toString(encoding) on each chunk, producing U+FFFD for split chars.
333+
//
334+
// The consume path (body.text(), body.json(), ...) copes with the
335+
// decoded strings this leaves in state.buffer, see consumeStart().
359336
super.setEncoding(encoding)
360337
}
361338
return this
@@ -464,17 +441,7 @@ function consumeStart (consume) {
464441

465442
const { _readableState: state } = consume.stream
466443

467-
// If setEncoding() was called, state.buffer may contain decoded strings
468-
// (which would break Buffer.concat in chunksDecode). Use the preserved
469-
// raw Buffers (saved before super.setEncoding() in setEncoding()) for
470-
// byte-level accurate consumption. Otherwise read from state.buffer.
471-
const preserved = consume.stream[kPreservedBuffer]
472-
if (preserved && preserved.length > 0) {
473-
for (const chunk of preserved) {
474-
consumePush(consume, chunk)
475-
}
476-
consume.stream[kPreservedBuffer] = null
477-
} else if (state.bufferIndex) {
444+
if (state.bufferIndex) {
478445
const start = state.bufferIndex
479446
const end = state.buffer.length
480447
for (let n = start; n < end; n++) {
@@ -486,14 +453,29 @@ function consumeStart (consume) {
486453
}
487454
}
488455

456+
// If setEncoding() was called, state.buffer holds decoded strings, which
457+
// consumePush() turns back into bytes. The trailing bytes of a multi-byte
458+
// sequence split across a chunk boundary are not part of any of those
459+
// strings, they are held inside the decoder until the rest arrives, so
460+
// take them from there.
461+
const decoder = state.decoder
462+
if (decoder != null && decoder.lastNeed > 0) {
463+
consumePush(consume, Buffer.from(decoder.lastChar.subarray(0, decoder.lastTotal - decoder.lastNeed)))
464+
}
465+
489466
if (state.endEmitted) {
490-
consumeEnd(this[kConsume], this._readableState.encoding)
491-
} else {
492-
consume.stream.on('end', function () {
493-
consumeEnd(this[kConsume], this._readableState.encoding)
494-
})
467+
// No `this` to read the consume off here: consumeStart is a free function, called from
468+
// the queueMicrotask above. The callback below does have one, because the emitter passes
469+
// the stream as its receiver. Returning matters too - consumeEnd() clears consume.stream,
470+
// which the resume() below would then dereference.
471+
consumeEnd(consume, state.encoding)
472+
return
495473
}
496474

475+
consume.stream.on('end', function () {
476+
consumeEnd(this[kConsume], this._readableState.encoding)
477+
})
478+
497479
consume.stream.resume()
498480

499481
while (consume.stream.read() != null) {
@@ -583,14 +565,22 @@ function consumeEnd (consume, encoding) {
583565

584566
/**
585567
* @param {Consume} consume
586-
* @param {Buffer} chunk
568+
* @param {Buffer|string} chunk
587569
* @returns {void}
588570
*/
589571
function consumePush (consume, chunk) {
590572
if (consume.body === null) {
591573
return
592574
}
593575

576+
if (typeof chunk === 'string') {
577+
// Buffered before the consume started, while an encoding was set.
578+
// consume.length has to stay a byte count and chunksDecode()/chunksConcat()
579+
// only work on bytes, so re-encode. A string's own length is in UTF-16 code
580+
// units and Uint8Array.prototype.set() ignores a string argument entirely.
581+
chunk = Buffer.from(chunk, consume.stream._readableState.encoding)
582+
}
583+
594584
consume.length += chunk.length
595585
consume.body.push(chunk)
596586
}

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,27 @@ function buildConnector ({ allowH2, preferH2, useH2c, maxCachedSessions, socketP
105105

106106
port = port || 80
107107

108-
socket = net.connect({
108+
const connectOptions = {
109109
highWaterMark: 64 * 1024, // Same as nodejs fs streams.
110110
...options,
111111
localAddress,
112112
port,
113113
host: hostname
114-
})
114+
}
115+
116+
const family = net.isIP(hostname)
117+
if (family !== 0 && servername && servername !== hostname) {
118+
connectOptions.host = servername
119+
connectOptions.lookup = (_hostname, lookupOptions, cb) => {
120+
if (lookupOptions.all) {
121+
cb(null, [{ address: hostname, family }])
122+
} else {
123+
cb(null, hostname, family)
124+
}
125+
}
126+
}
127+
128+
socket = net.connect(connectOptions)
115129
if (useH2c === true) {
116130
socket.alpnProtocol = 'h2'
117131
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ module.exports = {
5656
kCounter: Symbol('socket request counter'),
5757
kMaxResponseSize: Symbol('max response size'),
5858
kHTTP2Session: Symbol('http2Session'),
59+
kHTTP2Options: Symbol('http2 options'),
5960
kHTTP2SessionState: Symbol('http2Session state'),
6061
kRetryHandlerDefaultRetry: Symbol('retry agent default retry'),
6162
kConstruct: Symbol('constructable'),

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,7 +1052,7 @@ function onSocketClose () {
10521052

10531053
function clearIdleSocketValidation (socket) {
10541054
if (socket[kIdleSocketValidationTimeout]) {
1055-
clearImmediate(socket[kIdleSocketValidationTimeout])
1055+
clearTimeout(socket[kIdleSocketValidationTimeout])
10561056
socket[kIdleSocketValidationTimeout] = null
10571057
}
10581058

@@ -1061,14 +1061,14 @@ function clearIdleSocketValidation (socket) {
10611061

10621062
function scheduleIdleSocketValidation (client, socket) {
10631063
socket[kIdleSocketValidation] = 1
1064-
socket[kIdleSocketValidationTimeout] = setImmediate(() => {
1064+
socket[kIdleSocketValidationTimeout] = setTimeout(() => {
10651065
socket[kIdleSocketValidationTimeout] = null
10661066
socket[kIdleSocketValidation] = 2
10671067

10681068
if (client[kSocket] === socket && !socket.destroyed) {
10691069
client[kResume]()
10701070
}
1071-
})
1071+
}, 0)
10721072
socket[kIdleSocketValidationTimeout].unref?.()
10731073
}
10741074

0 commit comments

Comments
 (0)