Skip to content

deps: update undici to 6.13.0 #52493

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 2 commits into from
Apr 19, 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
12 changes: 12 additions & 0 deletions deps/undici/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,18 @@ const data = {
await fetch('https://example.com', { body: data, method: 'POST', duplex: 'half' })
```

[FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) besides text data and buffers can also utilize streams via [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) objects:

```js
import { openAsBlob } from 'node:fs'

const file = await openAsBlob('./big.csv')
const body = new FormData()
body.set('file', file, 'big.csv')

await fetch('http://example.com', { method: 'POST', body })
```

#### `request.duplex`

- half
Expand Down
6 changes: 6 additions & 0 deletions deps/undici/src/docs/docs/api/Dispatcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,12 @@ Parameters:
* **targets** `Array<Dispatcher>`
* **error** `Error`

Emitted when the dispatcher has been disconnected from the origin.

> **Note**: For HTTP/2, this event is also emitted when the dispatcher has received the [GOAWAY Frame](https://webconcepts.info/concepts/http2-frame-type/0x7) with an Error with the message `HTTP/2: "GOAWAY" frame received` and the code `UND_ERR_INFO`.
> Due to nature of the protocol of using binary frames, it is possible that requests gets hanging as a frame can be received between the `HEADER` and `DATA` frames.
> It is recommended to handle this event and close the dispatcher to create a new HTTP/2 session.

### Event: `'connectionError'`

Parameters:
Expand Down
5 changes: 4 additions & 1 deletion deps/undici/src/lib/api/abort-signal.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ function abort (self) {
if (self.abort) {
self.abort(self[kSignal]?.reason)
} else {
self.onError(self[kSignal]?.reason ?? new RequestAbortedError())
self.reason = self[kSignal]?.reason ?? new RequestAbortedError()
}
removeSignal(self)
}

function addSignal (self, signal) {
self.reason = null

self[kSignal] = null
self[kListener] = null

Expand Down
10 changes: 7 additions & 3 deletions deps/undici/src/lib/api/api-connect.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
'use strict'

const assert = require('node:assert')
const { AsyncResource } = require('node:async_hooks')
const { InvalidArgumentError, RequestAbortedError, SocketError } = require('../core/errors')
const { InvalidArgumentError, SocketError } = require('../core/errors')
const util = require('../core/util')
const { addSignal, removeSignal } = require('./abort-signal')

Expand Down Expand Up @@ -32,10 +33,13 @@ class ConnectHandler extends AsyncResource {
}

onConnect (abort, context) {
if (!this.callback) {
throw new RequestAbortedError()
if (this.reason) {
abort(this.reason)
return
}

assert(this.callback)

this.abort = abort
this.context = context
}
Expand Down
10 changes: 6 additions & 4 deletions deps/undici/src/lib/api/api-pipeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,14 @@ class PipelineHandler extends AsyncResource {
onConnect (abort, context) {
const { ret, res } = this

assert(!res, 'pipeline cannot be retried')

if (ret.destroyed) {
throw new RequestAbortedError()
if (this.reason) {
abort(this.reason)
return
}

assert(!res, 'pipeline cannot be retried')
assert(!ret.destroyed)

this.abort = abort
this.context = context
}
Expand Down
13 changes: 7 additions & 6 deletions deps/undici/src/lib/api/api-request.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
'use strict'

const assert = require('node:assert')
const { Readable } = require('./readable')
const {
InvalidArgumentError,
RequestAbortedError
} = require('../core/errors')
const { InvalidArgumentError } = require('../core/errors')
const util = require('../core/util')
const { getResolveErrorBodyCallback } = require('./util')
const { AsyncResource } = require('node:async_hooks')
Expand Down Expand Up @@ -69,10 +67,13 @@ class RequestHandler extends AsyncResource {
}

onConnect (abort, context) {
if (!this.callback) {
throw new RequestAbortedError()
if (this.reason) {
abort(this.reason)
return
}

assert(this.callback)

this.abort = abort
this.context = context
}
Expand Down
14 changes: 7 additions & 7 deletions deps/undici/src/lib/api/api-stream.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
'use strict'

const assert = require('node:assert')
const { finished, PassThrough } = require('node:stream')
const {
InvalidArgumentError,
InvalidReturnValueError,
RequestAbortedError
} = require('../core/errors')
const { InvalidArgumentError, InvalidReturnValueError } = require('../core/errors')
const util = require('../core/util')
const { getResolveErrorBodyCallback } = require('./util')
const { AsyncResource } = require('node:async_hooks')
Expand Down Expand Up @@ -70,10 +67,13 @@ class StreamHandler extends AsyncResource {
}

onConnect (abort, context) {
if (!this.callback) {
throw new RequestAbortedError()
if (this.reason) {
abort(this.reason)
return
}

assert(this.callback)

this.abort = abort
this.context = context
}
Expand Down
9 changes: 6 additions & 3 deletions deps/undici/src/lib/api/api-upgrade.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const { InvalidArgumentError, RequestAbortedError, SocketError } = require('../core/errors')
const { InvalidArgumentError, SocketError } = require('../core/errors')
const { AsyncResource } = require('node:async_hooks')
const util = require('../core/util')
const { addSignal, removeSignal } = require('./abort-signal')
Expand Down Expand Up @@ -34,10 +34,13 @@ class UpgradeHandler extends AsyncResource {
}

onConnect (abort, context) {
if (!this.callback) {
throw new RequestAbortedError()
if (this.reason) {
abort(this.reason)
return
}

assert(this.callback)

this.abort = abort
this.context = null
}
Expand Down
4 changes: 1 addition & 3 deletions deps/undici/src/lib/api/readable.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ class BodyReadable extends Readable {
// tick as it is created, then a user who is waiting for a
// promise (i.e micro tick) for installing a 'error' listener will
// never get a chance and will always encounter an unhandled exception.
// - tick => process.nextTick(fn)
// - micro tick => queueMicrotask(fn)
queueMicrotask(() => {
setImmediate(() => {
callback(err)
})
}
Expand Down
49 changes: 41 additions & 8 deletions deps/undici/src/lib/core/util.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict'

const assert = require('node:assert')
const { kDestroyed, kBodyUsed } = require('./symbols')
const { kDestroyed, kBodyUsed, kListeners } = require('./symbols')
const { IncomingMessage } = require('node:http')
const stream = require('node:stream')
const net = require('node:net')
Expand All @@ -22,13 +22,20 @@ function isStream (obj) {

// based on https://github.com/node-fetch/fetch-blob/blob/8ab587d34080de94140b54f07168451e7d0b655e/index.js#L229-L241 (MIT License)
function isBlobLike (object) {
return (Blob && object instanceof Blob) || (
object &&
typeof object === 'object' &&
(typeof object.stream === 'function' ||
typeof object.arrayBuffer === 'function') &&
/^(Blob|File)$/.test(object[Symbol.toStringTag])
)
if (object === null) {
return false
} else if (object instanceof Blob) {
return true
} else if (typeof object !== 'object') {
return false
} else {
const sTag = object[Symbol.toStringTag]

return (sTag === 'Blob' || sTag === 'File') && (
('stream' in object && typeof object.stream === 'function') ||
('arrayBuffer' in object && typeof object.arrayBuffer === 'function')
)
}
}

function buildURL (url, queryParams) {
Expand Down Expand Up @@ -534,6 +541,29 @@ function parseRangeHeader (range) {
: null
}

function addListener (obj, name, listener) {
const listeners = (obj[kListeners] ??= [])
listeners.push([name, listener])
obj.on(name, listener)
return obj
}

function removeAllListeners (obj) {
for (const [name, listener] of obj[kListeners] ?? []) {
obj.removeListener(name, listener)
}
obj[kListeners] = null
}

function errorRequest (client, request, err) {
try {
request.onError(err)
assert(request.aborted)
} catch (err) {
client.emit('error', err)
}
}

const kEnumerableProperty = Object.create(null)
kEnumerableProperty.enumerable = true

Expand All @@ -556,6 +586,9 @@ module.exports = {
isDestroyed,
headerNameToString,
bufferToLowerCasedHeaderName,
addListener,
removeAllListeners,
errorRequest,
parseRawHeaders,
parseHeaders,
parseKeepAliveTimeout,
Expand Down
Loading