Skip to content

Commit

Permalink
deps: update undici to 5.21.1
Browse files Browse the repository at this point in the history
PR-URL: #47488
Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
  • Loading branch information
nodejs-github-bot authored and MoLow committed Jul 6, 2023
1 parent bd1eb14 commit 6c8456d
Show file tree
Hide file tree
Showing 12 changed files with 196 additions and 94 deletions.
2 changes: 1 addition & 1 deletion deps/undici/src/lib/core/symbols.js
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
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
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
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
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
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
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
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
}

0 comments on commit 6c8456d

Please sign in to comment.