Skip to content

Commit 921ef9b

Browse files
deps: update undici to 5.4.0
PR-URL: #43262 Reviewed-By: Filip Skokan <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Richard Lau <[email protected]> Reviewed-By: Tobias Nießen <[email protected]> Reviewed-By: Darshan Sen <[email protected]>
1 parent 0ef81d1 commit 921ef9b

File tree

14 files changed

+79
-202
lines changed

14 files changed

+79
-202
lines changed

‎deps/undici/src/README.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,15 @@ const headers = await fetch(url)
288288
.then(res=>res.headers)
289289
```
290290

291+
##### Forbidden and Safelisted Header Names
292+
293+
*https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name
294+
*https://fetch.spec.whatwg.org/#forbidden-header-name
295+
*https://fetch.spec.whatwg.org/#forbidden-response-header-name
296+
*https://github.com/wintercg/fetch/issues/6
297+
298+
The [Fetch Standard](https://fetch.spec.whatwg.org) requires implementations to exclude certain headers from requests and responses. In browser environments, some headers are forbidden so the user agent remains in full control over them. In Undici, these constraints are removed to give more control to the user.
299+
291300
### `undici.upgrade([url, options]): Promise`
292301

293302
Upgrade to a different protocol. See [MDN - HTTP - Protocol upgrade mechanism](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism) for more details.

‎deps/undici/src/docs/api/MockPool.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ Returns: `MockInterceptor` corresponding to the input options.
5757
***method**`string | RegExp | (method: string) => boolean` - a matcher for the HTTP request method.
5858
***body**`string | RegExp | (body: string) => boolean` - (optional) - a matcher for the HTTP request body.
5959
***headers**`Record<string, string | RegExp | (body: string) => boolean`> - (optional) - a matcher for the HTTP request headers. To be intercepted, a request must match all defined headers. Extra headers not defined here may (or may not) be included in the request and do not affect the interception in any way.
60+
***query**`Record<string, any> | null` - (optional) - a matcher for the HTTP request query string params.
6061

6162
### Return: `MockInterceptor`
6263

‎deps/undici/src/lib/client.js‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,11 @@ class Parser{
873873
// have been queued since then.
874874
util.destroy(socket,newInformationalError('reset'))
875875
returnconstants.ERROR.PAUSED
876+
}elseif(client[kPipelining]===1){
877+
// We must wait a full event loop cycle to reuse this socket to make sure
878+
// that non-spec compliant servers are not closing the connection even if they
879+
// said they won't.
880+
setImmediate(resume,client)
876881
}else{
877882
resume(client)
878883
}

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

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,5 @@
11
'use strict'
22

3-
constforbiddenHeaderNames=[
4-
'accept-charset',
5-
'accept-encoding',
6-
'access-control-request-headers',
7-
'access-control-request-method',
8-
'connection',
9-
'content-length',
10-
'cookie',
11-
'cookie2',
12-
'date',
13-
'dnt',
14-
'expect',
15-
'host',
16-
'keep-alive',
17-
'origin',
18-
'referer',
19-
'te',
20-
'trailer',
21-
'transfer-encoding',
22-
'upgrade',
23-
'via'
24-
]
25-
263
constcorsSafeListedMethods=['GET','HEAD','POST']
274

285
constnullBodyStatus=[101,204,205,304]
@@ -58,9 +35,6 @@ const requestCache = [
5835
'only-if-cached'
5936
]
6037

61-
// https://fetch.spec.whatwg.org/#forbidden-response-header-name
62-
constforbiddenResponseHeaderNames=['set-cookie','set-cookie2']
63-
6438
constrequestBodyHeader=[
6539
'content-encoding',
6640
'content-language',
@@ -86,20 +60,15 @@ const subresource = [
8660
''
8761
]
8862

89-
constcorsSafeListedResponseHeaderNames=[]// TODO
90-
9163
module.exports={
9264
subresource,
93-
forbiddenResponseHeaderNames,
94-
corsSafeListedResponseHeaderNames,
9565
forbiddenMethods,
9666
requestBodyHeader,
9767
referrerPolicy,
9868
requestRedirect,
9969
requestMode,
10070
requestCredentials,
10171
requestCache,
102-
forbiddenHeaderNames,
10372
redirectStatus,
10473
corsSafeListedMethods,
10574
nullBodyStatus,

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,8 @@ function makeEntry (name, value, filename){
243243
// object, representing the same bytes, whose name attribute value is "blob".
244244
if(isBlobLike(value)&&!isFileLike(value)){
245245
value=valueinstanceofBlob
246-
? newFile([value],'blob')
247-
: newFileLike(value,'blob')
246+
? newFile([value],'blob',value)
247+
: newFileLike(value,'blob',value)
248248
}
249249

250250
// 4. If value is (now) a File object and filename is given, then set value to a
@@ -256,8 +256,8 @@ function makeEntry (name, value, filename){
256256
// creating one more File instance doesn't make much sense....
257257
if(isFileLike(value)&&filename!=null){
258258
value=valueinstanceofFile
259-
? newFile([value],filename)
260-
: newFileLike(value,filename)
259+
? newFile([value],filename,value)
260+
: newFileLike(value,filename,value)
261261
}
262262

263263
// 5. Set entry’s value to value.

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

Lines changed: 8 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ const{validateHeaderName, validateHeaderValue } = require('http')
66
const{ kHeadersList }=require('../core/symbols')
77
const{ kGuard }=require('./symbols')
88
const{ kEnumerableProperty }=require('../core/util')
9-
const{
10-
forbiddenHeaderNames,
11-
forbiddenResponseHeaderNames
12-
}=require('./constants')
139

1410
constkHeadersMap=Symbol('headers map')
1511
constkHeadersSortedMap=Symbol('headers map sorted')
@@ -115,6 +111,11 @@ class HeadersList{
115111
}
116112
}
117113

114+
clear(){
115+
this[kHeadersMap].clear()
116+
this[kHeadersSortedMap]=null
117+
}
118+
118119
append(name,value){
119120
this[kHeadersSortedMap]=null
120121

@@ -211,22 +212,11 @@ class Headers{
211212
)
212213
}
213214

214-
constnormalizedName=normalizeAndValidateHeaderName(String(name))
215-
215+
// Note: undici does not implement forbidden header names
216216
if(this[kGuard]==='immutable'){
217217
thrownewTypeError('immutable')
218-
}elseif(
219-
this[kGuard]==='request'&&
220-
forbiddenHeaderNames.includes(normalizedName)
221-
){
222-
return
223218
}elseif(this[kGuard]==='request-no-cors'){
224219
// TODO
225-
}elseif(
226-
this[kGuard]==='response'&&
227-
forbiddenResponseHeaderNames.includes(normalizedName)
228-
){
229-
return
230220
}
231221

232222
returnthis[kHeadersList].append(String(name),String(value))
@@ -244,22 +234,11 @@ class Headers{
244234
)
245235
}
246236

247-
constnormalizedName=normalizeAndValidateHeaderName(String(name))
248-
237+
// Note: undici does not implement forbidden header names
249238
if(this[kGuard]==='immutable'){
250239
thrownewTypeError('immutable')
251-
}elseif(
252-
this[kGuard]==='request'&&
253-
forbiddenHeaderNames.includes(normalizedName)
254-
){
255-
return
256240
}elseif(this[kGuard]==='request-no-cors'){
257241
// TODO
258-
}elseif(
259-
this[kGuard]==='response'&&
260-
forbiddenResponseHeaderNames.includes(normalizedName)
261-
){
262-
return
263242
}
264243

265244
returnthis[kHeadersList].delete(String(name))
@@ -307,20 +286,11 @@ class Headers{
307286
)
308287
}
309288

289+
// Note: undici does not implement forbidden header names
310290
if(this[kGuard]==='immutable'){
311291
thrownewTypeError('immutable')
312-
}elseif(
313-
this[kGuard]==='request'&&
314-
forbiddenHeaderNames.includes(String(name).toLocaleLowerCase())
315-
){
316-
return
317292
}elseif(this[kGuard]==='request-no-cors'){
318293
// TODO
319-
}elseif(
320-
this[kGuard]==='response'&&
321-
forbiddenResponseHeaderNames.includes(String(name).toLocaleLowerCase())
322-
){
323-
return
324294
}
325295

326296
returnthis[kHeadersList].set(String(name),String(value))

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,8 @@ class Request{
384384
// Realm, whose header list is request’s header list and guard is
385385
// "request".
386386
this[kHeaders]=newHeaders()
387-
this[kHeaders][kGuard]='request'
388387
this[kHeaders][kHeadersList]=request.headersList
388+
this[kHeaders][kGuard]='request'
389389
this[kHeaders][kRealm]=this[kRealm]
390390

391391
// 31. If this’s request’s mode is "no-cors", then:
@@ -406,26 +406,25 @@ class Request{
406406
if(Object.keys(init).length!==0){
407407
// 1. Let headers be a copy of this’s headers and its associated header
408408
// list.
409-
letheaders=newHeaders(this.headers)
409+
letheaders=newHeaders(this[kHeaders])
410410

411411
// 2. If init["headers"] exists, then set headers to init["headers"].
412412
if(init.headers!==undefined){
413413
headers=init.headers
414414
}
415415

416416
// 3. Empty this’s headers’s header list.
417-
this[kState].headersList=newHeadersList()
418-
this[kHeaders][kHeadersList]=this[kState].headersList
417+
this[kHeaders][kHeadersList].clear()
419418

420419
// 4. If headers is a Headers object, then for each header in its header
421420
// list, append header’s name/header’s value to this’s headers.
422421
if(headers.constructor.name==='Headers'){
423-
for(const[key,val]ofheaders[kHeadersList]||headers){
422+
for(const[key,val]ofheaders){
424423
this[kHeaders].append(key,val)
425424
}
426425
}else{
427426
// 5. Otherwise, fill this’s headers with headers.
428-
fillHeaders(this[kState].headersList,headers)
427+
fillHeaders(this[kHeaders],headers)
429428
}
430429
}
431430

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

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ const{kEnumerableProperty } = util
88
const{ responseURL, isValidReasonPhrase, toUSVString, isCancelled, isAborted, serializeJavascriptValueToJSONString }=require('./util')
99
const{
1010
redirectStatus,
11-
nullBodyStatus,
12-
forbiddenResponseHeaderNames,
13-
corsSafeListedResponseHeaderNames
11+
nullBodyStatus
1412
}=require('./constants')
1513
const{ kState, kHeaders, kGuard, kRealm }=require('./symbols')
1614
const{ kHeadersList }=require('../core/symbols')
@@ -380,28 +378,6 @@ function makeFilteredResponse (response, state){
380378
})
381379
}
382380

383-
functionmakeFilteredHeadersList(headersList,filter){
384-
returnnewProxy(headersList,{
385-
get(target,prop){
386-
// Override methods used by Headers class.
387-
if(prop==='get'||prop==='has'){
388-
constdefaultReturn=prop==='has' ? false : null
389-
return(name)=>filter(name) ? target[prop](name) : defaultReturn
390-
}elseif(prop===Symbol.iterator){
391-
returnfunction*(){
392-
for(constentryoftarget){
393-
if(filter(entry[0])){
394-
yieldentry
395-
}
396-
}
397-
}
398-
}else{
399-
returntarget[prop]
400-
}
401-
}
402-
})
403-
}
404-
405381
// https://fetch.spec.whatwg.org/#concept-filtered-response
406382
functionfilterResponse(response,type){
407383
// Set response to the following filtered response with response as its
@@ -411,22 +387,21 @@ function filterResponse (response, type){
411387
// and header list excludes any headers in internal response’s header list
412388
// whose name is a forbidden response-header name.
413389

390+
// Note: undici does not implement forbidden response-header names
414391
returnmakeFilteredResponse(response,{
415392
type: 'basic',
416-
headersList: makeFilteredHeadersList(
417-
response.headersList,
418-
(name)=>!forbiddenResponseHeaderNames.includes(name.toLowerCase())
419-
)
393+
headersList: response.headersList
420394
})
421395
}elseif(type==='cors'){
422396
// A CORS filtered response is a filtered response whose type is "cors"
423397
// and header list excludes any headers in internal response’s header
424398
// list whose name is not a CORS-safelisted response-header name, given
425399
// internal response’s CORS-exposed header-name list.
426400

401+
// Note: undici does not implement CORS-safelisted response-header names
427402
returnmakeFilteredResponse(response,{
428403
type: 'cors',
429-
headersList: makeFilteredHeadersList(response.headersList,(name)=>!corsSafeListedResponseHeaderNames.includes(name))
404+
headersList: response.headersList
430405
})
431406
}elseif(type==='opaque'){
432407
// An opaque filtered response is a filtered response whose type is
@@ -449,7 +424,7 @@ function filterResponse (response, type){
449424
type: 'opaqueredirect',
450425
status: 0,
451426
statusText: '',
452-
headersList: makeFilteredHeadersList(response.headersList,()=>false),
427+
headersList: [],
453428
body: null
454429
})
455430
}else{

‎deps/undici/src/lib/mock/mock-interceptor.js‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const{
1010
kMockDispatch
1111
}=require('./mock-symbols')
1212
const{ InvalidArgumentError }=require('../core/errors')
13+
const{ buildURL }=require('../core/util')
1314

1415
/**
1516
* Defines the scope API for an interceptor reply
@@ -70,9 +71,13 @@ class MockInterceptor{
7071
// As per RFC 3986, clients are not supposed to send URI
7172
// fragments to servers when they retrieve a document,
7273
if(typeofopts.path==='string'){
73-
// Matches https://github.com/nodejs/undici/blob/main/lib/fetch/index.js#L1811
74-
constparsedURL=newURL(opts.path,'data://')
75-
opts.path=parsedURL.pathname+parsedURL.search
74+
if(opts.query){
75+
opts.path=buildURL(opts.path,opts.query)
76+
}else{
77+
// Matches https://github.com/nodejs/undici/blob/main/lib/fetch/index.js#L1811
78+
constparsedURL=newURL(opts.path,'data://')
79+
opts.path=parsedURL.pathname+parsedURL.search
80+
}
7681
}
7782
if(typeofopts.method==='string'){
7883
opts.method=opts.method.toUpperCase()

‎deps/undici/src/lib/mock/mock-utils.js‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const{
88
kOrigin,
99
kGetNetConnect
1010
}=require('./mock-symbols')
11+
const{ buildURL }=require('../core/util')
1112

1213
functionmatchValue(match,value){
1314
if(typeofmatch==='string'){
@@ -98,10 +99,12 @@ function getResponseData (data){
9899
}
99100

100101
functiongetMockDispatch(mockDispatches,key){
102+
constresolvedPath=key.query ? buildURL(key.path,key.query) : key.path
103+
101104
// Match path
102-
letmatchedMockDispatches=mockDispatches.filter(({ consumed })=>!consumed).filter(({ path })=>matchValue(path,key.path))
105+
letmatchedMockDispatches=mockDispatches.filter(({ consumed })=>!consumed).filter(({ path })=>matchValue(path,resolvedPath))
103106
if(matchedMockDispatches.length===0){
104-
thrownewMockNotMatchedError(`Mock dispatch not matched for path '${key.path}'`)
107+
thrownewMockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`)
105108
}
106109

107110
// Match method
@@ -146,12 +149,13 @@ function deleteMockDispatch (mockDispatches, key){
146149
}
147150

148151
functionbuildKey(opts){
149-
const{ path, method, body, headers }=opts
152+
const{ path, method, body, headers, query}=opts
150153
return{
151154
path,
152155
method,
153156
body,
154-
headers
157+
headers,
158+
query
155159
}
156160
}
157161

0 commit comments

Comments
(0)