undici 6.20.0 → 7.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -10
- package/docs/docs/api/Agent.md +0 -3
- package/docs/docs/api/Client.md +1 -3
- package/docs/docs/api/Debug.md +1 -1
- package/docs/docs/api/Dispatcher.md +60 -8
- package/docs/docs/api/EnvHttpProxyAgent.md +0 -1
- package/docs/docs/api/Fetch.md +1 -0
- package/docs/docs/api/MockAgent.md +2 -0
- package/docs/docs/api/MockPool.md +2 -1
- package/docs/docs/api/Pool.md +0 -1
- package/docs/docs/api/RetryAgent.md +1 -1
- package/docs/docs/api/RetryHandler.md +1 -1
- package/docs/docs/api/WebSocket.md +45 -3
- package/index.js +6 -6
- package/lib/api/abort-signal.js +2 -0
- package/lib/api/api-connect.js +3 -1
- package/lib/api/api-pipeline.js +7 -6
- package/lib/api/api-request.js +32 -47
- package/lib/api/api-stream.js +39 -50
- package/lib/api/api-upgrade.js +5 -3
- package/lib/api/readable.js +261 -64
- package/lib/api/util.js +2 -0
- package/lib/core/constants.js +11 -9
- package/lib/core/diagnostics.js +122 -128
- package/lib/core/errors.js +4 -4
- package/lib/core/request.js +11 -9
- package/lib/core/symbols.js +2 -1
- package/lib/core/tree.js +9 -1
- package/lib/core/util.js +219 -48
- package/lib/dispatcher/agent.js +3 -17
- package/lib/dispatcher/balanced-pool.js +5 -8
- package/lib/dispatcher/client-h1.js +278 -54
- package/lib/dispatcher/client-h2.js +1 -1
- package/lib/dispatcher/client.js +23 -34
- package/lib/dispatcher/dispatcher-base.js +2 -34
- package/lib/dispatcher/dispatcher.js +3 -24
- package/lib/dispatcher/fixed-queue.js +91 -49
- package/lib/dispatcher/pool-stats.js +2 -0
- package/lib/dispatcher/pool.js +3 -6
- package/lib/dispatcher/proxy-agent.js +6 -7
- package/lib/handler/decorator-handler.js +24 -0
- package/lib/handler/redirect-handler.js +11 -2
- package/lib/handler/retry-handler.js +12 -3
- package/lib/interceptor/dns.js +346 -0
- package/lib/interceptor/dump.js +2 -2
- package/lib/interceptor/redirect.js +11 -14
- package/lib/interceptor/response-error.js +4 -1
- package/lib/llhttp/constants.d.ts +97 -0
- package/lib/llhttp/constants.js +412 -192
- package/lib/llhttp/constants.js.map +1 -0
- package/lib/llhttp/llhttp-wasm.js +11 -1
- package/lib/llhttp/llhttp_simd-wasm.js +11 -1
- package/lib/llhttp/utils.d.ts +2 -0
- package/lib/llhttp/utils.js +9 -9
- package/lib/llhttp/utils.js.map +1 -0
- package/lib/mock/mock-agent.js +5 -8
- package/lib/mock/mock-client.js +9 -4
- package/lib/mock/mock-errors.js +3 -1
- package/lib/mock/mock-interceptor.js +8 -6
- package/lib/mock/mock-pool.js +9 -4
- package/lib/mock/mock-symbols.js +3 -1
- package/lib/mock/mock-utils.js +29 -5
- package/lib/web/cache/cache.js +24 -21
- package/lib/web/cache/cachestorage.js +1 -1
- package/lib/web/cookies/index.js +17 -13
- package/lib/web/cookies/parse.js +2 -2
- package/lib/web/eventsource/eventsource-stream.js +9 -8
- package/lib/web/eventsource/eventsource.js +10 -6
- package/lib/web/fetch/body.js +42 -36
- package/lib/web/fetch/constants.js +35 -26
- package/lib/web/fetch/data-url.js +1 -1
- package/lib/web/fetch/formdata-parser.js +2 -2
- package/lib/web/fetch/formdata.js +65 -54
- package/lib/web/fetch/headers.js +117 -85
- package/lib/web/fetch/index.js +55 -62
- package/lib/web/fetch/request.js +135 -77
- package/lib/web/fetch/response.js +86 -56
- package/lib/web/fetch/util.js +90 -64
- package/lib/web/fetch/webidl.js +99 -64
- package/lib/web/websocket/connection.js +76 -147
- package/lib/web/websocket/constants.js +3 -4
- package/lib/web/websocket/events.js +4 -2
- package/lib/web/websocket/frame.js +45 -3
- package/lib/web/websocket/receiver.js +29 -33
- package/lib/web/websocket/sender.js +18 -13
- package/lib/web/websocket/stream/websocketerror.js +83 -0
- package/lib/web/websocket/stream/websocketstream.js +485 -0
- package/lib/web/websocket/util.js +128 -77
- package/lib/web/websocket/websocket.js +234 -135
- package/package.json +20 -33
- package/scripts/strip-comments.js +3 -1
- package/types/agent.d.ts +7 -7
- package/types/api.d.ts +24 -24
- package/types/balanced-pool.d.ts +11 -11
- package/types/client.d.ts +11 -12
- package/types/diagnostics-channel.d.ts +10 -10
- package/types/dispatcher.d.ts +96 -97
- package/types/env-http-proxy-agent.d.ts +2 -2
- package/types/errors.d.ts +53 -47
- package/types/fetch.d.ts +8 -8
- package/types/formdata.d.ts +7 -7
- package/types/global-dispatcher.d.ts +4 -4
- package/types/global-origin.d.ts +5 -5
- package/types/handlers.d.ts +4 -4
- package/types/header.d.ts +157 -1
- package/types/index.d.ts +42 -46
- package/types/interceptors.d.ts +22 -8
- package/types/mock-agent.d.ts +21 -18
- package/types/mock-client.d.ts +4 -4
- package/types/mock-errors.d.ts +3 -3
- package/types/mock-interceptor.d.ts +19 -19
- package/types/mock-pool.d.ts +4 -4
- package/types/patch.d.ts +0 -4
- package/types/pool-stats.d.ts +8 -8
- package/types/pool.d.ts +12 -12
- package/types/proxy-agent.d.ts +4 -4
- package/types/readable.d.ts +22 -14
- package/types/retry-agent.d.ts +1 -1
- package/types/retry-handler.d.ts +8 -8
- package/types/util.d.ts +3 -3
- package/types/utility.d.ts +7 -0
- package/types/webidl.d.ts +44 -6
- package/types/websocket.d.ts +34 -1
- package/docs/docs/api/DispatchInterceptor.md +0 -60
- package/lib/interceptor/redirect-interceptor.js +0 -21
- package/lib/mock/pluralizer.js +0 -29
- package/lib/web/cache/symbols.js +0 -5
- package/lib/web/fetch/file.js +0 -126
- package/lib/web/fetch/symbols.js +0 -9
- package/lib/web/fileapi/encoding.js +0 -290
- package/lib/web/fileapi/filereader.js +0 -344
- package/lib/web/fileapi/progressevent.js +0 -78
- package/lib/web/fileapi/symbols.js +0 -10
- package/lib/web/fileapi/util.js +0 -391
- package/lib/web/websocket/symbols.js +0 -12
- package/types/file.d.ts +0 -39
- package/types/filereader.d.ts +0 -54
|
@@ -9,7 +9,6 @@ const {
|
|
|
9
9
|
isValidReasonPhrase,
|
|
10
10
|
isCancelled,
|
|
11
11
|
isAborted,
|
|
12
|
-
isBlobLike,
|
|
13
12
|
serializeJavascriptValueToJSONString,
|
|
14
13
|
isErrorLike,
|
|
15
14
|
isomorphicEncode,
|
|
@@ -19,9 +18,7 @@ const {
|
|
|
19
18
|
redirectStatusSet,
|
|
20
19
|
nullBodyStatus
|
|
21
20
|
} = require('./constants')
|
|
22
|
-
const { kState, kHeaders } = require('./symbols')
|
|
23
21
|
const { webidl } = require('./webidl')
|
|
24
|
-
const { FormData } = require('./formdata')
|
|
25
22
|
const { URLSerializer } = require('./data-url')
|
|
26
23
|
const { kConstruct } = require('../../core/symbols')
|
|
27
24
|
const assert = require('node:assert')
|
|
@@ -31,6 +28,11 @@ const textEncoder = new TextEncoder('utf-8')
|
|
|
31
28
|
|
|
32
29
|
// https://fetch.spec.whatwg.org/#response-class
|
|
33
30
|
class Response {
|
|
31
|
+
/** @type {Headers} */
|
|
32
|
+
#headers
|
|
33
|
+
|
|
34
|
+
#state
|
|
35
|
+
|
|
34
36
|
// Creates network error Response.
|
|
35
37
|
static error () {
|
|
36
38
|
// The static error() method steps are to return the result of creating a
|
|
@@ -42,7 +44,7 @@ class Response {
|
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
// https://fetch.spec.whatwg.org/#dom-response-json
|
|
45
|
-
static json (data, init =
|
|
47
|
+
static json (data, init = undefined) {
|
|
46
48
|
webidl.argumentLengthCheck(arguments, 1, 'Response.json')
|
|
47
49
|
|
|
48
50
|
if (init !== null) {
|
|
@@ -96,20 +98,20 @@ class Response {
|
|
|
96
98
|
const responseObject = fromInnerResponse(makeResponse({}), 'immutable')
|
|
97
99
|
|
|
98
100
|
// 5. Set responseObject’s response’s status to status.
|
|
99
|
-
responseObject
|
|
101
|
+
responseObject.#state.status = status
|
|
100
102
|
|
|
101
103
|
// 6. Let value be parsedURL, serialized and isomorphic encoded.
|
|
102
104
|
const value = isomorphicEncode(URLSerializer(parsedURL))
|
|
103
105
|
|
|
104
106
|
// 7. Append `Location`/value to responseObject’s response’s header list.
|
|
105
|
-
responseObject
|
|
107
|
+
responseObject.#state.headersList.append('location', value, true)
|
|
106
108
|
|
|
107
109
|
// 8. Return responseObject.
|
|
108
110
|
return responseObject
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
// https://fetch.spec.whatwg.org/#dom-response
|
|
112
|
-
constructor (body = null, init =
|
|
114
|
+
constructor (body = null, init = undefined) {
|
|
113
115
|
if (body === kConstruct) {
|
|
114
116
|
return
|
|
115
117
|
}
|
|
@@ -121,14 +123,14 @@ class Response {
|
|
|
121
123
|
init = webidl.converters.ResponseInit(init)
|
|
122
124
|
|
|
123
125
|
// 1. Set this’s response to a new response.
|
|
124
|
-
this
|
|
126
|
+
this.#state = makeResponse({})
|
|
125
127
|
|
|
126
128
|
// 2. Set this’s headers to a new Headers object with this’s relevant
|
|
127
129
|
// Realm, whose header list is this’s response’s header list and guard
|
|
128
130
|
// is "response".
|
|
129
|
-
this
|
|
130
|
-
setHeadersGuard(this
|
|
131
|
-
setHeadersList(this
|
|
131
|
+
this.#headers = new Headers(kConstruct)
|
|
132
|
+
setHeadersGuard(this.#headers, 'response')
|
|
133
|
+
setHeadersList(this.#headers, this.#state.headersList)
|
|
132
134
|
|
|
133
135
|
// 3. Let bodyWithType be null.
|
|
134
136
|
let bodyWithType = null
|
|
@@ -148,14 +150,14 @@ class Response {
|
|
|
148
150
|
webidl.brandCheck(this, Response)
|
|
149
151
|
|
|
150
152
|
// The type getter steps are to return this’s response’s type.
|
|
151
|
-
return this
|
|
153
|
+
return this.#state.type
|
|
152
154
|
}
|
|
153
155
|
|
|
154
156
|
// Returns response’s URL, if it has one; otherwise the empty string.
|
|
155
157
|
get url () {
|
|
156
158
|
webidl.brandCheck(this, Response)
|
|
157
159
|
|
|
158
|
-
const urlList = this
|
|
160
|
+
const urlList = this.#state.urlList
|
|
159
161
|
|
|
160
162
|
// The url getter steps are to return the empty string if this’s
|
|
161
163
|
// response’s URL is null; otherwise this’s response’s URL,
|
|
@@ -175,7 +177,7 @@ class Response {
|
|
|
175
177
|
|
|
176
178
|
// The redirected getter steps are to return true if this’s response’s URL
|
|
177
179
|
// list has more than one item; otherwise false.
|
|
178
|
-
return this
|
|
180
|
+
return this.#state.urlList.length > 1
|
|
179
181
|
}
|
|
180
182
|
|
|
181
183
|
// Returns response’s status.
|
|
@@ -183,7 +185,7 @@ class Response {
|
|
|
183
185
|
webidl.brandCheck(this, Response)
|
|
184
186
|
|
|
185
187
|
// The status getter steps are to return this’s response’s status.
|
|
186
|
-
return this
|
|
188
|
+
return this.#state.status
|
|
187
189
|
}
|
|
188
190
|
|
|
189
191
|
// Returns whether response’s status is an ok status.
|
|
@@ -192,7 +194,7 @@ class Response {
|
|
|
192
194
|
|
|
193
195
|
// The ok getter steps are to return true if this’s response’s status is an
|
|
194
196
|
// ok status; otherwise false.
|
|
195
|
-
return this
|
|
197
|
+
return this.#state.status >= 200 && this.#state.status <= 299
|
|
196
198
|
}
|
|
197
199
|
|
|
198
200
|
// Returns response’s status message.
|
|
@@ -201,7 +203,7 @@ class Response {
|
|
|
201
203
|
|
|
202
204
|
// The statusText getter steps are to return this’s response’s status
|
|
203
205
|
// message.
|
|
204
|
-
return this
|
|
206
|
+
return this.#state.statusText
|
|
205
207
|
}
|
|
206
208
|
|
|
207
209
|
// Returns response’s headers as Headers.
|
|
@@ -209,19 +211,19 @@ class Response {
|
|
|
209
211
|
webidl.brandCheck(this, Response)
|
|
210
212
|
|
|
211
213
|
// The headers getter steps are to return this’s headers.
|
|
212
|
-
return this
|
|
214
|
+
return this.#headers
|
|
213
215
|
}
|
|
214
216
|
|
|
215
217
|
get body () {
|
|
216
218
|
webidl.brandCheck(this, Response)
|
|
217
219
|
|
|
218
|
-
return this
|
|
220
|
+
return this.#state.body ? this.#state.body.stream : null
|
|
219
221
|
}
|
|
220
222
|
|
|
221
223
|
get bodyUsed () {
|
|
222
224
|
webidl.brandCheck(this, Response)
|
|
223
225
|
|
|
224
|
-
return !!this
|
|
226
|
+
return !!this.#state.body && util.isDisturbed(this.#state.body.stream)
|
|
225
227
|
}
|
|
226
228
|
|
|
227
229
|
// Returns a clone of response.
|
|
@@ -229,7 +231,7 @@ class Response {
|
|
|
229
231
|
webidl.brandCheck(this, Response)
|
|
230
232
|
|
|
231
233
|
// 1. If this is unusable, then throw a TypeError.
|
|
232
|
-
if (bodyUnusable(this)) {
|
|
234
|
+
if (bodyUnusable(this.#state)) {
|
|
233
235
|
throw webidl.errors.exception({
|
|
234
236
|
header: 'Response.clone',
|
|
235
237
|
message: 'Body has already been consumed.'
|
|
@@ -237,11 +239,11 @@ class Response {
|
|
|
237
239
|
}
|
|
238
240
|
|
|
239
241
|
// 2. Let clonedResponse be the result of cloning this’s response.
|
|
240
|
-
const clonedResponse = cloneResponse(this
|
|
242
|
+
const clonedResponse = cloneResponse(this.#state)
|
|
241
243
|
|
|
242
244
|
// 3. Return the result of creating a Response object, given
|
|
243
245
|
// clonedResponse, this’s headers’s guard, and this’s relevant Realm.
|
|
244
|
-
return fromInnerResponse(clonedResponse, getHeadersGuard(this
|
|
246
|
+
return fromInnerResponse(clonedResponse, getHeadersGuard(this.#headers))
|
|
245
247
|
}
|
|
246
248
|
|
|
247
249
|
[nodeUtil.inspect.custom] (depth, options) {
|
|
@@ -265,9 +267,45 @@ class Response {
|
|
|
265
267
|
|
|
266
268
|
return `Response ${nodeUtil.formatWithOptions(options, properties)}`
|
|
267
269
|
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* @param {Response} response
|
|
273
|
+
*/
|
|
274
|
+
static getResponseHeaders (response) {
|
|
275
|
+
return response.#headers
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* @param {Response} response
|
|
280
|
+
* @param {Headers} newHeaders
|
|
281
|
+
*/
|
|
282
|
+
static setResponseHeaders (response, newHeaders) {
|
|
283
|
+
response.#headers = newHeaders
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* @param {Response} response
|
|
288
|
+
*/
|
|
289
|
+
static getResponseState (response) {
|
|
290
|
+
return response.#state
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* @param {Response} response
|
|
295
|
+
* @param {any} newState
|
|
296
|
+
*/
|
|
297
|
+
static setResponseState (response, newState) {
|
|
298
|
+
response.#state = newState
|
|
299
|
+
}
|
|
268
300
|
}
|
|
269
301
|
|
|
270
|
-
|
|
302
|
+
const { getResponseHeaders, setResponseHeaders, getResponseState, setResponseState } = Response
|
|
303
|
+
Reflect.deleteProperty(Response, 'getResponseHeaders')
|
|
304
|
+
Reflect.deleteProperty(Response, 'setResponseHeaders')
|
|
305
|
+
Reflect.deleteProperty(Response, 'getResponseState')
|
|
306
|
+
Reflect.deleteProperty(Response, 'setResponseState')
|
|
307
|
+
|
|
308
|
+
mixinBody(Response, getResponseState)
|
|
271
309
|
|
|
272
310
|
Object.defineProperties(Response.prototype, {
|
|
273
311
|
type: kEnumerableProperty,
|
|
@@ -464,17 +502,17 @@ function initializeResponse (response, init, body) {
|
|
|
464
502
|
|
|
465
503
|
// 3. Set response’s response’s status to init["status"].
|
|
466
504
|
if ('status' in init && init.status != null) {
|
|
467
|
-
response
|
|
505
|
+
getResponseState(response).status = init.status
|
|
468
506
|
}
|
|
469
507
|
|
|
470
508
|
// 4. Set response’s response’s status message to init["statusText"].
|
|
471
509
|
if ('statusText' in init && init.statusText != null) {
|
|
472
|
-
response
|
|
510
|
+
getResponseState(response).statusText = init.statusText
|
|
473
511
|
}
|
|
474
512
|
|
|
475
513
|
// 5. If init["headers"] exists, then fill response’s headers with init["headers"].
|
|
476
514
|
if ('headers' in init && init.headers != null) {
|
|
477
|
-
fill(response
|
|
515
|
+
fill(getResponseHeaders(response), init.headers)
|
|
478
516
|
}
|
|
479
517
|
|
|
480
518
|
// 6. If body was given, then:
|
|
@@ -488,12 +526,12 @@ function initializeResponse (response, init, body) {
|
|
|
488
526
|
}
|
|
489
527
|
|
|
490
528
|
// 2. Set response's body to body's body.
|
|
491
|
-
response
|
|
529
|
+
getResponseState(response).body = body.body
|
|
492
530
|
|
|
493
531
|
// 3. If body's type is non-null and response's header list does not contain
|
|
494
532
|
// `Content-Type`, then append (`Content-Type`, body's type) to response's header list.
|
|
495
|
-
if (body.type != null && !response
|
|
496
|
-
response
|
|
533
|
+
if (body.type != null && !getResponseState(response).headersList.contains('content-type', true)) {
|
|
534
|
+
getResponseState(response).headersList.append('content-type', body.type, true)
|
|
497
535
|
}
|
|
498
536
|
}
|
|
499
537
|
}
|
|
@@ -506,10 +544,11 @@ function initializeResponse (response, init, body) {
|
|
|
506
544
|
*/
|
|
507
545
|
function fromInnerResponse (innerResponse, guard) {
|
|
508
546
|
const response = new Response(kConstruct)
|
|
509
|
-
response
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
547
|
+
setResponseState(response, innerResponse)
|
|
548
|
+
const headers = new Headers(kConstruct)
|
|
549
|
+
setResponseHeaders(response, headers)
|
|
550
|
+
setHeadersList(headers, innerResponse.headersList)
|
|
551
|
+
setHeadersGuard(headers, guard)
|
|
513
552
|
|
|
514
553
|
if (hasFinalizationRegistry && innerResponse.body?.stream) {
|
|
515
554
|
// If the target (response) is reclaimed, the cleanup callback may be called at some point with
|
|
@@ -523,38 +562,26 @@ function fromInnerResponse (innerResponse, guard) {
|
|
|
523
562
|
return response
|
|
524
563
|
}
|
|
525
564
|
|
|
526
|
-
webidl.converters.ReadableStream = webidl.interfaceConverter(
|
|
527
|
-
ReadableStream
|
|
528
|
-
)
|
|
529
|
-
|
|
530
|
-
webidl.converters.FormData = webidl.interfaceConverter(
|
|
531
|
-
FormData
|
|
532
|
-
)
|
|
533
|
-
|
|
534
|
-
webidl.converters.URLSearchParams = webidl.interfaceConverter(
|
|
535
|
-
URLSearchParams
|
|
536
|
-
)
|
|
537
|
-
|
|
538
565
|
// https://fetch.spec.whatwg.org/#typedefdef-xmlhttprequestbodyinit
|
|
539
566
|
webidl.converters.XMLHttpRequestBodyInit = function (V, prefix, name) {
|
|
540
567
|
if (typeof V === 'string') {
|
|
541
568
|
return webidl.converters.USVString(V, prefix, name)
|
|
542
569
|
}
|
|
543
570
|
|
|
544
|
-
if (
|
|
545
|
-
return
|
|
571
|
+
if (webidl.is.Blob(V)) {
|
|
572
|
+
return V
|
|
546
573
|
}
|
|
547
574
|
|
|
548
575
|
if (ArrayBuffer.isView(V) || types.isArrayBuffer(V)) {
|
|
549
|
-
return
|
|
576
|
+
return V
|
|
550
577
|
}
|
|
551
578
|
|
|
552
|
-
if (
|
|
553
|
-
return
|
|
579
|
+
if (webidl.is.FormData(V)) {
|
|
580
|
+
return V
|
|
554
581
|
}
|
|
555
582
|
|
|
556
|
-
if (V
|
|
557
|
-
return
|
|
583
|
+
if (webidl.is.URLSearchParams(V)) {
|
|
584
|
+
return V
|
|
558
585
|
}
|
|
559
586
|
|
|
560
587
|
return webidl.converters.DOMString(V, prefix, name)
|
|
@@ -562,8 +589,8 @@ webidl.converters.XMLHttpRequestBodyInit = function (V, prefix, name) {
|
|
|
562
589
|
|
|
563
590
|
// https://fetch.spec.whatwg.org/#bodyinit
|
|
564
591
|
webidl.converters.BodyInit = function (V, prefix, argument) {
|
|
565
|
-
if (V
|
|
566
|
-
return
|
|
592
|
+
if (webidl.is.ReadableStream(V)) {
|
|
593
|
+
return V
|
|
567
594
|
}
|
|
568
595
|
|
|
569
596
|
// Note: the spec doesn't include async iterables,
|
|
@@ -592,6 +619,8 @@ webidl.converters.ResponseInit = webidl.dictionaryConverter([
|
|
|
592
619
|
}
|
|
593
620
|
])
|
|
594
621
|
|
|
622
|
+
webidl.is.Response = webidl.util.MakeTypeAssertion(Response.prototype)
|
|
623
|
+
|
|
595
624
|
module.exports = {
|
|
596
625
|
isNetworkError,
|
|
597
626
|
makeNetworkError,
|
|
@@ -600,5 +629,6 @@ module.exports = {
|
|
|
600
629
|
filterResponse,
|
|
601
630
|
Response,
|
|
602
631
|
cloneResponse,
|
|
603
|
-
fromInnerResponse
|
|
632
|
+
fromInnerResponse,
|
|
633
|
+
getResponseState
|
|
604
634
|
}
|
package/lib/web/fetch/util.js
CHANGED
|
@@ -6,7 +6,7 @@ const { redirectStatusSet, referrerPolicySet: referrerPolicyTokens, badPortsSet
|
|
|
6
6
|
const { getGlobalOrigin } = require('./global')
|
|
7
7
|
const { collectASequenceOfCodePoints, collectAnHTTPQuotedString, removeChars, parseMIMEType } = require('./data-url')
|
|
8
8
|
const { performance } = require('node:perf_hooks')
|
|
9
|
-
const {
|
|
9
|
+
const { ReadableStreamFrom, isValidHTTPToken, normalizedMethodRecordsBase } = require('../../core/util')
|
|
10
10
|
const assert = require('node:assert')
|
|
11
11
|
const { isUint8Array } = require('node:util/types')
|
|
12
12
|
const { webidl } = require('./webidl')
|
|
@@ -399,7 +399,7 @@ function determineRequestsReferrer (request) {
|
|
|
399
399
|
|
|
400
400
|
// note: we need to clone it as it's mutated
|
|
401
401
|
referrerSource = new URL(globalOrigin)
|
|
402
|
-
} else if (request.referrer
|
|
402
|
+
} else if (webidl.is.URL(request.referrer)) {
|
|
403
403
|
// Let referrerSource be request’s referrer.
|
|
404
404
|
referrerSource = request.referrer
|
|
405
405
|
}
|
|
@@ -418,18 +418,37 @@ function determineRequestsReferrer (request) {
|
|
|
418
418
|
referrerURL = referrerOrigin
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
421
|
+
// 7. The user agent MAY alter referrerURL or referrerOrigin at this point
|
|
422
|
+
// to enforce arbitrary policy considerations in the interests of minimizing
|
|
423
|
+
// data leakage. For example, the user agent could strip the URL down to an
|
|
424
|
+
// origin, modify its host, replace it with an empty string, etc.
|
|
424
425
|
|
|
425
426
|
// 8. Execute the switch statements corresponding to the value of policy:
|
|
426
427
|
switch (policy) {
|
|
427
|
-
case '
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
428
|
+
case 'no-referrer':
|
|
429
|
+
// Return no referrer
|
|
430
|
+
return 'no-referrer'
|
|
431
|
+
case 'origin':
|
|
432
|
+
// Return referrerOrigin
|
|
433
|
+
if (referrerOrigin != null) {
|
|
434
|
+
return referrerOrigin
|
|
435
|
+
}
|
|
436
|
+
return stripURLForReferrer(referrerSource, true)
|
|
437
|
+
case 'unsafe-url':
|
|
438
|
+
// Return referrerURL.
|
|
439
|
+
return referrerURL
|
|
440
|
+
case 'strict-origin': {
|
|
441
|
+
const currentURL = requestCurrentURL(request)
|
|
442
|
+
|
|
443
|
+
// 1. If referrerURL is a potentially trustworthy URL and request’s
|
|
444
|
+
// current URL is not a potentially trustworthy URL, then return no
|
|
445
|
+
// referrer.
|
|
446
|
+
if (isURLPotentiallyTrustworthy(referrerURL) && !isURLPotentiallyTrustworthy(currentURL)) {
|
|
447
|
+
return 'no-referrer'
|
|
448
|
+
}
|
|
449
|
+
// 2. Return referrerOrigin
|
|
450
|
+
return referrerOrigin
|
|
451
|
+
}
|
|
433
452
|
case 'strict-origin-when-cross-origin': {
|
|
434
453
|
const currentURL = requestCurrentURL(request)
|
|
435
454
|
|
|
@@ -449,34 +468,45 @@ function determineRequestsReferrer (request) {
|
|
|
449
468
|
// 3. Return referrerOrigin.
|
|
450
469
|
return referrerOrigin
|
|
451
470
|
}
|
|
452
|
-
case '
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
471
|
+
case 'same-origin':
|
|
472
|
+
// 1. If the origin of referrerURL and the origin of request’s current
|
|
473
|
+
// URL are the same, then return referrerURL.
|
|
474
|
+
if (sameOrigin(request, referrerURL)) {
|
|
475
|
+
return referrerURL
|
|
476
|
+
}
|
|
477
|
+
// 2. Return no referrer.
|
|
478
|
+
return 'no-referrer'
|
|
479
|
+
case 'origin-when-cross-origin':
|
|
480
|
+
// 1. If the origin of referrerURL and the origin of request’s current
|
|
481
|
+
// URL are the same, then return referrerURL.
|
|
482
|
+
if (sameOrigin(request, referrerURL)) {
|
|
483
|
+
return referrerURL
|
|
484
|
+
}
|
|
485
|
+
// 2. Return referrerOrigin.
|
|
486
|
+
return referrerOrigin
|
|
487
|
+
case 'no-referrer-when-downgrade': {
|
|
488
|
+
const currentURL = requestCurrentURL(request)
|
|
489
|
+
|
|
490
|
+
// 1. If referrerURL is a potentially trustworthy URL and request’s
|
|
491
|
+
// current URL is not a potentially trustworthy URL, then return no
|
|
492
|
+
// referrer.
|
|
493
|
+
if (isURLPotentiallyTrustworthy(referrerURL) && !isURLPotentiallyTrustworthy(currentURL)) {
|
|
494
|
+
return 'no-referrer'
|
|
495
|
+
}
|
|
496
|
+
// 2. Return referrerOrigin
|
|
497
|
+
return referrerOrigin
|
|
498
|
+
}
|
|
469
499
|
}
|
|
470
500
|
}
|
|
471
501
|
|
|
472
502
|
/**
|
|
473
503
|
* @see https://w3c.github.io/webappsec-referrer-policy/#strip-url
|
|
474
504
|
* @param {URL} url
|
|
475
|
-
* @param {boolean
|
|
505
|
+
* @param {boolean} [originOnly]
|
|
476
506
|
*/
|
|
477
507
|
function stripURLForReferrer (url, originOnly) {
|
|
478
508
|
// 1. Assert: url is a URL.
|
|
479
|
-
assert(url
|
|
509
|
+
assert(webidl.is.URL(url))
|
|
480
510
|
|
|
481
511
|
url = new URL(url)
|
|
482
512
|
|
|
@@ -508,7 +538,7 @@ function stripURLForReferrer (url, originOnly) {
|
|
|
508
538
|
}
|
|
509
539
|
|
|
510
540
|
function isURLPotentiallyTrustworthy (url) {
|
|
511
|
-
if (!(url
|
|
541
|
+
if (!webidl.is.URL(url)) {
|
|
512
542
|
return false
|
|
513
543
|
}
|
|
514
544
|
|
|
@@ -825,7 +855,7 @@ const esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbo
|
|
|
825
855
|
/**
|
|
826
856
|
* @see https://webidl.spec.whatwg.org/#dfn-iterator-prototype-object
|
|
827
857
|
* @param {string} name name of the instance
|
|
828
|
-
* @param {
|
|
858
|
+
* @param {((target: any) => any)} kInternalIterator
|
|
829
859
|
* @param {string | number} [keyIndex]
|
|
830
860
|
* @param {string | number} [valueIndex]
|
|
831
861
|
*/
|
|
@@ -867,7 +897,7 @@ function createIterator (name, kInternalIterator, keyIndex = 0, valueIndex = 1)
|
|
|
867
897
|
// 7. Let kind be object’s kind.
|
|
868
898
|
// 8. Let values be object’s target's value pairs to iterate over.
|
|
869
899
|
const index = this.#index
|
|
870
|
-
const values = this.#target
|
|
900
|
+
const values = kInternalIterator(this.#target)
|
|
871
901
|
|
|
872
902
|
// 9. Let len be the length of values.
|
|
873
903
|
const len = values.length
|
|
@@ -961,7 +991,7 @@ function createIterator (name, kInternalIterator, keyIndex = 0, valueIndex = 1)
|
|
|
961
991
|
* @see https://webidl.spec.whatwg.org/#dfn-iterator-prototype-object
|
|
962
992
|
* @param {string} name name of the instance
|
|
963
993
|
* @param {any} object class
|
|
964
|
-
* @param {
|
|
994
|
+
* @param {(target: any) => any} kInternalIterator
|
|
965
995
|
* @param {string | number} [keyIndex]
|
|
966
996
|
* @param {string | number} [valueIndex]
|
|
967
997
|
*/
|
|
@@ -1029,7 +1059,7 @@ function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueInde
|
|
|
1029
1059
|
/**
|
|
1030
1060
|
* @see https://fetch.spec.whatwg.org/#body-fully-read
|
|
1031
1061
|
*/
|
|
1032
|
-
|
|
1062
|
+
function fullyReadBody (body, processBody, processBodyError) {
|
|
1033
1063
|
// 1. If taskDestination is null, then set taskDestination to
|
|
1034
1064
|
// the result of starting a new parallel queue.
|
|
1035
1065
|
|
|
@@ -1054,18 +1084,7 @@ async function fullyReadBody (body, processBody, processBodyError) {
|
|
|
1054
1084
|
}
|
|
1055
1085
|
|
|
1056
1086
|
// 5. Read all bytes from reader, given successSteps and errorSteps.
|
|
1057
|
-
|
|
1058
|
-
successSteps(await readAllBytes(reader))
|
|
1059
|
-
} catch (e) {
|
|
1060
|
-
errorSteps(e)
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
function isReadableStreamLike (stream) {
|
|
1065
|
-
return stream instanceof ReadableStream || (
|
|
1066
|
-
stream[Symbol.toStringTag] === 'ReadableStream' &&
|
|
1067
|
-
typeof stream.tee === 'function'
|
|
1068
|
-
)
|
|
1087
|
+
readAllBytes(reader, successSteps, errorSteps)
|
|
1069
1088
|
}
|
|
1070
1089
|
|
|
1071
1090
|
/**
|
|
@@ -1103,30 +1122,39 @@ function isomorphicEncode (input) {
|
|
|
1103
1122
|
* @see https://streams.spec.whatwg.org/#readablestreamdefaultreader-read-all-bytes
|
|
1104
1123
|
* @see https://streams.spec.whatwg.org/#read-loop
|
|
1105
1124
|
* @param {ReadableStreamDefaultReader} reader
|
|
1125
|
+
* @param {(bytes: Uint8Array) => void} successSteps
|
|
1126
|
+
* @param {(error: Error) => void} failureSteps
|
|
1106
1127
|
*/
|
|
1107
|
-
async function readAllBytes (reader) {
|
|
1128
|
+
async function readAllBytes (reader, successSteps, failureSteps) {
|
|
1108
1129
|
const bytes = []
|
|
1109
1130
|
let byteLength = 0
|
|
1110
1131
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1132
|
+
try {
|
|
1133
|
+
do {
|
|
1134
|
+
const { done, value: chunk } = await reader.read()
|
|
1113
1135
|
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1136
|
+
if (done) {
|
|
1137
|
+
// 1. Call successSteps with bytes.
|
|
1138
|
+
successSteps(Buffer.concat(bytes, byteLength))
|
|
1139
|
+
return
|
|
1140
|
+
}
|
|
1118
1141
|
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1142
|
+
// 1. If chunk is not a Uint8Array object, call failureSteps
|
|
1143
|
+
// with a TypeError and abort these steps.
|
|
1144
|
+
if (!isUint8Array(chunk)) {
|
|
1145
|
+
failureSteps(TypeError('Received non-Uint8Array chunk'))
|
|
1146
|
+
return
|
|
1147
|
+
}
|
|
1124
1148
|
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1149
|
+
// 2. Append the bytes represented by chunk to bytes.
|
|
1150
|
+
bytes.push(chunk)
|
|
1151
|
+
byteLength += chunk.length
|
|
1128
1152
|
|
|
1129
1153
|
// 3. Read-loop given reader, bytes, successSteps, and failureSteps.
|
|
1154
|
+
} while (true)
|
|
1155
|
+
} catch (e) {
|
|
1156
|
+
// 1. Call failureSteps with e.
|
|
1157
|
+
failureSteps(e)
|
|
1130
1158
|
}
|
|
1131
1159
|
}
|
|
1132
1160
|
|
|
@@ -1601,7 +1629,6 @@ module.exports = {
|
|
|
1601
1629
|
requestCurrentURL,
|
|
1602
1630
|
responseURL,
|
|
1603
1631
|
responseLocationURL,
|
|
1604
|
-
isBlobLike,
|
|
1605
1632
|
isURLPotentiallyTrustworthy,
|
|
1606
1633
|
isValidReasonPhrase,
|
|
1607
1634
|
sameOrigin,
|
|
@@ -1614,7 +1641,6 @@ module.exports = {
|
|
|
1614
1641
|
isErrorLike,
|
|
1615
1642
|
fullyReadBody,
|
|
1616
1643
|
bytesMatch,
|
|
1617
|
-
isReadableStreamLike,
|
|
1618
1644
|
readableStreamClose,
|
|
1619
1645
|
isomorphicEncode,
|
|
1620
1646
|
urlIsLocal,
|