undici 5.28.1 → 6.0.0
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 +0 -2
- package/docs/api/BalancedPool.md +1 -1
- package/index.js +36 -40
- package/lib/api/api-request.js +1 -0
- package/lib/api/readable.js +1 -1
- package/lib/cache/symbols.js +1 -1
- package/lib/client.js +4 -4
- package/lib/compat/dispatcher-weakref.js +1 -6
- package/lib/core/connect.js +5 -1
- package/lib/core/constants.js +116 -0
- package/lib/core/request.js +0 -4
- package/lib/core/symbols.js +2 -1
- package/lib/core/util.js +18 -24
- package/lib/fetch/body.js +14 -19
- package/lib/fetch/constants.js +0 -36
- package/lib/fetch/dataURL.js +11 -8
- package/lib/fetch/headers.js +4 -1
- package/lib/fetch/index.js +242 -114
- package/lib/fetch/request.js +6 -13
- package/lib/fetch/response.js +23 -17
- package/lib/fetch/util.js +169 -12
- package/lib/fetch/webidl.js +3 -3
- package/lib/fileapi/util.js +0 -1
- package/lib/handler/RedirectHandler.js +2 -2
- package/lib/handler/RetryHandler.js +18 -9
- package/lib/proxy-agent.js +6 -4
- package/lib/websocket/connection.js +1 -0
- package/lib/websocket/util.js +1 -0
- package/lib/websocket/websocket.js +0 -1
- package/package.json +5 -5
- package/types/fetch.d.ts +1 -1
package/lib/fetch/index.js
CHANGED
|
@@ -40,25 +40,25 @@ const {
|
|
|
40
40
|
isomorphicEncode,
|
|
41
41
|
urlIsLocal,
|
|
42
42
|
urlIsHttpHttpsScheme,
|
|
43
|
-
urlHasHttpsScheme
|
|
43
|
+
urlHasHttpsScheme,
|
|
44
|
+
simpleRangeHeaderValue,
|
|
45
|
+
buildContentRange
|
|
44
46
|
} = require('./util')
|
|
45
47
|
const { kState, kHeaders, kGuard, kRealm } = require('./symbols')
|
|
46
48
|
const assert = require('assert')
|
|
47
|
-
const { safelyExtractBody } = require('./body')
|
|
49
|
+
const { safelyExtractBody, extractBody } = require('./body')
|
|
48
50
|
const {
|
|
49
51
|
redirectStatusSet,
|
|
50
52
|
nullBodyStatus,
|
|
51
53
|
safeMethodsSet,
|
|
52
54
|
requestBodyHeader,
|
|
53
|
-
subresourceSet
|
|
54
|
-
DOMException
|
|
55
|
+
subresourceSet
|
|
55
56
|
} = require('./constants')
|
|
56
|
-
const { kHeadersList } = require('../core/symbols')
|
|
57
|
+
const { kHeadersList, kConstruct } = require('../core/symbols')
|
|
57
58
|
const EE = require('events')
|
|
58
59
|
const { Readable, pipeline } = require('stream')
|
|
59
60
|
const { addAbortListener, isErrored, isReadable, nodeMajor, nodeMinor } = require('../core/util')
|
|
60
|
-
const { dataURLProcessor, serializeAMimeType } = require('./dataURL')
|
|
61
|
-
const { TransformStream } = require('stream/web')
|
|
61
|
+
const { dataURLProcessor, serializeAMimeType, parseMIMEType } = require('./dataURL')
|
|
62
62
|
const { getGlobalDispatcher } = require('../global')
|
|
63
63
|
const { webidl } = require('./webidl')
|
|
64
64
|
const { STATUS_CODES } = require('http')
|
|
@@ -66,7 +66,6 @@ const GET_OR_HEAD = ['GET', 'HEAD']
|
|
|
66
66
|
|
|
67
67
|
/** @type {import('buffer').resolveObjectURL} */
|
|
68
68
|
let resolveObjectURL
|
|
69
|
-
let ReadableStream = globalThis.ReadableStream
|
|
70
69
|
|
|
71
70
|
class Fetch extends EE {
|
|
72
71
|
constructor (dispatcher) {
|
|
@@ -232,9 +231,10 @@ function fetch (input, init = {}) {
|
|
|
232
231
|
|
|
233
232
|
// 4. Set responseObject to the result of creating a Response object,
|
|
234
233
|
// given response, "immutable", and relevantRealm.
|
|
235
|
-
responseObject = new Response()
|
|
234
|
+
responseObject = new Response(kConstruct)
|
|
236
235
|
responseObject[kState] = response
|
|
237
236
|
responseObject[kRealm] = relevantRealm
|
|
237
|
+
responseObject[kHeaders] = new Headers(kConstruct)
|
|
238
238
|
responseObject[kHeaders][kHeadersList] = response.headersList
|
|
239
239
|
responseObject[kHeaders][kGuard] = 'immutable'
|
|
240
240
|
responseObject[kHeaders][kRealm] = relevantRealm
|
|
@@ -286,7 +286,7 @@ function finalizeAndReportTiming (response, initiatorType = 'other') {
|
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
// 8. If response’s timing allow passed flag is not set, then:
|
|
289
|
-
if (!
|
|
289
|
+
if (!response.timingAllowPassed) {
|
|
290
290
|
// 1. Set timingInfo to a the result of creating an opaque timing info for timingInfo.
|
|
291
291
|
timingInfo = createOpaqueTimingInfo({
|
|
292
292
|
startTime: timingInfo.startTime
|
|
@@ -404,9 +404,9 @@ function fetching ({
|
|
|
404
404
|
// 5. Let timingInfo be a new fetch timing info whose start time and
|
|
405
405
|
// post-redirect start time are the coarsened shared current time given
|
|
406
406
|
// crossOriginIsolatedCapability.
|
|
407
|
-
const
|
|
407
|
+
const currentTime = coarsenedSharedCurrentTime(crossOriginIsolatedCapability)
|
|
408
408
|
const timingInfo = createOpaqueTimingInfo({
|
|
409
|
-
startTime:
|
|
409
|
+
startTime: currentTime
|
|
410
410
|
})
|
|
411
411
|
|
|
412
412
|
// 6. Let fetchParams be a new fetch params whose
|
|
@@ -815,38 +815,118 @@ function schemeFetch (fetchParams) {
|
|
|
815
815
|
return Promise.resolve(makeNetworkError('NetworkError when attempting to fetch resource.'))
|
|
816
816
|
}
|
|
817
817
|
|
|
818
|
-
const
|
|
818
|
+
const blob = resolveObjectURL(blobURLEntry.toString())
|
|
819
819
|
|
|
820
820
|
// 2. If request’s method is not `GET`, blobURLEntry is null, or blobURLEntry’s
|
|
821
821
|
// object is not a Blob object, then return a network error.
|
|
822
|
-
if (request.method !== 'GET' || !isBlobLike(
|
|
822
|
+
if (request.method !== 'GET' || !isBlobLike(blob)) {
|
|
823
823
|
return Promise.resolve(makeNetworkError('invalid method'))
|
|
824
824
|
}
|
|
825
825
|
|
|
826
|
-
// 3. Let
|
|
827
|
-
|
|
826
|
+
// 3. Let blob be blobURLEntry’s object.
|
|
827
|
+
// Note: done above
|
|
828
828
|
|
|
829
|
-
// 4. Let
|
|
830
|
-
const
|
|
829
|
+
// 4. Let response be a new response.
|
|
830
|
+
const response = makeResponse()
|
|
831
831
|
|
|
832
|
-
// 5. Let
|
|
833
|
-
const
|
|
832
|
+
// 5. Let fullLength be blob’s size.
|
|
833
|
+
const fullLength = blob.size
|
|
834
834
|
|
|
835
|
-
// 6. Let
|
|
836
|
-
const
|
|
835
|
+
// 6. Let serializedFullLength be fullLength, serialized and isomorphic encoded.
|
|
836
|
+
const serializedFullLength = isomorphicEncode(`${fullLength}`)
|
|
837
837
|
|
|
838
|
-
// 7.
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
838
|
+
// 7. Let type be blob’s type.
|
|
839
|
+
const type = blob.type
|
|
840
|
+
|
|
841
|
+
// 8. If request’s header list does not contain `Range`:
|
|
842
|
+
// 9. Otherwise:
|
|
843
|
+
if (!request.headersList.contains('range')) {
|
|
844
|
+
// 1. Let bodyWithType be the result of safely extracting blob.
|
|
845
|
+
// Note: in the FileAPI a blob "object" is a Blob *or* a MediaSource.
|
|
846
|
+
// In node, this can only ever be a Blob. Therefore we can safely
|
|
847
|
+
// use extractBody directly.
|
|
848
|
+
const bodyWithType = extractBody(blob)
|
|
849
|
+
|
|
850
|
+
// 2. Set response’s status message to `OK`.
|
|
851
|
+
response.statusText = 'OK'
|
|
852
|
+
|
|
853
|
+
// 3. Set response’s body to bodyWithType’s body.
|
|
854
|
+
response.body = bodyWithType[0]
|
|
855
|
+
|
|
856
|
+
// 4. Set response’s header list to « (`Content-Length`, serializedFullLength), (`Content-Type`, type) ».
|
|
857
|
+
response.headersList.set('content-length', serializedFullLength)
|
|
858
|
+
response.headersList.set('content-type', type)
|
|
859
|
+
} else {
|
|
860
|
+
// 1. Set response’s range-requested flag.
|
|
861
|
+
response.rangeRequested = true
|
|
862
|
+
|
|
863
|
+
// 2. Let rangeHeader be the result of getting `Range` from request’s header list.
|
|
864
|
+
const rangeHeader = request.headersList.get('range')
|
|
865
|
+
|
|
866
|
+
// 3. Let rangeValue be the result of parsing a single range header value given rangeHeader and true.
|
|
867
|
+
const rangeValue = simpleRangeHeaderValue(rangeHeader, true)
|
|
868
|
+
|
|
869
|
+
// 4. If rangeValue is failure, then return a network error.
|
|
870
|
+
if (rangeValue === 'failure') {
|
|
871
|
+
return Promise.resolve(makeNetworkError('failed to fetch the data URL'))
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// 5. Let (rangeStart, rangeEnd) be rangeValue.
|
|
875
|
+
let { rangeStartValue: rangeStart, rangeEndValue: rangeEnd } = rangeValue
|
|
876
|
+
|
|
877
|
+
// 6. If rangeStart is null:
|
|
878
|
+
// 7. Otherwise:
|
|
879
|
+
if (rangeStart === null) {
|
|
880
|
+
// 1. Set rangeStart to fullLength − rangeEnd.
|
|
881
|
+
rangeStart = fullLength - rangeEnd
|
|
882
|
+
|
|
883
|
+
// 2. Set rangeEnd to rangeStart + rangeEnd − 1.
|
|
884
|
+
rangeEnd = rangeStart + rangeEnd - 1
|
|
885
|
+
} else {
|
|
886
|
+
// 1. If rangeStart is greater than or equal to fullLength, then return a network error.
|
|
887
|
+
if (rangeStart >= fullLength) {
|
|
888
|
+
return Promise.resolve(makeNetworkError('Range start is greater than the blob\'s size.'))
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
// 2. If rangeEnd is null or rangeEnd is greater than or equal to fullLength, then set
|
|
892
|
+
// rangeEnd to fullLength − 1.
|
|
893
|
+
if (rangeEnd === null || rangeEnd >= fullLength) {
|
|
894
|
+
rangeEnd = fullLength - 1
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// 8. Let slicedBlob be the result of invoking slice blob given blob, rangeStart,
|
|
899
|
+
// rangeEnd + 1, and type.
|
|
900
|
+
const slicedBlob = blob.slice(rangeStart, rangeEnd, type)
|
|
901
|
+
|
|
902
|
+
// 9. Let slicedBodyWithType be the result of safely extracting slicedBlob.
|
|
903
|
+
// Note: same reason as mentioned above as to why we use extractBody
|
|
904
|
+
const slicedBodyWithType = extractBody(slicedBlob)
|
|
847
905
|
|
|
848
|
-
|
|
906
|
+
// 10. Set response’s body to slicedBodyWithType’s body.
|
|
907
|
+
response.body = slicedBodyWithType[0]
|
|
849
908
|
|
|
909
|
+
// 11. Let serializedSlicedLength be slicedBlob’s size, serialized and isomorphic encoded.
|
|
910
|
+
const serializedSlicedLength = isomorphicEncode(`${slicedBlob.size}`)
|
|
911
|
+
|
|
912
|
+
// 12. Let contentRange be the result of invoking build a content range given rangeStart,
|
|
913
|
+
// rangeEnd, and fullLength.
|
|
914
|
+
const contentRange = buildContentRange(rangeStart, rangeEnd, fullLength)
|
|
915
|
+
|
|
916
|
+
// 13. Set response’s status to 206.
|
|
917
|
+
response.status = 206
|
|
918
|
+
|
|
919
|
+
// 14. Set response’s status message to `Partial Content`.
|
|
920
|
+
response.statusText = 'Partial Content'
|
|
921
|
+
|
|
922
|
+
// 15. Set response’s header list to « (`Content-Length`, serializedSlicedLength),
|
|
923
|
+
// (`Content-Type`, type), (`Content-Range`, contentRange) ».
|
|
924
|
+
response.headersList.set('content-length', serializedSlicedLength)
|
|
925
|
+
response.headersList.set('content-type', type)
|
|
926
|
+
response.headersList.set('content-range', contentRange)
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
// 10. Return response.
|
|
850
930
|
return Promise.resolve(response)
|
|
851
931
|
}
|
|
852
932
|
case 'data:': {
|
|
@@ -908,92 +988,147 @@ function finalizeResponse (fetchParams, response) {
|
|
|
908
988
|
|
|
909
989
|
// https://fetch.spec.whatwg.org/#fetch-finale
|
|
910
990
|
function fetchFinale (fetchParams, response) {
|
|
911
|
-
// 1.
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
response.timingInfo = createOpaqueTimingInfo({
|
|
919
|
-
startTime: fetchParams.timingInfo.startTime
|
|
920
|
-
})
|
|
921
|
-
}
|
|
991
|
+
// 1. Let timingInfo be fetchParams’s timing info.
|
|
992
|
+
let timingInfo = fetchParams.timingInfo
|
|
993
|
+
|
|
994
|
+
// 2. If response is not a network error and fetchParams’s request’s client is a secure context,
|
|
995
|
+
// then set timingInfo’s server-timing headers to the result of getting, decoding, and splitting
|
|
996
|
+
// `Server-Timing` from response’s internal response’s header list.
|
|
997
|
+
// TODO
|
|
922
998
|
|
|
923
|
-
//
|
|
999
|
+
// 3. Let processResponseEndOfBody be the following steps:
|
|
924
1000
|
const processResponseEndOfBody = () => {
|
|
925
|
-
// 1.
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
// If fetchParams’s
|
|
929
|
-
//
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
1001
|
+
// 1. Let unsafeEndTime be the unsafe shared current time.
|
|
1002
|
+
const unsafeEndTime = Date.now() // ?
|
|
1003
|
+
|
|
1004
|
+
// 2. If fetchParams’s request’s destination is "document", then set fetchParams’s controller’s
|
|
1005
|
+
// full timing info to fetchParams’s timing info.
|
|
1006
|
+
if (fetchParams.request.destination === 'document') {
|
|
1007
|
+
fetchParams.controller.fullTimingInfo = timingInfo
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
// 3. Set fetchParams’s controller’s report timing steps to the following steps given a global object global:
|
|
1011
|
+
fetchParams.controller.reportTimingSteps = () => {
|
|
1012
|
+
// 1. If fetchParams’s request’s URL’s scheme is not an HTTP(S) scheme, then return.
|
|
1013
|
+
if (fetchParams.request.url.protocol !== 'https:') {
|
|
1014
|
+
return
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// 2. Set timingInfo’s end time to the relative high resolution time given unsafeEndTime and global.
|
|
1018
|
+
timingInfo.endTime = unsafeEndTime
|
|
1019
|
+
|
|
1020
|
+
// 3. Let cacheState be response’s cache state.
|
|
1021
|
+
let cacheState = response.cacheState
|
|
1022
|
+
|
|
1023
|
+
// 4. Let bodyInfo be response’s body info.
|
|
1024
|
+
const bodyInfo = response.bodyInfo
|
|
1025
|
+
|
|
1026
|
+
// 5. If response’s timing allow passed flag is not set, then set timingInfo to the result of creating an
|
|
1027
|
+
// opaque timing info for timingInfo and set cacheState to the empty string.
|
|
1028
|
+
if (!response.timingAllowPassed) {
|
|
1029
|
+
timingInfo = createOpaqueTimingInfo(timingInfo)
|
|
1030
|
+
|
|
1031
|
+
cacheState = ''
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
// 6. Let responseStatus be 0.
|
|
1035
|
+
let responseStatus = 0
|
|
1036
|
+
|
|
1037
|
+
// 7. If fetchParams’s request’s mode is not "navigate" or response’s has-cross-origin-redirects is false:
|
|
1038
|
+
if (fetchParams.request.mode !== 'navigator' || !response.hasCrossOriginRedirects) {
|
|
1039
|
+
// 1. Set responseStatus to response’s status.
|
|
1040
|
+
responseStatus = response.status
|
|
1041
|
+
|
|
1042
|
+
// 2. Let mimeType be the result of extracting a MIME type from response’s header list.
|
|
1043
|
+
const mimeType = parseMIMEType(response.headersList.get('content-type')) // TODO: fix
|
|
1044
|
+
|
|
1045
|
+
// 3. If mimeType is not failure, then set bodyInfo’s content type to the result of minimizing a supported MIME type given mimeType.
|
|
1046
|
+
if (mimeType !== 'failure') {
|
|
1047
|
+
// TODO
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
// 8. If fetchParams’s request’s initiator type is non-null, then mark resource timing given timingInfo,
|
|
1052
|
+
// fetchParams’s request’s URL, fetchParams’s request’s initiator type, global, cacheState, bodyInfo,
|
|
1053
|
+
// and responseStatus.
|
|
1054
|
+
if (fetchParams.request.initiatorType != null) {
|
|
1055
|
+
// TODO: update markresourcetiming
|
|
1056
|
+
markResourceTiming(timingInfo, fetchParams.request.url, fetchParams.request.initiatorType, globalThis, cacheState, bodyInfo, responseStatus)
|
|
1057
|
+
}
|
|
933
1058
|
}
|
|
1059
|
+
|
|
1060
|
+
// 4. Let processResponseEndOfBodyTask be the following steps:
|
|
1061
|
+
const processResponseEndOfBodyTask = () => {
|
|
1062
|
+
// 1. Set fetchParams’s request’s done flag.
|
|
1063
|
+
fetchParams.request.done = true
|
|
1064
|
+
|
|
1065
|
+
// 2. If fetchParams’s process response end-of-body is non-null, then run fetchParams’s process
|
|
1066
|
+
// response end-of-body given response.
|
|
1067
|
+
if (fetchParams.processResponseEndOfBody != null) {
|
|
1068
|
+
queueMicrotask(() => fetchParams.processResponseEndOfBody(response))
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// 3. If fetchParams’s request’s initiator type is non-null and fetchParams’s request’s client’s
|
|
1072
|
+
// global object is fetchParams’s task destination, then run fetchParams’s controller’s report
|
|
1073
|
+
// timing steps given fetchParams’s request’s client’s global object.
|
|
1074
|
+
if (fetchParams.request.initiatorType != null) {
|
|
1075
|
+
fetchParams.controller.reportTimingSteps()
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
// 5. Queue a fetch task to run processResponseEndOfBodyTask with fetchParams’s task destination
|
|
1080
|
+
queueMicrotask(() => processResponseEndOfBodyTask())
|
|
934
1081
|
}
|
|
935
1082
|
|
|
936
|
-
//
|
|
937
|
-
//
|
|
938
|
-
// task destination.
|
|
1083
|
+
// 4. If fetchParams’s process response is non-null, then queue a fetch task to run fetchParams’s
|
|
1084
|
+
// process response given response, with fetchParams’s task destination.
|
|
939
1085
|
if (fetchParams.processResponse != null) {
|
|
940
1086
|
queueMicrotask(() => fetchParams.processResponse(response))
|
|
941
1087
|
}
|
|
942
1088
|
|
|
943
|
-
//
|
|
944
|
-
|
|
1089
|
+
// 5. Let internalResponse be response, if response is a network error; otherwise response’s internal response.
|
|
1090
|
+
const internalResponse = response.type === 'error' ? response : (response.internalResponse ?? response)
|
|
1091
|
+
|
|
1092
|
+
// 6. If internalResponse’s body is null, then run processResponseEndOfBody.
|
|
1093
|
+
// 7. Otherwise:
|
|
1094
|
+
if (internalResponse.body == null) {
|
|
945
1095
|
processResponseEndOfBody()
|
|
946
1096
|
} else {
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
//
|
|
950
|
-
|
|
951
|
-
// 2. Let identityTransformAlgorithm be an algorithm which, given chunk,
|
|
952
|
-
// enqueues chunk in transformStream.
|
|
953
|
-
const identityTransformAlgorithm = (chunk, controller) => {
|
|
954
|
-
controller.enqueue(chunk)
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
// 3. Set up transformStream with transformAlgorithm set to identityTransformAlgorithm
|
|
958
|
-
// and flushAlgorithm set to processResponseEndOfBody.
|
|
1097
|
+
// 1. Let transformStream be a new TransformStream.
|
|
1098
|
+
// 2. Let identityTransformAlgorithm be an algorithm which, given chunk, enqueues chunk in transformStream.
|
|
1099
|
+
// 3. Set up transformStream with transformAlgorithm set to identityTransformAlgorithm and flushAlgorithm
|
|
1100
|
+
// set to processResponseEndOfBody.
|
|
959
1101
|
const transformStream = new TransformStream({
|
|
960
1102
|
start () {},
|
|
961
|
-
transform
|
|
1103
|
+
transform (chunk, controller) {
|
|
1104
|
+
controller.enqueue(chunk)
|
|
1105
|
+
},
|
|
962
1106
|
flush: processResponseEndOfBody
|
|
963
|
-
}, {
|
|
964
|
-
size () {
|
|
965
|
-
return 1
|
|
966
|
-
}
|
|
967
|
-
}, {
|
|
968
|
-
size () {
|
|
969
|
-
return 1
|
|
970
|
-
}
|
|
971
1107
|
})
|
|
972
1108
|
|
|
973
|
-
// 4. Set
|
|
974
|
-
|
|
975
|
-
|
|
1109
|
+
// 4. Set internalResponse’s body’s stream to the result of internalResponse’s body’s stream piped through transformStream.
|
|
1110
|
+
internalResponse.body.stream.pipeThrough(transformStream)
|
|
1111
|
+
|
|
1112
|
+
const byteStream = new ReadableStream({
|
|
1113
|
+
readableStream: transformStream.readable,
|
|
1114
|
+
async start (controller) {
|
|
1115
|
+
const reader = this.readableStream.getReader()
|
|
976
1116
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
// 1. Let processBody given nullOrBytes be this step: run fetchParams’s
|
|
980
|
-
// process response consume body given response and nullOrBytes.
|
|
981
|
-
const processBody = (nullOrBytes) => fetchParams.processResponseConsumeBody(response, nullOrBytes)
|
|
1117
|
+
while (true) {
|
|
1118
|
+
const { done, value } = await reader.read()
|
|
982
1119
|
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1120
|
+
if (done) {
|
|
1121
|
+
queueMicrotask(() => readableStreamClose(controller))
|
|
1122
|
+
break
|
|
1123
|
+
}
|
|
986
1124
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
return fullyReadBody(response.body, processBody, processBodyError)
|
|
995
|
-
}
|
|
996
|
-
return Promise.resolve()
|
|
1125
|
+
controller.enqueue(value)
|
|
1126
|
+
}
|
|
1127
|
+
},
|
|
1128
|
+
type: 'bytes'
|
|
1129
|
+
})
|
|
1130
|
+
|
|
1131
|
+
internalResponse.body.stream = byteStream
|
|
997
1132
|
}
|
|
998
1133
|
}
|
|
999
1134
|
|
|
@@ -1795,13 +1930,8 @@ async function httpNetworkFetch (
|
|
|
1795
1930
|
// TODO
|
|
1796
1931
|
|
|
1797
1932
|
// 15. Let stream be a new ReadableStream.
|
|
1798
|
-
// 16. Set up stream with pullAlgorithm set to pullAlgorithm,
|
|
1799
|
-
//
|
|
1800
|
-
// highWaterMark, and sizeAlgorithm set to sizeAlgorithm.
|
|
1801
|
-
if (!ReadableStream) {
|
|
1802
|
-
ReadableStream = require('stream/web').ReadableStream
|
|
1803
|
-
}
|
|
1804
|
-
|
|
1933
|
+
// 16. Set up stream with byte reading support with pullAlgorithm set to pullAlgorithm,
|
|
1934
|
+
// cancelAlgorithm set to cancelAlgorithm.
|
|
1805
1935
|
const stream = new ReadableStream(
|
|
1806
1936
|
{
|
|
1807
1937
|
async start (controller) {
|
|
@@ -1812,13 +1942,8 @@ async function httpNetworkFetch (
|
|
|
1812
1942
|
},
|
|
1813
1943
|
async cancel (reason) {
|
|
1814
1944
|
await cancelAlgorithm(reason)
|
|
1815
|
-
}
|
|
1816
|
-
|
|
1817
|
-
{
|
|
1818
|
-
highWaterMark: 0,
|
|
1819
|
-
size () {
|
|
1820
|
-
return 1
|
|
1821
|
-
}
|
|
1945
|
+
},
|
|
1946
|
+
type: 'bytes'
|
|
1822
1947
|
}
|
|
1823
1948
|
)
|
|
1824
1949
|
|
|
@@ -1898,7 +2023,10 @@ async function httpNetworkFetch (
|
|
|
1898
2023
|
|
|
1899
2024
|
// 7. Enqueue a Uint8Array wrapping an ArrayBuffer containing bytes
|
|
1900
2025
|
// into stream.
|
|
1901
|
-
|
|
2026
|
+
const buffer = new Uint8Array(bytes)
|
|
2027
|
+
if (buffer.byteLength) {
|
|
2028
|
+
fetchParams.controller.controller.enqueue(buffer)
|
|
2029
|
+
}
|
|
1902
2030
|
|
|
1903
2031
|
// 8. If stream is errored, then terminate the ongoing fetch.
|
|
1904
2032
|
if (isErrored(stream)) {
|
package/lib/fetch/request.js
CHANGED
|
@@ -28,13 +28,10 @@ const { kHeaders, kSignal, kState, kGuard, kRealm } = require('./symbols')
|
|
|
28
28
|
const { webidl } = require('./webidl')
|
|
29
29
|
const { getGlobalOrigin } = require('./global')
|
|
30
30
|
const { URLSerializer } = require('./dataURL')
|
|
31
|
-
const { kHeadersList } = require('../core/symbols')
|
|
31
|
+
const { kHeadersList, kConstruct } = require('../core/symbols')
|
|
32
32
|
const assert = require('assert')
|
|
33
33
|
const { getMaxListeners, setMaxListeners, getEventListeners, defaultMaxListeners } = require('events')
|
|
34
34
|
|
|
35
|
-
let TransformStream = globalThis.TransformStream
|
|
36
|
-
|
|
37
|
-
const kInit = Symbol('init')
|
|
38
35
|
const kAbortController = Symbol('abortController')
|
|
39
36
|
|
|
40
37
|
const requestFinalizer = new FinalizationRegistry(({ signal, abort }) => {
|
|
@@ -45,7 +42,7 @@ const requestFinalizer = new FinalizationRegistry(({ signal, abort }) => {
|
|
|
45
42
|
class Request {
|
|
46
43
|
// https://fetch.spec.whatwg.org/#dom-request
|
|
47
44
|
constructor (input, init = {}) {
|
|
48
|
-
if (input ===
|
|
45
|
+
if (input === kConstruct) {
|
|
49
46
|
return
|
|
50
47
|
}
|
|
51
48
|
|
|
@@ -302,7 +299,7 @@ class Request {
|
|
|
302
299
|
}
|
|
303
300
|
|
|
304
301
|
// 23. If init["integrity"] exists, then set request’s integrity metadata to it.
|
|
305
|
-
if (init.integrity
|
|
302
|
+
if (init.integrity != null) {
|
|
306
303
|
request.integrity = String(init.integrity)
|
|
307
304
|
}
|
|
308
305
|
|
|
@@ -398,7 +395,7 @@ class Request {
|
|
|
398
395
|
// 30. Set this’s headers to a new Headers object with this’s relevant
|
|
399
396
|
// Realm, whose header list is request’s header list and guard is
|
|
400
397
|
// "request".
|
|
401
|
-
this[kHeaders] = new Headers()
|
|
398
|
+
this[kHeaders] = new Headers(kConstruct)
|
|
402
399
|
this[kHeaders][kHeadersList] = request.headersList
|
|
403
400
|
this[kHeaders][kGuard] = 'request'
|
|
404
401
|
this[kHeaders][kRealm] = this[kRealm]
|
|
@@ -517,10 +514,6 @@ class Request {
|
|
|
517
514
|
}
|
|
518
515
|
|
|
519
516
|
// 2. Set finalBody to the result of creating a proxy for inputBody.
|
|
520
|
-
if (!TransformStream) {
|
|
521
|
-
TransformStream = require('stream/web').TransformStream
|
|
522
|
-
}
|
|
523
|
-
|
|
524
517
|
// https://streams.spec.whatwg.org/#readablestream-create-a-proxy
|
|
525
518
|
const identityTransform = new TransformStream()
|
|
526
519
|
inputBody.stream.pipeThrough(identityTransform)
|
|
@@ -725,10 +718,10 @@ class Request {
|
|
|
725
718
|
|
|
726
719
|
// 3. Let clonedRequestObject be the result of creating a Request object,
|
|
727
720
|
// given clonedRequest, this’s headers’s guard, and this’s relevant Realm.
|
|
728
|
-
const clonedRequestObject = new Request(
|
|
721
|
+
const clonedRequestObject = new Request(kConstruct)
|
|
729
722
|
clonedRequestObject[kState] = clonedRequest
|
|
730
723
|
clonedRequestObject[kRealm] = this[kRealm]
|
|
731
|
-
clonedRequestObject[kHeaders] = new Headers()
|
|
724
|
+
clonedRequestObject[kHeaders] = new Headers(kConstruct)
|
|
732
725
|
clonedRequestObject[kHeaders][kHeadersList] = clonedRequest.headersList
|
|
733
726
|
clonedRequestObject[kHeaders][kGuard] = this[kHeaders][kGuard]
|
|
734
727
|
clonedRequestObject[kHeaders][kRealm] = this[kHeaders][kRealm]
|
package/lib/fetch/response.js
CHANGED
|
@@ -15,19 +15,17 @@ const {
|
|
|
15
15
|
} = require('./util')
|
|
16
16
|
const {
|
|
17
17
|
redirectStatusSet,
|
|
18
|
-
nullBodyStatus
|
|
19
|
-
DOMException
|
|
18
|
+
nullBodyStatus
|
|
20
19
|
} = require('./constants')
|
|
21
20
|
const { kState, kHeaders, kGuard, kRealm } = require('./symbols')
|
|
22
21
|
const { webidl } = require('./webidl')
|
|
23
22
|
const { FormData } = require('./formdata')
|
|
24
23
|
const { getGlobalOrigin } = require('./global')
|
|
25
24
|
const { URLSerializer } = require('./dataURL')
|
|
26
|
-
const { kHeadersList } = require('../core/symbols')
|
|
25
|
+
const { kHeadersList, kConstruct } = require('../core/symbols')
|
|
27
26
|
const assert = require('assert')
|
|
28
27
|
const { types } = require('util')
|
|
29
28
|
|
|
30
|
-
const ReadableStream = globalThis.ReadableStream || require('stream/web').ReadableStream
|
|
31
29
|
const textEncoder = new TextEncoder('utf-8')
|
|
32
30
|
|
|
33
31
|
// https://fetch.spec.whatwg.org/#response-class
|
|
@@ -40,9 +38,10 @@ class Response {
|
|
|
40
38
|
// The static error() method steps are to return the result of creating a
|
|
41
39
|
// Response object, given a new network error, "immutable", and this’s
|
|
42
40
|
// relevant Realm.
|
|
43
|
-
const responseObject = new Response()
|
|
41
|
+
const responseObject = new Response(kConstruct)
|
|
44
42
|
responseObject[kState] = makeNetworkError()
|
|
45
43
|
responseObject[kRealm] = relevantRealm
|
|
44
|
+
responseObject[kHeaders] = new Headers(kConstruct)
|
|
46
45
|
responseObject[kHeaders][kHeadersList] = responseObject[kState].headersList
|
|
47
46
|
responseObject[kHeaders][kGuard] = 'immutable'
|
|
48
47
|
responseObject[kHeaders][kRealm] = relevantRealm
|
|
@@ -68,8 +67,11 @@ class Response {
|
|
|
68
67
|
// 3. Let responseObject be the result of creating a Response object, given a new response,
|
|
69
68
|
// "response", and this’s relevant Realm.
|
|
70
69
|
const relevantRealm = { settingsObject: {} }
|
|
71
|
-
const responseObject = new Response()
|
|
70
|
+
const responseObject = new Response(kConstruct)
|
|
71
|
+
responseObject[kState] = makeResponse({})
|
|
72
72
|
responseObject[kRealm] = relevantRealm
|
|
73
|
+
responseObject[kHeaders] = new Headers(kConstruct)
|
|
74
|
+
responseObject[kHeaders][kHeadersList] = responseObject[kState].headersList
|
|
73
75
|
responseObject[kHeaders][kGuard] = 'response'
|
|
74
76
|
responseObject[kHeaders][kRealm] = relevantRealm
|
|
75
77
|
|
|
@@ -109,8 +111,11 @@ class Response {
|
|
|
109
111
|
|
|
110
112
|
// 4. Let responseObject be the result of creating a Response object,
|
|
111
113
|
// given a new response, "immutable", and this’s relevant Realm.
|
|
112
|
-
const responseObject = new Response()
|
|
114
|
+
const responseObject = new Response(kConstruct)
|
|
115
|
+
responseObject[kState] = makeResponse({})
|
|
113
116
|
responseObject[kRealm] = relevantRealm
|
|
117
|
+
responseObject[kHeaders] = new Headers(kConstruct)
|
|
118
|
+
responseObject[kHeaders][kHeadersList] = responseObject[kState].headersList
|
|
114
119
|
responseObject[kHeaders][kGuard] = 'immutable'
|
|
115
120
|
responseObject[kHeaders][kRealm] = relevantRealm
|
|
116
121
|
|
|
@@ -129,6 +134,10 @@ class Response {
|
|
|
129
134
|
|
|
130
135
|
// https://fetch.spec.whatwg.org/#dom-response
|
|
131
136
|
constructor (body = null, init = {}) {
|
|
137
|
+
if (body === kConstruct) {
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
|
|
132
141
|
if (body !== null) {
|
|
133
142
|
body = webidl.converters.BodyInit(body)
|
|
134
143
|
}
|
|
@@ -144,7 +153,7 @@ class Response {
|
|
|
144
153
|
// 2. Set this’s headers to a new Headers object with this’s relevant
|
|
145
154
|
// Realm, whose header list is this’s response’s header list and guard
|
|
146
155
|
// is "response".
|
|
147
|
-
this[kHeaders] = new Headers()
|
|
156
|
+
this[kHeaders] = new Headers(kConstruct)
|
|
148
157
|
this[kHeaders][kGuard] = 'response'
|
|
149
158
|
this[kHeaders][kHeadersList] = this[kState].headersList
|
|
150
159
|
this[kHeaders][kRealm] = this[kRealm]
|
|
@@ -260,9 +269,10 @@ class Response {
|
|
|
260
269
|
|
|
261
270
|
// 3. Return the result of creating a Response object, given
|
|
262
271
|
// clonedResponse, this’s headers’s guard, and this’s relevant Realm.
|
|
263
|
-
const clonedResponseObject = new Response()
|
|
272
|
+
const clonedResponseObject = new Response(kConstruct)
|
|
264
273
|
clonedResponseObject[kState] = clonedResponse
|
|
265
274
|
clonedResponseObject[kRealm] = this[kRealm]
|
|
275
|
+
clonedResponseObject[kHeaders] = new Headers(kConstruct)
|
|
266
276
|
clonedResponseObject[kHeaders][kHeadersList] = clonedResponse.headersList
|
|
267
277
|
clonedResponseObject[kHeaders][kGuard] = this[kHeaders][kGuard]
|
|
268
278
|
clonedResponseObject[kHeaders][kRealm] = this[kHeaders][kRealm]
|
|
@@ -335,10 +345,10 @@ function makeResponse (init) {
|
|
|
335
345
|
cacheState: '',
|
|
336
346
|
statusText: '',
|
|
337
347
|
...init,
|
|
338
|
-
headersList: init
|
|
339
|
-
? new HeadersList(init
|
|
348
|
+
headersList: init?.headersList
|
|
349
|
+
? new HeadersList(init?.headersList)
|
|
340
350
|
: new HeadersList(),
|
|
341
|
-
urlList: init
|
|
351
|
+
urlList: init?.urlList ? [...init.urlList] : []
|
|
342
352
|
}
|
|
343
353
|
}
|
|
344
354
|
|
|
@@ -514,11 +524,7 @@ webidl.converters.XMLHttpRequestBodyInit = function (V) {
|
|
|
514
524
|
return webidl.converters.Blob(V, { strict: false })
|
|
515
525
|
}
|
|
516
526
|
|
|
517
|
-
if (
|
|
518
|
-
types.isAnyArrayBuffer(V) ||
|
|
519
|
-
types.isTypedArray(V) ||
|
|
520
|
-
types.isDataView(V)
|
|
521
|
-
) {
|
|
527
|
+
if (types.isArrayBuffer(V) || types.isTypedArray(V) || types.isDataView(V)) {
|
|
522
528
|
return webidl.converters.BufferSource(V)
|
|
523
529
|
}
|
|
524
530
|
|