deepv-code 1.0.182 → 1.0.185

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.
Files changed (193) hide show
  1. package/bundle/dvcode.js +757 -753
  2. package/package.json +1 -1
  3. package/bundle/assets/help/README.md +0 -113
  4. package/bundle/assets/sounds/README.md +0 -74
  5. package/bundle/node_modules/undici/LICENSE +0 -21
  6. package/bundle/node_modules/undici/README.md +0 -472
  7. package/bundle/node_modules/undici/docs/docs/api/Agent.md +0 -83
  8. package/bundle/node_modules/undici/docs/docs/api/BalancedPool.md +0 -99
  9. package/bundle/node_modules/undici/docs/docs/api/CacheStorage.md +0 -30
  10. package/bundle/node_modules/undici/docs/docs/api/CacheStore.md +0 -151
  11. package/bundle/node_modules/undici/docs/docs/api/Client.md +0 -281
  12. package/bundle/node_modules/undici/docs/docs/api/ClientStats.md +0 -27
  13. package/bundle/node_modules/undici/docs/docs/api/Connector.md +0 -115
  14. package/bundle/node_modules/undici/docs/docs/api/ContentType.md +0 -57
  15. package/bundle/node_modules/undici/docs/docs/api/Cookies.md +0 -101
  16. package/bundle/node_modules/undici/docs/docs/api/Debug.md +0 -62
  17. package/bundle/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +0 -204
  18. package/bundle/node_modules/undici/docs/docs/api/Dispatcher.md +0 -1200
  19. package/bundle/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +0 -159
  20. package/bundle/node_modules/undici/docs/docs/api/Errors.md +0 -49
  21. package/bundle/node_modules/undici/docs/docs/api/EventSource.md +0 -45
  22. package/bundle/node_modules/undici/docs/docs/api/Fetch.md +0 -52
  23. package/bundle/node_modules/undici/docs/docs/api/H2CClient.md +0 -262
  24. package/bundle/node_modules/undici/docs/docs/api/MockAgent.md +0 -603
  25. package/bundle/node_modules/undici/docs/docs/api/MockCallHistory.md +0 -197
  26. package/bundle/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +0 -43
  27. package/bundle/node_modules/undici/docs/docs/api/MockClient.md +0 -77
  28. package/bundle/node_modules/undici/docs/docs/api/MockErrors.md +0 -12
  29. package/bundle/node_modules/undici/docs/docs/api/MockPool.md +0 -548
  30. package/bundle/node_modules/undici/docs/docs/api/Pool.md +0 -84
  31. package/bundle/node_modules/undici/docs/docs/api/PoolStats.md +0 -35
  32. package/bundle/node_modules/undici/docs/docs/api/ProxyAgent.md +0 -227
  33. package/bundle/node_modules/undici/docs/docs/api/RedirectHandler.md +0 -96
  34. package/bundle/node_modules/undici/docs/docs/api/RetryAgent.md +0 -45
  35. package/bundle/node_modules/undici/docs/docs/api/RetryHandler.md +0 -117
  36. package/bundle/node_modules/undici/docs/docs/api/Util.md +0 -25
  37. package/bundle/node_modules/undici/docs/docs/api/WebSocket.md +0 -85
  38. package/bundle/node_modules/undici/docs/docs/api/api-lifecycle.md +0 -91
  39. package/bundle/node_modules/undici/docs/docs/best-practices/client-certificate.md +0 -64
  40. package/bundle/node_modules/undici/docs/docs/best-practices/mocking-request.md +0 -190
  41. package/bundle/node_modules/undici/docs/docs/best-practices/proxy.md +0 -127
  42. package/bundle/node_modules/undici/docs/docs/best-practices/writing-tests.md +0 -20
  43. package/bundle/node_modules/undici/index-fetch.js +0 -35
  44. package/bundle/node_modules/undici/index.d.ts +0 -3
  45. package/bundle/node_modules/undici/index.js +0 -183
  46. package/bundle/node_modules/undici/lib/api/abort-signal.js +0 -59
  47. package/bundle/node_modules/undici/lib/api/api-connect.js +0 -110
  48. package/bundle/node_modules/undici/lib/api/api-pipeline.js +0 -252
  49. package/bundle/node_modules/undici/lib/api/api-request.js +0 -199
  50. package/bundle/node_modules/undici/lib/api/api-stream.js +0 -209
  51. package/bundle/node_modules/undici/lib/api/api-upgrade.js +0 -110
  52. package/bundle/node_modules/undici/lib/api/index.js +0 -7
  53. package/bundle/node_modules/undici/lib/api/readable.js +0 -558
  54. package/bundle/node_modules/undici/lib/api/util.js +0 -95
  55. package/bundle/node_modules/undici/lib/cache/memory-cache-store.js +0 -234
  56. package/bundle/node_modules/undici/lib/cache/sqlite-cache-store.js +0 -461
  57. package/bundle/node_modules/undici/lib/core/connect.js +0 -164
  58. package/bundle/node_modules/undici/lib/core/constants.js +0 -143
  59. package/bundle/node_modules/undici/lib/core/diagnostics.js +0 -196
  60. package/bundle/node_modules/undici/lib/core/errors.js +0 -244
  61. package/bundle/node_modules/undici/lib/core/request.js +0 -397
  62. package/bundle/node_modules/undici/lib/core/symbols.js +0 -68
  63. package/bundle/node_modules/undici/lib/core/tree.js +0 -160
  64. package/bundle/node_modules/undici/lib/core/util.js +0 -988
  65. package/bundle/node_modules/undici/lib/dispatcher/agent.js +0 -135
  66. package/bundle/node_modules/undici/lib/dispatcher/balanced-pool.js +0 -206
  67. package/bundle/node_modules/undici/lib/dispatcher/client-h1.js +0 -1615
  68. package/bundle/node_modules/undici/lib/dispatcher/client-h2.js +0 -798
  69. package/bundle/node_modules/undici/lib/dispatcher/client.js +0 -614
  70. package/bundle/node_modules/undici/lib/dispatcher/dispatcher-base.js +0 -161
  71. package/bundle/node_modules/undici/lib/dispatcher/dispatcher.js +0 -48
  72. package/bundle/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +0 -151
  73. package/bundle/node_modules/undici/lib/dispatcher/fixed-queue.js +0 -159
  74. package/bundle/node_modules/undici/lib/dispatcher/h2c-client.js +0 -122
  75. package/bundle/node_modules/undici/lib/dispatcher/pool-base.js +0 -191
  76. package/bundle/node_modules/undici/lib/dispatcher/pool.js +0 -118
  77. package/bundle/node_modules/undici/lib/dispatcher/proxy-agent.js +0 -275
  78. package/bundle/node_modules/undici/lib/dispatcher/retry-agent.js +0 -35
  79. package/bundle/node_modules/undici/lib/global.js +0 -32
  80. package/bundle/node_modules/undici/lib/handler/cache-handler.js +0 -448
  81. package/bundle/node_modules/undici/lib/handler/cache-revalidation-handler.js +0 -124
  82. package/bundle/node_modules/undici/lib/handler/decorator-handler.js +0 -67
  83. package/bundle/node_modules/undici/lib/handler/redirect-handler.js +0 -227
  84. package/bundle/node_modules/undici/lib/handler/retry-handler.js +0 -342
  85. package/bundle/node_modules/undici/lib/handler/unwrap-handler.js +0 -96
  86. package/bundle/node_modules/undici/lib/handler/wrap-handler.js +0 -95
  87. package/bundle/node_modules/undici/lib/interceptor/cache.js +0 -372
  88. package/bundle/node_modules/undici/lib/interceptor/dns.js +0 -432
  89. package/bundle/node_modules/undici/lib/interceptor/dump.js +0 -111
  90. package/bundle/node_modules/undici/lib/interceptor/redirect.js +0 -21
  91. package/bundle/node_modules/undici/lib/interceptor/response-error.js +0 -95
  92. package/bundle/node_modules/undici/lib/interceptor/retry.js +0 -19
  93. package/bundle/node_modules/undici/lib/llhttp/.gitkeep +0 -0
  94. package/bundle/node_modules/undici/lib/llhttp/constants.d.ts +0 -97
  95. package/bundle/node_modules/undici/lib/llhttp/constants.js +0 -498
  96. package/bundle/node_modules/undici/lib/llhttp/constants.js.map +0 -1
  97. package/bundle/node_modules/undici/lib/llhttp/llhttp-wasm.js +0 -15
  98. package/bundle/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +0 -15
  99. package/bundle/node_modules/undici/lib/llhttp/utils.d.ts +0 -2
  100. package/bundle/node_modules/undici/lib/llhttp/utils.js +0 -15
  101. package/bundle/node_modules/undici/lib/llhttp/utils.js.map +0 -1
  102. package/bundle/node_modules/undici/lib/mock/mock-agent.js +0 -224
  103. package/bundle/node_modules/undici/lib/mock/mock-call-history.js +0 -248
  104. package/bundle/node_modules/undici/lib/mock/mock-client.js +0 -64
  105. package/bundle/node_modules/undici/lib/mock/mock-errors.js +0 -19
  106. package/bundle/node_modules/undici/lib/mock/mock-interceptor.js +0 -209
  107. package/bundle/node_modules/undici/lib/mock/mock-pool.js +0 -64
  108. package/bundle/node_modules/undici/lib/mock/mock-symbols.js +0 -31
  109. package/bundle/node_modules/undici/lib/mock/mock-utils.js +0 -433
  110. package/bundle/node_modules/undici/lib/mock/pending-interceptors-formatter.js +0 -43
  111. package/bundle/node_modules/undici/lib/util/cache.js +0 -368
  112. package/bundle/node_modules/undici/lib/util/date.js +0 -259
  113. package/bundle/node_modules/undici/lib/util/stats.js +0 -32
  114. package/bundle/node_modules/undici/lib/util/timers.js +0 -423
  115. package/bundle/node_modules/undici/lib/web/cache/cache.js +0 -862
  116. package/bundle/node_modules/undici/lib/web/cache/cachestorage.js +0 -152
  117. package/bundle/node_modules/undici/lib/web/cache/util.js +0 -45
  118. package/bundle/node_modules/undici/lib/web/cookies/constants.js +0 -12
  119. package/bundle/node_modules/undici/lib/web/cookies/index.js +0 -199
  120. package/bundle/node_modules/undici/lib/web/cookies/parse.js +0 -322
  121. package/bundle/node_modules/undici/lib/web/cookies/util.js +0 -282
  122. package/bundle/node_modules/undici/lib/web/eventsource/eventsource-stream.js +0 -399
  123. package/bundle/node_modules/undici/lib/web/eventsource/eventsource.js +0 -484
  124. package/bundle/node_modules/undici/lib/web/eventsource/util.js +0 -37
  125. package/bundle/node_modules/undici/lib/web/fetch/LICENSE +0 -21
  126. package/bundle/node_modules/undici/lib/web/fetch/body.js +0 -532
  127. package/bundle/node_modules/undici/lib/web/fetch/constants.js +0 -131
  128. package/bundle/node_modules/undici/lib/web/fetch/data-url.js +0 -744
  129. package/bundle/node_modules/undici/lib/web/fetch/dispatcher-weakref.js +0 -46
  130. package/bundle/node_modules/undici/lib/web/fetch/formdata-parser.js +0 -501
  131. package/bundle/node_modules/undici/lib/web/fetch/formdata.js +0 -263
  132. package/bundle/node_modules/undici/lib/web/fetch/global.js +0 -40
  133. package/bundle/node_modules/undici/lib/web/fetch/headers.js +0 -719
  134. package/bundle/node_modules/undici/lib/web/fetch/index.js +0 -2258
  135. package/bundle/node_modules/undici/lib/web/fetch/request.js +0 -1099
  136. package/bundle/node_modules/undici/lib/web/fetch/response.js +0 -636
  137. package/bundle/node_modules/undici/lib/web/fetch/util.js +0 -1782
  138. package/bundle/node_modules/undici/lib/web/fetch/webidl.js +0 -740
  139. package/bundle/node_modules/undici/lib/web/websocket/connection.js +0 -325
  140. package/bundle/node_modules/undici/lib/web/websocket/constants.js +0 -126
  141. package/bundle/node_modules/undici/lib/web/websocket/events.js +0 -331
  142. package/bundle/node_modules/undici/lib/web/websocket/frame.js +0 -138
  143. package/bundle/node_modules/undici/lib/web/websocket/permessage-deflate.js +0 -70
  144. package/bundle/node_modules/undici/lib/web/websocket/receiver.js +0 -454
  145. package/bundle/node_modules/undici/lib/web/websocket/sender.js +0 -109
  146. package/bundle/node_modules/undici/lib/web/websocket/stream/websocketerror.js +0 -83
  147. package/bundle/node_modules/undici/lib/web/websocket/stream/websocketstream.js +0 -485
  148. package/bundle/node_modules/undici/lib/web/websocket/util.js +0 -338
  149. package/bundle/node_modules/undici/lib/web/websocket/websocket.js +0 -686
  150. package/bundle/node_modules/undici/package.json +0 -149
  151. package/bundle/node_modules/undici/scripts/strip-comments.js +0 -10
  152. package/bundle/node_modules/undici/types/README.md +0 -6
  153. package/bundle/node_modules/undici/types/agent.d.ts +0 -35
  154. package/bundle/node_modules/undici/types/api.d.ts +0 -43
  155. package/bundle/node_modules/undici/types/balanced-pool.d.ts +0 -29
  156. package/bundle/node_modules/undici/types/cache-interceptor.d.ts +0 -172
  157. package/bundle/node_modules/undici/types/cache.d.ts +0 -36
  158. package/bundle/node_modules/undici/types/client-stats.d.ts +0 -15
  159. package/bundle/node_modules/undici/types/client.d.ts +0 -110
  160. package/bundle/node_modules/undici/types/connector.d.ts +0 -34
  161. package/bundle/node_modules/undici/types/content-type.d.ts +0 -21
  162. package/bundle/node_modules/undici/types/cookies.d.ts +0 -30
  163. package/bundle/node_modules/undici/types/diagnostics-channel.d.ts +0 -66
  164. package/bundle/node_modules/undici/types/dispatcher.d.ts +0 -281
  165. package/bundle/node_modules/undici/types/env-http-proxy-agent.d.ts +0 -21
  166. package/bundle/node_modules/undici/types/errors.d.ts +0 -171
  167. package/bundle/node_modules/undici/types/eventsource.d.ts +0 -61
  168. package/bundle/node_modules/undici/types/fetch.d.ts +0 -210
  169. package/bundle/node_modules/undici/types/formdata.d.ts +0 -108
  170. package/bundle/node_modules/undici/types/global-dispatcher.d.ts +0 -9
  171. package/bundle/node_modules/undici/types/global-origin.d.ts +0 -7
  172. package/bundle/node_modules/undici/types/h2c-client.d.ts +0 -75
  173. package/bundle/node_modules/undici/types/handlers.d.ts +0 -15
  174. package/bundle/node_modules/undici/types/header.d.ts +0 -160
  175. package/bundle/node_modules/undici/types/index.d.ts +0 -75
  176. package/bundle/node_modules/undici/types/interceptors.d.ts +0 -34
  177. package/bundle/node_modules/undici/types/mock-agent.d.ts +0 -68
  178. package/bundle/node_modules/undici/types/mock-call-history.d.ts +0 -111
  179. package/bundle/node_modules/undici/types/mock-client.d.ts +0 -25
  180. package/bundle/node_modules/undici/types/mock-errors.d.ts +0 -12
  181. package/bundle/node_modules/undici/types/mock-interceptor.d.ts +0 -93
  182. package/bundle/node_modules/undici/types/mock-pool.d.ts +0 -25
  183. package/bundle/node_modules/undici/types/patch.d.ts +0 -29
  184. package/bundle/node_modules/undici/types/pool-stats.d.ts +0 -19
  185. package/bundle/node_modules/undici/types/pool.d.ts +0 -41
  186. package/bundle/node_modules/undici/types/proxy-agent.d.ts +0 -29
  187. package/bundle/node_modules/undici/types/readable.d.ts +0 -68
  188. package/bundle/node_modules/undici/types/retry-agent.d.ts +0 -8
  189. package/bundle/node_modules/undici/types/retry-handler.d.ts +0 -116
  190. package/bundle/node_modules/undici/types/util.d.ts +0 -18
  191. package/bundle/node_modules/undici/types/utility.d.ts +0 -7
  192. package/bundle/node_modules/undici/types/webidl.d.ts +0 -266
  193. package/bundle/node_modules/undici/types/websocket.d.ts +0 -184
