Skip to content
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

deps: update undici to 6.20.1 #55503

Merged
merged 1 commit into from
Oct 26, 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
1 change: 1 addition & 0 deletions deps/undici/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ The `body` mixins are the most common way to format the request/response body. M

- [`.arrayBuffer()`](https://fetch.spec.whatwg.org/#dom-body-arraybuffer)
- [`.blob()`](https://fetch.spec.whatwg.org/#dom-body-blob)
- [`.bytes()`](https://fetch.spec.whatwg.org/#dom-body-bytes)
- [`.json()`](https://fetch.spec.whatwg.org/#dom-body-json)
- [`.text()`](https://fetch.spec.whatwg.org/#dom-body-text)

Expand Down
12 changes: 7 additions & 5 deletions deps/undici/src/docs/docs/api/Dispatcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,11 +488,13 @@ The `RequestOptions.method` property should not be value `'CONNECT'`.

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

- `text()`
- `json()`
- `arrayBuffer()`
- `body`
- `bodyUsed`
* [`.arrayBuffer()`](https://fetch.spec.whatwg.org/#dom-body-arraybuffer)
* [`.blob()`](https://fetch.spec.whatwg.org/#dom-body-blob)
* [`.bytes()`](https://fetch.spec.whatwg.org/#dom-body-bytes)
* [`.json()`](https://fetch.spec.whatwg.org/#dom-body-json)
* [`.text()`](https://fetch.spec.whatwg.org/#dom-body-text)
* `body`
* `bodyUsed`

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

Expand Down
1 change: 1 addition & 0 deletions deps/undici/src/docs/docs/api/Fetch.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ This API is implemented as per the standard, you can find documentation on [MDN]

- [`.arrayBuffer()`](https://fetch.spec.whatwg.org/#dom-body-arraybuffer)
- [`.blob()`](https://fetch.spec.whatwg.org/#dom-body-blob)
- [`.bytes()`](https://fetch.spec.whatwg.org/#dom-body-bytes)
- [`.formData()`](https://fetch.spec.whatwg.org/#dom-body-formdata)
- [`.json()`](https://fetch.spec.whatwg.org/#dom-body-json)
- [`.text()`](https://fetch.spec.whatwg.org/#dom-body-text)
Expand Down
42 changes: 33 additions & 9 deletions deps/undici/src/lib/api/readable.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ class BodyReadable extends Readable {
return consume(this, 'blob')
}

// https://fetch.spec.whatwg.org/#dom-body-bytes
async bytes () {
return consume(this, 'bytes')
}

// https://fetch.spec.whatwg.org/#dom-body-arraybuffer
async arrayBuffer () {
return consume(this, 'arrayBuffer')
Expand Down Expand Up @@ -306,6 +311,31 @@ function chunksDecode (chunks, length) {
return buffer.utf8Slice(start, bufferLength)
}

/**
* @param {Buffer[]} chunks
* @param {number} length
* @returns {Uint8Array}
*/
function chunksConcat (chunks, length) {
if (chunks.length === 0 || length === 0) {
return new Uint8Array(0)
}
if (chunks.length === 1) {
// fast-path
return new Uint8Array(chunks[0])
}
const buffer = new Uint8Array(Buffer.allocUnsafeSlow(length).buffer)

let offset = 0
for (let i = 0; i < chunks.length; ++i) {
const chunk = chunks[i]
buffer.set(chunk, offset)
offset += chunk.length
}

return buffer
}

function consumeEnd (consume) {
const { type, body, resolve, stream, length } = consume

Expand All @@ -315,17 +345,11 @@ function consumeEnd (consume) {
} else if (type === 'json') {
resolve(JSON.parse(chunksDecode(body, length)))
} else if (type === 'arrayBuffer') {
const dst = new Uint8Array(length)

let pos = 0
for (const buf of body) {
dst.set(buf, pos)
pos += buf.byteLength
}

resolve(dst.buffer)
resolve(chunksConcat(body, length).buffer)
} else if (type === 'blob') {
resolve(new Blob(body, { type: stream[kContentType] }))
} else if (type === 'bytes') {
resolve(chunksConcat(body, length))
}

consumeFinish(consume)
Expand Down
11 changes: 7 additions & 4 deletions deps/undici/src/lib/dispatcher/client-h1.js
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,10 @@ function writeH1 (client, request) {
const expectsPayload = (
method === 'PUT' ||
method === 'POST' ||
method === 'PATCH'
method === 'PATCH' ||
method === 'QUERY' ||
method === 'PROPFIND' ||
method === 'PROPPATCH'
)

if (util.isFormDataLike(body)) {
Expand Down Expand Up @@ -1139,7 +1142,7 @@ function writeBuffer (abort, body, client, request, socket, contentLength, heade
socket.uncork()
request.onBodySent(body)

if (!expectsPayload) {
if (!expectsPayload && request.reset !== false) {
socket[kReset] = true
}
}
Expand Down Expand Up @@ -1169,7 +1172,7 @@ async function writeBlob (abort, body, client, request, socket, contentLength, h
request.onBodySent(buffer)
request.onRequestSent()

if (!expectsPayload) {
if (!expectsPayload && request.reset !== false) {
socket[kReset] = true
}

Expand Down Expand Up @@ -1270,7 +1273,7 @@ class AsyncWriter {
socket.cork()

if (bytesWritten === 0) {
if (!expectsPayload) {
if (!expectsPayload && request.reset !== false) {
socket[kReset] = true
}

Expand Down
75 changes: 56 additions & 19 deletions deps/undici/src/lib/dispatcher/client-h2.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ const {
kOnError,
kMaxConcurrentStreams,
kHTTP2Session,
kResume
kResume,
kSize,
kHTTPContext
} = require('../core/symbols.js')

const kOpenStreams = Symbol('open streams')
Expand Down Expand Up @@ -160,11 +162,10 @@ async function connectH2 (client, socket) {
version: 'h2',
defaultPipelining: Infinity,
write (...args) {
// TODO (fix): return
writeH2(client, ...args)
return writeH2(client, ...args)
},
resume () {

resumeH2(client)
},
destroy (err, callback) {
if (closed) {
Expand All @@ -183,6 +184,20 @@ async function connectH2 (client, socket) {
}
}

function resumeH2 (client) {
const socket = client[kSocket]

if (socket?.destroyed === false) {
if (client[kSize] === 0 && client[kMaxConcurrentStreams] === 0) {
socket.unref()
client[kHTTP2Session].unref()
} else {
socket.ref()
client[kHTTP2Session].ref()
}
}
}

function onHttp2SessionError (err) {
assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID')

Expand Down Expand Up @@ -210,17 +225,32 @@ function onHttp2SessionEnd () {
* along with the socket right away
*/
function onHTTP2GoAway (code) {
const err = new RequestAbortedError(`HTTP/2: "GOAWAY" frame received with code ${code}`)
// We cannot recover, so best to close the session and the socket
const err = this[kError] || new SocketError(`HTTP/2: "GOAWAY" frame received with code ${code}`, util.getSocketInfo(this))
const client = this[kClient]

// We need to trigger the close cycle right away
// We need to destroy the session and the socket
// Requests should be failed with the error after the current one is handled
this[kSocket][kError] = err
this[kClient][kOnError](err)
client[kSocket] = null
client[kHTTPContext] = null

this.unref()
if (this[kHTTP2Session] != null) {
this[kHTTP2Session].destroy(err)
this[kHTTP2Session] = null
}

util.destroy(this[kSocket], err)

// Fail head of pipeline.
const request = client[kQueue][client[kRunningIdx]]
client[kQueue][client[kRunningIdx]++] = null
util.errorRequest(client, request, err)

client[kPendingIdx] = client[kRunningIdx]

assert(client[kRunning] === 0)

client.emit('disconnect', client[kUrl], [client], err)

client[kResume]()
}

// https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2
Expand All @@ -237,10 +267,6 @@ function writeH2 (client, request) {
return false
}

if (request.aborted) {
return false
}

const headers = {}
for (let n = 0; n < reqHeaders.length; n += 2) {
const key = reqHeaders[n + 0]
Expand Down Expand Up @@ -283,6 +309,8 @@ function writeH2 (client, request) {
// We do not destroy the socket as we can continue using the session
// the stream get's destroyed and the session remains to create new streams
util.destroy(body, err)
client[kQueue][client[kRunningIdx]++] = null
client[kResume]()
}

try {
Expand All @@ -293,6 +321,10 @@ function writeH2 (client, request) {
util.errorRequest(client, request, err)
}

if (request.aborted) {
return false
}

if (method === 'CONNECT') {
session.ref()
// We are already connected, streams are pending, first request
Expand All @@ -304,10 +336,12 @@ function writeH2 (client, request) {
if (stream.id && !stream.pending) {
request.onUpgrade(null, null, stream)
++session[kOpenStreams]
client[kQueue][client[kRunningIdx]++] = null
} else {
stream.once('ready', () => {
request.onUpgrade(null, null, stream)
++session[kOpenStreams]
client[kQueue][client[kRunningIdx]++] = null
})
}

Expand Down Expand Up @@ -428,17 +462,20 @@ function writeH2 (client, request) {
// Present specially when using pipeline or stream
if (stream.state?.state == null || stream.state.state < 6) {
request.onComplete([])
return
}

// Stream is closed or half-closed-remote (6), decrement counter and cleanup
// It does not have sense to continue working with the stream as we do not
// have yet RST_STREAM support on client-side
if (session[kOpenStreams] === 0) {
// Stream is closed or half-closed-remote (6), decrement counter and cleanup
// It does not have sense to continue working with the stream as we do not
// have yet RST_STREAM support on client-side

session.unref()
}

abort(new InformationalError('HTTP/2: stream half-closed (remote)'))
client[kQueue][client[kRunningIdx]++] = null
client[kPendingIdx] = client[kRunningIdx]
client[kResume]()
})

stream.once('close', () => {
Expand Down
6 changes: 4 additions & 2 deletions deps/undici/src/lib/dispatcher/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ let deprecatedInterceptorWarned = false

const kClosedResolve = Symbol('kClosedResolve')

const noop = () => {}

function getPipelining (client) {
return client[kPipelining] ?? client[kHTTPContext]?.defaultPipelining ?? 1
}
Expand Down Expand Up @@ -442,7 +444,7 @@ async function connect (client) {
})

if (client.destroyed) {
util.destroy(socket.on('error', () => {}), new ClientDestroyedError())
util.destroy(socket.on('error', noop), new ClientDestroyedError())
return
}

Expand All @@ -453,7 +455,7 @@ async function connect (client) {
? await connectH2(client, socket)
: await connectH1(client, socket)
} catch (err) {
socket.destroy().on('error', () => {})
socket.destroy().on('error', noop)
throw err
}

Expand Down
6 changes: 3 additions & 3 deletions deps/undici/src/lib/dispatcher/pool-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ class PoolBase extends DispatcherBase {

async [kClose] () {
if (this[kQueue].isEmpty()) {
return Promise.all(this[kClients].map(c => c.close()))
await Promise.all(this[kClients].map(c => c.close()))
} else {
return new Promise((resolve) => {
await new Promise((resolve) => {
this[kClosedResolve] = resolve
})
}
Expand All @@ -130,7 +130,7 @@ class PoolBase extends DispatcherBase {
item.handler.onError(err)
}

return Promise.all(this[kClients].map(c => c.destroy(err)))
await Promise.all(this[kClients].map(c => c.destroy(err)))
}

[kDispatch] (opts, handler) {
Expand Down
4 changes: 3 additions & 1 deletion deps/undici/src/lib/dispatcher/proxy-agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ function defaultFactory (origin, opts) {
return new Pool(origin, opts)
}

const noop = () => {}

class ProxyAgent extends DispatcherBase {
constructor (opts) {
super()
Expand Down Expand Up @@ -81,7 +83,7 @@ class ProxyAgent extends DispatcherBase {
servername: this[kProxyTls]?.servername || proxyHostname
})
if (statusCode !== 200) {
socket.on('error', () => {}).destroy()
socket.on('error', noop).destroy()
callback(new RequestAbortedError(`Proxy response (${statusCode}) !== 200 when HTTP Tunneling`))
}
if (opts.protocol !== 'https:') {
Expand Down
4 changes: 2 additions & 2 deletions deps/undici/src/lib/llhttp/wasm_build_env.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@

> undici@6.20.0 prebuild:wasm
> undici@6.20.1 prebuild:wasm
> node build/wasm.js --prebuild

> docker build --platform=linux/x86_64 -t llhttp_wasm_builder -f /home/runner/work/node/node/deps/undici/src/build/Dockerfile /home/runner/work/node/node/deps/undici/src



> undici@6.20.0 build:wasm
> undici@6.20.1 build:wasm
> node build/wasm.js --docker

> docker run --rm -t --platform=linux/x86_64 --user 1001:127 --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/lib/llhttp,target=/home/node/undici/lib/llhttp llhttp_wasm_builder node build/wasm.js
Expand Down
Loading
Loading