undici 6.5.0 → 6.6.1
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/docs/best-practices/client-certificate.md +3 -3
- package/lib/agent.js +5 -7
- package/lib/api/api-connect.js +2 -2
- package/lib/api/api-pipeline.js +4 -4
- package/lib/api/api-request.js +2 -2
- package/lib/api/api-stream.js +4 -4
- package/lib/api/api-upgrade.js +3 -3
- package/lib/api/readable.js +2 -2
- package/lib/api/util.js +1 -1
- package/lib/balanced-pool.js +1 -1
- package/lib/cache/cache.js +4 -10
- package/lib/cache/util.js +1 -1
- package/lib/client.js +14 -14
- package/lib/cookies/parse.js +1 -1
- package/lib/cookies/util.js +1 -1
- package/lib/core/connect.js +3 -3
- package/lib/core/diagnostics.js +2 -2
- package/lib/core/request.js +18 -13
- package/lib/core/tree.js +3 -5
- package/lib/core/util.js +15 -15
- package/lib/dispatcher.js +1 -1
- package/lib/eventsource/eventsource-stream.js +1 -1
- package/lib/eventsource/eventsource.js +2 -2
- package/lib/eventsource/util.js +9 -1
- package/lib/fetch/body.js +29 -21
- package/lib/fetch/dataURL.js +97 -17
- package/lib/fetch/file.js +5 -5
- package/lib/fetch/formdata.js +24 -9
- package/lib/fetch/headers.js +11 -26
- package/lib/fetch/index.js +37 -40
- package/lib/fetch/request.js +3 -2
- package/lib/fetch/response.js +31 -39
- package/lib/fetch/util.js +258 -96
- package/lib/fetch/webidl.js +1 -1
- package/lib/fileapi/util.js +2 -2
- package/lib/handler/RedirectHandler.js +2 -2
- package/lib/handler/RetryHandler.js +3 -3
- package/lib/llhttp/llhttp-wasm.js +3 -1
- package/lib/llhttp/llhttp_simd-wasm.js +3 -1
- package/lib/mock/mock-agent.js +2 -2
- package/lib/mock/mock-client.js +1 -1
- package/lib/mock/mock-pool.js +1 -1
- package/lib/mock/mock-utils.js +2 -2
- package/lib/mock/pending-interceptors-formatter.js +2 -2
- package/lib/pool.js +7 -8
- package/lib/proxy-agent.js +2 -2
- package/lib/timers.js +1 -1
- package/lib/websocket/connection.js +1 -1
- package/lib/websocket/events.js +1 -1
- package/lib/websocket/frame.js +1 -1
- package/lib/websocket/receiver.js +7 -6
- package/lib/websocket/util.js +1 -1
- package/lib/websocket/websocket.js +1 -1
- package/package.json +5 -8
package/lib/fetch/response.js
CHANGED
|
@@ -23,8 +23,8 @@ const { FormData } = require('./formdata')
|
|
|
23
23
|
const { getGlobalOrigin } = require('./global')
|
|
24
24
|
const { URLSerializer } = require('./dataURL')
|
|
25
25
|
const { kHeadersList, kConstruct } = require('../core/symbols')
|
|
26
|
-
const assert = require('assert')
|
|
27
|
-
const { types } = require('util')
|
|
26
|
+
const assert = require('node:assert')
|
|
27
|
+
const { types } = require('node:util')
|
|
28
28
|
|
|
29
29
|
const textEncoder = new TextEncoder('utf-8')
|
|
30
30
|
|
|
@@ -38,13 +38,8 @@ class Response {
|
|
|
38
38
|
// The static error() method steps are to return the result of creating a
|
|
39
39
|
// Response object, given a new network error, "immutable", and this’s
|
|
40
40
|
// relevant Realm.
|
|
41
|
-
const responseObject =
|
|
42
|
-
|
|
43
|
-
responseObject[kRealm] = relevantRealm
|
|
44
|
-
responseObject[kHeaders] = new Headers(kConstruct)
|
|
45
|
-
responseObject[kHeaders][kHeadersList] = responseObject[kState].headersList
|
|
46
|
-
responseObject[kHeaders][kGuard] = 'immutable'
|
|
47
|
-
responseObject[kHeaders][kRealm] = relevantRealm
|
|
41
|
+
const responseObject = fromInnerResponse(makeNetworkError(), 'immutable', relevantRealm)
|
|
42
|
+
|
|
48
43
|
return responseObject
|
|
49
44
|
}
|
|
50
45
|
|
|
@@ -67,13 +62,7 @@ class Response {
|
|
|
67
62
|
// 3. Let responseObject be the result of creating a Response object, given a new response,
|
|
68
63
|
// "response", and this’s relevant Realm.
|
|
69
64
|
const relevantRealm = { settingsObject: {} }
|
|
70
|
-
const responseObject =
|
|
71
|
-
responseObject[kState] = makeResponse({})
|
|
72
|
-
responseObject[kRealm] = relevantRealm
|
|
73
|
-
responseObject[kHeaders] = new Headers(kConstruct)
|
|
74
|
-
responseObject[kHeaders][kHeadersList] = responseObject[kState].headersList
|
|
75
|
-
responseObject[kHeaders][kGuard] = 'response'
|
|
76
|
-
responseObject[kHeaders][kRealm] = relevantRealm
|
|
65
|
+
const responseObject = fromInnerResponse(makeResponse({}), 'response', relevantRealm)
|
|
77
66
|
|
|
78
67
|
// 4. Perform initialize a response given responseObject, init, and (body, "application/json").
|
|
79
68
|
initializeResponse(responseObject, init, { body: body[0], type: 'application/json' })
|
|
@@ -99,25 +88,17 @@ class Response {
|
|
|
99
88
|
try {
|
|
100
89
|
parsedURL = new URL(url, getGlobalOrigin())
|
|
101
90
|
} catch (err) {
|
|
102
|
-
throw
|
|
103
|
-
cause: err
|
|
104
|
-
})
|
|
91
|
+
throw new TypeError(`Failed to parse URL from ${url}`, { cause: err })
|
|
105
92
|
}
|
|
106
93
|
|
|
107
94
|
// 3. If status is not a redirect status, then throw a RangeError.
|
|
108
95
|
if (!redirectStatusSet.has(status)) {
|
|
109
|
-
throw new RangeError(
|
|
96
|
+
throw new RangeError(`Invalid status code ${status}`)
|
|
110
97
|
}
|
|
111
98
|
|
|
112
99
|
// 4. Let responseObject be the result of creating a Response object,
|
|
113
100
|
// given a new response, "immutable", and this’s relevant Realm.
|
|
114
|
-
const responseObject =
|
|
115
|
-
responseObject[kState] = makeResponse({})
|
|
116
|
-
responseObject[kRealm] = relevantRealm
|
|
117
|
-
responseObject[kHeaders] = new Headers(kConstruct)
|
|
118
|
-
responseObject[kHeaders][kHeadersList] = responseObject[kState].headersList
|
|
119
|
-
responseObject[kHeaders][kGuard] = 'immutable'
|
|
120
|
-
responseObject[kHeaders][kRealm] = relevantRealm
|
|
101
|
+
const responseObject = fromInnerResponse(makeResponse({}), 'immutable', relevantRealm)
|
|
121
102
|
|
|
122
103
|
// 5. Set responseObject’s response’s status to status.
|
|
123
104
|
responseObject[kState].status = status
|
|
@@ -257,7 +238,7 @@ class Response {
|
|
|
257
238
|
webidl.brandCheck(this, Response)
|
|
258
239
|
|
|
259
240
|
// 1. If this is unusable, then throw a TypeError.
|
|
260
|
-
if (this.bodyUsed ||
|
|
241
|
+
if (this.bodyUsed || this.body?.locked) {
|
|
261
242
|
throw webidl.errors.exception({
|
|
262
243
|
header: 'Response.clone',
|
|
263
244
|
message: 'Body has already been consumed.'
|
|
@@ -269,15 +250,7 @@ class Response {
|
|
|
269
250
|
|
|
270
251
|
// 3. Return the result of creating a Response object, given
|
|
271
252
|
// clonedResponse, this’s headers’s guard, and this’s relevant Realm.
|
|
272
|
-
|
|
273
|
-
clonedResponseObject[kState] = clonedResponse
|
|
274
|
-
clonedResponseObject[kRealm] = this[kRealm]
|
|
275
|
-
clonedResponseObject[kHeaders] = new Headers(kConstruct)
|
|
276
|
-
clonedResponseObject[kHeaders][kHeadersList] = clonedResponse.headersList
|
|
277
|
-
clonedResponseObject[kHeaders][kGuard] = this[kHeaders][kGuard]
|
|
278
|
-
clonedResponseObject[kHeaders][kRealm] = this[kHeaders][kRealm]
|
|
279
|
-
|
|
280
|
-
return clonedResponseObject
|
|
253
|
+
return fromInnerResponse(clonedResponse, this[kHeaders][kGuard], this[kRealm])
|
|
281
254
|
}
|
|
282
255
|
}
|
|
283
256
|
|
|
@@ -497,7 +470,7 @@ function initializeResponse (response, init, body) {
|
|
|
497
470
|
if (nullBodyStatus.includes(response.status)) {
|
|
498
471
|
throw webidl.errors.exception({
|
|
499
472
|
header: 'Response constructor',
|
|
500
|
-
message:
|
|
473
|
+
message: `Invalid response status code ${response.status}`
|
|
501
474
|
})
|
|
502
475
|
}
|
|
503
476
|
|
|
@@ -512,6 +485,24 @@ function initializeResponse (response, init, body) {
|
|
|
512
485
|
}
|
|
513
486
|
}
|
|
514
487
|
|
|
488
|
+
/**
|
|
489
|
+
* @see https://fetch.spec.whatwg.org/#response-create
|
|
490
|
+
* @param {any} innerResponse
|
|
491
|
+
* @param {'request' | 'immutable' | 'request-no-cors' | 'response' | 'none'} guard
|
|
492
|
+
* @param {any} [realm]
|
|
493
|
+
* @returns {Response}
|
|
494
|
+
*/
|
|
495
|
+
function fromInnerResponse (innerResponse, guard, realm) {
|
|
496
|
+
const response = new Response(kConstruct)
|
|
497
|
+
response[kState] = innerResponse
|
|
498
|
+
response[kRealm] = realm
|
|
499
|
+
response[kHeaders] = new Headers(kConstruct)
|
|
500
|
+
response[kHeaders][kHeadersList] = innerResponse.headersList
|
|
501
|
+
response[kHeaders][kGuard] = guard
|
|
502
|
+
response[kHeaders][kRealm] = realm
|
|
503
|
+
return response
|
|
504
|
+
}
|
|
505
|
+
|
|
515
506
|
webidl.converters.ReadableStream = webidl.interfaceConverter(
|
|
516
507
|
ReadableStream
|
|
517
508
|
)
|
|
@@ -588,5 +579,6 @@ module.exports = {
|
|
|
588
579
|
makeAppropriateNetworkError,
|
|
589
580
|
filterResponse,
|
|
590
581
|
Response,
|
|
591
|
-
cloneResponse
|
|
582
|
+
cloneResponse,
|
|
583
|
+
fromInnerResponse
|
|
592
584
|
}
|
package/lib/fetch/util.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { Transform } = require('node:stream')
|
|
4
|
+
const zlib = require('node:zlib')
|
|
3
5
|
const { redirectStatusSet, referrerPolicySet: referrerPolicyTokens, badPortsSet } = require('./constants')
|
|
4
6
|
const { getGlobalOrigin } = require('./global')
|
|
5
|
-
const {
|
|
7
|
+
const { collectASequenceOfCodePoints, collectAnHTTPQuotedString, removeChars, parseMIMEType } = require('./dataURL')
|
|
8
|
+
const { performance } = require('node:perf_hooks')
|
|
6
9
|
const { isBlobLike, toUSVString, ReadableStreamFrom, isValidHTTPToken } = require('../core/util')
|
|
7
|
-
const assert = require('assert')
|
|
10
|
+
const assert = require('node:assert')
|
|
8
11
|
const { isUint8Array } = require('util/types')
|
|
9
12
|
|
|
10
13
|
// https://nodejs.org/api/crypto.html#determining-if-crypto-support-is-unavailable
|
|
@@ -12,7 +15,7 @@ const { isUint8Array } = require('util/types')
|
|
|
12
15
|
let crypto
|
|
13
16
|
|
|
14
17
|
try {
|
|
15
|
-
crypto = require('crypto')
|
|
18
|
+
crypto = require('node:crypto')
|
|
16
19
|
} catch {
|
|
17
20
|
|
|
18
21
|
}
|
|
@@ -272,7 +275,7 @@ function coarsenTime (timestamp, crossOriginIsolatedCapability) {
|
|
|
272
275
|
}
|
|
273
276
|
|
|
274
277
|
// https://fetch.spec.whatwg.org/#clamp-and-coarsen-connection-timing-info
|
|
275
|
-
function
|
|
278
|
+
function clampAndCoarsenConnectionTimingInfo (connectionTimingInfo, defaultStartTime, crossOriginIsolatedCapability) {
|
|
276
279
|
if (!connectionTimingInfo?.startTime || connectionTimingInfo.startTime < defaultStartTime) {
|
|
277
280
|
return {
|
|
278
281
|
domainLookupStartTime: defaultStartTime,
|
|
@@ -736,19 +739,23 @@ const esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbo
|
|
|
736
739
|
|
|
737
740
|
/**
|
|
738
741
|
* @see https://webidl.spec.whatwg.org/#dfn-iterator-prototype-object
|
|
739
|
-
* @param {() => unknown
|
|
742
|
+
* @param {() => unknown} iterator
|
|
740
743
|
* @param {string} name name of the instance
|
|
741
744
|
* @param {'key'|'value'|'key+value'} kind
|
|
745
|
+
* @param {string | number} [keyIndex]
|
|
746
|
+
* @param {string | number} [valueIndex]
|
|
742
747
|
*/
|
|
743
|
-
function makeIterator (iterator, name, kind) {
|
|
748
|
+
function makeIterator (iterator, name, kind, keyIndex = 0, valueIndex = 1) {
|
|
744
749
|
const object = {
|
|
745
750
|
index: 0,
|
|
746
751
|
kind,
|
|
747
752
|
target: iterator
|
|
748
753
|
}
|
|
754
|
+
// The [[Prototype]] internal slot of an iterator prototype object must be %IteratorPrototype%.
|
|
755
|
+
const iteratorObject = Object.create(esIteratorPrototype)
|
|
749
756
|
|
|
750
|
-
|
|
751
|
-
next () {
|
|
757
|
+
Object.defineProperty(iteratorObject, 'next', {
|
|
758
|
+
value: function next () {
|
|
752
759
|
// 1. Let interface be the interface for which the iterator prototype object exists.
|
|
753
760
|
|
|
754
761
|
// 2. Let thisValue be the this value.
|
|
@@ -760,7 +767,7 @@ function makeIterator (iterator, name, kind) {
|
|
|
760
767
|
|
|
761
768
|
// 5. If object is not a default iterator object for interface,
|
|
762
769
|
// then throw a TypeError.
|
|
763
|
-
if (Object.getPrototypeOf(this) !==
|
|
770
|
+
if (Object.getPrototypeOf(this) !== iteratorObject) {
|
|
764
771
|
throw new TypeError(
|
|
765
772
|
`'next' called on an object that does not implement interface ${name} Iterator.`
|
|
766
773
|
)
|
|
@@ -780,68 +787,66 @@ function makeIterator (iterator, name, kind) {
|
|
|
780
787
|
if (index >= len) {
|
|
781
788
|
return { value: undefined, done: true }
|
|
782
789
|
}
|
|
783
|
-
|
|
784
790
|
// 11. Let pair be the entry in values at index index.
|
|
785
|
-
const
|
|
786
|
-
|
|
791
|
+
const { [keyIndex]: key, [valueIndex]: value } = values[index]
|
|
787
792
|
// 12. Set object’s index to index + 1.
|
|
788
793
|
object.index = index + 1
|
|
789
|
-
|
|
790
794
|
// 13. Return the iterator result for pair and kind.
|
|
791
|
-
|
|
795
|
+
// https://webidl.spec.whatwg.org/#iterator-result
|
|
796
|
+
// 1. Let result be a value determined by the value of kind:
|
|
797
|
+
let result
|
|
798
|
+
switch (kind) {
|
|
799
|
+
case 'key':
|
|
800
|
+
// 1. Let idlKey be pair’s key.
|
|
801
|
+
// 2. Let key be the result of converting idlKey to an
|
|
802
|
+
// ECMAScript value.
|
|
803
|
+
// 3. result is key.
|
|
804
|
+
result = key
|
|
805
|
+
break
|
|
806
|
+
case 'value':
|
|
807
|
+
// 1. Let idlValue be pair’s value.
|
|
808
|
+
// 2. Let value be the result of converting idlValue to
|
|
809
|
+
// an ECMAScript value.
|
|
810
|
+
// 3. result is value.
|
|
811
|
+
result = value
|
|
812
|
+
break
|
|
813
|
+
case 'key+value':
|
|
814
|
+
// 1. Let idlKey be pair’s key.
|
|
815
|
+
// 2. Let idlValue be pair’s value.
|
|
816
|
+
// 3. Let key be the result of converting idlKey to an
|
|
817
|
+
// ECMAScript value.
|
|
818
|
+
// 4. Let value be the result of converting idlValue to
|
|
819
|
+
// an ECMAScript value.
|
|
820
|
+
// 5. Let array be ! ArrayCreate(2).
|
|
821
|
+
// 6. Call ! CreateDataProperty(array, "0", key).
|
|
822
|
+
// 7. Call ! CreateDataProperty(array, "1", value).
|
|
823
|
+
// 8. result is array.
|
|
824
|
+
result = [key, value]
|
|
825
|
+
break
|
|
826
|
+
}
|
|
827
|
+
// 2. Return CreateIterResultObject(result, false).
|
|
828
|
+
return {
|
|
829
|
+
value: result,
|
|
830
|
+
done: false
|
|
831
|
+
}
|
|
792
832
|
},
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
// The [[Prototype]] internal slot of an iterator prototype object must be %IteratorPrototype%.
|
|
799
|
-
Object.setPrototypeOf(i, esIteratorPrototype)
|
|
800
|
-
// esIteratorPrototype needs to be the prototype of i
|
|
801
|
-
// which is the prototype of an empty object. Yes, it's confusing.
|
|
802
|
-
return Object.setPrototypeOf({}, i)
|
|
803
|
-
}
|
|
833
|
+
writable: true,
|
|
834
|
+
enumerable: true,
|
|
835
|
+
configurable: true
|
|
836
|
+
})
|
|
804
837
|
|
|
805
|
-
//
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
// 2. Let key be the result of converting idlKey to an
|
|
814
|
-
// ECMAScript value.
|
|
815
|
-
// 3. result is key.
|
|
816
|
-
result = pair[0]
|
|
817
|
-
break
|
|
818
|
-
}
|
|
819
|
-
case 'value': {
|
|
820
|
-
// 1. Let idlValue be pair’s value.
|
|
821
|
-
// 2. Let value be the result of converting idlValue to
|
|
822
|
-
// an ECMAScript value.
|
|
823
|
-
// 3. result is value.
|
|
824
|
-
result = pair[1]
|
|
825
|
-
break
|
|
826
|
-
}
|
|
827
|
-
case 'key+value': {
|
|
828
|
-
// 1. Let idlKey be pair’s key.
|
|
829
|
-
// 2. Let idlValue be pair’s value.
|
|
830
|
-
// 3. Let key be the result of converting idlKey to an
|
|
831
|
-
// ECMAScript value.
|
|
832
|
-
// 4. Let value be the result of converting idlValue to
|
|
833
|
-
// an ECMAScript value.
|
|
834
|
-
// 5. Let array be ! ArrayCreate(2).
|
|
835
|
-
// 6. Call ! CreateDataProperty(array, "0", key).
|
|
836
|
-
// 7. Call ! CreateDataProperty(array, "1", value).
|
|
837
|
-
// 8. result is array.
|
|
838
|
-
result = pair
|
|
839
|
-
break
|
|
840
|
-
}
|
|
841
|
-
}
|
|
838
|
+
// The class string of an iterator prototype object for a given interface is the
|
|
839
|
+
// result of concatenating the identifier of the interface and the string " Iterator".
|
|
840
|
+
Object.defineProperty(iteratorObject, Symbol.toStringTag, {
|
|
841
|
+
value: `${name} Iterator`,
|
|
842
|
+
writable: false,
|
|
843
|
+
enumerable: false,
|
|
844
|
+
configurable: true
|
|
845
|
+
})
|
|
842
846
|
|
|
843
|
-
//
|
|
844
|
-
|
|
847
|
+
// esIteratorPrototype needs to be the prototype of iteratorObject
|
|
848
|
+
// which is the prototype of an empty object. Yes, it's confusing.
|
|
849
|
+
return Object.create(iteratorObject)
|
|
845
850
|
}
|
|
846
851
|
|
|
847
852
|
/**
|
|
@@ -887,29 +892,6 @@ function isReadableStreamLike (stream) {
|
|
|
887
892
|
)
|
|
888
893
|
}
|
|
889
894
|
|
|
890
|
-
/**
|
|
891
|
-
* @see https://infra.spec.whatwg.org/#isomorphic-decode
|
|
892
|
-
* @param {Uint8Array} input
|
|
893
|
-
*/
|
|
894
|
-
function isomorphicDecode (input) {
|
|
895
|
-
// 1. To isomorphic decode a byte sequence input, return a string whose code point
|
|
896
|
-
// length is equal to input’s length and whose code points have the same values
|
|
897
|
-
// as the values of input’s bytes, in the same order.
|
|
898
|
-
const length = input.length
|
|
899
|
-
if ((2 << 15) - 1 > length) {
|
|
900
|
-
return String.fromCharCode.apply(null, input)
|
|
901
|
-
}
|
|
902
|
-
let result = ''; let i = 0
|
|
903
|
-
let addition = (2 << 15) - 1
|
|
904
|
-
while (i < length) {
|
|
905
|
-
if (i + addition > length) {
|
|
906
|
-
addition = length - i
|
|
907
|
-
}
|
|
908
|
-
result += String.fromCharCode.apply(null, input.subarray(i, i += addition))
|
|
909
|
-
}
|
|
910
|
-
return result
|
|
911
|
-
}
|
|
912
|
-
|
|
913
895
|
/**
|
|
914
896
|
* @param {ReadableStreamController<Uint8Array>} controller
|
|
915
897
|
*/
|
|
@@ -1007,18 +989,12 @@ function urlIsHttpHttpsScheme (url) {
|
|
|
1007
989
|
return protocol === 'http:' || protocol === 'https:'
|
|
1008
990
|
}
|
|
1009
991
|
|
|
1010
|
-
/** @type {import('./dataURL')['collectASequenceOfCodePoints']} */
|
|
1011
|
-
let collectASequenceOfCodePoints
|
|
1012
|
-
|
|
1013
992
|
/**
|
|
1014
993
|
* @see https://fetch.spec.whatwg.org/#simple-range-header-value
|
|
1015
994
|
* @param {string} value
|
|
1016
995
|
* @param {boolean} allowWhitespace
|
|
1017
996
|
*/
|
|
1018
997
|
function simpleRangeHeaderValue (value, allowWhitespace) {
|
|
1019
|
-
// Note: avoid circular require
|
|
1020
|
-
collectASequenceOfCodePoints ??= require('./dataURL').collectASequenceOfCodePoints
|
|
1021
|
-
|
|
1022
998
|
// 1. Let data be the isomorphic decoding of value.
|
|
1023
999
|
// Note: isomorphic decoding takes a sequence of bytes (ie. a Uint8Array) and turns it into a string,
|
|
1024
1000
|
// nothing more. We obviously don't need to do that if value is a string already.
|
|
@@ -1174,6 +1150,191 @@ function buildContentRange (rangeStart, rangeEnd, fullLength) {
|
|
|
1174
1150
|
return contentRange
|
|
1175
1151
|
}
|
|
1176
1152
|
|
|
1153
|
+
// A Stream, which pipes the response to zlib.createInflate() or
|
|
1154
|
+
// zlib.createInflateRaw() depending on the first byte of the Buffer.
|
|
1155
|
+
// If the lower byte of the first byte is 0x08, then the stream is
|
|
1156
|
+
// interpreted as a zlib stream, otherwise it's interpreted as a
|
|
1157
|
+
// raw deflate stream.
|
|
1158
|
+
class InflateStream extends Transform {
|
|
1159
|
+
_transform (chunk, encoding, callback) {
|
|
1160
|
+
if (!this._inflateStream) {
|
|
1161
|
+
if (chunk.length === 0) {
|
|
1162
|
+
callback()
|
|
1163
|
+
return
|
|
1164
|
+
}
|
|
1165
|
+
this._inflateStream = (chunk[0] & 0x0F) === 0x08
|
|
1166
|
+
? zlib.createInflate()
|
|
1167
|
+
: zlib.createInflateRaw()
|
|
1168
|
+
|
|
1169
|
+
this._inflateStream.on('data', this.push.bind(this))
|
|
1170
|
+
this._inflateStream.on('end', () => this.push(null))
|
|
1171
|
+
this._inflateStream.on('error', (err) => this.destroy(err))
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
this._inflateStream.write(chunk, encoding, callback)
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
_final (callback) {
|
|
1178
|
+
if (this._inflateStream) {
|
|
1179
|
+
this._inflateStream.end()
|
|
1180
|
+
this._inflateStream = null
|
|
1181
|
+
}
|
|
1182
|
+
callback()
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
function createInflate () {
|
|
1187
|
+
return new InflateStream()
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
/**
|
|
1191
|
+
* @see https://fetch.spec.whatwg.org/#concept-header-extract-mime-type
|
|
1192
|
+
* @param {import('./headers').HeadersList} headers
|
|
1193
|
+
*/
|
|
1194
|
+
function extractMimeType (headers) {
|
|
1195
|
+
// 1. Let charset be null.
|
|
1196
|
+
let charset = null
|
|
1197
|
+
|
|
1198
|
+
// 2. Let essence be null.
|
|
1199
|
+
let essence = null
|
|
1200
|
+
|
|
1201
|
+
// 3. Let mimeType be null.
|
|
1202
|
+
let mimeType = null
|
|
1203
|
+
|
|
1204
|
+
// 4. Let values be the result of getting, decoding, and splitting `Content-Type` from headers.
|
|
1205
|
+
const values = getDecodeSplit('content-type', headers)
|
|
1206
|
+
|
|
1207
|
+
// 5. If values is null, then return failure.
|
|
1208
|
+
if (values === null) {
|
|
1209
|
+
return 'failure'
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
// 6. For each value of values:
|
|
1213
|
+
for (const value of values) {
|
|
1214
|
+
// 6.1. Let temporaryMimeType be the result of parsing value.
|
|
1215
|
+
const temporaryMimeType = parseMIMEType(value)
|
|
1216
|
+
|
|
1217
|
+
// 6.2. If temporaryMimeType is failure or its essence is "*/*", then continue.
|
|
1218
|
+
if (temporaryMimeType === 'failure' || temporaryMimeType.essence === '*/*') {
|
|
1219
|
+
continue
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// 6.3. Set mimeType to temporaryMimeType.
|
|
1223
|
+
mimeType = temporaryMimeType
|
|
1224
|
+
|
|
1225
|
+
// 6.4. If mimeType’s essence is not essence, then:
|
|
1226
|
+
if (mimeType.essence !== essence) {
|
|
1227
|
+
// 6.4.1. Set charset to null.
|
|
1228
|
+
charset = null
|
|
1229
|
+
|
|
1230
|
+
// 6.4.2. If mimeType’s parameters["charset"] exists, then set charset to
|
|
1231
|
+
// mimeType’s parameters["charset"].
|
|
1232
|
+
if (mimeType.parameters.has('charset')) {
|
|
1233
|
+
charset = mimeType.parameters.get('charset')
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// 6.4.3. Set essence to mimeType’s essence.
|
|
1237
|
+
essence = mimeType.essence
|
|
1238
|
+
} else if (!mimeType.parameters.has('charset') && charset !== null) {
|
|
1239
|
+
// 6.5. Otherwise, if mimeType’s parameters["charset"] does not exist, and
|
|
1240
|
+
// charset is non-null, set mimeType’s parameters["charset"] to charset.
|
|
1241
|
+
mimeType.parameters.set('charset', charset)
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
// 7. If mimeType is null, then return failure.
|
|
1246
|
+
if (mimeType == null) {
|
|
1247
|
+
return 'failure'
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
// 8. Return mimeType.
|
|
1251
|
+
return mimeType
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
/**
|
|
1255
|
+
* @see https://fetch.spec.whatwg.org/#header-value-get-decode-and-split
|
|
1256
|
+
* @param {string|null} value
|
|
1257
|
+
*/
|
|
1258
|
+
function gettingDecodingSplitting (value) {
|
|
1259
|
+
// 1. Let input be the result of isomorphic decoding value.
|
|
1260
|
+
const input = value
|
|
1261
|
+
|
|
1262
|
+
// 2. Let position be a position variable for input, initially pointing at the start of input.
|
|
1263
|
+
const position = { position: 0 }
|
|
1264
|
+
|
|
1265
|
+
// 3. Let values be a list of strings, initially empty.
|
|
1266
|
+
const values = []
|
|
1267
|
+
|
|
1268
|
+
// 4. Let temporaryValue be the empty string.
|
|
1269
|
+
let temporaryValue = ''
|
|
1270
|
+
|
|
1271
|
+
// 5. While position is not past the end of input:
|
|
1272
|
+
while (position.position < input.length) {
|
|
1273
|
+
// 5.1. Append the result of collecting a sequence of code points that are not U+0022 (")
|
|
1274
|
+
// or U+002C (,) from input, given position, to temporaryValue.
|
|
1275
|
+
temporaryValue += collectASequenceOfCodePoints(
|
|
1276
|
+
(char) => char !== '"' && char !== ',',
|
|
1277
|
+
input,
|
|
1278
|
+
position
|
|
1279
|
+
)
|
|
1280
|
+
|
|
1281
|
+
// 5.2. If position is not past the end of input, then:
|
|
1282
|
+
if (position.position < input.length) {
|
|
1283
|
+
// 5.2.1. If the code point at position within input is U+0022 ("), then:
|
|
1284
|
+
if (input.charCodeAt(position.position) === 0x22) {
|
|
1285
|
+
// 5.2.1.1. Append the result of collecting an HTTP quoted string from input, given position, to temporaryValue.
|
|
1286
|
+
temporaryValue += collectAnHTTPQuotedString(
|
|
1287
|
+
input,
|
|
1288
|
+
position
|
|
1289
|
+
)
|
|
1290
|
+
|
|
1291
|
+
// 5.2.1.2. If position is not past the end of input, then continue.
|
|
1292
|
+
if (position.position < input.length) {
|
|
1293
|
+
continue
|
|
1294
|
+
}
|
|
1295
|
+
} else {
|
|
1296
|
+
// 5.2.2. Otherwise:
|
|
1297
|
+
|
|
1298
|
+
// 5.2.2.1. Assert: the code point at position within input is U+002C (,).
|
|
1299
|
+
assert(input.charCodeAt(position.position) === 0x2C)
|
|
1300
|
+
|
|
1301
|
+
// 5.2.2.2. Advance position by 1.
|
|
1302
|
+
position.position++
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
// 5.3. Remove all HTTP tab or space from the start and end of temporaryValue.
|
|
1307
|
+
temporaryValue = removeChars(temporaryValue, true, true, (char) => char === 0x9 || char === 0x20)
|
|
1308
|
+
|
|
1309
|
+
// 5.4. Append temporaryValue to values.
|
|
1310
|
+
values.push(temporaryValue)
|
|
1311
|
+
|
|
1312
|
+
// 5.6. Set temporaryValue to the empty string.
|
|
1313
|
+
temporaryValue = ''
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
// 6. Return values.
|
|
1317
|
+
return values
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
/**
|
|
1321
|
+
* @see https://fetch.spec.whatwg.org/#concept-header-list-get-decode-split
|
|
1322
|
+
* @param {string} name lowercase header name
|
|
1323
|
+
* @param {import('./headers').HeadersList} list
|
|
1324
|
+
*/
|
|
1325
|
+
function getDecodeSplit (name, list) {
|
|
1326
|
+
// 1. Let value be the result of getting name from list.
|
|
1327
|
+
const value = list.get(name, true)
|
|
1328
|
+
|
|
1329
|
+
// 2. If value is null, then return null.
|
|
1330
|
+
if (value === null) {
|
|
1331
|
+
return null
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// 3. Return the result of getting, decoding, and splitting value.
|
|
1335
|
+
return gettingDecodingSplitting(value)
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1177
1338
|
module.exports = {
|
|
1178
1339
|
isAborted,
|
|
1179
1340
|
isCancelled,
|
|
@@ -1181,7 +1342,7 @@ module.exports = {
|
|
|
1181
1342
|
ReadableStreamFrom,
|
|
1182
1343
|
toUSVString,
|
|
1183
1344
|
tryUpgradeRequestToAPotentiallyTrustworthyURL,
|
|
1184
|
-
|
|
1345
|
+
clampAndCoarsenConnectionTimingInfo,
|
|
1185
1346
|
coarsenedSharedCurrentTime,
|
|
1186
1347
|
determineRequestsReferrer,
|
|
1187
1348
|
makePolicyContainer,
|
|
@@ -1213,7 +1374,6 @@ module.exports = {
|
|
|
1213
1374
|
isReadableStreamLike,
|
|
1214
1375
|
readableStreamClose,
|
|
1215
1376
|
isomorphicEncode,
|
|
1216
|
-
isomorphicDecode,
|
|
1217
1377
|
urlIsLocal,
|
|
1218
1378
|
urlHasHttpsScheme,
|
|
1219
1379
|
urlIsHttpHttpsScheme,
|
|
@@ -1221,5 +1381,7 @@ module.exports = {
|
|
|
1221
1381
|
normalizeMethodRecord,
|
|
1222
1382
|
simpleRangeHeaderValue,
|
|
1223
1383
|
buildContentRange,
|
|
1224
|
-
parseMetadata
|
|
1384
|
+
parseMetadata,
|
|
1385
|
+
createInflate,
|
|
1386
|
+
extractMimeType
|
|
1225
1387
|
}
|
package/lib/fetch/webidl.js
CHANGED
package/lib/fileapi/util.js
CHANGED
|
@@ -10,9 +10,9 @@ const {
|
|
|
10
10
|
const { ProgressEvent } = require('./progressevent')
|
|
11
11
|
const { getEncoding } = require('./encoding')
|
|
12
12
|
const { serializeAMimeType, parseMIMEType } = require('../fetch/dataURL')
|
|
13
|
-
const { types } = require('util')
|
|
13
|
+
const { types } = require('node:util')
|
|
14
14
|
const { StringDecoder } = require('string_decoder')
|
|
15
|
-
const { btoa } = require('buffer')
|
|
15
|
+
const { btoa } = require('node:buffer')
|
|
16
16
|
|
|
17
17
|
/** @type {PropertyDescriptor} */
|
|
18
18
|
const staticPropertyDescriptors = {
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
const util = require('../core/util')
|
|
4
4
|
const { kBodyUsed } = require('../core/symbols')
|
|
5
|
-
const assert = require('assert')
|
|
5
|
+
const assert = require('node:assert')
|
|
6
6
|
const { InvalidArgumentError } = require('../core/errors')
|
|
7
|
-
const EE = require('events')
|
|
7
|
+
const EE = require('node:events')
|
|
8
8
|
|
|
9
9
|
const redirectableStatusCodes = [300, 301, 302, 303, 307, 308]
|
|
10
10
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const assert = require('assert')
|
|
1
|
+
const assert = require('node:assert')
|
|
2
2
|
|
|
3
3
|
const { kRetryHandlerDefaultRetry } = require('../core/symbols')
|
|
4
4
|
const { RequestRetryError } = require('../core/errors')
|
|
@@ -148,10 +148,10 @@ class RetryHandler {
|
|
|
148
148
|
return
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
let retryAfterHeader = headers
|
|
151
|
+
let retryAfterHeader = headers?.['retry-after']
|
|
152
152
|
if (retryAfterHeader) {
|
|
153
153
|
retryAfterHeader = Number(retryAfterHeader)
|
|
154
|
-
retryAfterHeader = isNaN(retryAfterHeader)
|
|
154
|
+
retryAfterHeader = Number.isNaN(retryAfterHeader)
|
|
155
155
|
? calculateRetryAfterHeader(retryAfterHeader)
|
|
156
156
|
: retryAfterHeader * 1e3 // Retry-After is in seconds
|
|
157
157
|
}
|