undici 7.0.0-alpha.1 → 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 +2 -2
- package/docs/docs/api/Client.md +1 -1
- package/docs/docs/api/Debug.md +1 -1
- package/docs/docs/api/Dispatcher.md +53 -2
- package/docs/docs/api/MockAgent.md +2 -0
- package/docs/docs/api/MockPool.md +2 -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 -2
- package/lib/api/abort-signal.js +2 -0
- package/lib/api/api-pipeline.js +4 -2
- package/lib/api/api-request.js +4 -2
- package/lib/api/api-stream.js +3 -1
- package/lib/api/api-upgrade.js +2 -2
- package/lib/api/readable.js +194 -41
- package/lib/api/util.js +2 -0
- package/lib/core/connect.js +49 -22
- package/lib/core/constants.js +11 -9
- package/lib/core/diagnostics.js +122 -128
- package/lib/core/request.js +4 -4
- package/lib/core/symbols.js +2 -0
- package/lib/core/tree.js +4 -2
- package/lib/core/util.js +220 -39
- package/lib/dispatcher/client-h1.js +299 -60
- package/lib/dispatcher/client-h2.js +1 -1
- package/lib/dispatcher/client.js +24 -7
- package/lib/dispatcher/fixed-queue.js +91 -49
- package/lib/dispatcher/pool-stats.js +2 -0
- package/lib/dispatcher/proxy-agent.js +3 -1
- package/lib/handler/redirect-handler.js +2 -2
- package/lib/handler/retry-handler.js +2 -2
- package/lib/interceptor/dns.js +346 -0
- package/lib/mock/mock-agent.js +5 -8
- package/lib/mock/mock-client.js +7 -2
- package/lib/mock/mock-errors.js +3 -1
- package/lib/mock/mock-interceptor.js +8 -6
- package/lib/mock/mock-pool.js +7 -2
- package/lib/mock/mock-symbols.js +2 -1
- package/lib/mock/mock-utils.js +33 -5
- package/lib/util/timers.js +50 -6
- package/lib/web/cache/cache.js +24 -21
- package/lib/web/cache/cachestorage.js +1 -1
- package/lib/web/cookies/index.js +6 -4
- package/lib/web/fetch/body.js +42 -34
- package/lib/web/fetch/constants.js +35 -26
- package/lib/web/fetch/formdata-parser.js +14 -3
- package/lib/web/fetch/formdata.js +40 -20
- package/lib/web/fetch/headers.js +116 -84
- package/lib/web/fetch/index.js +65 -59
- package/lib/web/fetch/request.js +130 -55
- package/lib/web/fetch/response.js +79 -36
- package/lib/web/fetch/util.js +104 -57
- package/lib/web/fetch/webidl.js +38 -14
- package/lib/web/websocket/connection.js +92 -15
- package/lib/web/websocket/constants.js +2 -3
- package/lib/web/websocket/events.js +4 -2
- package/lib/web/websocket/receiver.js +20 -26
- package/lib/web/websocket/stream/websocketerror.js +83 -0
- package/lib/web/websocket/stream/websocketstream.js +485 -0
- package/lib/web/websocket/util.js +115 -10
- package/lib/web/websocket/websocket.js +45 -170
- package/package.json +6 -6
- package/types/interceptors.d.ts +14 -0
- package/types/mock-agent.d.ts +3 -0
- package/types/readable.d.ts +10 -7
- package/types/webidl.d.ts +24 -4
- package/types/websocket.d.ts +33 -0
- package/lib/mock/pluralizer.js +0 -29
- package/lib/web/cache/symbols.js +0 -5
- package/lib/web/fetch/symbols.js +0 -8
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,
|
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,
|
|
@@ -46,7 +47,6 @@ const {
|
|
|
46
47
|
createInflate,
|
|
47
48
|
extractMimeType
|
|
48
49
|
} = require('./util')
|
|
49
|
-
const { kState, kDispatcher } = require('./symbols')
|
|
50
50
|
const assert = require('node:assert')
|
|
51
51
|
const { safelyExtractBody, extractBody } = require('./body')
|
|
52
52
|
const {
|
|
@@ -143,7 +143,7 @@ function fetch (input, init = undefined) {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
// 3. Let request be requestObject’s request.
|
|
146
|
-
const request = requestObject
|
|
146
|
+
const request = getRequestState(requestObject)
|
|
147
147
|
|
|
148
148
|
// 4. If requestObject’s signal’s aborted flag is set, then:
|
|
149
149
|
if (requestObject.signal.aborted) {
|
|
@@ -243,7 +243,7 @@ function fetch (input, init = undefined) {
|
|
|
243
243
|
request,
|
|
244
244
|
processResponseEndOfBody: handleFetchDone,
|
|
245
245
|
processResponse,
|
|
246
|
-
dispatcher: requestObject
|
|
246
|
+
dispatcher: getRequestDispatcher(requestObject) // undici
|
|
247
247
|
})
|
|
248
248
|
|
|
249
249
|
// 14. Return p.
|
|
@@ -342,7 +342,7 @@ function abortFetch (p, request, responseObject, error) {
|
|
|
342
342
|
}
|
|
343
343
|
|
|
344
344
|
// 4. Let response be responseObject’s response.
|
|
345
|
-
const response = responseObject
|
|
345
|
+
const response = getResponseState(responseObject)
|
|
346
346
|
|
|
347
347
|
// 5. If response’s body is not null and is readable, then error response’s
|
|
348
348
|
// body with error.
|
|
@@ -571,53 +571,46 @@ async function mainFetch (fetchParams, recursive = false) {
|
|
|
571
571
|
// 11. If response is null, then set response to the result of running
|
|
572
572
|
// the steps corresponding to the first matching statement:
|
|
573
573
|
if (response === null) {
|
|
574
|
-
|
|
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
|
-
return makeNetworkError(
|
|
605
|
-
'redirect mode cannot be "follow" for "no-cors" request'
|
|
606
|
-
)
|
|
607
|
-
}
|
|
608
|
-
|
|
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 {
|
|
609
604
|
// 2. Set request’s response tainting to "opaque".
|
|
610
605
|
request.responseTainting = 'opaque'
|
|
611
606
|
|
|
612
607
|
// 3. Return the result of running scheme fetch given fetchParams.
|
|
613
|
-
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
// request’s current URL’s scheme is not an HTTP(S) scheme
|
|
617
|
-
if (!urlIsHttpHttpsScheme(requestCurrentURL(request))) {
|
|
618
|
-
// Return a network error.
|
|
619
|
-
return makeNetworkError('URL scheme must be a HTTP(S) scheme')
|
|
608
|
+
response = await schemeFetch(fetchParams)
|
|
620
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')
|
|
621
614
|
|
|
622
615
|
// - request’s use-CORS-preflight flag is set
|
|
623
616
|
// - request’s unsafe-request flag is set and either request’s method is
|
|
@@ -631,13 +624,14 @@ async function mainFetch (fetchParams, recursive = false) {
|
|
|
631
624
|
// 4. Return corsWithPreflightResponse.
|
|
632
625
|
// TODO
|
|
633
626
|
|
|
634
|
-
|
|
627
|
+
// Otherwise
|
|
628
|
+
} else {
|
|
635
629
|
// 1. Set request’s response tainting to "cors".
|
|
636
630
|
request.responseTainting = 'cors'
|
|
637
631
|
|
|
638
632
|
// 2. Return the result of running HTTP fetch given fetchParams.
|
|
639
|
-
|
|
640
|
-
}
|
|
633
|
+
response = await httpFetch(fetchParams)
|
|
634
|
+
}
|
|
641
635
|
}
|
|
642
636
|
|
|
643
637
|
// 12. If recursive is true, then return response.
|
|
@@ -809,7 +803,7 @@ function schemeFetch (fetchParams) {
|
|
|
809
803
|
|
|
810
804
|
// 2. If request’s method is not `GET`, blobURLEntry is null, or blobURLEntry’s
|
|
811
805
|
// object is not a Blob object, then return a network error.
|
|
812
|
-
if (request.method !== 'GET' || !(blob
|
|
806
|
+
if (request.method !== 'GET' || !webidl.is.Blob(blob)) {
|
|
813
807
|
return Promise.resolve(makeNetworkError('invalid method'))
|
|
814
808
|
}
|
|
815
809
|
|
|
@@ -1445,7 +1439,7 @@ async function httpNetworkOrCacheFetch (
|
|
|
1445
1439
|
// 11. If httpRequest’s referrer is a URL, then append
|
|
1446
1440
|
// `Referer`/httpRequest’s referrer, serialized and isomorphic encoded,
|
|
1447
1441
|
// to httpRequest’s header list.
|
|
1448
|
-
if (httpRequest.referrer
|
|
1442
|
+
if (webidl.is.URL(httpRequest.referrer)) {
|
|
1449
1443
|
httpRequest.headersList.append('referer', isomorphicEncode(httpRequest.referrer.href), true)
|
|
1450
1444
|
}
|
|
1451
1445
|
|
|
@@ -1887,8 +1881,8 @@ async function httpNetworkFetch (
|
|
|
1887
1881
|
|
|
1888
1882
|
// 11. Let pullAlgorithm be an action that resumes the ongoing fetch
|
|
1889
1883
|
// if it is suspended.
|
|
1890
|
-
const pullAlgorithm =
|
|
1891
|
-
|
|
1884
|
+
const pullAlgorithm = () => {
|
|
1885
|
+
return fetchParams.controller.resume()
|
|
1892
1886
|
}
|
|
1893
1887
|
|
|
1894
1888
|
// 12. Let cancelAlgorithm be an algorithm that aborts fetchParams’s
|
|
@@ -2149,9 +2143,15 @@ async function httpNetworkFetch (
|
|
|
2149
2143
|
finishFlush: zlib.constants.Z_SYNC_FLUSH
|
|
2150
2144
|
}))
|
|
2151
2145
|
} else if (coding === 'deflate') {
|
|
2152
|
-
decoders.push(createInflate(
|
|
2146
|
+
decoders.push(createInflate({
|
|
2147
|
+
flush: zlib.constants.Z_SYNC_FLUSH,
|
|
2148
|
+
finishFlush: zlib.constants.Z_SYNC_FLUSH
|
|
2149
|
+
}))
|
|
2153
2150
|
} else if (coding === 'br') {
|
|
2154
|
-
decoders.push(zlib.createBrotliDecompress(
|
|
2151
|
+
decoders.push(zlib.createBrotliDecompress({
|
|
2152
|
+
flush: zlib.constants.BROTLI_OPERATION_FLUSH,
|
|
2153
|
+
finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH
|
|
2154
|
+
}))
|
|
2155
2155
|
} else {
|
|
2156
2156
|
decoders.length = 0
|
|
2157
2157
|
break
|
|
@@ -2159,13 +2159,19 @@ async function httpNetworkFetch (
|
|
|
2159
2159
|
}
|
|
2160
2160
|
}
|
|
2161
2161
|
|
|
2162
|
+
const onError = this.onError.bind(this)
|
|
2163
|
+
|
|
2162
2164
|
resolve({
|
|
2163
2165
|
status,
|
|
2164
2166
|
statusText,
|
|
2165
2167
|
headersList,
|
|
2166
2168
|
body: decoders.length
|
|
2167
|
-
? pipeline(this.body, ...decoders, () => {
|
|
2168
|
-
|
|
2169
|
+
? pipeline(this.body, ...decoders, (err) => {
|
|
2170
|
+
if (err) {
|
|
2171
|
+
this.onError(err)
|
|
2172
|
+
}
|
|
2173
|
+
}).on('error', onError)
|
|
2174
|
+
: this.body.on('error', onError)
|
|
2169
2175
|
})
|
|
2170
2176
|
|
|
2171
2177
|
return true
|