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 5.21.1 #47488

Merged
merged 1 commit into from
Apr 11, 2023
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
2 changes: 1 addition & 1 deletion deps/undici/src/lib/core/symbols.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ module.exports = {
kClient: Symbol('client'),
kParser: Symbol('parser'),
kOnDestroyed: Symbol('destroy callbacks'),
kPipelining: Symbol('pipelinig'),
kPipelining: Symbol('pipelining'),
kSocket: Symbol('socket'),
kHostHeader: Symbol('host header'),
kConnector: Symbol('connector'),
Expand Down
33 changes: 24 additions & 9 deletions deps/undici/src/lib/core/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,38 +48,38 @@ function parseURL (url) {
url = new URL(url)

if (!/^https?:/.test(url.origin || url.protocol)) {
throw new InvalidArgumentError('invalid protocol')
throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.')
}

return url
}

if (!url || typeof url !== 'object') {
throw new InvalidArgumentError('invalid url')
throw new InvalidArgumentError('Invalid URL: The URL argument must be a non-null object.')
}

if (url.port != null && url.port !== '' && !Number.isFinite(parseInt(url.port))) {
throw new InvalidArgumentError('invalid port')
throw new InvalidArgumentError('Invalid URL: port must be a valid integer or a string representation of an integer.')
}

if (url.path != null && typeof url.path !== 'string') {
throw new InvalidArgumentError('invalid path')
throw new InvalidArgumentError('Invalid URL path: the path must be a string or null/undefined.')
}

if (url.pathname != null && typeof url.pathname !== 'string') {
throw new InvalidArgumentError('invalid pathname')
throw new InvalidArgumentError('Invalid URL pathname: the pathname must be a string or null/undefined.')
}

if (url.hostname != null && typeof url.hostname !== 'string') {
throw new InvalidArgumentError('invalid hostname')
throw new InvalidArgumentError('Invalid URL hostname: the hostname must be a string or null/undefined.')
}

if (url.origin != null && typeof url.origin !== 'string') {
throw new InvalidArgumentError('invalid origin')
throw new InvalidArgumentError('Invalid URL origin: the origin must be a string or null/undefined.')
}

if (!/^https?:/.test(url.origin || url.protocol)) {
throw new InvalidArgumentError('invalid protocol')
throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.')
}

if (!(url instanceof URL)) {
Expand Down Expand Up @@ -409,6 +409,21 @@ function throwIfAborted (signal) {
}
}

const hasToWellFormed = !!String.prototype.toWellFormed

/**
* @param {string} val
*/
function toUSVString (val) {
if (hasToWellFormed) {
return `${val}`.toWellFormed()
} else if (nodeUtil.toUSVString) {
return nodeUtil.toUSVString(val)
}

return `${val}`
}

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

Expand All @@ -418,7 +433,7 @@ module.exports = {
isDisturbed,
isErrored,
isReadable,
toUSVString: nodeUtil.toUSVString || ((val) => `${val}`),
toUSVString,
isReadableAborted,
isBlobLike,
parseOrigin,
Expand Down
8 changes: 7 additions & 1 deletion deps/undici/src/lib/fetch/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,17 @@ const requestCache = [
'only-if-cached'
]

// https://fetch.spec.whatwg.org/#request-body-header-name
const requestBodyHeader = [
'content-encoding',
'content-language',
'content-location',
'content-type'
'content-type',
// See https://github.com/nodejs/undici/issues/2021
// 'Content-Length' is a forbidden header name, which is typically
// removed in the Headers implementation. However, undici doesn't
// filter out headers, so we add it here.
'content-length'
]

// https://fetch.spec.whatwg.org/#enumdef-requestduplex
Expand Down
9 changes: 1 addition & 8 deletions deps/undici/src/lib/fetch/formdata.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,7 @@ class FormData {

// The delete(name) method steps are to remove all entries whose name
// is name from this’s entry list.
const next = []
for (const entry of this[kState]) {
if (entry.name !== name) {
next.push(entry)
}
}

this[kState] = next
this[kState] = this[kState].filter(entry => entry.name !== name)
}

get (name) {
Expand Down
36 changes: 22 additions & 14 deletions deps/undici/src/lib/fetch/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ const {
isErrorLike,
fullyReadBody,
readableStreamClose,
isomorphicEncode
isomorphicEncode,
urlIsLocal,
urlIsHttpHttpsScheme,
urlHasHttpsScheme
} = require('./util')
const { kState, kHeaders, kGuard, kRealm, kHeadersCaseInsensitive } = require('./symbols')
const assert = require('assert')
Expand Down Expand Up @@ -272,7 +275,7 @@ function finalizeAndReportTiming (response, initiatorType = 'other') {
let cacheState = response.cacheState

// 6. If originalURL’s scheme is not an HTTP(S) scheme, then return.
if (!/^https?:/.test(originalURL.protocol)) {
if (!urlIsHttpHttpsScheme(originalURL)) {
return
}

Expand Down Expand Up @@ -530,10 +533,7 @@ async function mainFetch (fetchParams, recursive = false) {

// 3. If request’s local-URLs-only flag is set and request’s current URL is
// not local, then set response to a network error.
if (
request.localURLsOnly &&
!/^(about|blob|data):/.test(requestCurrentURL(request).protocol)
) {
if (request.localURLsOnly && !urlIsLocal(requestCurrentURL(request))) {
response = makeNetworkError('local URLs only')
}

Expand Down Expand Up @@ -623,7 +623,7 @@ async function mainFetch (fetchParams, recursive = false) {
}

// request’s current URL’s scheme is not an HTTP(S) scheme
if (!/^https?:/.test(requestCurrentURL(request).protocol)) {
if (!urlIsHttpHttpsScheme(requestCurrentURL(request))) {
// Return a network error.
return makeNetworkError('URL scheme must be a HTTP(S) scheme')
}
Expand Down Expand Up @@ -1130,7 +1130,7 @@ async function httpRedirectFetch (fetchParams, response) {

// 6. If locationURL’s scheme is not an HTTP(S) scheme, then return a network
// error.
if (!/^https?:/.test(locationURL.protocol)) {
if (!urlIsHttpHttpsScheme(locationURL)) {
return makeNetworkError('URL scheme must be a HTTP(S) scheme')
}

Expand Down Expand Up @@ -1205,7 +1205,7 @@ async function httpRedirectFetch (fetchParams, response) {
// 14. If request’s body is non-null, then set request’s body to the first return
// value of safely extracting request’s body’s source.
if (request.body != null) {
assert(request.body.source)
assert(request.body.source != null)
request.body = safelyExtractBody(request.body.source)[0]
}

Expand Down Expand Up @@ -1399,7 +1399,7 @@ async function httpNetworkOrCacheFetch (
// header if httpRequest’s header list contains that header’s name.
// TODO: https://github.com/whatwg/fetch/issues/1285#issuecomment-896560129
if (!httpRequest.headersList.contains('accept-encoding')) {
if (/^https:/.test(requestCurrentURL(httpRequest).protocol)) {
if (urlHasHttpsScheme(requestCurrentURL(httpRequest))) {
httpRequest.headersList.append('accept-encoding', 'br, gzip, deflate')
} else {
httpRequest.headersList.append('accept-encoding', 'gzip, deflate')
Expand Down Expand Up @@ -1845,6 +1845,7 @@ async function httpNetworkFetch (
// 4. Set bytes to the result of handling content codings given
// codings and bytes.
let bytes
let isFailure
try {
const { done, value } = await fetchParams.controller.next()

Expand All @@ -1859,6 +1860,10 @@ async function httpNetworkFetch (
bytes = undefined
} else {
bytes = err

// err may be propagated from the result of calling readablestream.cancel,
// which might not be an error. https://github.com/nodejs/undici/issues/2009
isFailure = true
}
}

Expand All @@ -1878,7 +1883,7 @@ async function httpNetworkFetch (
timingInfo.decodedBodySize += bytes?.byteLength ?? 0

// 6. If bytes is failure, then terminate fetchParams’s controller.
if (isErrorLike(bytes)) {
if (isFailure) {
fetchParams.controller.terminate(bytes)
return
}
Expand Down Expand Up @@ -1979,7 +1984,9 @@ async function httpNetworkFetch (
const val = headersList[n + 1].toString('latin1')

if (key.toLowerCase() === 'content-encoding') {
codings = val.split(',').map((x) => x.trim())
// https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.1
// "All content-coding values are case-insensitive..."
codings = val.toLowerCase().split(',').map((x) => x.trim())
} else if (key.toLowerCase() === 'location') {
location = val
}
Expand All @@ -1998,9 +2005,10 @@ async function httpNetworkFetch (
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) {
for (const coding of codings) {
if (/(x-)?gzip/.test(coding)) {
// https://www.rfc-editor.org/rfc/rfc9112.html#section-7.2
if (coding === 'x-gzip' || coding === 'gzip') {
decoders.push(zlib.createGunzip())
} else if (/(x-)?deflate/.test(coding)) {
} else if (coding === 'deflate') {
decoders.push(zlib.createInflate())
} else if (coding === 'br') {
decoders.push(zlib.createBrotliDecompress())
Expand Down
25 changes: 18 additions & 7 deletions deps/undici/src/lib/fetch/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const { setMaxListeners, getEventListeners, defaultMaxListeners } = require('eve
let TransformStream = globalThis.TransformStream

const kInit = Symbol('init')
const kAbortController = Symbol('abortController')

const requestFinalizer = new FinalizationRegistry(({ signal, abort }) => {
signal.removeEventListener('abort', abort)
Expand Down Expand Up @@ -128,12 +129,12 @@ class Request {
}

// 10. If init["window"] exists and is non-null, then throw a TypeError.
if (init.window !== undefined && init.window != null) {
if (init.window != null) {
throw new TypeError(`'window' option '${window}' must be null`)
}

// 11. If init["window"] exists, then set window to "no-window".
if (init.window !== undefined) {
if ('window' in init) {
window = 'no-window'
}

Expand Down Expand Up @@ -354,20 +355,30 @@ class Request {
if (signal.aborted) {
ac.abort(signal.reason)
} else {
// Keep a strong ref to ac while request object
// is alive. This is needed to prevent AbortController
// from being prematurely garbage collected.
// See, https://github.com/nodejs/undici/issues/1926.
this[kAbortController] = ac

const acRef = new WeakRef(ac)
const abort = function () {
ac.abort(this.reason)
const ac = acRef.deref()
if (ac !== undefined) {
ac.abort(this.reason)
}
}

// Third-party AbortControllers may not work with these.
// See https://github.com/nodejs/undici/pull/1910#issuecomment-1464495619
// 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 })
requestFinalizer.register(ac, { signal, abort })
}
}

Expand Down Expand Up @@ -427,7 +438,7 @@ class Request {
// non-null, and request’s method is `GET` or `HEAD`, then throw a
// TypeError.
if (
((init.body !== undefined && init.body != null) || inputBody != null) &&
(init.body != null || inputBody != null) &&
(request.method === 'GET' || request.method === 'HEAD')
) {
throw new TypeError('Request with GET/HEAD method cannot have body.')
Expand All @@ -437,7 +448,7 @@ class Request {
let initBody = null

// 36. If init["body"] exists and is non-null, then:
if (init.body !== undefined && init.body != null) {
if (init.body != null) {
// 1. Let Content-Type be null.
// 2. Set initBody and Content-Type to the result of extracting
// init["body"], with keepalive set to request’s keepalive.
Expand Down
4 changes: 1 addition & 3 deletions deps/undici/src/lib/fetch/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -348,9 +348,7 @@ function makeNetworkError (reason) {
status: 0,
error: isError
? reason
: new Error(reason ? String(reason) : reason, {
cause: isError ? reason : undefined
}),
: new Error(reason ? String(reason) : reason),
aborted: reason && reason.name === 'AbortError'
})
}
Expand Down
44 changes: 41 additions & 3 deletions deps/undici/src/lib/fetch/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ function requestBadPort (request) {

// 2. If url’s scheme is an HTTP(S) scheme and url’s port is a bad port,
// then return blocked.
if (/^https?:/.test(url.protocol) && badPorts.includes(url.port)) {
if (urlIsHttpHttpsScheme(url) && badPorts.includes(url.port)) {
return 'blocked'
}

Expand Down Expand Up @@ -285,7 +285,7 @@ function appendRequestOriginHeader (request) {
case 'strict-origin':
case 'strict-origin-when-cross-origin':
// If request’s origin is a tuple origin, its scheme is "https", and request’s current URL’s scheme is not "https", then set serializedOrigin to `null`.
if (/^https:/.test(request.origin) && !/^https:/.test(requestCurrentURL(request))) {
if (request.origin && urlHasHttpsScheme(request.origin) && !urlHasHttpsScheme(requestCurrentURL(request))) {
serializedOrigin = null
}
break
Expand Down Expand Up @@ -944,6 +944,41 @@ async function readAllBytes (reader, successSteps, failureSteps) {
}
}

/**
* @see https://fetch.spec.whatwg.org/#is-local
* @param {URL} url
*/
function urlIsLocal (url) {
assert('protocol' in url) // ensure it's a url object

const protocol = url.protocol

return protocol === 'about:' || protocol === 'blob:' || protocol === 'data:'
}

/**
* @param {string|URL} url
*/
function urlHasHttpsScheme (url) {
if (typeof url === 'string') {
return url.startsWith('https:')
}

return url.protocol === 'https:'
}

/**
* @see https://fetch.spec.whatwg.org/#http-scheme
* @param {URL} url
*/
function urlIsHttpHttpsScheme (url) {
assert('protocol' in url) // ensure it's a url object

const protocol = url.protocol

return protocol === 'http:' || protocol === 'https:'
}

/**
* Fetch supports node >= 16.8.0, but Object.hasOwn was added in v16.9.0.
*/
Expand Down Expand Up @@ -988,5 +1023,8 @@ module.exports = {
isReadableStreamLike,
readableStreamClose,
isomorphicEncode,
isomorphicDecode
isomorphicDecode,
urlIsLocal,
urlHasHttpsScheme,
urlIsHttpHttpsScheme
}
Loading