Skip to content

Commit

Permalink
deps: update undici to 5.21.0
Browse files Browse the repository at this point in the history
PR-URL: #47063
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
  • Loading branch information
nodejs-github-bot authored and danielleadams committed Apr 11, 2023
1 parent e435199 commit 956f786
Show file tree
Hide file tree
Showing 23 changed files with 542 additions and 356 deletions.
2 changes: 1 addition & 1 deletion deps/undici/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ Refs: https://fetch.spec.whatwg.org/#atomic-http-redirect-handling

## Workarounds

### Network address family autoselection.
### Network address family autoselection.

If you experience problem when connecting to a remote server that is resolved by your DNS servers to a IPv6 (AAAA record)
first, there are chances that your local router or ISP might have problem connecting to IPv6 networks. In that case
Expand Down
4 changes: 3 additions & 1 deletion deps/undici/src/docs/api/ProxyAgent.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Extends: [`AgentOptions`](Agent.md#parameter-agentoptions)
* **uri** `string` (required) - It can be passed either by a string or a object containing `uri` as string.
* **token** `string` (optional) - It can be passed by a string of token for authentication.
* **auth** `string` (**deprecated**) - Use token.
* **clientFactory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Pool(origin, opts)`

Examples:

Expand Down Expand Up @@ -83,7 +84,8 @@ import { setGlobalDispatcher, request, ProxyAgent } from 'undici';

const proxyAgent = new ProxyAgent({
uri: 'my.proxy.server',
token: 'Bearer xxxx'
// token: 'Bearer xxxx'
token: `Basic ${Buffer.from('username:password').toString('base64')}`
});
setGlobalDispatcher(proxyAgent);

Expand Down
38 changes: 33 additions & 5 deletions deps/undici/src/lib/api/api-stream.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
'use strict'

const { finished } = require('stream')
const { finished, PassThrough } = require('stream')
const {
InvalidArgumentError,
InvalidReturnValueError,
RequestAbortedError
RequestAbortedError,
ResponseStatusCodeError
} = require('../core/errors')
const util = require('../core/util')
const { AsyncResource } = require('async_hooks')
Expand All @@ -16,7 +17,7 @@ class StreamHandler extends AsyncResource {
throw new InvalidArgumentError('invalid opts')
}

const { signal, method, opaque, body, onInfo, responseHeaders } = opts
const { signal, method, opaque, body, onInfo, responseHeaders, throwOnError } = opts

try {
if (typeof callback !== 'function') {
Expand Down Expand Up @@ -57,6 +58,7 @@ class StreamHandler extends AsyncResource {
this.trailers = null
this.body = body
this.onInfo = onInfo || null
this.throwOnError = throwOnError || false

if (util.isStream(body)) {
body.on('error', (err) => {
Expand All @@ -76,8 +78,8 @@ class StreamHandler extends AsyncResource {
this.context = context
}

onHeaders (statusCode, rawHeaders, resume) {
const { factory, opaque, context } = this
onHeaders (statusCode, rawHeaders, resume, statusMessage) {
const { factory, opaque, context, callback } = this

if (statusCode < 200) {
if (this.onInfo) {
Expand All @@ -96,6 +98,32 @@ class StreamHandler extends AsyncResource {
context
})

if (this.throwOnError && statusCode >= 400) {
const headers = this.responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders)
const chunks = []
const pt = new PassThrough()
pt
.on('data', (chunk) => chunks.push(chunk))
.on('end', () => {
const payload = Buffer.concat(chunks).toString('utf8')
this.runInAsyncScope(
callback,
null,
new ResponseStatusCodeError(
`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`,
statusCode,
headers,
payload
)
)
})
.on('error', (err) => {
this.onError(err)
})
this.res = pt
return
}

if (
!res ||
typeof res.write !== 'function' ||
Expand Down
20 changes: 18 additions & 2 deletions deps/undici/src/lib/api/readable.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

const assert = require('assert')
const { Readable } = require('stream')
const { RequestAbortedError, NotSupportedError } = require('../core/errors')
const { RequestAbortedError, NotSupportedError, InvalidArgumentError } = require('../core/errors')
const util = require('../core/util')
const { ReadableStreamFrom, toUSVString } = require('../core/util')

Expand Down Expand Up @@ -146,15 +146,31 @@ module.exports = class BodyReadable extends Readable {

async dump (opts) {
let limit = opts && Number.isFinite(opts.limit) ? opts.limit : 262144
const signal = opts && opts.signal
const abortFn = () => {
this.destroy()
}
if (signal) {
if (typeof signal !== 'object' || !('aborted' in signal)) {
throw new InvalidArgumentError('signal must be an AbortSignal')
}
util.throwIfAborted(signal)
signal.addEventListener('abort', abortFn, { once: true })
}
try {
for await (const chunk of this) {
util.throwIfAborted(signal)
limit -= Buffer.byteLength(chunk)
if (limit < 0) {
return
}
}
} catch {
// Do nothing...
util.throwIfAborted(signal)
} finally {
if (signal) {
signal.removeEventListener('abort', abortFn)
}
}
}
}
Expand Down
14 changes: 14 additions & 0 deletions deps/undici/src/lib/client.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// @ts-check

'use strict'

/* global WebAssembly */
Expand Down Expand Up @@ -85,7 +87,15 @@ try {
channels.connected = { hasSubscribers: false }
}

/**
* @type {import('../types/client').default}
*/
class Client extends DispatcherBase {
/**
*
* @param {string|URL} url
* @param {import('../types/client').Client.Options} options
*/
constructor (url, {
interceptors,
maxHeaderSize,
Expand Down Expand Up @@ -1658,6 +1668,8 @@ class AsyncWriter {
process.emitWarning(new RequestContentLengthMismatchError())
}

socket.cork()

if (bytesWritten === 0) {
if (!expectsPayload) {
socket[kReset] = true
Expand All @@ -1678,6 +1690,8 @@ class AsyncWriter {

const ret = socket.write(chunk)

socket.uncork()

request.onBodySent(chunk)

if (!ret) {
Expand Down
48 changes: 33 additions & 15 deletions deps/undici/src/lib/core/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(v => Number(
function nop () {}

function isStream (obj) {
return obj && typeof obj.pipe === 'function'
return obj && typeof obj === 'object' && typeof obj.pipe === 'function' && typeof obj.on === 'function'
}

// based on https://github.com/node-fetch/fetch-blob/blob/8ab587d34080de94140b54f07168451e7d0b655e/index.js#L229-L241 (MIT License)
Expand Down Expand Up @@ -46,6 +46,12 @@ function buildURL (url, queryParams) {
function parseURL (url) {
if (typeof url === 'string') {
url = new URL(url)

if (!/^https?:/.test(url.origin || url.protocol)) {
throw new InvalidArgumentError('invalid protocol')
}

return url
}

if (!url || typeof url !== 'object') {
Expand Down Expand Up @@ -375,23 +381,34 @@ function ReadableStreamFrom (iterable) {

// The chunk should be a FormData instance and contains
// all the required methods.
function isFormDataLike (chunk) {
return (chunk &&
chunk.constructor && chunk.constructor.name === 'FormData' &&
typeof chunk === 'object' &&
(typeof chunk.append === 'function' &&
typeof chunk.delete === 'function' &&
typeof chunk.get === 'function' &&
typeof chunk.getAll === 'function' &&
typeof chunk.has === 'function' &&
typeof chunk.set === 'function' &&
typeof chunk.entries === 'function' &&
typeof chunk.keys === 'function' &&
typeof chunk.values === 'function' &&
typeof chunk.forEach === 'function')
function isFormDataLike (object) {
return (
object &&
typeof object === 'object' &&
typeof object.append === 'function' &&
typeof object.delete === 'function' &&
typeof object.get === 'function' &&
typeof object.getAll === 'function' &&
typeof object.has === 'function' &&
typeof object.set === 'function' &&
object[Symbol.toStringTag] === 'FormData'
)
}

function throwIfAborted (signal) {
if (!signal) { return }
if (typeof signal.throwIfAborted === 'function') {
signal.throwIfAborted()
} else {
if (signal.aborted) {
// DOMException not available < v17.0.0
const err = new Error('The operation was aborted')
err.name = 'AbortError'
throw err
}
}
}

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

Expand Down Expand Up @@ -423,6 +440,7 @@ module.exports = {
getSocketInfo,
isFormDataLike,
buildURL,
throwIfAborted,
nodeMajor,
nodeMinor,
nodeHasAutoSelectFamily: nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 13)
Expand Down
13 changes: 11 additions & 2 deletions deps/undici/src/lib/fetch/dataURL.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const assert = require('assert')
const { atob } = require('buffer')
const { format } = require('url')
const { isValidHTTPToken, isomorphicDecode } = require('./util')

const encoder = new TextEncoder()
Expand Down Expand Up @@ -118,7 +117,17 @@ function dataURLProcessor (dataURL) {
* @param {boolean} excludeFragment
*/
function URLSerializer (url, excludeFragment = false) {
return format(url, { fragment: !excludeFragment })
const href = url.href

if (!excludeFragment) {
return href
}

const hash = href.lastIndexOf('#')
if (hash === -1) {
return href
}
return href.slice(0, hash)
}

// https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points
Expand Down
2 changes: 1 addition & 1 deletion deps/undici/src/lib/fetch/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ function finalizeAndReportTiming (response, initiatorType = 'other') {
// capability.
// TODO: given global’s relevant settings object’s cross-origin isolated
// capability?
response.timingInfo.endTime = coarsenedSharedCurrentTime()
timingInfo.endTime = coarsenedSharedCurrentTime()

// 10. Set response’s timing info to timingInfo.
response.timingInfo = timingInfo
Expand Down
24 changes: 16 additions & 8 deletions deps/undici/src/lib/fetch/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const util = require('../core/util')
const {
isValidHTTPToken,
sameOrigin,
normalizeMethod
normalizeMethod,
makePolicyContainer
} = require('./util')
const {
forbiddenMethods,
Expand Down Expand Up @@ -51,10 +52,14 @@ class Request {
input = webidl.converters.RequestInfo(input)
init = webidl.converters.RequestInit(init)

// TODO
// https://html.spec.whatwg.org/multipage/webappapis.html#environment-settings-object
this[kRealm] = {
settingsObject: {
baseUrl: getGlobalOrigin()
baseUrl: getGlobalOrigin(),
get origin () {
return this.baseUrl?.origin
},
policyContainer: makePolicyContainer()
}
}

Expand Down Expand Up @@ -349,14 +354,17 @@ class Request {
if (signal.aborted) {
ac.abort(signal.reason)
} else {
const acRef = new WeakRef(ac)
const abort = function () {
acRef.deref()?.abort(this.reason)
ac.abort(this.reason)
}

if (getEventListeners(signal, 'abort').length >= defaultMaxListeners) {
setMaxListeners(100, signal)
}
// Third-party AbortControllers may not work with these.
// See https://github.com/nodejs/undici/pull/1910#issuecomment-1464495619
try {
if (getEventListeners(signal, 'abort').length >= defaultMaxListeners) {
setMaxListeners(100, signal)
}
} catch {}

signal.addEventListener('abort', abort, { once: true })
requestFinalizer.register(this, { signal, abort })
Expand Down
Loading

0 comments on commit 956f786

Please sign in to comment.