undici 6.20.0 → 7.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -10
- package/docs/docs/api/Agent.md +0 -3
- package/docs/docs/api/Client.md +1 -3
- package/docs/docs/api/Debug.md +1 -1
- package/docs/docs/api/Dispatcher.md +60 -8
- package/docs/docs/api/EnvHttpProxyAgent.md +0 -1
- package/docs/docs/api/Fetch.md +1 -0
- package/docs/docs/api/MockAgent.md +2 -0
- package/docs/docs/api/MockPool.md +2 -1
- package/docs/docs/api/Pool.md +0 -1
- package/docs/docs/api/RetryAgent.md +1 -1
- package/docs/docs/api/RetryHandler.md +1 -1
- package/docs/docs/api/WebSocket.md +45 -3
- package/index.js +6 -6
- package/lib/api/abort-signal.js +2 -0
- package/lib/api/api-connect.js +3 -1
- package/lib/api/api-pipeline.js +7 -6
- package/lib/api/api-request.js +32 -47
- package/lib/api/api-stream.js +39 -50
- package/lib/api/api-upgrade.js +5 -3
- package/lib/api/readable.js +261 -64
- package/lib/api/util.js +2 -0
- package/lib/core/constants.js +11 -9
- package/lib/core/diagnostics.js +122 -128
- package/lib/core/errors.js +4 -4
- package/lib/core/request.js +11 -9
- package/lib/core/symbols.js +2 -1
- package/lib/core/tree.js +9 -1
- package/lib/core/util.js +219 -48
- package/lib/dispatcher/agent.js +3 -17
- package/lib/dispatcher/balanced-pool.js +5 -8
- package/lib/dispatcher/client-h1.js +278 -54
- package/lib/dispatcher/client-h2.js +1 -1
- package/lib/dispatcher/client.js +23 -34
- package/lib/dispatcher/dispatcher-base.js +2 -34
- package/lib/dispatcher/dispatcher.js +3 -24
- package/lib/dispatcher/fixed-queue.js +91 -49
- package/lib/dispatcher/pool-stats.js +2 -0
- package/lib/dispatcher/pool.js +3 -6
- package/lib/dispatcher/proxy-agent.js +6 -7
- package/lib/handler/decorator-handler.js +24 -0
- package/lib/handler/redirect-handler.js +11 -2
- package/lib/handler/retry-handler.js +12 -3
- package/lib/interceptor/dns.js +346 -0
- package/lib/interceptor/dump.js +2 -2
- package/lib/interceptor/redirect.js +11 -14
- package/lib/interceptor/response-error.js +4 -1
- package/lib/llhttp/constants.d.ts +97 -0
- package/lib/llhttp/constants.js +412 -192
- package/lib/llhttp/constants.js.map +1 -0
- package/lib/llhttp/llhttp-wasm.js +11 -1
- package/lib/llhttp/llhttp_simd-wasm.js +11 -1
- package/lib/llhttp/utils.d.ts +2 -0
- package/lib/llhttp/utils.js +9 -9
- package/lib/llhttp/utils.js.map +1 -0
- package/lib/mock/mock-agent.js +5 -8
- package/lib/mock/mock-client.js +9 -4
- package/lib/mock/mock-errors.js +3 -1
- package/lib/mock/mock-interceptor.js +8 -6
- package/lib/mock/mock-pool.js +9 -4
- package/lib/mock/mock-symbols.js +3 -1
- package/lib/mock/mock-utils.js +29 -5
- package/lib/web/cache/cache.js +24 -21
- package/lib/web/cache/cachestorage.js +1 -1
- package/lib/web/cookies/index.js +17 -13
- package/lib/web/cookies/parse.js +2 -2
- package/lib/web/eventsource/eventsource-stream.js +9 -8
- package/lib/web/eventsource/eventsource.js +10 -6
- package/lib/web/fetch/body.js +42 -36
- package/lib/web/fetch/constants.js +35 -26
- package/lib/web/fetch/data-url.js +1 -1
- package/lib/web/fetch/formdata-parser.js +2 -2
- package/lib/web/fetch/formdata.js +65 -54
- package/lib/web/fetch/headers.js +117 -85
- package/lib/web/fetch/index.js +55 -62
- package/lib/web/fetch/request.js +135 -77
- package/lib/web/fetch/response.js +86 -56
- package/lib/web/fetch/util.js +90 -64
- package/lib/web/fetch/webidl.js +99 -64
- package/lib/web/websocket/connection.js +76 -147
- package/lib/web/websocket/constants.js +3 -4
- package/lib/web/websocket/events.js +4 -2
- package/lib/web/websocket/frame.js +45 -3
- package/lib/web/websocket/receiver.js +29 -33
- package/lib/web/websocket/sender.js +18 -13
- package/lib/web/websocket/stream/websocketerror.js +83 -0
- package/lib/web/websocket/stream/websocketstream.js +485 -0
- package/lib/web/websocket/util.js +128 -77
- package/lib/web/websocket/websocket.js +234 -135
- package/package.json +20 -33
- package/scripts/strip-comments.js +3 -1
- package/types/agent.d.ts +7 -7
- package/types/api.d.ts +24 -24
- package/types/balanced-pool.d.ts +11 -11
- package/types/client.d.ts +11 -12
- package/types/diagnostics-channel.d.ts +10 -10
- package/types/dispatcher.d.ts +96 -97
- package/types/env-http-proxy-agent.d.ts +2 -2
- package/types/errors.d.ts +53 -47
- package/types/fetch.d.ts +8 -8
- package/types/formdata.d.ts +7 -7
- package/types/global-dispatcher.d.ts +4 -4
- package/types/global-origin.d.ts +5 -5
- package/types/handlers.d.ts +4 -4
- package/types/header.d.ts +157 -1
- package/types/index.d.ts +42 -46
- package/types/interceptors.d.ts +22 -8
- package/types/mock-agent.d.ts +21 -18
- package/types/mock-client.d.ts +4 -4
- package/types/mock-errors.d.ts +3 -3
- package/types/mock-interceptor.d.ts +19 -19
- package/types/mock-pool.d.ts +4 -4
- package/types/patch.d.ts +0 -4
- package/types/pool-stats.d.ts +8 -8
- package/types/pool.d.ts +12 -12
- package/types/proxy-agent.d.ts +4 -4
- package/types/readable.d.ts +22 -14
- package/types/retry-agent.d.ts +1 -1
- package/types/retry-handler.d.ts +8 -8
- package/types/util.d.ts +3 -3
- package/types/utility.d.ts +7 -0
- package/types/webidl.d.ts +44 -6
- package/types/websocket.d.ts +34 -1
- package/docs/docs/api/DispatchInterceptor.md +0 -60
- package/lib/interceptor/redirect-interceptor.js +0 -21
- package/lib/mock/pluralizer.js +0 -29
- package/lib/web/cache/symbols.js +0 -5
- package/lib/web/fetch/file.js +0 -126
- package/lib/web/fetch/symbols.js +0 -9
- package/lib/web/fileapi/encoding.js +0 -290
- package/lib/web/fileapi/filereader.js +0 -344
- package/lib/web/fileapi/progressevent.js +0 -78
- package/lib/web/fileapi/symbols.js +0 -10
- package/lib/web/fileapi/util.js +0 -391
- package/lib/web/websocket/symbols.js +0 -12
- package/types/file.d.ts +0 -39
- package/types/filereader.d.ts +0 -54
package/lib/web/fetch/headers.js
CHANGED
|
@@ -13,19 +13,18 @@ const { webidl } = require('./webidl')
|
|
|
13
13
|
const assert = require('node:assert')
|
|
14
14
|
const util = require('node:util')
|
|
15
15
|
|
|
16
|
-
const kHeadersMap = Symbol('headers map')
|
|
17
|
-
const kHeadersSortedMap = Symbol('headers map sorted')
|
|
18
|
-
|
|
19
16
|
/**
|
|
20
17
|
* @param {number} code
|
|
18
|
+
* @returns {code is (0x0a | 0x0d | 0x09 | 0x20)}
|
|
21
19
|
*/
|
|
22
20
|
function isHTTPWhiteSpaceCharCode (code) {
|
|
23
|
-
return code ===
|
|
21
|
+
return code === 0x0a || code === 0x0d || code === 0x09 || code === 0x20
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
/**
|
|
27
25
|
* @see https://fetch.spec.whatwg.org/#concept-header-value-normalize
|
|
28
26
|
* @param {string} potentialValue
|
|
27
|
+
* @returns {string}
|
|
29
28
|
*/
|
|
30
29
|
function headerValueNormalize (potentialValue) {
|
|
31
30
|
// To normalize a byte sequence potentialValue, remove
|
|
@@ -39,6 +38,10 @@ function headerValueNormalize (potentialValue) {
|
|
|
39
38
|
return i === 0 && j === potentialValue.length ? potentialValue : potentialValue.substring(i, j)
|
|
40
39
|
}
|
|
41
40
|
|
|
41
|
+
/**
|
|
42
|
+
* @param {Headers} headers
|
|
43
|
+
* @param {Array|Object} object
|
|
44
|
+
*/
|
|
42
45
|
function fill (headers, object) {
|
|
43
46
|
// To fill a Headers object headers with a given object object, run these steps:
|
|
44
47
|
|
|
@@ -78,6 +81,9 @@ function fill (headers, object) {
|
|
|
78
81
|
|
|
79
82
|
/**
|
|
80
83
|
* @see https://fetch.spec.whatwg.org/#concept-headers-append
|
|
84
|
+
* @param {Headers} headers
|
|
85
|
+
* @param {string} name
|
|
86
|
+
* @param {string} value
|
|
81
87
|
*/
|
|
82
88
|
function appendHeader (headers, name, value) {
|
|
83
89
|
// 1. Normalize value.
|
|
@@ -119,6 +125,67 @@ function appendHeader (headers, name, value) {
|
|
|
119
125
|
// privileged no-CORS request headers from headers
|
|
120
126
|
}
|
|
121
127
|
|
|
128
|
+
// https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine
|
|
129
|
+
/**
|
|
130
|
+
* @param {Headers} target
|
|
131
|
+
*/
|
|
132
|
+
function headersListSortAndCombine (target) {
|
|
133
|
+
const headersList = getHeadersList(target)
|
|
134
|
+
|
|
135
|
+
if (!headersList) {
|
|
136
|
+
return []
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (headersList.sortedMap) {
|
|
140
|
+
return headersList.sortedMap
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 1. Let headers be an empty list of headers with the key being the name
|
|
144
|
+
// and value the value.
|
|
145
|
+
const headers = []
|
|
146
|
+
|
|
147
|
+
// 2. Let names be the result of convert header names to a sorted-lowercase
|
|
148
|
+
// set with all the names of the headers in list.
|
|
149
|
+
const names = headersList.toSortedArray()
|
|
150
|
+
|
|
151
|
+
const cookies = headersList.cookies
|
|
152
|
+
|
|
153
|
+
// fast-path
|
|
154
|
+
if (cookies === null || cookies.length === 1) {
|
|
155
|
+
// Note: The non-null assertion of value has already been done by `HeadersList#toSortedArray`
|
|
156
|
+
return (headersList.sortedMap = names)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 3. For each name of names:
|
|
160
|
+
for (let i = 0; i < names.length; ++i) {
|
|
161
|
+
const { 0: name, 1: value } = names[i]
|
|
162
|
+
// 1. If name is `set-cookie`, then:
|
|
163
|
+
if (name === 'set-cookie') {
|
|
164
|
+
// 1. Let values be a list of all values of headers in list whose name
|
|
165
|
+
// is a byte-case-insensitive match for name, in order.
|
|
166
|
+
|
|
167
|
+
// 2. For each value of values:
|
|
168
|
+
// 1. Append (name, value) to headers.
|
|
169
|
+
for (let j = 0; j < cookies.length; ++j) {
|
|
170
|
+
headers.push([name, cookies[j]])
|
|
171
|
+
}
|
|
172
|
+
} else {
|
|
173
|
+
// 2. Otherwise:
|
|
174
|
+
|
|
175
|
+
// 1. Let value be the result of getting name from list.
|
|
176
|
+
|
|
177
|
+
// 2. Assert: value is non-null.
|
|
178
|
+
// Note: This operation was done by `HeadersList#toSortedArray`.
|
|
179
|
+
|
|
180
|
+
// 3. Append (name, value) to headers.
|
|
181
|
+
headers.push([name, value])
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// 4. Return headers.
|
|
186
|
+
return (headersList.sortedMap = headers)
|
|
187
|
+
}
|
|
188
|
+
|
|
122
189
|
function compareHeaderName (a, b) {
|
|
123
190
|
return a[0] < b[0] ? -1 : 1
|
|
124
191
|
}
|
|
@@ -127,14 +194,17 @@ class HeadersList {
|
|
|
127
194
|
/** @type {[string, string][]|null} */
|
|
128
195
|
cookies = null
|
|
129
196
|
|
|
197
|
+
sortedMap
|
|
198
|
+
headersMap
|
|
199
|
+
|
|
130
200
|
constructor (init) {
|
|
131
201
|
if (init instanceof HeadersList) {
|
|
132
|
-
this
|
|
133
|
-
this
|
|
202
|
+
this.headersMap = new Map(init.headersMap)
|
|
203
|
+
this.sortedMap = init.sortedMap
|
|
134
204
|
this.cookies = init.cookies === null ? null : [...init.cookies]
|
|
135
205
|
} else {
|
|
136
|
-
this
|
|
137
|
-
this
|
|
206
|
+
this.headersMap = new Map(init)
|
|
207
|
+
this.sortedMap = null
|
|
138
208
|
}
|
|
139
209
|
}
|
|
140
210
|
|
|
@@ -148,12 +218,12 @@ class HeadersList {
|
|
|
148
218
|
// contains a header whose name is a byte-case-insensitive
|
|
149
219
|
// match for name.
|
|
150
220
|
|
|
151
|
-
return this
|
|
221
|
+
return this.headersMap.has(isLowerCase ? name : name.toLowerCase())
|
|
152
222
|
}
|
|
153
223
|
|
|
154
224
|
clear () {
|
|
155
|
-
this
|
|
156
|
-
this
|
|
225
|
+
this.headersMap.clear()
|
|
226
|
+
this.sortedMap = null
|
|
157
227
|
this.cookies = null
|
|
158
228
|
}
|
|
159
229
|
|
|
@@ -164,22 +234,22 @@ class HeadersList {
|
|
|
164
234
|
* @param {boolean} isLowerCase
|
|
165
235
|
*/
|
|
166
236
|
append (name, value, isLowerCase) {
|
|
167
|
-
this
|
|
237
|
+
this.sortedMap = null
|
|
168
238
|
|
|
169
239
|
// 1. If list contains name, then set name to the first such
|
|
170
240
|
// header’s name.
|
|
171
241
|
const lowercaseName = isLowerCase ? name : name.toLowerCase()
|
|
172
|
-
const exists = this
|
|
242
|
+
const exists = this.headersMap.get(lowercaseName)
|
|
173
243
|
|
|
174
244
|
// 2. Append (name, value) to list.
|
|
175
245
|
if (exists) {
|
|
176
246
|
const delimiter = lowercaseName === 'cookie' ? '; ' : ', '
|
|
177
|
-
this
|
|
247
|
+
this.headersMap.set(lowercaseName, {
|
|
178
248
|
name: exists.name,
|
|
179
249
|
value: `${exists.value}${delimiter}${value}`
|
|
180
250
|
})
|
|
181
251
|
} else {
|
|
182
|
-
this
|
|
252
|
+
this.headersMap.set(lowercaseName, { name, value })
|
|
183
253
|
}
|
|
184
254
|
|
|
185
255
|
if (lowercaseName === 'set-cookie') {
|
|
@@ -194,7 +264,7 @@ class HeadersList {
|
|
|
194
264
|
* @param {boolean} isLowerCase
|
|
195
265
|
*/
|
|
196
266
|
set (name, value, isLowerCase) {
|
|
197
|
-
this
|
|
267
|
+
this.sortedMap = null
|
|
198
268
|
const lowercaseName = isLowerCase ? name : name.toLowerCase()
|
|
199
269
|
|
|
200
270
|
if (lowercaseName === 'set-cookie') {
|
|
@@ -205,7 +275,7 @@ class HeadersList {
|
|
|
205
275
|
// the first such header to value and remove the
|
|
206
276
|
// others.
|
|
207
277
|
// 2. Otherwise, append header (name, value) to list.
|
|
208
|
-
this
|
|
278
|
+
this.headersMap.set(lowercaseName, { name, value })
|
|
209
279
|
}
|
|
210
280
|
|
|
211
281
|
/**
|
|
@@ -214,14 +284,14 @@ class HeadersList {
|
|
|
214
284
|
* @param {boolean} isLowerCase
|
|
215
285
|
*/
|
|
216
286
|
delete (name, isLowerCase) {
|
|
217
|
-
this
|
|
287
|
+
this.sortedMap = null
|
|
218
288
|
if (!isLowerCase) name = name.toLowerCase()
|
|
219
289
|
|
|
220
290
|
if (name === 'set-cookie') {
|
|
221
291
|
this.cookies = null
|
|
222
292
|
}
|
|
223
293
|
|
|
224
|
-
this
|
|
294
|
+
this.headersMap.delete(name)
|
|
225
295
|
}
|
|
226
296
|
|
|
227
297
|
/**
|
|
@@ -235,12 +305,12 @@ class HeadersList {
|
|
|
235
305
|
// 2. Return the values of all headers in list whose name
|
|
236
306
|
// is a byte-case-insensitive match for name,
|
|
237
307
|
// separated from each other by 0x2C 0x20, in order.
|
|
238
|
-
return this
|
|
308
|
+
return this.headersMap.get(isLowerCase ? name : name.toLowerCase())?.value ?? null
|
|
239
309
|
}
|
|
240
310
|
|
|
241
311
|
* [Symbol.iterator] () {
|
|
242
312
|
// use the lowercased name
|
|
243
|
-
for (const { 0: name, 1: { value } } of this
|
|
313
|
+
for (const { 0: name, 1: { value } } of this.headersMap) {
|
|
244
314
|
yield [name, value]
|
|
245
315
|
}
|
|
246
316
|
}
|
|
@@ -248,8 +318,8 @@ class HeadersList {
|
|
|
248
318
|
get entries () {
|
|
249
319
|
const headers = {}
|
|
250
320
|
|
|
251
|
-
if (this
|
|
252
|
-
for (const { name, value } of this
|
|
321
|
+
if (this.headersMap.size !== 0) {
|
|
322
|
+
for (const { name, value } of this.headersMap.values()) {
|
|
253
323
|
headers[name] = value
|
|
254
324
|
}
|
|
255
325
|
}
|
|
@@ -258,14 +328,14 @@ class HeadersList {
|
|
|
258
328
|
}
|
|
259
329
|
|
|
260
330
|
rawValues () {
|
|
261
|
-
return this
|
|
331
|
+
return this.headersMap.values()
|
|
262
332
|
}
|
|
263
333
|
|
|
264
334
|
get entriesList () {
|
|
265
335
|
const headers = []
|
|
266
336
|
|
|
267
|
-
if (this
|
|
268
|
-
for (const { 0: lowerName, 1: { name, value } } of this
|
|
337
|
+
if (this.headersMap.size !== 0) {
|
|
338
|
+
for (const { 0: lowerName, 1: { name, value } } of this.headersMap) {
|
|
269
339
|
if (lowerName === 'set-cookie') {
|
|
270
340
|
for (const cookie of this.cookies) {
|
|
271
341
|
headers.push([name, cookie])
|
|
@@ -281,7 +351,7 @@ class HeadersList {
|
|
|
281
351
|
|
|
282
352
|
// https://fetch.spec.whatwg.org/#convert-header-names-to-a-sorted-lowercase-set
|
|
283
353
|
toSortedArray () {
|
|
284
|
-
const size = this
|
|
354
|
+
const size = this.headersMap.size
|
|
285
355
|
const array = new Array(size)
|
|
286
356
|
// In most cases, you will use the fast-path.
|
|
287
357
|
// fast-path: Use binary insertion sort for small arrays.
|
|
@@ -292,7 +362,7 @@ class HeadersList {
|
|
|
292
362
|
}
|
|
293
363
|
// Improve performance by unrolling loop and avoiding double-loop.
|
|
294
364
|
// Double-loop-less version of the binary insertion sort.
|
|
295
|
-
const iterator = this[
|
|
365
|
+
const iterator = this.headersMap[Symbol.iterator]()
|
|
296
366
|
const firstValue = iterator.next().value
|
|
297
367
|
// set [name, value] to first index.
|
|
298
368
|
array[0] = [firstValue[0], firstValue[1].value]
|
|
@@ -342,7 +412,7 @@ class HeadersList {
|
|
|
342
412
|
// This case would be a rare occurrence.
|
|
343
413
|
// slow-path: fallback
|
|
344
414
|
let i = 0
|
|
345
|
-
for (const { 0: name, 1: { value } } of this
|
|
415
|
+
for (const { 0: name, 1: { value } } of this.headersMap) {
|
|
346
416
|
array[i++] = [name, value]
|
|
347
417
|
// https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine
|
|
348
418
|
// 3.2.2. Assert: value is non-null.
|
|
@@ -356,8 +426,15 @@ class HeadersList {
|
|
|
356
426
|
// https://fetch.spec.whatwg.org/#headers-class
|
|
357
427
|
class Headers {
|
|
358
428
|
#guard
|
|
429
|
+
/**
|
|
430
|
+
* @type {HeadersList}
|
|
431
|
+
*/
|
|
359
432
|
#headersList
|
|
360
433
|
|
|
434
|
+
/**
|
|
435
|
+
* @param {HeadersInit|Symbol} [init]
|
|
436
|
+
* @returns
|
|
437
|
+
*/
|
|
361
438
|
constructor (init = undefined) {
|
|
362
439
|
if (init === kConstruct) {
|
|
363
440
|
return
|
|
@@ -545,58 +622,6 @@ class Headers {
|
|
|
545
622
|
return []
|
|
546
623
|
}
|
|
547
624
|
|
|
548
|
-
// https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine
|
|
549
|
-
get [kHeadersSortedMap] () {
|
|
550
|
-
if (this.#headersList[kHeadersSortedMap]) {
|
|
551
|
-
return this.#headersList[kHeadersSortedMap]
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
// 1. Let headers be an empty list of headers with the key being the name
|
|
555
|
-
// and value the value.
|
|
556
|
-
const headers = []
|
|
557
|
-
|
|
558
|
-
// 2. Let names be the result of convert header names to a sorted-lowercase
|
|
559
|
-
// set with all the names of the headers in list.
|
|
560
|
-
const names = this.#headersList.toSortedArray()
|
|
561
|
-
|
|
562
|
-
const cookies = this.#headersList.cookies
|
|
563
|
-
|
|
564
|
-
// fast-path
|
|
565
|
-
if (cookies === null || cookies.length === 1) {
|
|
566
|
-
// Note: The non-null assertion of value has already been done by `HeadersList#toSortedArray`
|
|
567
|
-
return (this.#headersList[kHeadersSortedMap] = names)
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
// 3. For each name of names:
|
|
571
|
-
for (let i = 0; i < names.length; ++i) {
|
|
572
|
-
const { 0: name, 1: value } = names[i]
|
|
573
|
-
// 1. If name is `set-cookie`, then:
|
|
574
|
-
if (name === 'set-cookie') {
|
|
575
|
-
// 1. Let values be a list of all values of headers in list whose name
|
|
576
|
-
// is a byte-case-insensitive match for name, in order.
|
|
577
|
-
|
|
578
|
-
// 2. For each value of values:
|
|
579
|
-
// 1. Append (name, value) to headers.
|
|
580
|
-
for (let j = 0; j < cookies.length; ++j) {
|
|
581
|
-
headers.push([name, cookies[j]])
|
|
582
|
-
}
|
|
583
|
-
} else {
|
|
584
|
-
// 2. Otherwise:
|
|
585
|
-
|
|
586
|
-
// 1. Let value be the result of getting name from list.
|
|
587
|
-
|
|
588
|
-
// 2. Assert: value is non-null.
|
|
589
|
-
// Note: This operation was done by `HeadersList#toSortedArray`.
|
|
590
|
-
|
|
591
|
-
// 3. Append (name, value) to headers.
|
|
592
|
-
headers.push([name, value])
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// 4. Return headers.
|
|
597
|
-
return (this.#headersList[kHeadersSortedMap] = headers)
|
|
598
|
-
}
|
|
599
|
-
|
|
600
625
|
[util.inspect.custom] (depth, options) {
|
|
601
626
|
options.depth ??= depth
|
|
602
627
|
|
|
@@ -611,12 +636,19 @@ class Headers {
|
|
|
611
636
|
o.#guard = guard
|
|
612
637
|
}
|
|
613
638
|
|
|
639
|
+
/**
|
|
640
|
+
* @param {Headers} o
|
|
641
|
+
*/
|
|
614
642
|
static getHeadersList (o) {
|
|
615
643
|
return o.#headersList
|
|
616
644
|
}
|
|
617
645
|
|
|
618
|
-
|
|
619
|
-
|
|
646
|
+
/**
|
|
647
|
+
* @param {Headers} target
|
|
648
|
+
* @param {HeadersList} list
|
|
649
|
+
*/
|
|
650
|
+
static setHeadersList (target, list) {
|
|
651
|
+
target.#headersList = list
|
|
620
652
|
}
|
|
621
653
|
}
|
|
622
654
|
|
|
@@ -626,7 +658,7 @@ Reflect.deleteProperty(Headers, 'setHeadersGuard')
|
|
|
626
658
|
Reflect.deleteProperty(Headers, 'getHeadersList')
|
|
627
659
|
Reflect.deleteProperty(Headers, 'setHeadersList')
|
|
628
660
|
|
|
629
|
-
iteratorMixin('Headers', Headers,
|
|
661
|
+
iteratorMixin('Headers', Headers, headersListSortAndCombine, 0, 1)
|
|
630
662
|
|
|
631
663
|
Object.defineProperties(Headers.prototype, {
|
|
632
664
|
append: kEnumerableProperty,
|
|
@@ -645,7 +677,7 @@ Object.defineProperties(Headers.prototype, {
|
|
|
645
677
|
})
|
|
646
678
|
|
|
647
679
|
webidl.converters.HeadersInit = function (V, prefix, argument) {
|
|
648
|
-
if (webidl.util.Type(V) ===
|
|
680
|
+
if (webidl.util.Type(V) === webidl.util.Types.OBJECT) {
|
|
649
681
|
const iterator = Reflect.get(V, Symbol.iterator)
|
|
650
682
|
|
|
651
683
|
// A work-around to ensure we send the properly-cased Headers when V is a Headers object.
|
package/lib/web/fetch/index.js
CHANGED
|
@@ -7,10 +7,11 @@ const {
|
|
|
7
7
|
makeAppropriateNetworkError,
|
|
8
8
|
filterResponse,
|
|
9
9
|
makeResponse,
|
|
10
|
-
fromInnerResponse
|
|
10
|
+
fromInnerResponse,
|
|
11
|
+
getResponseState
|
|
11
12
|
} = require('./response')
|
|
12
13
|
const { HeadersList } = require('./headers')
|
|
13
|
-
const { Request, cloneRequest } = require('./request')
|
|
14
|
+
const { Request, cloneRequest, getRequestDispatcher, getRequestState } = require('./request')
|
|
14
15
|
const zlib = require('node:zlib')
|
|
15
16
|
const {
|
|
16
17
|
bytesMatch,
|
|
@@ -30,7 +31,6 @@ const {
|
|
|
30
31
|
determineRequestsReferrer,
|
|
31
32
|
coarsenedSharedCurrentTime,
|
|
32
33
|
createDeferredPromise,
|
|
33
|
-
isBlobLike,
|
|
34
34
|
sameOrigin,
|
|
35
35
|
isCancelled,
|
|
36
36
|
isAborted,
|
|
@@ -47,7 +47,6 @@ const {
|
|
|
47
47
|
createInflate,
|
|
48
48
|
extractMimeType
|
|
49
49
|
} = require('./util')
|
|
50
|
-
const { kState, kDispatcher } = require('./symbols')
|
|
51
50
|
const assert = require('node:assert')
|
|
52
51
|
const { safelyExtractBody, extractBody } = require('./body')
|
|
53
52
|
const {
|
|
@@ -58,8 +57,8 @@ const {
|
|
|
58
57
|
subresourceSet
|
|
59
58
|
} = require('./constants')
|
|
60
59
|
const EE = require('node:events')
|
|
61
|
-
const { Readable, pipeline, finished } = require('node:stream')
|
|
62
|
-
const { addAbortListener,
|
|
60
|
+
const { Readable, pipeline, finished, isErrored, isReadable } = require('node:stream')
|
|
61
|
+
const { addAbortListener, bufferToLowerCasedHeaderName } = require('../../core/util')
|
|
63
62
|
const { dataURLProcessor, serializeAMimeType, minimizeSupportedMimeType } = require('./data-url')
|
|
64
63
|
const { getGlobalDispatcher } = require('../../global')
|
|
65
64
|
const { webidl } = require('./webidl')
|
|
@@ -144,7 +143,7 @@ function fetch (input, init = undefined) {
|
|
|
144
143
|
}
|
|
145
144
|
|
|
146
145
|
// 3. Let request be requestObject’s request.
|
|
147
|
-
const request = requestObject
|
|
146
|
+
const request = getRequestState(requestObject)
|
|
148
147
|
|
|
149
148
|
// 4. If requestObject’s signal’s aborted flag is set, then:
|
|
150
149
|
if (requestObject.signal.aborted) {
|
|
@@ -244,7 +243,7 @@ function fetch (input, init = undefined) {
|
|
|
244
243
|
request,
|
|
245
244
|
processResponseEndOfBody: handleFetchDone,
|
|
246
245
|
processResponse,
|
|
247
|
-
dispatcher: requestObject
|
|
246
|
+
dispatcher: getRequestDispatcher(requestObject) // undici
|
|
248
247
|
})
|
|
249
248
|
|
|
250
249
|
// 14. Return p.
|
|
@@ -327,7 +326,7 @@ function abortFetch (p, request, responseObject, error) {
|
|
|
327
326
|
|
|
328
327
|
// 2. If request’s body is not null and is readable, then cancel request’s
|
|
329
328
|
// body with error.
|
|
330
|
-
if (request.body != null && isReadable(request.body
|
|
329
|
+
if (request.body?.stream != null && isReadable(request.body.stream)) {
|
|
331
330
|
request.body.stream.cancel(error).catch((err) => {
|
|
332
331
|
if (err.code === 'ERR_INVALID_STATE') {
|
|
333
332
|
// Node bug?
|
|
@@ -343,11 +342,11 @@ function abortFetch (p, request, responseObject, error) {
|
|
|
343
342
|
}
|
|
344
343
|
|
|
345
344
|
// 4. Let response be responseObject’s response.
|
|
346
|
-
const response = responseObject
|
|
345
|
+
const response = getResponseState(responseObject)
|
|
347
346
|
|
|
348
347
|
// 5. If response’s body is not null and is readable, then error response’s
|
|
349
348
|
// body with error.
|
|
350
|
-
if (response.body != null && isReadable(response.body
|
|
349
|
+
if (response.body?.stream != null && isReadable(response.body.stream)) {
|
|
351
350
|
response.body.stream.cancel(error).catch((err) => {
|
|
352
351
|
if (err.code === 'ERR_INVALID_STATE') {
|
|
353
352
|
// Node bug?
|
|
@@ -572,53 +571,46 @@ async function mainFetch (fetchParams, recursive = false) {
|
|
|
572
571
|
// 11. If response is null, then set response to the result of running
|
|
573
572
|
// the steps corresponding to the first matching statement:
|
|
574
573
|
if (response === null) {
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
return makeNetworkError(
|
|
606
|
-
'redirect mode cannot be "follow" for "no-cors" request'
|
|
607
|
-
)
|
|
608
|
-
}
|
|
609
|
-
|
|
574
|
+
const currentURL = requestCurrentURL(request)
|
|
575
|
+
if (
|
|
576
|
+
// - request’s current URL’s origin is same origin with request’s origin,
|
|
577
|
+
// and request’s response tainting is "basic"
|
|
578
|
+
(sameOrigin(currentURL, request.url) && request.responseTainting === 'basic') ||
|
|
579
|
+
// request’s current URL’s scheme is "data"
|
|
580
|
+
(currentURL.protocol === 'data:') ||
|
|
581
|
+
// - request’s mode is "navigate" or "websocket"
|
|
582
|
+
(request.mode === 'navigate' || request.mode === 'websocket')
|
|
583
|
+
) {
|
|
584
|
+
// 1. Set request’s response tainting to "basic".
|
|
585
|
+
request.responseTainting = 'basic'
|
|
586
|
+
|
|
587
|
+
// 2. Return the result of running scheme fetch given fetchParams.
|
|
588
|
+
response = await schemeFetch(fetchParams)
|
|
589
|
+
|
|
590
|
+
// request’s mode is "same-origin"
|
|
591
|
+
} else if (request.mode === 'same-origin') {
|
|
592
|
+
// 1. Return a network error.
|
|
593
|
+
response = makeNetworkError('request mode cannot be "same-origin"')
|
|
594
|
+
|
|
595
|
+
// request’s mode is "no-cors"
|
|
596
|
+
} else if (request.mode === 'no-cors') {
|
|
597
|
+
// 1. If request’s redirect mode is not "follow", then return a network
|
|
598
|
+
// error.
|
|
599
|
+
if (request.redirect !== 'follow') {
|
|
600
|
+
response = makeNetworkError(
|
|
601
|
+
'redirect mode cannot be "follow" for "no-cors" request'
|
|
602
|
+
)
|
|
603
|
+
} else {
|
|
610
604
|
// 2. Set request’s response tainting to "opaque".
|
|
611
605
|
request.responseTainting = 'opaque'
|
|
612
606
|
|
|
613
607
|
// 3. Return the result of running scheme fetch given fetchParams.
|
|
614
|
-
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
// request’s current URL’s scheme is not an HTTP(S) scheme
|
|
618
|
-
if (!urlIsHttpHttpsScheme(requestCurrentURL(request))) {
|
|
619
|
-
// Return a network error.
|
|
620
|
-
return makeNetworkError('URL scheme must be a HTTP(S) scheme')
|
|
608
|
+
response = await schemeFetch(fetchParams)
|
|
621
609
|
}
|
|
610
|
+
// request’s current URL’s scheme is not an HTTP(S) scheme
|
|
611
|
+
} else if (!urlIsHttpHttpsScheme(requestCurrentURL(request))) {
|
|
612
|
+
// Return a network error.
|
|
613
|
+
response = makeNetworkError('URL scheme must be a HTTP(S) scheme')
|
|
622
614
|
|
|
623
615
|
// - request’s use-CORS-preflight flag is set
|
|
624
616
|
// - request’s unsafe-request flag is set and either request’s method is
|
|
@@ -632,13 +624,14 @@ async function mainFetch (fetchParams, recursive = false) {
|
|
|
632
624
|
// 4. Return corsWithPreflightResponse.
|
|
633
625
|
// TODO
|
|
634
626
|
|
|
635
|
-
|
|
627
|
+
// Otherwise
|
|
628
|
+
} else {
|
|
636
629
|
// 1. Set request’s response tainting to "cors".
|
|
637
630
|
request.responseTainting = 'cors'
|
|
638
631
|
|
|
639
632
|
// 2. Return the result of running HTTP fetch given fetchParams.
|
|
640
|
-
|
|
641
|
-
}
|
|
633
|
+
response = await httpFetch(fetchParams)
|
|
634
|
+
}
|
|
642
635
|
}
|
|
643
636
|
|
|
644
637
|
// 12. If recursive is true, then return response.
|
|
@@ -810,7 +803,7 @@ function schemeFetch (fetchParams) {
|
|
|
810
803
|
|
|
811
804
|
// 2. If request’s method is not `GET`, blobURLEntry is null, or blobURLEntry’s
|
|
812
805
|
// object is not a Blob object, then return a network error.
|
|
813
|
-
if (request.method !== 'GET' || !
|
|
806
|
+
if (request.method !== 'GET' || !webidl.is.Blob(blob)) {
|
|
814
807
|
return Promise.resolve(makeNetworkError('invalid method'))
|
|
815
808
|
}
|
|
816
809
|
|
|
@@ -1446,7 +1439,7 @@ async function httpNetworkOrCacheFetch (
|
|
|
1446
1439
|
// 11. If httpRequest’s referrer is a URL, then append
|
|
1447
1440
|
// `Referer`/httpRequest’s referrer, serialized and isomorphic encoded,
|
|
1448
1441
|
// to httpRequest’s header list.
|
|
1449
|
-
if (httpRequest.referrer
|
|
1442
|
+
if (webidl.is.URL(httpRequest.referrer)) {
|
|
1450
1443
|
httpRequest.headersList.append('referer', isomorphicEncode(httpRequest.referrer.href), true)
|
|
1451
1444
|
}
|
|
1452
1445
|
|
|
@@ -1460,7 +1453,7 @@ async function httpNetworkOrCacheFetch (
|
|
|
1460
1453
|
// user agents should append `User-Agent`/default `User-Agent` value to
|
|
1461
1454
|
// httpRequest’s header list.
|
|
1462
1455
|
if (!httpRequest.headersList.contains('user-agent', true)) {
|
|
1463
|
-
httpRequest.headersList.append('user-agent', defaultUserAgent)
|
|
1456
|
+
httpRequest.headersList.append('user-agent', defaultUserAgent, true)
|
|
1464
1457
|
}
|
|
1465
1458
|
|
|
1466
1459
|
// 15. If httpRequest’s cache mode is "default" and httpRequest’s header
|
|
@@ -1888,8 +1881,8 @@ async function httpNetworkFetch (
|
|
|
1888
1881
|
|
|
1889
1882
|
// 11. Let pullAlgorithm be an action that resumes the ongoing fetch
|
|
1890
1883
|
// if it is suspended.
|
|
1891
|
-
const pullAlgorithm =
|
|
1892
|
-
|
|
1884
|
+
const pullAlgorithm = () => {
|
|
1885
|
+
return fetchParams.controller.resume()
|
|
1893
1886
|
}
|
|
1894
1887
|
|
|
1895
1888
|
// 12. Let cancelAlgorithm be an algorithm that aborts fetchParams’s
|
|
@@ -2137,7 +2130,7 @@ async function httpNetworkFetch (
|
|
|
2137
2130
|
|
|
2138
2131
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
|
|
2139
2132
|
if (codings.length !== 0 && request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) {
|
|
2140
|
-
for (let i =
|
|
2133
|
+
for (let i = codings.length - 1; i >= 0; --i) {
|
|
2141
2134
|
const coding = codings[i]
|
|
2142
2135
|
// https://www.rfc-editor.org/rfc/rfc9112.html#section-7.2
|
|
2143
2136
|
if (coding === 'x-gzip' || coding === 'gzip') {
|