@@ -1,2258 +0,0 @@
1
- // https://github.com/Ethan-Arrowood/undici-fetch
2
-
3
- 'use strict'
4
-
5
- const {
6
- makeNetworkError,
7
- makeAppropriateNetworkError,
8
- filterResponse,
9
- makeResponse,
10
- fromInnerResponse,
11
- getResponseState
12
- } = require('./response')
13
- const { HeadersList } = require('./headers')
14
- const { Request, cloneRequest, getRequestDispatcher, getRequestState } = require('./request')
15
- const zlib = require('node:zlib')
16
- const {
17
- bytesMatch,
18
- makePolicyContainer,
19
- clonePolicyContainer,
20
- requestBadPort,
21
- TAOCheck,
22
- appendRequestOriginHeader,
23
- responseLocationURL,
24
- requestCurrentURL,
25
- setRequestReferrerPolicyOnRedirect,
26
- tryUpgradeRequestToAPotentiallyTrustworthyURL,
27
- createOpaqueTimingInfo,
28
- appendFetchMetadata,
29
- corsCheck,
30
- crossOriginResourcePolicyCheck,
31
- determineRequestsReferrer,
32
- coarsenedSharedCurrentTime,
33
- createDeferredPromise,
34
- sameOrigin,
35
- isCancelled,
36
- isAborted,
37
- isErrorLike,
38
- fullyReadBody,
39
- readableStreamClose,
40
- isomorphicEncode,
41
- urlIsLocal,
42
- urlIsHttpHttpsScheme,
43
- urlHasHttpsScheme,
44
- clampAndCoarsenConnectionTimingInfo,
45
- simpleRangeHeaderValue,
46
- buildContentRange,
47
- createInflate,
48
- extractMimeType
49
- } = require('./util')
50
- const assert = require('node:assert')
51
- const { safelyExtractBody, extractBody } = require('./body')
52
- const {
53
- redirectStatusSet,
54
- nullBodyStatus,
55
- safeMethodsSet,
56
- requestBodyHeader,
57
- subresourceSet
58
- } = require('./constants')
59
- const EE = require('node:events')
60
- const { Readable, pipeline, finished, isErrored, isReadable } = require('node:stream')
61
- const { addAbortListener, bufferToLowerCasedHeaderName } = require('../../core/util')
62
- const { dataURLProcessor, serializeAMimeType, minimizeSupportedMimeType } = require('./data-url')
63
- const { getGlobalDispatcher } = require('../../global')
64
- const { webidl } = require('./webidl')
65
- const { STATUS_CODES } = require('node:http')
66
- const GET_OR_HEAD = ['GET', 'HEAD']
67
-
68
- const defaultUserAgent = typeof __UNDICI_IS_NODE__ !== 'undefined' || typeof esbuildDetection !== 'undefined'
69
- ? 'node'
70
- : 'undici'
71
-
72
- /** @type {import('buffer').resolveObjectURL} */
73
- let resolveObjectURL
74
-
75
- class Fetch extends EE {
76
- constructor (dispatcher) {
77
- super()
78
-
79
- this.dispatcher = dispatcher
80
- this.connection = null
81
- this.dump = false
82
- this.state = 'ongoing'
83
- }
84
-
85
- terminate (reason) {
86
- if (this.state !== 'ongoing') {
87
- return
88
- }
89
-
90
- this.state = 'terminated'
91
- this.connection?.destroy(reason)
92
- this.emit('terminated', reason)
93
- }
94
-
95
- // https://fetch.spec.whatwg.org/#fetch-controller-abort
96
- abort (error) {
97
- if (this.state !== 'ongoing') {
98
- return
99
- }
100
-
101
- // 1. Set controller’s state to "aborted".
102
- this.state = 'aborted'
103
-
104
- // 2. Let fallbackError be an "AbortError" DOMException.
105
- // 3. Set error to fallbackError if it is not given.
106
- if (!error) {
107
- error = new DOMException('The operation was aborted.', 'AbortError')
108
- }
109
-
110
- // 4. Let serializedError be StructuredSerialize(error).
111
- // If that threw an exception, catch it, and let
112
- // serializedError be StructuredSerialize(fallbackError).
113
-
114
- // 5. Set controller’s serialized abort reason to serializedError.
115
- this.serializedAbortReason = error
116
-
117
- this.connection?.destroy(error)
118
- this.emit('terminated', error)
119
- }
120
- }
121
-
122
- function handleFetchDone (response) {
123
- finalizeAndReportTiming(response, 'fetch')
124
- }
125
-
126
- // https://fetch.spec.whatwg.org/#fetch-method
127
- function fetch (input, init = undefined) {
128
- webidl.argumentLengthCheck(arguments, 1, 'globalThis.fetch')
129
-
130
- // 1. Let p be a new promise.
131
- let p = createDeferredPromise()
132
-
133
- // 2. Let requestObject be the result of invoking the initial value of
134
- // Request as constructor with input and init as arguments. If this throws
135
- // an exception, reject p with it and return p.
136
- let requestObject
137
-
138
- try {
139
- requestObject = new Request(input, init)
140
- } catch (e) {
141
- p.reject(e)
142
- return p.promise
143
- }
144
-
145
- // 3. Let request be requestObject’s request.
146
- const request = getRequestState(requestObject)
147
-
148
- // 4. If requestObject’s signal’s aborted flag is set, then:
149
- if (requestObject.signal.aborted) {
150
- // 1. Abort the fetch() call with p, request, null, and
151
- // requestObject’s signal’s abort reason.
152
- abortFetch(p, request, null, requestObject.signal.reason)
153
-
154
- // 2. Return p.
155
- return p.promise
156
- }
157
-
158
- // 5. Let globalObject be request’s client’s global object.
159
- const globalObject = request.client.globalObject
160
-
161
- // 6. If globalObject is a ServiceWorkerGlobalScope object, then set
162
- // request’s service-workers mode to "none".
163
- if (globalObject?.constructor?.name === 'ServiceWorkerGlobalScope') {
164
- request.serviceWorkers = 'none'
165
- }
166
-
167
- // 7. Let responseObject be null.
168
- let responseObject = null
169
-
170
- // 8. Let relevantRealm be this’s relevant Realm.
171
-
172
- // 9. Let locallyAborted be false.
173
- let locallyAborted = false
174
-
175
- // 10. Let controller be null.
176
- let controller = null
177
-
178
- // 11. Add the following abort steps to requestObject’s signal:
179
- addAbortListener(
180
- requestObject.signal,
181
- () => {
182
- // 1. Set locallyAborted to true.
183
- locallyAborted = true
184
-
185
- // 2. Assert: controller is non-null.
186
- assert(controller != null)
187
-
188
- // 3. Abort controller with requestObject’s signal’s abort reason.
189
- controller.abort(requestObject.signal.reason)
190
-
191
- const realResponse = responseObject?.deref()
192
-
193
- // 4. Abort the fetch() call with p, request, responseObject,
194
- // and requestObject’s signal’s abort reason.
195
- abortFetch(p, request, realResponse, requestObject.signal.reason)
196
- }
197
- )
198
-
199
- // 12. Let handleFetchDone given response response be to finalize and
200
- // report timing with response, globalObject, and "fetch".
201
- // see function handleFetchDone
202
-
203
- // 13. Set controller to the result of calling fetch given request,
204
- // with processResponseEndOfBody set to handleFetchDone, and processResponse
205
- // given response being these substeps:
206
-
207
- const processResponse = (response) => {
208
- // 1. If locallyAborted is true, terminate these substeps.
209
- if (locallyAborted) {
210
- return
211
- }
212
-
213
- // 2. If response’s aborted flag is set, then:
214
- if (response.aborted) {
215
- // 1. Let deserializedError be the result of deserialize a serialized
216
- // abort reason given controller’s serialized abort reason and
217
- // relevantRealm.
218
-
219
- // 2. Abort the fetch() call with p, request, responseObject, and
220
- // deserializedError.
221
-
222
- abortFetch(p, request, responseObject, controller.serializedAbortReason)
223
- return
224
- }
225
-
226
- // 3. If response is a network error, then reject p with a TypeError
227
- // and terminate these substeps.
228
- if (response.type === 'error') {
229
- p.reject(new TypeError('fetch failed', { cause: response.error }))
230
- return
231
- }
232
-
233
- // 4. Set responseObject to the result of creating a Response object,
234
- // given response, "immutable", and relevantRealm.
235
- responseObject = new WeakRef(fromInnerResponse(response, 'immutable'))
236
-
237
- // 5. Resolve p with responseObject.
238
- p.resolve(responseObject.deref())
239
- p = null
240
- }
241
-
242
- controller = fetching({
243
- request,
244
- processResponseEndOfBody: handleFetchDone,
245
- processResponse,
246
- dispatcher: getRequestDispatcher(requestObject) // undici
247
- })
248
-
249
- // 14. Return p.
250
- return p.promise
251
- }
252
-
253
- // https://fetch.spec.whatwg.org/#finalize-and-report-timing
254
- function finalizeAndReportTiming (response, initiatorType = 'other') {
255
- // 1. If response is an aborted network error, then return.
256
- if (response.type === 'error' && response.aborted) {
257
- return
258
- }
259
-
260
- // 2. If response’s URL list is null or empty, then return.
261
- if (!response.urlList?.length) {
262
- return
263
- }
264
-
265
- // 3. Let originalURL be response’s URL list[0].
266
- const originalURL = response.urlList[0]
267
-
268
- // 4. Let timingInfo be response’s timing info.
269
- let timingInfo = response.timingInfo
270
-
271
- // 5. Let cacheState be response’s cache state.
272
- let cacheState = response.cacheState
273
-
274
- // 6. If originalURL’s scheme is not an HTTP(S) scheme, then return.
275
- if (!urlIsHttpHttpsScheme(originalURL)) {
276
- return
277
- }
278
-
279
- // 7. If timingInfo is null, then return.
280
- if (timingInfo === null) {
281
- return
282
- }
283
-
284
- // 8. If response’s timing allow passed flag is not set, then:
285
- if (!response.timingAllowPassed) {
286
- // 1. Set timingInfo to a the result of creating an opaque timing info for timingInfo.
287
- timingInfo = createOpaqueTimingInfo({
288
- startTime: timingInfo.startTime
289
- })
290
-
291
- // 2. Set cacheState to the empty string.
292
- cacheState = ''
293
- }
294
-
295
- // 9. Set timingInfo’s end time to the coarsened shared current time
296
- // given global’s relevant settings object’s cross-origin isolated
297
- // capability.
298
- // TODO: given global’s relevant settings object’s cross-origin isolated
299
- // capability?
300
- timingInfo.endTime = coarsenedSharedCurrentTime()
301
-
302
- // 10. Set response’s timing info to timingInfo.
303
- response.timingInfo = timingInfo
304
-
305
- // 11. Mark resource timing for timingInfo, originalURL, initiatorType,
306
- // global, and cacheState.
307
- markResourceTiming(
308
- timingInfo,
309
- originalURL.href,
310
- initiatorType,
311
- globalThis,
312
- cacheState,
313
- '', // bodyType
314
- response.status
315
- )
316
- }
317
-
318
- // https://w3c.github.io/resource-timing/#dfn-mark-resource-timing
319
- const markResourceTiming = performance.markResourceTiming
320
-
321
- // https://fetch.spec.whatwg.org/#abort-fetch
322
- function abortFetch (p, request, responseObject, error) {
323
- // 1. Reject promise with error.
324
- if (p) {
325
- // We might have already resolved the promise at this stage
326
- p.reject(error)
327
- }
328
-
329
- // 2. If request’s body is not null and is readable, then cancel request’s
330
- // body with error.
331
- if (request.body?.stream != null && isReadable(request.body.stream)) {
332
- request.body.stream.cancel(error).catch((err) => {
333
- if (err.code === 'ERR_INVALID_STATE') {
334
- // Node bug?
335
- return
336
- }
337
- throw err
338
- })
339
- }
340
-
341
- // 3. If responseObject is null, then return.
342
- if (responseObject == null) {
343
- return
344
- }
345
-
346
- // 4. Let response be responseObject’s response.
347
- const response = getResponseState(responseObject)
348
-
349
- // 5. If response’s body is not null and is readable, then error response’s
350
- // body with error.
351
- if (response.body?.stream != null && isReadable(response.body.stream)) {
352
- response.body.stream.cancel(error).catch((err) => {
353
- if (err.code === 'ERR_INVALID_STATE') {
354
- // Node bug?
355
- return
356
- }
357
- throw err
358
- })
359
- }
360
- }
361
-
362
- // https://fetch.spec.whatwg.org/#fetching
363
- function fetching ({
364
- request,
365
- processRequestBodyChunkLength,
366
- processRequestEndOfBody,
367
- processResponse,
368
- processResponseEndOfBody,
369
- processResponseConsumeBody,
370
- useParallelQueue = false,
371
- dispatcher = getGlobalDispatcher() // undici
372
- }) {
373
- // Ensure that the dispatcher is set accordingly
374
- assert(dispatcher)
375
-
376
- // 1. Let taskDestination be null.
377
- let taskDestination = null
378
-
379
- // 2. Let crossOriginIsolatedCapability be false.
380
- let crossOriginIsolatedCapability = false
381
-
382
- // 3. If request’s client is non-null, then:
383
- if (request.client != null) {
384
- // 1. Set taskDestination to request’s client’s global object.
385
- taskDestination = request.client.globalObject
386
-
387
- // 2. Set crossOriginIsolatedCapability to request’s client’s cross-origin
388
- // isolated capability.
389
- crossOriginIsolatedCapability =
390
- request.client.crossOriginIsolatedCapability
391
- }
392
-
393
- // 4. If useParallelQueue is true, then set taskDestination to the result of
394
- // starting a new parallel queue.
395
- // TODO
396
-
397
- // 5. Let timingInfo be a new fetch timing info whose start time and
398
- // post-redirect start time are the coarsened shared current time given
399
- // crossOriginIsolatedCapability.
400
- const currentTime = coarsenedSharedCurrentTime(crossOriginIsolatedCapability)
401
- const timingInfo = createOpaqueTimingInfo({
402
- startTime: currentTime
403
- })
404
-
405
- // 6. Let fetchParams be a new fetch params whose
406
- // request is request,
407
- // timing info is timingInfo,
408
- // process request body chunk length is processRequestBodyChunkLength,
409
- // process request end-of-body is processRequestEndOfBody,
410
- // process response is processResponse,
411
- // process response consume body is processResponseConsumeBody,
412
- // process response end-of-body is processResponseEndOfBody,
413
- // task destination is taskDestination,
414
- // and cross-origin isolated capability is crossOriginIsolatedCapability.
415
- const fetchParams = {
416
- controller: new Fetch(dispatcher),
417
- request,
418
- timingInfo,
419
- processRequestBodyChunkLength,
420
- processRequestEndOfBody,
421
- processResponse,
422
- processResponseConsumeBody,
423
- processResponseEndOfBody,
424
- taskDestination,
425
- crossOriginIsolatedCapability
426
- }
427
-
428
- // 7. If request’s body is a byte sequence, then set request’s body to
429
- // request’s body as a body.
430
- // NOTE: Since fetching is only called from fetch, body should already be
431
- // extracted.
432
- assert(!request.body || request.body.stream)
433
-
434
- // 8. If request’s window is "client", then set request’s window to request’s
435
- // client, if request’s client’s global object is a Window object; otherwise
436
- // "no-window".
437
- if (request.window === 'client') {
438
- // TODO: What if request.client is null?
439
- request.window =
440
- request.client?.globalObject?.constructor?.name === 'Window'
441
- ? request.client
442
- : 'no-window'
443
- }
444
-
445
- // 9. If request’s origin is "client", then set request’s origin to request’s
446
- // client’s origin.
447
- if (request.origin === 'client') {
448
- request.origin = request.client.origin
449
- }
450
-
451
- // 10. If all of the following conditions are true:
452
- // TODO
453
-
454
- // 11. If request’s policy container is "client", then:
455
- if (request.policyContainer === 'client') {
456
- // 1. If request’s client is non-null, then set request’s policy
457
- // container to a clone of request’s client’s policy container. [HTML]
458
- if (request.client != null) {
459
- request.policyContainer = clonePolicyContainer(
460
- request.client.policyContainer
461
- )
462
- } else {
463
- // 2. Otherwise, set request’s policy container to a new policy
464
- // container.
465
- request.policyContainer = makePolicyContainer()
466
- }
467
- }
468
-
469
- // 12. If request’s header list does not contain `Accept`, then:
470
- if (!request.headersList.contains('accept', true)) {
471
- // 1. Let value be `*/*`.
472
- const value = '*/*'
473
-
474
- // 2. A user agent should set value to the first matching statement, if
475
- // any, switching on request’s destination:
476
- // "document"
477
- // "frame"
478
- // "iframe"
479
- // `text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8`
480
- // "image"
481
- // `image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5`
482
- // "style"
483
- // `text/css,*/*;q=0.1`
484
- // TODO
485
-
486
- // 3. Append `Accept`/value to request’s header list.
487
- request.headersList.append('accept', value, true)
488
- }
489
-
490
- // 13. If request’s header list does not contain `Accept-Language`, then
491
- // user agents should append `Accept-Language`/an appropriate value to
492
- // request’s header list.
493
- if (!request.headersList.contains('accept-language', true)) {
494
- request.headersList.append('accept-language', '*', true)
495
- }
496
-
497
- // 14. If request’s priority is null, then use request’s initiator and
498
- // destination appropriately in setting request’s priority to a
499
- // user-agent-defined object.
500
- if (request.priority === null) {
501
- // TODO
502
- }
503
-
504
- // 15. If request is a subresource request, then:
505
- if (subresourceSet.has(request.destination)) {
506
- // TODO
507
- }
508
-
509
- // 16. Run main fetch given fetchParams.
510
- mainFetch(fetchParams)
511
- .catch(err => {
512
- fetchParams.controller.terminate(err)
513
- })
514
-
515
- // 17. Return fetchParam's controller
516
- return fetchParams.controller
517
- }
518
-
519
- // https://fetch.spec.whatwg.org/#concept-main-fetch
520
- async function mainFetch (fetchParams, recursive = false) {
521
- // 1. Let request be fetchParams’s request.
522
- const request = fetchParams.request
523
-
524
- // 2. Let response be null.
525
- let response = null
526
-
527
- // 3. If request’s local-URLs-only flag is set and request’s current URL is
528
- // not local, then set response to a network error.
529
- if (request.localURLsOnly && !urlIsLocal(requestCurrentURL(request))) {
530
- response = makeNetworkError('local URLs only')
531
- }
532
-
533
- // 4. Run report Content Security Policy violations for request.
534
- // TODO
535
-
536
- // 5. Upgrade request to a potentially trustworthy URL, if appropriate.
537
- tryUpgradeRequestToAPotentiallyTrustworthyURL(request)
538
-
539
- // 6. If should request be blocked due to a bad port, should fetching request
540
- // be blocked as mixed content, or should request be blocked by Content
541
- // Security Policy returns blocked, then set response to a network error.
542
- if (requestBadPort(request) === 'blocked') {
543
- response = makeNetworkError('bad port')
544
- }
545
- // TODO: should fetching request be blocked as mixed content?
546
- // TODO: should request be blocked by Content Security Policy?
547
-
548
- // 7. If request’s referrer policy is the empty string, then set request’s
549
- // referrer policy to request’s policy container’s referrer policy.
550
- if (request.referrerPolicy === '') {
551
- request.referrerPolicy = request.policyContainer.referrerPolicy
552
- }
553
-
554
- // 8. If request’s referrer is not "no-referrer", then set request’s
555
- // referrer to the result of invoking determine request’s referrer.
556
- if (request.referrer !== 'no-referrer') {
557
- request.referrer = determineRequestsReferrer(request)
558
- }
559
-
560
- // 9. Set request’s current URL’s scheme to "https" if all of the following
561
- // conditions are true:
562
- // - request’s current URL’s scheme is "http"
563
- // - request’s current URL’s host is a domain
564
- // - Matching request’s current URL’s host per Known HSTS Host Domain Name
565
- // Matching results in either a superdomain match with an asserted
566
- // includeSubDomains directive or a congruent match (with or without an
567
- // asserted includeSubDomains directive). [HSTS]
568
- // TODO
569
-
570
- // 10. If recursive is false, then run the remaining steps in parallel.
571
- // TODO
572
-
573
- // 11. If response is null, then set response to the result of running
574
- // the steps corresponding to the first matching statement:
575
- if (response === null) {
576
- const currentURL = requestCurrentURL(request)
577
- if (
578
- // - request’s current URL’s origin is same origin with request’s origin,
579
- // and request’s response tainting is "basic"
580
- (sameOrigin(currentURL, request.url) && request.responseTainting === 'basic') ||
581
- // request’s current URL’s scheme is "data"
582
- (currentURL.protocol === 'data:') ||
583
- // - request’s mode is "navigate" or "websocket"
584
- (request.mode === 'navigate' || request.mode === 'websocket')
585
- ) {
586
- // 1. Set request’s response tainting to "basic".
587
- request.responseTainting = 'basic'
588
-
589
- // 2. Return the result of running scheme fetch given fetchParams.
590
- response = await schemeFetch(fetchParams)
591
-
592
- // request’s mode is "same-origin"
593
- } else if (request.mode === 'same-origin') {
594
- // 1. Return a network error.
595
- response = makeNetworkError('request mode cannot be "same-origin"')
596
-
597
- // request’s mode is "no-cors"
598
- } else if (request.mode === 'no-cors') {
599
- // 1. If request’s redirect mode is not "follow", then return a network
600
- // error.
601
- if (request.redirect !== 'follow') {
602
- response = makeNetworkError(
603
- 'redirect mode cannot be "follow" for "no-cors" request'
604
- )
605
- } else {
606
- // 2. Set request’s response tainting to "opaque".
607
- request.responseTainting = 'opaque'
608
-
609
- // 3. Return the result of running scheme fetch given fetchParams.
610
- response = await schemeFetch(fetchParams)
611
- }
612
- // request’s current URL’s scheme is not an HTTP(S) scheme
613
- } else if (!urlIsHttpHttpsScheme(requestCurrentURL(request))) {
614
- // Return a network error.
615
- response = makeNetworkError('URL scheme must be a HTTP(S) scheme')
616
-
617
- // - request’s use-CORS-preflight flag is set
618
- // - request’s unsafe-request flag is set and either request’s method is
619
- // not a CORS-safelisted method or CORS-unsafe request-header names with
620
- // request’s header list is not empty
621
- // 1. Set request’s response tainting to "cors".
622
- // 2. Let corsWithPreflightResponse be the result of running HTTP fetch
623
- // given fetchParams and true.
624
- // 3. If corsWithPreflightResponse is a network error, then clear cache
625
- // entries using request.
626
- // 4. Return corsWithPreflightResponse.
627
- // TODO
628
-
629
- // Otherwise
630
- } else {
631
- // 1. Set request’s response tainting to "cors".
632
- request.responseTainting = 'cors'
633
-
634
- // 2. Return the result of running HTTP fetch given fetchParams.
635
- response = await httpFetch(fetchParams)
636
- }
637
- }
638
-
639
- // 12. If recursive is true, then return response.
640
- if (recursive) {
641
- return response
642
- }
643
-
644
- // 13. If response is not a network error and response is not a filtered
645
- // response, then:
646
- if (response.status !== 0 && !response.internalResponse) {
647
- // If request’s response tainting is "cors", then:
648
- if (request.responseTainting === 'cors') {
649
- // 1. Let headerNames be the result of extracting header list values
650
- // given `Access-Control-Expose-Headers` and response’s header list.
651
- // TODO
652
- // 2. If request’s credentials mode is not "include" and headerNames
653
- // contains `*`, then set response’s CORS-exposed header-name list to
654
- // all unique header names in response’s header list.
655
- // TODO
656
- // 3. Otherwise, if headerNames is not null or failure, then set
657
- // response’s CORS-exposed header-name list to headerNames.
658
- // TODO
659
- }
660
-
661
- // Set response to the following filtered response with response as its
662
- // internal response, depending on request’s response tainting:
663
- if (request.responseTainting === 'basic') {
664
- response = filterResponse(response, 'basic')
665
- } else if (request.responseTainting === 'cors') {
666
- response = filterResponse(response, 'cors')
667
- } else if (request.responseTainting === 'opaque') {
668
- response = filterResponse(response, 'opaque')
669
- } else {
670
- assert(false)
671
- }
672
- }
673
-
674
- // 14. Let internalResponse be response, if response is a network error,
675
- // and response’s internal response otherwise.
676
- let internalResponse =
677
- response.status === 0 ? response : response.internalResponse
678
-
679
- // 15. If internalResponse’s URL list is empty, then set it to a clone of
680
- // request’s URL list.
681
- if (internalResponse.urlList.length === 0) {
682
- internalResponse.urlList.push(...request.urlList)
683
- }
684
-
685
- // 16. If request’s timing allow failed flag is unset, then set
686
- // internalResponse’s timing allow passed flag.
687
- if (!request.timingAllowFailed) {
688
- response.timingAllowPassed = true
689
- }
690
-
691
- // 17. If response is not a network error and any of the following returns
692
- // blocked
693
- // - should internalResponse to request be blocked as mixed content
694
- // - should internalResponse to request be blocked by Content Security Policy
695
- // - should internalResponse to request be blocked due to its MIME type
696
- // - should internalResponse to request be blocked due to nosniff
697
- // TODO
698
-
699
- // 18. If response’s type is "opaque", internalResponse’s status is 206,
700
- // internalResponse’s range-requested flag is set, and request’s header
701
- // list does not contain `Range`, then set response and internalResponse
702
- // to a network error.
703
- if (
704
- response.type === 'opaque' &&
705
- internalResponse.status === 206 &&
706
- internalResponse.rangeRequested &&
707
- !request.headers.contains('range', true)
708
- ) {
709
- response = internalResponse = makeNetworkError()
710
- }
711
-
712
- // 19. If response is not a network error and either request’s method is
713
- // `HEAD` or `CONNECT`, or internalResponse’s status is a null body status,
714
- // set internalResponse’s body to null and disregard any enqueuing toward
715
- // it (if any).
716
- if (
717
- response.status !== 0 &&
718
- (request.method === 'HEAD' ||
719
- request.method === 'CONNECT' ||
720
- nullBodyStatus.includes(internalResponse.status))
721
- ) {
722
- internalResponse.body = null
723
- fetchParams.controller.dump = true
724
- }
725
-
726
- // 20. If request’s integrity metadata is not the empty string, then:
727
- if (request.integrity) {
728
- // 1. Let processBodyError be this step: run fetch finale given fetchParams
729
- // and a network error.
730
- const processBodyError = (reason) =>
731
- fetchFinale(fetchParams, makeNetworkError(reason))
732
-
733
- // 2. If request’s response tainting is "opaque", or response’s body is null,
734
- // then run processBodyError and abort these steps.
735
- if (request.responseTainting === 'opaque' || response.body == null) {
736
- processBodyError(response.error)
737
- return
738
- }
739
-
740
- // 3. Let processBody given bytes be these steps:
741
- const processBody = (bytes) => {
742
- // 1. If bytes do not match request’s integrity metadata,
743
- // then run processBodyError and abort these steps. [SRI]
744
- if (!bytesMatch(bytes, request.integrity)) {
745
- processBodyError('integrity mismatch')
746
- return
747
- }
748
-
749
- // 2. Set response’s body to bytes as a body.
750
- response.body = safelyExtractBody(bytes)[0]
751
-
752
- // 3. Run fetch finale given fetchParams and response.
753
- fetchFinale(fetchParams, response)
754
- }
755
-
756
- // 4. Fully read response’s body given processBody and processBodyError.
757
- await fullyReadBody(response.body, processBody, processBodyError)
758
- } else {
759
- // 21. Otherwise, run fetch finale given fetchParams and response.
760
- fetchFinale(fetchParams, response)
761
- }
762
- }
763
-
764
- // https://fetch.spec.whatwg.org/#concept-scheme-fetch
765
- // given a fetch params fetchParams
766
- function schemeFetch (fetchParams) {
767
- // Note: since the connection is destroyed on redirect, which sets fetchParams to a
768
- // cancelled state, we do not want this condition to trigger *unless* there have been
769
- // no redirects. See https://github.com/nodejs/undici/issues/1776
770
- // 1. If fetchParams is canceled, then return the appropriate network error for fetchParams.
771
- if (isCancelled(fetchParams) && fetchParams.request.redirectCount === 0) {
772
- return Promise.resolve(makeAppropriateNetworkError(fetchParams))
773
- }
774
-
775
- // 2. Let request be fetchParams’s request.
776
- const { request } = fetchParams
777
-
778
- const { protocol: scheme } = requestCurrentURL(request)
779
-
780
- // 3. Switch on request’s current URL’s scheme and run the associated steps:
781
- switch (scheme) {
782
- case 'about:': {
783
- // If request’s current URL’s path is the string "blank", then return a new response
784
- // whose status message is `OK`, header list is « (`Content-Type`, `text/html;charset=utf-8`) »,
785
- // and body is the empty byte sequence as a body.
786
-
787
- // Otherwise, return a network error.
788
- return Promise.resolve(makeNetworkError('about scheme is not supported'))
789
- }
790
- case 'blob:': {
791
- if (!resolveObjectURL) {
792
- resolveObjectURL = require('node:buffer').resolveObjectURL
793
- }
794
-
795
- // 1. Let blobURLEntry be request’s current URL’s blob URL entry.
796
- const blobURLEntry = requestCurrentURL(request)
797
-
798
- // https://github.com/web-platform-tests/wpt/blob/7b0ebaccc62b566a1965396e5be7bb2bc06f841f/FileAPI/url/resources/fetch-tests.js#L52-L56
799
- // Buffer.resolveObjectURL does not ignore URL queries.
800
- if (blobURLEntry.search.length !== 0) {
801
- return Promise.resolve(makeNetworkError('NetworkError when attempting to fetch resource.'))
802
- }
803
-
804
- const blob = resolveObjectURL(blobURLEntry.toString())
805
-
806
- // 2. If request’s method is not `GET`, blobURLEntry is null, or blobURLEntry’s
807
- // object is not a Blob object, then return a network error.
808
- if (request.method !== 'GET' || !webidl.is.Blob(blob)) {
809
- return Promise.resolve(makeNetworkError('invalid method'))
810
- }
811
-
812
- // 3. Let blob be blobURLEntry’s object.
813
- // Note: done above
814
-
815
- // 4. Let response be a new response.
816
- const response = makeResponse()
817
-
818
- // 5. Let fullLength be blob’s size.
819
- const fullLength = blob.size
820
-
821
- // 6. Let serializedFullLength be fullLength, serialized and isomorphic encoded.
822
- const serializedFullLength = isomorphicEncode(`${fullLength}`)
823
-
824
- // 7. Let type be blob’s type.
825
- const type = blob.type
826
-
827
- // 8. If request’s header list does not contain `Range`:
828
- // 9. Otherwise:
829
- if (!request.headersList.contains('range', true)) {
830
- // 1. Let bodyWithType be the result of safely extracting blob.
831
- // Note: in the FileAPI a blob "object" is a Blob *or* a MediaSource.
832
- // In node, this can only ever be a Blob. Therefore we can safely
833
- // use extractBody directly.
834
- const bodyWithType = extractBody(blob)
835
-
836
- // 2. Set response’s status message to `OK`.
837
- response.statusText = 'OK'
838
-
839
- // 3. Set response’s body to bodyWithType’s body.
840
- response.body = bodyWithType[0]
841
-
842
- // 4. Set response’s header list to « (`Content-Length`, serializedFullLength), (`Content-Type`, type) ».
843
- response.headersList.set('content-length', serializedFullLength, true)
844
- response.headersList.set('content-type', type, true)
845
- } else {
846
- // 1. Set response’s range-requested flag.
847
- response.rangeRequested = true
848
-
849
- // 2. Let rangeHeader be the result of getting `Range` from request’s header list.
850
- const rangeHeader = request.headersList.get('range', true)
851
-
852
- // 3. Let rangeValue be the result of parsing a single range header value given rangeHeader and true.
853
- const rangeValue = simpleRangeHeaderValue(rangeHeader, true)
854
-
855
- // 4. If rangeValue is failure, then return a network error.
856
- if (rangeValue === 'failure') {
857
- return Promise.resolve(makeNetworkError('failed to fetch the data URL'))
858
- }
859
-
860
- // 5. Let (rangeStart, rangeEnd) be rangeValue.
861
- let { rangeStartValue: rangeStart, rangeEndValue: rangeEnd } = rangeValue
862
-
863
- // 6. If rangeStart is null:
864
- // 7. Otherwise:
865
- if (rangeStart === null) {
866
- // 1. Set rangeStart to fullLength − rangeEnd.
867
- rangeStart = fullLength - rangeEnd
868
-
869
- // 2. Set rangeEnd to rangeStart + rangeEnd − 1.
870
- rangeEnd = rangeStart + rangeEnd - 1
871
- } else {
872
- // 1. If rangeStart is greater than or equal to fullLength, then return a network error.
873
- if (rangeStart >= fullLength) {
874
- return Promise.resolve(makeNetworkError('Range start is greater than the blob\'s size.'))
875
- }
876
-
877
- // 2. If rangeEnd is null or rangeEnd is greater than or equal to fullLength, then set
878
- // rangeEnd to fullLength − 1.
879
- if (rangeEnd === null || rangeEnd >= fullLength) {
880
- rangeEnd = fullLength - 1
881
- }
882
- }
883
-
884
- // 8. Let slicedBlob be the result of invoking slice blob given blob, rangeStart,
885
- // rangeEnd + 1, and type.
886
- const slicedBlob = blob.slice(rangeStart, rangeEnd, type)
887
-
888
- // 9. Let slicedBodyWithType be the result of safely extracting slicedBlob.
889
- // Note: same reason as mentioned above as to why we use extractBody
890
- const slicedBodyWithType = extractBody(slicedBlob)
891
-
892
- // 10. Set response’s body to slicedBodyWithType’s body.
893
- response.body = slicedBodyWithType[0]
894
-
895
- // 11. Let serializedSlicedLength be slicedBlob’s size, serialized and isomorphic encoded.
896
- const serializedSlicedLength = isomorphicEncode(`${slicedBlob.size}`)
897
-
898
- // 12. Let contentRange be the result of invoking build a content range given rangeStart,
899
- // rangeEnd, and fullLength.
900
- const contentRange = buildContentRange(rangeStart, rangeEnd, fullLength)
901
-
902
- // 13. Set response’s status to 206.
903
- response.status = 206
904
-
905
- // 14. Set response’s status message to `Partial Content`.
906
- response.statusText = 'Partial Content'
907
-
908
- // 15. Set response’s header list to « (`Content-Length`, serializedSlicedLength),
909
- // (`Content-Type`, type), (`Content-Range`, contentRange) ».
910
- response.headersList.set('content-length', serializedSlicedLength, true)
911
- response.headersList.set('content-type', type, true)
912
- response.headersList.set('content-range', contentRange, true)
913
- }
914
-
915
- // 10. Return response.
916
- return Promise.resolve(response)
917
- }
918
- case 'data:': {
919
- // 1. Let dataURLStruct be the result of running the
920
- // data: URL processor on request’s current URL.
921
- const currentURL = requestCurrentURL(request)
922
- const dataURLStruct = dataURLProcessor(currentURL)
923
-
924
- // 2. If dataURLStruct is failure, then return a
925
- // network error.
926
- if (dataURLStruct === 'failure') {
927
- return Promise.resolve(makeNetworkError('failed to fetch the data URL'))
928
- }
929
-
930
- // 3. Let mimeType be dataURLStruct’s MIME type, serialized.
931
- const mimeType = serializeAMimeType(dataURLStruct.mimeType)
932
-
933
- // 4. Return a response whose status message is `OK`,
934
- // header list is « (`Content-Type`, mimeType) »,
935
- // and body is dataURLStruct’s body as a body.
936
- return Promise.resolve(makeResponse({
937
- statusText: 'OK',
938
- headersList: [
939
- ['content-type', { name: 'Content-Type', value: mimeType }]
940
- ],
941
- body: safelyExtractBody(dataURLStruct.body)[0]
942
- }))
943
- }
944
- case 'file:': {
945
- // For now, unfortunate as it is, file URLs are left as an exercise for the reader.
946
- // When in doubt, return a network error.
947
- return Promise.resolve(makeNetworkError('not implemented... yet...'))
948
- }
949
- case 'http:':
950
- case 'https:': {
951
- // Return the result of running HTTP fetch given fetchParams.
952
-
953
- return httpFetch(fetchParams)
954
- .catch((err) => makeNetworkError(err))
955
- }
956
- default: {
957
- return Promise.resolve(makeNetworkError('unknown scheme'))
958
- }
959
- }
960
- }
961
-
962
- // https://fetch.spec.whatwg.org/#finalize-response
963
- function finalizeResponse (fetchParams, response) {
964
- // 1. Set fetchParams’s request’s done flag.
965
- fetchParams.request.done = true
966
-
967
- // 2, If fetchParams’s process response done is not null, then queue a fetch
968
- // task to run fetchParams’s process response done given response, with
969
- // fetchParams’s task destination.
970
- if (fetchParams.processResponseDone != null) {
971
- queueMicrotask(() => fetchParams.processResponseDone(response))
972
- }
973
- }
974
-
975
- // https://fetch.spec.whatwg.org/#fetch-finale
976
- function fetchFinale (fetchParams, response) {
977
- // 1. Let timingInfo be fetchParams’s timing info.
978
- let timingInfo = fetchParams.timingInfo
979
-
980
- // 2. If response is not a network error and fetchParams’s request’s client is a secure context,
981
- // then set timingInfo’s server-timing headers to the result of getting, decoding, and splitting
982
- // `Server-Timing` from response’s internal response’s header list.
983
- // TODO
984
-
985
- // 3. Let processResponseEndOfBody be the following steps:
986
- const processResponseEndOfBody = () => {
987
- // 1. Let unsafeEndTime be the unsafe shared current time.
988
- const unsafeEndTime = Date.now() // ?
989
-
990
- // 2. If fetchParams’s request’s destination is "document", then set fetchParams’s controller’s
991
- // full timing info to fetchParams’s timing info.
992
- if (fetchParams.request.destination === 'document') {
993
- fetchParams.controller.fullTimingInfo = timingInfo
994
- }
995
-
996
- // 3. Set fetchParams’s controller’s report timing steps to the following steps given a global object global:
997
- fetchParams.controller.reportTimingSteps = () => {
998
- // 1. If fetchParams’s request’s URL’s scheme is not an HTTP(S) scheme, then return.
999
- if (!urlIsHttpHttpsScheme(fetchParams.request.url)) {
1000
- return
1001
- }
1002
-
1003
- // 2. Set timingInfo’s end time to the relative high resolution time given unsafeEndTime and global.
1004
- timingInfo.endTime = unsafeEndTime
1005
-
1006
- // 3. Let cacheState be response’s cache state.
1007
- let cacheState = response.cacheState
1008
-
1009
- // 4. Let bodyInfo be response’s body info.
1010
- const bodyInfo = response.bodyInfo
1011
-
1012
- // 5. If response’s timing allow passed flag is not set, then set timingInfo to the result of creating an
1013
- // opaque timing info for timingInfo and set cacheState to the empty string.
1014
- if (!response.timingAllowPassed) {
1015
- timingInfo = createOpaqueTimingInfo(timingInfo)
1016
-
1017
- cacheState = ''
1018
- }
1019
-
1020
- // 6. Let responseStatus be 0.
1021
- let responseStatus = 0
1022
-
1023
- // 7. If fetchParams’s request’s mode is not "navigate" or response’s has-cross-origin-redirects is false:
1024
- if (fetchParams.request.mode !== 'navigator' || !response.hasCrossOriginRedirects) {
1025
- // 1. Set responseStatus to response’s status.
1026
- responseStatus = response.status
1027
-
1028
- // 2. Let mimeType be the result of extracting a MIME type from response’s header list.
1029
- const mimeType = extractMimeType(response.headersList)
1030
-
1031
- // 3. If mimeType is not failure, then set bodyInfo’s content type to the result of minimizing a supported MIME type given mimeType.
1032
- if (mimeType !== 'failure') {
1033
- bodyInfo.contentType = minimizeSupportedMimeType(mimeType)
1034
- }
1035
- }
1036
-
1037
- // 8. If fetchParams’s request’s initiator type is non-null, then mark resource timing given timingInfo,
1038
- // fetchParams’s request’s URL, fetchParams’s request’s initiator type, global, cacheState, bodyInfo,
1039
- // and responseStatus.
1040
- if (fetchParams.request.initiatorType != null) {
1041
- markResourceTiming(timingInfo, fetchParams.request.url.href, fetchParams.request.initiatorType, globalThis, cacheState, bodyInfo, responseStatus)
1042
- }
1043
- }
1044
-
1045
- // 4. Let processResponseEndOfBodyTask be the following steps:
1046
- const processResponseEndOfBodyTask = () => {
1047
- // 1. Set fetchParams’s request’s done flag.
1048
- fetchParams.request.done = true
1049
-
1050
- // 2. If fetchParams’s process response end-of-body is non-null, then run fetchParams’s process
1051
- // response end-of-body given response.
1052
- if (fetchParams.processResponseEndOfBody != null) {
1053
- queueMicrotask(() => fetchParams.processResponseEndOfBody(response))
1054
- }
1055
-
1056
- // 3. If fetchParams’s request’s initiator type is non-null and fetchParams’s request’s client’s
1057
- // global object is fetchParams’s task destination, then run fetchParams’s controller’s report
1058
- // timing steps given fetchParams’s request’s client’s global object.
1059
- if (fetchParams.request.initiatorType != null) {
1060
- fetchParams.controller.reportTimingSteps()
1061
- }
1062
- }
1063
-
1064
- // 5. Queue a fetch task to run processResponseEndOfBodyTask with fetchParams’s task destination
1065
- queueMicrotask(() => processResponseEndOfBodyTask())
1066
- }
1067
-
1068
- // 4. If fetchParams’s process response is non-null, then queue a fetch task to run fetchParams’s
1069
- // process response given response, with fetchParams’s task destination.
1070
- if (fetchParams.processResponse != null) {
1071
- queueMicrotask(() => {
1072
- fetchParams.processResponse(response)
1073
- fetchParams.processResponse = null
1074
- })
1075
- }
1076
-
1077
- // 5. Let internalResponse be response, if response is a network error; otherwise response’s internal response.
1078
- const internalResponse = response.type === 'error' ? response : (response.internalResponse ?? response)
1079
-
1080
- // 6. If internalResponse’s body is null, then run processResponseEndOfBody.
1081
- // 7. Otherwise:
1082
- if (internalResponse.body == null) {
1083
- processResponseEndOfBody()
1084
- } else {
1085
- // mcollina: all the following steps of the specs are skipped.
1086
- // The internal transform stream is not needed.
1087
- // See https://github.com/nodejs/undici/pull/3093#issuecomment-2050198541
1088
-
1089
- // 1. Let transformStream be a new TransformStream.
1090
- // 2. Let identityTransformAlgorithm be an algorithm which, given chunk, enqueues chunk in transformStream.
1091
- // 3. Set up transformStream with transformAlgorithm set to identityTransformAlgorithm and flushAlgorithm
1092
- // set to processResponseEndOfBody.
1093
- // 4. Set internalResponse’s body’s stream to the result of internalResponse’s body’s stream piped through transformStream.
1094
-
1095
- finished(internalResponse.body.stream, () => {
1096
- processResponseEndOfBody()
1097
- })
1098
- }
1099
- }
1100
-
1101
- // https://fetch.spec.whatwg.org/#http-fetch
1102
- async function httpFetch (fetchParams) {
1103
- // 1. Let request be fetchParams’s request.
1104
- const request = fetchParams.request
1105
-
1106
- // 2. Let response be null.
1107
- let response = null
1108
-
1109
- // 3. Let actualResponse be null.
1110
- let actualResponse = null
1111
-
1112
- // 4. Let timingInfo be fetchParams’s timing info.
1113
- const timingInfo = fetchParams.timingInfo
1114
-
1115
- // 5. If request’s service-workers mode is "all", then:
1116
- if (request.serviceWorkers === 'all') {
1117
- // TODO
1118
- }
1119
-
1120
- // 6. If response is null, then:
1121
- if (response === null) {
1122
- // 1. If makeCORSPreflight is true and one of these conditions is true:
1123
- // TODO
1124
-
1125
- // 2. If request’s redirect mode is "follow", then set request’s
1126
- // service-workers mode to "none".
1127
- if (request.redirect === 'follow') {
1128
- request.serviceWorkers = 'none'
1129
- }
1130
-
1131
- // 3. Set response and actualResponse to the result of running
1132
- // HTTP-network-or-cache fetch given fetchParams.
1133
- actualResponse = response = await httpNetworkOrCacheFetch(fetchParams)
1134
-
1135
- // 4. If request’s response tainting is "cors" and a CORS check
1136
- // for request and response returns failure, then return a network error.
1137
- if (
1138
- request.responseTainting === 'cors' &&
1139
- corsCheck(request, response) === 'failure'
1140
- ) {
1141
- return makeNetworkError('cors failure')
1142
- }
1143
-
1144
- // 5. If the TAO check for request and response returns failure, then set
1145
- // request’s timing allow failed flag.
1146
- if (TAOCheck(request, response) === 'failure') {
1147
- request.timingAllowFailed = true
1148
- }
1149
- }
1150
-
1151
- // 7. If either request’s response tainting or response’s type
1152
- // is "opaque", and the cross-origin resource policy check with
1153
- // request’s origin, request’s client, request’s destination,
1154
- // and actualResponse returns blocked, then return a network error.
1155
- if (
1156
- (request.responseTainting === 'opaque' || response.type === 'opaque') &&
1157
- crossOriginResourcePolicyCheck(
1158
- request.origin,
1159
- request.client,
1160
- request.destination,
1161
- actualResponse
1162
- ) === 'blocked'
1163
- ) {
1164
- return makeNetworkError('blocked')
1165
- }
1166
-
1167
- // 8. If actualResponse’s status is a redirect status, then:
1168
- if (redirectStatusSet.has(actualResponse.status)) {
1169
- // 1. If actualResponse’s status is not 303, request’s body is not null,
1170
- // and the connection uses HTTP/2, then user agents may, and are even
1171
- // encouraged to, transmit an RST_STREAM frame.
1172
- // See, https://github.com/whatwg/fetch/issues/1288
1173
- if (request.redirect !== 'manual') {
1174
- fetchParams.controller.connection.destroy(undefined, false)
1175
- }
1176
-
1177
- // 2. Switch on request’s redirect mode:
1178
- if (request.redirect === 'error') {
1179
- // Set response to a network error.
1180
- response = makeNetworkError('unexpected redirect')
1181
- } else if (request.redirect === 'manual') {
1182
- // Set response to an opaque-redirect filtered response whose internal
1183
- // response is actualResponse.
1184
- // NOTE(spec): On the web this would return an `opaqueredirect` response,
1185
- // but that doesn't make sense server side.
1186
- // See https://github.com/nodejs/undici/issues/1193.
1187
- response = actualResponse
1188
- } else if (request.redirect === 'follow') {
1189
- // Set response to the result of running HTTP-redirect fetch given
1190
- // fetchParams and response.
1191
- response = await httpRedirectFetch(fetchParams, response)
1192
- } else {
1193
- assert(false)
1194
- }
1195
- }
1196
-
1197
- // 9. Set response’s timing info to timingInfo.
1198
- response.timingInfo = timingInfo
1199
-
1200
- // 10. Return response.
1201
- return response
1202
- }
1203
-
1204
- // https://fetch.spec.whatwg.org/#http-redirect-fetch
1205
- function httpRedirectFetch (fetchParams, response) {
1206
- // 1. Let request be fetchParams’s request.
1207
- const request = fetchParams.request
1208
-
1209
- // 2. Let actualResponse be response, if response is not a filtered response,
1210
- // and response’s internal response otherwise.
1211
- const actualResponse = response.internalResponse
1212
- ? response.internalResponse
1213
- : response
1214
-
1215
- // 3. Let locationURL be actualResponse’s location URL given request’s current
1216
- // URL’s fragment.
1217
- let locationURL
1218
-
1219
- try {
1220
- locationURL = responseLocationURL(
1221
- actualResponse,
1222
- requestCurrentURL(request).hash
1223
- )
1224
-
1225
- // 4. If locationURL is null, then return response.
1226
- if (locationURL == null) {
1227
- return response
1228
- }
1229
- } catch (err) {
1230
- // 5. If locationURL is failure, then return a network error.
1231
- return Promise.resolve(makeNetworkError(err))
1232
- }
1233
-
1234
- // 6. If locationURL’s scheme is not an HTTP(S) scheme, then return a network
1235
- // error.
1236
- if (!urlIsHttpHttpsScheme(locationURL)) {
1237
- return Promise.resolve(makeNetworkError('URL scheme must be a HTTP(S) scheme'))
1238
- }
1239
-
1240
- // 7. If request’s redirect count is 20, then return a network error.
1241
- if (request.redirectCount === 20) {
1242
- return Promise.resolve(makeNetworkError('redirect count exceeded'))
1243
- }
1244
-
1245
- // 8. Increase request’s redirect count by 1.
1246
- request.redirectCount += 1
1247
-
1248
- // 9. If request’s mode is "cors", locationURL includes credentials, and
1249
- // request’s origin is not same origin with locationURL’s origin, then return
1250
- // a network error.
1251
- if (
1252
- request.mode === 'cors' &&
1253
- (locationURL.username || locationURL.password) &&
1254
- !sameOrigin(request, locationURL)
1255
- ) {
1256
- return Promise.resolve(makeNetworkError('cross origin not allowed for request mode "cors"'))
1257
- }
1258
-
1259
- // 10. If request’s response tainting is "cors" and locationURL includes
1260
- // credentials, then return a network error.
1261
- if (
1262
- request.responseTainting === 'cors' &&
1263
- (locationURL.username || locationURL.password)
1264
- ) {
1265
- return Promise.resolve(makeNetworkError(
1266
- 'URL cannot contain credentials for request mode "cors"'
1267
- ))
1268
- }
1269
-
1270
- // 11. If actualResponse’s status is not 303, request’s body is non-null,
1271
- // and request’s body’s source is null, then return a network error.
1272
- if (
1273
- actualResponse.status !== 303 &&
1274
- request.body != null &&
1275
- request.body.source == null
1276
- ) {
1277
- return Promise.resolve(makeNetworkError())
1278
- }
1279
-
1280
- // 12. If one of the following is true
1281
- // - actualResponse’s status is 301 or 302 and request’s method is `POST`
1282
- // - actualResponse’s status is 303 and request’s method is not `GET` or `HEAD`
1283
- if (
1284
- ([301, 302].includes(actualResponse.status) && request.method === 'POST') ||
1285
- (actualResponse.status === 303 &&
1286
- !GET_OR_HEAD.includes(request.method))
1287
- ) {
1288
- // then:
1289
- // 1. Set request’s method to `GET` and request’s body to null.
1290
- request.method = 'GET'
1291
- request.body = null
1292
-
1293
- // 2. For each headerName of request-body-header name, delete headerName from
1294
- // request’s header list.
1295
- for (const headerName of requestBodyHeader) {
1296
- request.headersList.delete(headerName)
1297
- }
1298
- }
1299
-
1300
- // 13. If request’s current URL’s origin is not same origin with locationURL’s
1301
- // origin, then for each headerName of CORS non-wildcard request-header name,
1302
- // delete headerName from request’s header list.
1303
- if (!sameOrigin(requestCurrentURL(request), locationURL)) {
1304
- // https://fetch.spec.whatwg.org/#cors-non-wildcard-request-header-name
1305
- request.headersList.delete('authorization', true)
1306
-
1307
- // https://fetch.spec.whatwg.org/#authentication-entries
1308
- request.headersList.delete('proxy-authorization', true)
1309
-
1310
- // "Cookie" and "Host" are forbidden request-headers, which undici doesn't implement.
1311
- request.headersList.delete('cookie', true)
1312
- request.headersList.delete('host', true)
1313
- }
1314
-
1315
- // 14. If request’s body is non-null, then set request’s body to the first return
1316
- // value of safely extracting request’s body’s source.
1317
- if (request.body != null) {
1318
- assert(request.body.source != null)
1319
- request.body = safelyExtractBody(request.body.source)[0]
1320
- }
1321
-
1322
- // 15. Let timingInfo be fetchParams’s timing info.
1323
- const timingInfo = fetchParams.timingInfo
1324
-
1325
- // 16. Set timingInfo’s redirect end time and post-redirect start time to the
1326
- // coarsened shared current time given fetchParams’s cross-origin isolated
1327
- // capability.
1328
- timingInfo.redirectEndTime = timingInfo.postRedirectStartTime =
1329
- coarsenedSharedCurrentTime(fetchParams.crossOriginIsolatedCapability)
1330
-
1331
- // 17. If timingInfo’s redirect start time is 0, then set timingInfo’s
1332
- // redirect start time to timingInfo’s start time.
1333
- if (timingInfo.redirectStartTime === 0) {
1334
- timingInfo.redirectStartTime = timingInfo.startTime
1335
- }
1336
-
1337
- // 18. Append locationURL to request’s URL list.
1338
- request.urlList.push(locationURL)
1339
-
1340
- // 19. Invoke set request’s referrer policy on redirect on request and
1341
- // actualResponse.
1342
- setRequestReferrerPolicyOnRedirect(request, actualResponse)
1343
-
1344
- // 20. Return the result of running main fetch given fetchParams and true.
1345
- return mainFetch(fetchParams, true)
1346
- }
1347
-
1348
- // https://fetch.spec.whatwg.org/#http-network-or-cache-fetch
1349
- async function httpNetworkOrCacheFetch (
1350
- fetchParams,
1351
- isAuthenticationFetch = false,
1352
- isNewConnectionFetch = false
1353
- ) {
1354
- // 1. Let request be fetchParams’s request.
1355
- const request = fetchParams.request
1356
-
1357
- // 2. Let httpFetchParams be null.
1358
- let httpFetchParams = null
1359
-
1360
- // 3. Let httpRequest be null.
1361
- let httpRequest = null
1362
-
1363
- // 4. Let response be null.
1364
- let response = null
1365
-
1366
- // 5. Let storedResponse be null.
1367
- // TODO: cache
1368
-
1369
- // 6. Let httpCache be null.
1370
- const httpCache = null
1371
-
1372
- // 7. Let the revalidatingFlag be unset.
1373
- const revalidatingFlag = false
1374
-
1375
- // 8. Run these steps, but abort when the ongoing fetch is terminated:
1376
-
1377
- // 1. If request’s window is "no-window" and request’s redirect mode is
1378
- // "error", then set httpFetchParams to fetchParams and httpRequest to
1379
- // request.
1380
- if (request.window === 'no-window' && request.redirect === 'error') {
1381
- httpFetchParams = fetchParams
1382
- httpRequest = request
1383
- } else {
1384
- // Otherwise:
1385
-
1386
- // 1. Set httpRequest to a clone of request.
1387
- httpRequest = cloneRequest(request)
1388
-
1389
- // 2. Set httpFetchParams to a copy of fetchParams.
1390
- httpFetchParams = { ...fetchParams }
1391
-
1392
- // 3. Set httpFetchParams’s request to httpRequest.
1393
- httpFetchParams.request = httpRequest
1394
- }
1395
-
1396
- // 3. Let includeCredentials be true if one of
1397
- const includeCredentials =
1398
- request.credentials === 'include' ||
1399
- (request.credentials === 'same-origin' &&
1400
- request.responseTainting === 'basic')
1401
-
1402
- // 4. Let contentLength be httpRequest’s body’s length, if httpRequest’s
1403
- // body is non-null; otherwise null.
1404
- const contentLength = httpRequest.body ? httpRequest.body.length : null
1405
-
1406
- // 5. Let contentLengthHeaderValue be null.
1407
- let contentLengthHeaderValue = null
1408
-
1409
- // 6. If httpRequest’s body is null and httpRequest’s method is `POST` or
1410
- // `PUT`, then set contentLengthHeaderValue to `0`.
1411
- if (
1412
- httpRequest.body == null &&
1413
- ['POST', 'PUT'].includes(httpRequest.method)
1414
- ) {
1415
- contentLengthHeaderValue = '0'
1416
- }
1417
-
1418
- // 7. If contentLength is non-null, then set contentLengthHeaderValue to
1419
- // contentLength, serialized and isomorphic encoded.
1420
- if (contentLength != null) {
1421
- contentLengthHeaderValue = isomorphicEncode(`${contentLength}`)
1422
- }
1423
-
1424
- // 8. If contentLengthHeaderValue is non-null, then append
1425
- // `Content-Length`/contentLengthHeaderValue to httpRequest’s header
1426
- // list.
1427
- if (contentLengthHeaderValue != null) {
1428
- httpRequest.headersList.append('content-length', contentLengthHeaderValue, true)
1429
- }
1430
-
1431
- // 9. If contentLengthHeaderValue is non-null, then append (`Content-Length`,
1432
- // contentLengthHeaderValue) to httpRequest’s header list.
1433
-
1434
- // 10. If contentLength is non-null and httpRequest’s keepalive is true,
1435
- // then:
1436
- if (contentLength != null && httpRequest.keepalive) {
1437
- // NOTE: keepalive is a noop outside of browser context.
1438
- }
1439
-
1440
- // 11. If httpRequest’s referrer is a URL, then append
1441
- // `Referer`/httpRequest’s referrer, serialized and isomorphic encoded,
1442
- // to httpRequest’s header list.
1443
- if (webidl.is.URL(httpRequest.referrer)) {
1444
- httpRequest.headersList.append('referer', isomorphicEncode(httpRequest.referrer.href), true)
1445
- }
1446
-
1447
- // 12. Append a request `Origin` header for httpRequest.
1448
- appendRequestOriginHeader(httpRequest)
1449
-
1450
- // 13. Append the Fetch metadata headers for httpRequest. [FETCH-METADATA]
1451
- appendFetchMetadata(httpRequest)
1452
-
1453
- // 14. If httpRequest’s header list does not contain `User-Agent`, then
1454
- // user agents should append `User-Agent`/default `User-Agent` value to
1455
- // httpRequest’s header list.
1456
- if (!httpRequest.headersList.contains('user-agent', true)) {
1457
- httpRequest.headersList.append('user-agent', defaultUserAgent, true)
1458
- }
1459
-
1460
- // 15. If httpRequest’s cache mode is "default" and httpRequest’s header
1461
- // list contains `If-Modified-Since`, `If-None-Match`,
1462
- // `If-Unmodified-Since`, `If-Match`, or `If-Range`, then set
1463
- // httpRequest’s cache mode to "no-store".
1464
- if (
1465
- httpRequest.cache === 'default' &&
1466
- (httpRequest.headersList.contains('if-modified-since', true) ||
1467
- httpRequest.headersList.contains('if-none-match', true) ||
1468
- httpRequest.headersList.contains('if-unmodified-since', true) ||
1469
- httpRequest.headersList.contains('if-match', true) ||
1470
- httpRequest.headersList.contains('if-range', true))
1471
- ) {
1472
- httpRequest.cache = 'no-store'
1473
- }
1474
-
1475
- // 16. If httpRequest’s cache mode is "no-cache", httpRequest’s prevent
1476
- // no-cache cache-control header modification flag is unset, and
1477
- // httpRequest’s header list does not contain `Cache-Control`, then append
1478
- // `Cache-Control`/`max-age=0` to httpRequest’s header list.
1479
- if (
1480
- httpRequest.cache === 'no-cache' &&
1481
- !httpRequest.preventNoCacheCacheControlHeaderModification &&
1482
- !httpRequest.headersList.contains('cache-control', true)
1483
- ) {
1484
- httpRequest.headersList.append('cache-control', 'max-age=0', true)
1485
- }
1486
-
1487
- // 17. If httpRequest’s cache mode is "no-store" or "reload", then:
1488
- if (httpRequest.cache === 'no-store' || httpRequest.cache === 'reload') {
1489
- // 1. If httpRequest’s header list does not contain `Pragma`, then append
1490
- // `Pragma`/`no-cache` to httpRequest’s header list.
1491
- if (!httpRequest.headersList.contains('pragma', true)) {
1492
- httpRequest.headersList.append('pragma', 'no-cache', true)
1493
- }
1494
-
1495
- // 2. If httpRequest’s header list does not contain `Cache-Control`,
1496
- // then append `Cache-Control`/`no-cache` to httpRequest’s header list.
1497
- if (!httpRequest.headersList.contains('cache-control', true)) {
1498
- httpRequest.headersList.append('cache-control', 'no-cache', true)
1499
- }
1500
- }
1501
-
1502
- // 18. If httpRequest’s header list contains `Range`, then append
1503
- // `Accept-Encoding`/`identity` to httpRequest’s header list.
1504
- if (httpRequest.headersList.contains('range', true)) {
1505
- httpRequest.headersList.append('accept-encoding', 'identity', true)
1506
- }
1507
-
1508
- // 19. Modify httpRequest’s header list per HTTP. Do not append a given
1509
- // header if httpRequest’s header list contains that header’s name.
1510
- // TODO: https://github.com/whatwg/fetch/issues/1285#issuecomment-896560129
1511
- if (!httpRequest.headersList.contains('accept-encoding', true)) {
1512
- if (urlHasHttpsScheme(requestCurrentURL(httpRequest))) {
1513
- httpRequest.headersList.append('accept-encoding', 'br, gzip, deflate', true)
1514
- } else {
1515
- httpRequest.headersList.append('accept-encoding', 'gzip, deflate', true)
1516
- }
1517
- }
1518
-
1519
- httpRequest.headersList.delete('host', true)
1520
-
1521
- // 20. If includeCredentials is true, then:
1522
- if (includeCredentials) {
1523
- // 1. If the user agent is not configured to block cookies for httpRequest
1524
- // (see section 7 of [COOKIES]), then:
1525
- // TODO: credentials
1526
- // 2. If httpRequest’s header list does not contain `Authorization`, then:
1527
- // TODO: credentials
1528
- }
1529
-
1530
- // 21. If there’s a proxy-authentication entry, use it as appropriate.
1531
- // TODO: proxy-authentication
1532
-
1533
- // 22. Set httpCache to the result of determining the HTTP cache
1534
- // partition, given httpRequest.
1535
- // TODO: cache
1536
-
1537
- // 23. If httpCache is null, then set httpRequest’s cache mode to
1538
- // "no-store".
1539
- if (httpCache == null) {
1540
- httpRequest.cache = 'no-store'
1541
- }
1542
-
1543
- // 24. If httpRequest’s cache mode is neither "no-store" nor "reload",
1544
- // then:
1545
- if (httpRequest.cache !== 'no-store' && httpRequest.cache !== 'reload') {
1546
- // TODO: cache
1547
- }
1548
-
1549
- // 9. If aborted, then return the appropriate network error for fetchParams.
1550
- // TODO
1551
-
1552
- // 10. If response is null, then:
1553
- if (response == null) {
1554
- // 1. If httpRequest’s cache mode is "only-if-cached", then return a
1555
- // network error.
1556
- if (httpRequest.cache === 'only-if-cached') {
1557
- return makeNetworkError('only if cached')
1558
- }
1559
-
1560
- // 2. Let forwardResponse be the result of running HTTP-network fetch
1561
- // given httpFetchParams, includeCredentials, and isNewConnectionFetch.
1562
- const forwardResponse = await httpNetworkFetch(
1563
- httpFetchParams,
1564
- includeCredentials,
1565
- isNewConnectionFetch
1566
- )
1567
-
1568
- // 3. If httpRequest’s method is unsafe and forwardResponse’s status is
1569
- // in the range 200 to 399, inclusive, invalidate appropriate stored
1570
- // responses in httpCache, as per the "Invalidation" chapter of HTTP
1571
- // Caching, and set storedResponse to null. [HTTP-CACHING]
1572
- if (
1573
- !safeMethodsSet.has(httpRequest.method) &&
1574
- forwardResponse.status >= 200 &&
1575
- forwardResponse.status <= 399
1576
- ) {
1577
- // TODO: cache
1578
- }
1579
-
1580
- // 4. If the revalidatingFlag is set and forwardResponse’s status is 304,
1581
- // then:
1582
- if (revalidatingFlag && forwardResponse.status === 304) {
1583
- // TODO: cache
1584
- }
1585
-
1586
- // 5. If response is null, then:
1587
- if (response == null) {
1588
- // 1. Set response to forwardResponse.
1589
- response = forwardResponse
1590
-
1591
- // 2. Store httpRequest and forwardResponse in httpCache, as per the
1592
- // "Storing Responses in Caches" chapter of HTTP Caching. [HTTP-CACHING]
1593
- // TODO: cache
1594
- }
1595
- }
1596
-
1597
- // 11. Set response’s URL list to a clone of httpRequest’s URL list.
1598
- response.urlList = [...httpRequest.urlList]
1599
-
1600
- // 12. If httpRequest’s header list contains `Range`, then set response’s
1601
- // range-requested flag.
1602
- if (httpRequest.headersList.contains('range', true)) {
1603
- response.rangeRequested = true
1604
- }
1605
-
1606
- // 13. Set response’s request-includes-credentials to includeCredentials.
1607
- response.requestIncludesCredentials = includeCredentials
1608
-
1609
- // 14. If response’s status is 401, httpRequest’s response tainting is not
1610
- // "cors", includeCredentials is true, and request’s window is an environment
1611
- // settings object, then:
1612
- // TODO
1613
-
1614
- // 15. If response’s status is 407, then:
1615
- if (response.status === 407) {
1616
- // 1. If request’s window is "no-window", then return a network error.
1617
- if (request.window === 'no-window') {
1618
- return makeNetworkError()
1619
- }
1620
-
1621
- // 2. ???
1622
-
1623
- // 3. If fetchParams is canceled, then return the appropriate network error for fetchParams.
1624
- if (isCancelled(fetchParams)) {
1625
- return makeAppropriateNetworkError(fetchParams)
1626
- }
1627
-
1628
- // 4. Prompt the end user as appropriate in request’s window and store
1629
- // the result as a proxy-authentication entry. [HTTP-AUTH]
1630
- // TODO: Invoke some kind of callback?
1631
-
1632
- // 5. Set response to the result of running HTTP-network-or-cache fetch given
1633
- // fetchParams.
1634
- // TODO
1635
- return makeNetworkError('proxy authentication required')
1636
- }
1637
-
1638
- // 16. If all of the following are true
1639
- if (
1640
- // response’s status is 421
1641
- response.status === 421 &&
1642
- // isNewConnectionFetch is false
1643
- !isNewConnectionFetch &&
1644
- // request’s body is null, or request’s body is non-null and request’s body’s source is non-null
1645
- (request.body == null || request.body.source != null)
1646
- ) {
1647
- // then:
1648
-
1649
- // 1. If fetchParams is canceled, then return the appropriate network error for fetchParams.
1650
- if (isCancelled(fetchParams)) {
1651
- return makeAppropriateNetworkError(fetchParams)
1652
- }
1653
-
1654
- // 2. Set response to the result of running HTTP-network-or-cache
1655
- // fetch given fetchParams, isAuthenticationFetch, and true.
1656
-
1657
- // TODO (spec): The spec doesn't specify this but we need to cancel
1658
- // the active response before we can start a new one.
1659
- // https://github.com/whatwg/fetch/issues/1293
1660
- fetchParams.controller.connection.destroy()
1661
-
1662
- response = await httpNetworkOrCacheFetch(
1663
- fetchParams,
1664
- isAuthenticationFetch,
1665
- true
1666
- )
1667
- }
1668
-
1669
- // 17. If isAuthenticationFetch is true, then create an authentication entry
1670
- if (isAuthenticationFetch) {
1671
- // TODO
1672
- }
1673
-
1674
- // 18. Return response.
1675
- return response
1676
- }
1677
-
1678
- // https://fetch.spec.whatwg.org/#http-network-fetch
1679
- async function httpNetworkFetch (
1680
- fetchParams,
1681
- includeCredentials = false,
1682
- forceNewConnection = false
1683
- ) {
1684
- assert(!fetchParams.controller.connection || fetchParams.controller.connection.destroyed)
1685
-
1686
- fetchParams.controller.connection = {
1687
- abort: null,
1688
- destroyed: false,
1689
- destroy (err, abort = true) {
1690
- if (!this.destroyed) {
1691
- this.destroyed = true
1692
- if (abort) {
1693
- this.abort?.(err ?? new DOMException('The operation was aborted.', 'AbortError'))
1694
- }
1695
- }
1696
- }
1697
- }
1698
-
1699
- // 1. Let request be fetchParams’s request.
1700
- const request = fetchParams.request
1701
-
1702
- // 2. Let response be null.
1703
- let response = null
1704
-
1705
- // 3. Let timingInfo be fetchParams’s timing info.
1706
- const timingInfo = fetchParams.timingInfo
1707
-
1708
- // 4. Let httpCache be the result of determining the HTTP cache partition,
1709
- // given request.
1710
- // TODO: cache
1711
- const httpCache = null
1712
-
1713
- // 5. If httpCache is null, then set request’s cache mode to "no-store".
1714
- if (httpCache == null) {
1715
- request.cache = 'no-store'
1716
- }
1717
-
1718
- // 6. Let networkPartitionKey be the result of determining the network
1719
- // partition key given request.
1720
- // TODO
1721
-
1722
- // 7. Let newConnection be "yes" if forceNewConnection is true; otherwise
1723
- // "no".
1724
- const newConnection = forceNewConnection ? 'yes' : 'no' // eslint-disable-line no-unused-vars
1725
-
1726
- // 8. Switch on request’s mode:
1727
- if (request.mode === 'websocket') {
1728
- // Let connection be the result of obtaining a WebSocket connection,
1729
- // given request’s current URL.
1730
- // TODO
1731
- } else {
1732
- // Let connection be the result of obtaining a connection, given
1733
- // networkPartitionKey, request’s current URL’s origin,
1734
- // includeCredentials, and forceNewConnection.
1735
- // TODO
1736
- }
1737
-
1738
- // 9. Run these steps, but abort when the ongoing fetch is terminated:
1739
-
1740
- // 1. If connection is failure, then return a network error.
1741
-
1742
- // 2. Set timingInfo’s final connection timing info to the result of
1743
- // calling clamp and coarsen connection timing info with connection’s
1744
- // timing info, timingInfo’s post-redirect start time, and fetchParams’s
1745
- // cross-origin isolated capability.
1746
-
1747
- // 3. If connection is not an HTTP/2 connection, request’s body is non-null,
1748
- // and request’s body’s source is null, then append (`Transfer-Encoding`,
1749
- // `chunked`) to request’s header list.
1750
-
1751
- // 4. Set timingInfo’s final network-request start time to the coarsened
1752
- // shared current time given fetchParams’s cross-origin isolated
1753
- // capability.
1754
-
1755
- // 5. Set response to the result of making an HTTP request over connection
1756
- // using request with the following caveats:
1757
-
1758
- // - Follow the relevant requirements from HTTP. [HTTP] [HTTP-SEMANTICS]
1759
- // [HTTP-COND] [HTTP-CACHING] [HTTP-AUTH]
1760
-
1761
- // - If request’s body is non-null, and request’s body’s source is null,
1762
- // then the user agent may have a buffer of up to 64 kibibytes and store
1763
- // a part of request’s body in that buffer. If the user agent reads from
1764
- // request’s body beyond that buffer’s size and the user agent needs to
1765
- // resend request, then instead return a network error.
1766
-
1767
- // - Set timingInfo’s final network-response start time to the coarsened
1768
- // shared current time given fetchParams’s cross-origin isolated capability,
1769
- // immediately after the user agent’s HTTP parser receives the first byte
1770
- // of the response (e.g., frame header bytes for HTTP/2 or response status
1771
- // line for HTTP/1.x).
1772
-
1773
- // - Wait until all the headers are transmitted.
1774
-
1775
- // - Any responses whose status is in the range 100 to 199, inclusive,
1776
- // and is not 101, are to be ignored, except for the purposes of setting
1777
- // timingInfo’s final network-response start time above.
1778
-
1779
- // - If request’s header list contains `Transfer-Encoding`/`chunked` and
1780
- // response is transferred via HTTP/1.0 or older, then return a network
1781
- // error.
1782
-
1783
- // - If the HTTP request results in a TLS client certificate dialog, then:
1784
-
1785
- // 1. If request’s window is an environment settings object, make the
1786
- // dialog available in request’s window.
1787
-
1788
- // 2. Otherwise, return a network error.
1789
-
1790
- // To transmit request’s body body, run these steps:
1791
- let requestBody = null
1792
- // 1. If body is null and fetchParams’s process request end-of-body is
1793
- // non-null, then queue a fetch task given fetchParams’s process request
1794
- // end-of-body and fetchParams’s task destination.
1795
- if (request.body == null && fetchParams.processRequestEndOfBody) {
1796
- queueMicrotask(() => fetchParams.processRequestEndOfBody())
1797
- } else if (request.body != null) {
1798
- // 2. Otherwise, if body is non-null:
1799
-
1800
- // 1. Let processBodyChunk given bytes be these steps:
1801
- const processBodyChunk = async function * (bytes) {
1802
- // 1. If the ongoing fetch is terminated, then abort these steps.
1803
- if (isCancelled(fetchParams)) {
1804
- return
1805
- }
1806
-
1807
- // 2. Run this step in parallel: transmit bytes.
1808
- yield bytes
1809
-
1810
- // 3. If fetchParams’s process request body is non-null, then run
1811
- // fetchParams’s process request body given bytes’s length.
1812
- fetchParams.processRequestBodyChunkLength?.(bytes.byteLength)
1813
- }
1814
-
1815
- // 2. Let processEndOfBody be these steps:
1816
- const processEndOfBody = () => {
1817
- // 1. If fetchParams is canceled, then abort these steps.
1818
- if (isCancelled(fetchParams)) {
1819
- return
1820
- }
1821
-
1822
- // 2. If fetchParams’s process request end-of-body is non-null,
1823
- // then run fetchParams’s process request end-of-body.
1824
- if (fetchParams.processRequestEndOfBody) {
1825
- fetchParams.processRequestEndOfBody()
1826
- }
1827
- }
1828
-
1829
- // 3. Let processBodyError given e be these steps:
1830
- const processBodyError = (e) => {
1831
- // 1. If fetchParams is canceled, then abort these steps.
1832
- if (isCancelled(fetchParams)) {
1833
- return
1834
- }
1835
-
1836
- // 2. If e is an "AbortError" DOMException, then abort fetchParams’s controller.
1837
- if (e.name === 'AbortError') {
1838
- fetchParams.controller.abort()
1839
- } else {
1840
- fetchParams.controller.terminate(e)
1841
- }
1842
- }
1843
-
1844
- // 4. Incrementally read request’s body given processBodyChunk, processEndOfBody,
1845
- // processBodyError, and fetchParams’s task destination.
1846
- requestBody = (async function * () {
1847
- try {
1848
- for await (const bytes of request.body.stream) {
1849
- yield * processBodyChunk(bytes)
1850
- }
1851
- processEndOfBody()
1852
- } catch (err) {
1853
- processBodyError(err)
1854
- }
1855
- })()
1856
- }
1857
-
1858
- try {
1859
- // socket is only provided for websockets
1860
- const { body, status, statusText, headersList, socket } = await dispatch({ body: requestBody })
1861
-
1862
- if (socket) {
1863
- response = makeResponse({ status, statusText, headersList, socket })
1864
- } else {
1865
- const iterator = body[Symbol.asyncIterator]()
1866
- fetchParams.controller.next = () => iterator.next()
1867
-
1868
- response = makeResponse({ status, statusText, headersList })
1869
- }
1870
- } catch (err) {
1871
- // 10. If aborted, then:
1872
- if (err.name === 'AbortError') {
1873
- // 1. If connection uses HTTP/2, then transmit an RST_STREAM frame.
1874
- fetchParams.controller.connection.destroy()
1875
-
1876
- // 2. Return the appropriate network error for fetchParams.
1877
- return makeAppropriateNetworkError(fetchParams, err)
1878
- }
1879
-
1880
- return makeNetworkError(err)
1881
- }
1882
-
1883
- // 11. Let pullAlgorithm be an action that resumes the ongoing fetch
1884
- // if it is suspended.
1885
- const pullAlgorithm = () => {
1886
- return fetchParams.controller.resume()
1887
- }
1888
-
1889
- // 12. Let cancelAlgorithm be an algorithm that aborts fetchParams’s
1890
- // controller with reason, given reason.
1891
- const cancelAlgorithm = (reason) => {
1892
- // If the aborted fetch was already terminated, then we do not
1893
- // need to do anything.
1894
- if (!isCancelled(fetchParams)) {
1895
- fetchParams.controller.abort(reason)
1896
- }
1897
- }
1898
-
1899
- // 13. Let highWaterMark be a non-negative, non-NaN number, chosen by
1900
- // the user agent.
1901
- // TODO
1902
-
1903
- // 14. Let sizeAlgorithm be an algorithm that accepts a chunk object
1904
- // and returns a non-negative, non-NaN, non-infinite number, chosen by the user agent.
1905
- // TODO
1906
-
1907
- // 15. Let stream be a new ReadableStream.
1908
- // 16. Set up stream with byte reading support with pullAlgorithm set to pullAlgorithm,
1909
- // cancelAlgorithm set to cancelAlgorithm.
1910
- const stream = new ReadableStream(
1911
- {
1912
- async start (controller) {
1913
- fetchParams.controller.controller = controller
1914
- },
1915
- async pull (controller) {
1916
- await pullAlgorithm(controller)
1917
- },
1918
- async cancel (reason) {
1919
- await cancelAlgorithm(reason)
1920
- },
1921
- type: 'bytes'
1922
- }
1923
- )
1924
-
1925
- // 17. Run these steps, but abort when the ongoing fetch is terminated:
1926
-
1927
- // 1. Set response’s body to a new body whose stream is stream.
1928
- response.body = { stream, source: null, length: null }
1929
-
1930
- // 2. If response is not a network error and request’s cache mode is
1931
- // not "no-store", then update response in httpCache for request.
1932
- // TODO
1933
-
1934
- // 3. If includeCredentials is true and the user agent is not configured
1935
- // to block cookies for request (see section 7 of [COOKIES]), then run the
1936
- // "set-cookie-string" parsing algorithm (see section 5.2 of [COOKIES]) on
1937
- // the value of each header whose name is a byte-case-insensitive match for
1938
- // `Set-Cookie` in response’s header list, if any, and request’s current URL.
1939
- // TODO
1940
-
1941
- // 18. If aborted, then:
1942
- // TODO
1943
-
1944
- // 19. Run these steps in parallel:
1945
-
1946
- // 1. Run these steps, but abort when fetchParams is canceled:
1947
- if (!fetchParams.controller.resume) {
1948
- fetchParams.controller.on('terminated', onAborted)
1949
- }
1950
-
1951
- fetchParams.controller.resume = async () => {
1952
- // 1. While true
1953
- while (true) {
1954
- // 1-3. See onData...
1955
-
1956
- // 4. Set bytes to the result of handling content codings given
1957
- // codings and bytes.
1958
- let bytes
1959
- let isFailure
1960
- try {
1961
- const { done, value } = await fetchParams.controller.next()
1962
-
1963
- if (isAborted(fetchParams)) {
1964
- break
1965
- }
1966
-
1967
- bytes = done ? undefined : value
1968
- } catch (err) {
1969
- if (fetchParams.controller.ended && !timingInfo.encodedBodySize) {
1970
- // zlib doesn't like empty streams.
1971
- bytes = undefined
1972
- } else {
1973
- bytes = err
1974
-
1975
- // err may be propagated from the result of calling readablestream.cancel,
1976
- // which might not be an error. https://github.com/nodejs/undici/issues/2009
1977
- isFailure = true
1978
- }
1979
- }
1980
-
1981
- if (bytes === undefined) {
1982
- // 2. Otherwise, if the bytes transmission for response’s message
1983
- // body is done normally and stream is readable, then close
1984
- // stream, finalize response for fetchParams and response, and
1985
- // abort these in-parallel steps.
1986
- readableStreamClose(fetchParams.controller.controller)
1987
-
1988
- finalizeResponse(fetchParams, response)
1989
-
1990
- return
1991
- }
1992
-
1993
- // 5. Increase timingInfo’s decoded body size by bytes’s length.
1994
- timingInfo.decodedBodySize += bytes?.byteLength ?? 0
1995
-
1996
- // 6. If bytes is failure, then terminate fetchParams’s controller.
1997
- if (isFailure) {
1998
- fetchParams.controller.terminate(bytes)
1999
- return
2000
- }
2001
-
2002
- // 7. Enqueue a Uint8Array wrapping an ArrayBuffer containing bytes
2003
- // into stream.
2004
- const buffer = new Uint8Array(bytes)
2005
- if (buffer.byteLength) {
2006
- fetchParams.controller.controller.enqueue(buffer)
2007
- }
2008
-
2009
- // 8. If stream is errored, then terminate the ongoing fetch.
2010
- if (isErrored(stream)) {
2011
- fetchParams.controller.terminate()
2012
- return
2013
- }
2014
-
2015
- // 9. If stream doesn’t need more data ask the user agent to suspend
2016
- // the ongoing fetch.
2017
- if (fetchParams.controller.controller.desiredSize <= 0) {
2018
- return
2019
- }
2020
- }
2021
- }
2022
-
2023
- // 2. If aborted, then:
2024
- function onAborted (reason) {
2025
- // 2. If fetchParams is aborted, then:
2026
- if (isAborted(fetchParams)) {
2027
- // 1. Set response’s aborted flag.
2028
- response.aborted = true
2029
-
2030
- // 2. If stream is readable, then error stream with the result of
2031
- // deserialize a serialized abort reason given fetchParams’s
2032
- // controller’s serialized abort reason and an
2033
- // implementation-defined realm.
2034
- if (isReadable(stream)) {
2035
- fetchParams.controller.controller.error(
2036
- fetchParams.controller.serializedAbortReason
2037
- )
2038
- }
2039
- } else {
2040
- // 3. Otherwise, if stream is readable, error stream with a TypeError.
2041
- if (isReadable(stream)) {
2042
- fetchParams.controller.controller.error(new TypeError('terminated', {
2043
- cause: isErrorLike(reason) ? reason : undefined
2044
- }))
2045
- }
2046
- }
2047
-
2048
- // 4. If connection uses HTTP/2, then transmit an RST_STREAM frame.
2049
- // 5. Otherwise, the user agent should close connection unless it would be bad for performance to do so.
2050
- fetchParams.controller.connection.destroy()
2051
- }
2052
-
2053
- // 20. Return response.
2054
- return response
2055
-
2056
- function dispatch ({ body }) {
2057
- const url = requestCurrentURL(request)
2058
- /** @type {import('../..').Agent} */
2059
- const agent = fetchParams.controller.dispatcher
2060
-
2061
- return new Promise((resolve, reject) => agent.dispatch(
2062
- {
2063
- path: url.pathname + url.search,
2064
- origin: url.origin,
2065
- method: request.method,
2066
- body: agent.isMockActive ? request.body && (request.body.source || request.body.stream) : body,
2067
- headers: request.headersList.entries,
2068
- maxRedirections: 0,
2069
- upgrade: request.mode === 'websocket' ? 'websocket' : undefined
2070
- },
2071
- {
2072
- body: null,
2073
- abort: null,
2074
-
2075
- onConnect (abort) {
2076
- // TODO (fix): Do we need connection here?
2077
- const { connection } = fetchParams.controller
2078
-
2079
- // Set timingInfo’s final connection timing info to the result of calling clamp and coarsen
2080
- // connection timing info with connection’s timing info, timingInfo’s post-redirect start
2081
- // time, and fetchParams’s cross-origin isolated capability.
2082
- // TODO: implement connection timing
2083
- timingInfo.finalConnectionTimingInfo = clampAndCoarsenConnectionTimingInfo(undefined, timingInfo.postRedirectStartTime, fetchParams.crossOriginIsolatedCapability)
2084
-
2085
- if (connection.destroyed) {
2086
- abort(new DOMException('The operation was aborted.', 'AbortError'))
2087
- } else {
2088
- fetchParams.controller.on('terminated', abort)
2089
- this.abort = connection.abort = abort
2090
- }
2091
-
2092
- // Set timingInfo’s final network-request start time to the coarsened shared current time given
2093
- // fetchParams’s cross-origin isolated capability.
2094
- timingInfo.finalNetworkRequestStartTime = coarsenedSharedCurrentTime(fetchParams.crossOriginIsolatedCapability)
2095
- },
2096
-
2097
- onResponseStarted () {
2098
- // Set timingInfo’s final network-response start time to the coarsened shared current
2099
- // time given fetchParams’s cross-origin isolated capability, immediately after the
2100
- // user agent’s HTTP parser receives the first byte of the response (e.g., frame header
2101
- // bytes for HTTP/2 or response status line for HTTP/1.x).
2102
- timingInfo.finalNetworkResponseStartTime = coarsenedSharedCurrentTime(fetchParams.crossOriginIsolatedCapability)
2103
- },
2104
-
2105
- onHeaders (status, rawHeaders, resume, statusText) {
2106
- if (status < 200) {
2107
- return
2108
- }
2109
-
2110
- /** @type {string[]} */
2111
- let codings = []
2112
- let location = ''
2113
-
2114
- const headersList = new HeadersList()
2115
-
2116
- for (let i = 0; i < rawHeaders.length; i += 2) {
2117
- headersList.append(bufferToLowerCasedHeaderName(rawHeaders[i]), rawHeaders[i + 1].toString('latin1'), true)
2118
- }
2119
- const contentEncoding = headersList.get('content-encoding', true)
2120
- if (contentEncoding) {
2121
- // https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.1
2122
- // "All content-coding values are case-insensitive..."
2123
- codings = contentEncoding.toLowerCase().split(',').map((x) => x.trim())
2124
- }
2125
- location = headersList.get('location', true)
2126
-
2127
- this.body = new Readable({ read: resume })
2128
-
2129
- const decoders = []
2130
-
2131
- const willFollow = location && request.redirect === 'follow' &&
2132
- redirectStatusSet.has(status)
2133
-
2134
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
2135
- if (codings.length !== 0 && request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) {
2136
- for (let i = codings.length - 1; i >= 0; --i) {
2137
- const coding = codings[i]
2138
- // https://www.rfc-editor.org/rfc/rfc9112.html#section-7.2
2139
- if (coding === 'x-gzip' || coding === 'gzip') {
2140
- decoders.push(zlib.createGunzip({
2141
- // Be less strict when decoding compressed responses, since sometimes
2142
- // servers send slightly invalid responses that are still accepted
2143
- // by common browsers.
2144
- // Always using Z_SYNC_FLUSH is what cURL does.
2145
- flush: zlib.constants.Z_SYNC_FLUSH,
2146
- finishFlush: zlib.constants.Z_SYNC_FLUSH
2147
- }))
2148
- } else if (coding === 'deflate') {
2149
- decoders.push(createInflate({
2150
- flush: zlib.constants.Z_SYNC_FLUSH,
2151
- finishFlush: zlib.constants.Z_SYNC_FLUSH
2152
- }))
2153
- } else if (coding === 'br') {
2154
- decoders.push(zlib.createBrotliDecompress({
2155
- flush: zlib.constants.BROTLI_OPERATION_FLUSH,
2156
- finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH
2157
- }))
2158
- } else {
2159
- decoders.length = 0
2160
- break
2161
- }
2162
- }
2163
- }
2164
-
2165
- const onError = this.onError.bind(this)
2166
-
2167
- resolve({
2168
- status,
2169
- statusText,
2170
- headersList,
2171
- body: decoders.length
2172
- ? pipeline(this.body, ...decoders, (err) => {
2173
- if (err) {
2174
- this.onError(err)
2175
- }
2176
- }).on('error', onError)
2177
- : this.body.on('error', onError)
2178
- })
2179
-
2180
- return true
2181
- },
2182
-
2183
- onData (chunk) {
2184
- if (fetchParams.controller.dump) {
2185
- return
2186
- }
2187
-
2188
- // 1. If one or more bytes have been transmitted from response’s
2189
- // message body, then:
2190
-
2191
- // 1. Let bytes be the transmitted bytes.
2192
- const bytes = chunk
2193
-
2194
- // 2. Let codings be the result of extracting header list values
2195
- // given `Content-Encoding` and response’s header list.
2196
- // See pullAlgorithm.
2197
-
2198
- // 3. Increase timingInfo’s encoded body size by bytes’s length.
2199
- timingInfo.encodedBodySize += bytes.byteLength
2200
-
2201
- // 4. See pullAlgorithm...
2202
-
2203
- return this.body.push(bytes)
2204
- },
2205
-
2206
- onComplete () {
2207
- if (this.abort) {
2208
- fetchParams.controller.off('terminated', this.abort)
2209
- }
2210
-
2211
- fetchParams.controller.ended = true
2212
-
2213
- this.body.push(null)
2214
- },
2215
-
2216
- onError (error) {
2217
- if (this.abort) {
2218
- fetchParams.controller.off('terminated', this.abort)
2219
- }
2220
-
2221
- this.body?.destroy(error)
2222
-
2223
- fetchParams.controller.terminate(error)
2224
-
2225
- reject(error)
2226
- },
2227
-
2228
- onUpgrade (status, rawHeaders, socket) {
2229
- if (status !== 101) {
2230
- return
2231
- }
2232
-
2233
- const headersList = new HeadersList()
2234
-
2235
- for (let i = 0; i < rawHeaders.length; i += 2) {
2236
- headersList.append(bufferToLowerCasedHeaderName(rawHeaders[i]), rawHeaders[i + 1].toString('latin1'), true)
2237
- }
2238
-
2239
- resolve({
2240
- status,
2241
- statusText: STATUS_CODES[status],
2242
- headersList,
2243
- socket
2244
- })
2245
-
2246
- return true
2247
- }
2248
- }
2249
- ))
2250
- }
2251
- }
2252
-
2253
- module.exports = {
2254
- fetch,
2255
- Fetch,
2256
- fetching,
2257
- finalizeAndReportTiming
2258
- }