Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 6c8456d

Browse files
nodejs-github-botMoLow
authored andcommittedJul 6, 2023
deps: update undici to 5.21.1
PR-URL: nodejs#47488 Reviewed-By: Debadree Chatterjee <debadree333@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
1 parent bd1eb14 commit 6c8456d

12 files changed

+196
-94
lines changed
 

‎deps/undici/src/lib/core/symbols.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ module.exports = {
4141
kClient: Symbol('client'),
4242
kParser: Symbol('parser'),
4343
kOnDestroyed: Symbol('destroy callbacks'),
44-
kPipelining: Symbol('pipelinig'),
44+
kPipelining: Symbol('pipelining'),
4545
kSocket: Symbol('socket'),
4646
kHostHeader: Symbol('host header'),
4747
kConnector: Symbol('connector'),

‎deps/undici/src/lib/core/util.js

+24-9
Original file line numberDiff line numberDiff line change
@@ -48,38 +48,38 @@ function parseURL (url) {
4848
url = new URL(url)
4949

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

5454
return url
5555
}
5656

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

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

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

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

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

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

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

8585
if (!(url instanceof URL)) {
@@ -409,6 +409,21 @@ function throwIfAborted (signal) {
409409
}
410410
}
411411

412+
const hasToWellFormed = !!String.prototype.toWellFormed
413+
414+
/**
415+
* @param {string} val
416+
*/
417+
function toUSVString (val) {
418+
if (hasToWellFormed) {
419+
return `${val}`.toWellFormed()
420+
} else if (nodeUtil.toUSVString) {
421+
return nodeUtil.toUSVString(val)
422+
}
423+
424+
return `${val}`
425+
}
426+
412427
const kEnumerableProperty = Object.create(null)
413428
kEnumerableProperty.enumerable = true
414429

@@ -418,7 +433,7 @@ module.exports = {
418433
isDisturbed,
419434
isErrored,
420435
isReadable,
421-
toUSVString: nodeUtil.toUSVString || ((val) => `${val}`),
436+
toUSVString,
422437
isReadableAborted,
423438
isBlobLike,
424439
parseOrigin,

‎deps/undici/src/lib/fetch/constants.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,17 @@ const requestCache = [
4848
'only-if-cached'
4949
]
5050

51+
// https://fetch.spec.whatwg.org/#request-body-header-name
5152
const requestBodyHeader = [
5253
'content-encoding',
5354
'content-language',
5455
'content-location',
55-
'content-type'
56+
'content-type',
57+
// See https://github.com/nodejs/undici/issues/2021
58+
// 'Content-Length' is a forbidden header name, which is typically
59+
// removed in the Headers implementation. However, undici doesn't
60+
// filter out headers, so we add it here.
61+
'content-length'
5662
]
5763

5864
// https://fetch.spec.whatwg.org/#enumdef-requestduplex

‎deps/undici/src/lib/fetch/formdata.js

+1-8
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,7 @@ class FormData {
6161

6262
// The delete(name) method steps are to remove all entries whose name
6363
// is name from this’s entry list.
64-
const next = []
65-
for (const entry of this[kState]) {
66-
if (entry.name !== name) {
67-
next.push(entry)
68-
}
69-
}
70-
71-
this[kState] = next
64+
this[kState] = this[kState].filter(entry => entry.name !== name)
7265
}
7366

7467
get (name) {

‎deps/undici/src/lib/fetch/index.js

+22-14
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ const {
3737
isErrorLike,
3838
fullyReadBody,
3939
readableStreamClose,
40-
isomorphicEncode
40+
isomorphicEncode,
41+
urlIsLocal,
42+
urlIsHttpHttpsScheme,
43+
urlHasHttpsScheme
4144
} = require('./util')
4245
const { kState, kHeaders, kGuard, kRealm, kHeadersCaseInsensitive } = require('./symbols')
4346
const assert = require('assert')
@@ -272,7 +275,7 @@ function finalizeAndReportTiming (response, initiatorType = 'other') {
272275
let cacheState = response.cacheState
273276

274277
// 6. If originalURL’s scheme is not an HTTP(S) scheme, then return.
275-
if (!/^https?:/.test(originalURL.protocol)) {
278+
if (!urlIsHttpHttpsScheme(originalURL)) {
276279
return
277280
}
278281

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

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

@@ -623,7 +623,7 @@ async function mainFetch (fetchParams, recursive = false) {
623623
}
624624

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

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

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

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

@@ -1859,6 +1860,10 @@ async function httpNetworkFetch (
18591860
bytes = undefined
18601861
} else {
18611862
bytes = err
1863+
1864+
// err may be propagated from the result of calling readablestream.cancel,
1865+
// which might not be an error. https://github.com/nodejs/undici/issues/2009
1866+
isFailure = true
18621867
}
18631868
}
18641869

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

18801885
// 6. If bytes is failure, then terminate fetchParams’s controller.
1881-
if (isErrorLike(bytes)) {
1886+
if (isFailure) {
18821887
fetchParams.controller.terminate(bytes)
18831888
return
18841889
}
@@ -1979,7 +1984,9 @@ async function httpNetworkFetch (
19791984
const val = headersList[n + 1].toString('latin1')
19801985

19811986
if (key.toLowerCase() === 'content-encoding') {
1982-
codings = val.split(',').map((x) => x.trim())
1987+
// https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.1
1988+
// "All content-coding values are case-insensitive..."
1989+
codings = val.toLowerCase().split(',').map((x) => x.trim())
19831990
} else if (key.toLowerCase() === 'location') {
19841991
location = val
19851992
}
@@ -1998,9 +2005,10 @@ async function httpNetworkFetch (
19982005
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
19992006
if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) {
20002007
for (const coding of codings) {
2001-
if (/(x-)?gzip/.test(coding)) {
2008+
// https://www.rfc-editor.org/rfc/rfc9112.html#section-7.2
2009+
if (coding === 'x-gzip' || coding === 'gzip') {
20022010
decoders.push(zlib.createGunzip())
2003-
} else if (/(x-)?deflate/.test(coding)) {
2011+
} else if (coding === 'deflate') {
20042012
decoders.push(zlib.createInflate())
20052013
} else if (coding === 'br') {
20062014
decoders.push(zlib.createBrotliDecompress())

‎deps/undici/src/lib/fetch/request.js

+18-7
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const { setMaxListeners, getEventListeners, defaultMaxListeners } = require('eve
3434
let TransformStream = globalThis.TransformStream
3535

3636
const kInit = Symbol('init')
37+
const kAbortController = Symbol('abortController')
3738

3839
const requestFinalizer = new FinalizationRegistry(({ signal, abort }) => {
3940
signal.removeEventListener('abort', abort)
@@ -128,12 +129,12 @@ class Request {
128129
}
129130

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

135136
// 11. If init["window"] exists, then set window to "no-window".
136-
if (init.window !== undefined) {
137+
if ('window' in init) {
137138
window = 'no-window'
138139
}
139140

@@ -354,20 +355,30 @@ class Request {
354355
if (signal.aborted) {
355356
ac.abort(signal.reason)
356357
} else {
358+
// Keep a strong ref to ac while request object
359+
// is alive. This is needed to prevent AbortController
360+
// from being prematurely garbage collected.
361+
// See, https://github.com/nodejs/undici/issues/1926.
362+
this[kAbortController] = ac
363+
364+
const acRef = new WeakRef(ac)
357365
const abort = function () {
358-
ac.abort(this.reason)
366+
const ac = acRef.deref()
367+
if (ac !== undefined) {
368+
ac.abort(this.reason)
369+
}
359370
}
360371

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

369380
signal.addEventListener('abort', abort, { once: true })
370-
requestFinalizer.register(this, { signal, abort })
381+
requestFinalizer.register(ac, { signal, abort })
371382
}
372383
}
373384

@@ -427,7 +438,7 @@ class Request {
427438
// non-null, and request’s method is `GET` or `HEAD`, then throw a
428439
// TypeError.
429440
if (
430-
((init.body !== undefined && init.body != null) || inputBody != null) &&
441+
(init.body != null || inputBody != null) &&
431442
(request.method === 'GET' || request.method === 'HEAD')
432443
) {
433444
throw new TypeError('Request with GET/HEAD method cannot have body.')
@@ -437,7 +448,7 @@ class Request {
437448
let initBody = null
438449

439450
// 36. If init["body"] exists and is non-null, then:
440-
if (init.body !== undefined && init.body != null) {
451+
if (init.body != null) {
441452
// 1. Let Content-Type be null.
442453
// 2. Set initBody and Content-Type to the result of extracting
443454
// init["body"], with keepalive set to request’s keepalive.

‎deps/undici/src/lib/fetch/response.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -348,9 +348,7 @@ function makeNetworkError (reason) {
348348
status: 0,
349349
error: isError
350350
? reason
351-
: new Error(reason ? String(reason) : reason, {
352-
cause: isError ? reason : undefined
353-
}),
351+
: new Error(reason ? String(reason) : reason),
354352
aborted: reason && reason.name === 'AbortError'
355353
})
356354
}

‎deps/undici/src/lib/fetch/util.js

+41-3
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ function requestBadPort (request) {
6464

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

@@ -285,7 +285,7 @@ function appendRequestOriginHeader (request) {
285285
case 'strict-origin':
286286
case 'strict-origin-when-cross-origin':
287287
// 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`.
288-
if (/^https:/.test(request.origin) && !/^https:/.test(requestCurrentURL(request))) {
288+
if (request.origin && urlHasHttpsScheme(request.origin) && !urlHasHttpsScheme(requestCurrentURL(request))) {
289289
serializedOrigin = null
290290
}
291291
break
@@ -944,6 +944,41 @@ async function readAllBytes (reader, successSteps, failureSteps) {
944944
}
945945
}
946946

947+
/**
948+
* @see https://fetch.spec.whatwg.org/#is-local
949+
* @param {URL} url
950+
*/
951+
function urlIsLocal (url) {
952+
assert('protocol' in url) // ensure it's a url object
953+
954+
const protocol = url.protocol
955+
956+
return protocol === 'about:' || protocol === 'blob:' || protocol === 'data:'
957+
}
958+
959+
/**
960+
* @param {string|URL} url
961+
*/
962+
function urlHasHttpsScheme (url) {
963+
if (typeof url === 'string') {
964+
return url.startsWith('https:')
965+
}
966+
967+
return url.protocol === 'https:'
968+
}
969+
970+
/**
971+
* @see https://fetch.spec.whatwg.org/#http-scheme
972+
* @param {URL} url
973+
*/
974+
function urlIsHttpHttpsScheme (url) {
975+
assert('protocol' in url) // ensure it's a url object
976+
977+
const protocol = url.protocol
978+
979+
return protocol === 'http:' || protocol === 'https:'
980+
}
981+
947982
/**
948983
* Fetch supports node >= 16.8.0, but Object.hasOwn was added in v16.9.0.
949984
*/
@@ -988,5 +1023,8 @@ module.exports = {
9881023
isReadableStreamLike,
9891024
readableStreamClose,
9901025
isomorphicEncode,
991-
isomorphicDecode
1026+
isomorphicDecode,
1027+
urlIsLocal,
1028+
urlHasHttpsScheme,
1029+
urlIsHttpHttpsScheme
9921030
}

0 commit comments

Comments
 (0)
Please sign in to comment.