undici 7.0.0-alpha.1 → 7.0.0-alpha.10
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 +24 -38
- package/docs/docs/api/Agent.md +14 -14
- package/docs/docs/api/BalancedPool.md +16 -16
- package/docs/docs/api/CacheStore.md +131 -0
- package/docs/docs/api/Client.md +12 -12
- package/docs/docs/api/Debug.md +1 -1
- package/docs/docs/api/Dispatcher.md +98 -193
- package/docs/docs/api/EnvHttpProxyAgent.md +12 -12
- package/docs/docs/api/MockAgent.md +5 -3
- package/docs/docs/api/MockClient.md +5 -5
- package/docs/docs/api/MockPool.md +4 -3
- package/docs/docs/api/Pool.md +15 -15
- package/docs/docs/api/PoolStats.md +1 -1
- package/docs/docs/api/ProxyAgent.md +3 -3
- package/docs/docs/api/RedirectHandler.md +1 -1
- package/docs/docs/api/RetryAgent.md +1 -1
- package/docs/docs/api/RetryHandler.md +4 -4
- package/docs/docs/api/WebSocket.md +46 -4
- package/docs/docs/api/api-lifecycle.md +11 -11
- package/docs/docs/best-practices/mocking-request.md +2 -2
- package/docs/docs/best-practices/proxy.md +1 -1
- package/index.d.ts +1 -1
- package/index.js +23 -3
- package/lib/api/abort-signal.js +2 -0
- package/lib/api/api-pipeline.js +4 -2
- package/lib/api/api-request.js +6 -4
- package/lib/api/api-stream.js +3 -1
- package/lib/api/api-upgrade.js +2 -2
- package/lib/api/readable.js +200 -47
- package/lib/api/util.js +2 -0
- package/lib/cache/memory-cache-store.js +177 -0
- package/lib/cache/sqlite-cache-store.js +446 -0
- package/lib/core/connect.js +54 -22
- package/lib/core/constants.js +35 -10
- package/lib/core/diagnostics.js +122 -128
- package/lib/core/errors.js +2 -2
- package/lib/core/request.js +6 -6
- package/lib/core/symbols.js +2 -0
- package/lib/core/tree.js +4 -2
- package/lib/core/util.js +238 -40
- package/lib/dispatcher/client-h1.js +405 -142
- package/lib/dispatcher/client-h2.js +212 -109
- package/lib/dispatcher/client.js +24 -7
- package/lib/dispatcher/dispatcher-base.js +4 -1
- package/lib/dispatcher/dispatcher.js +4 -0
- package/lib/dispatcher/fixed-queue.js +91 -49
- package/lib/dispatcher/pool-base.js +3 -3
- package/lib/dispatcher/pool-stats.js +2 -0
- package/lib/dispatcher/proxy-agent.js +3 -1
- package/lib/handler/cache-handler.js +393 -0
- package/lib/handler/cache-revalidation-handler.js +124 -0
- package/lib/handler/decorator-handler.js +3 -0
- package/lib/handler/redirect-handler.js +45 -59
- package/lib/handler/retry-handler.js +68 -109
- package/lib/handler/unwrap-handler.js +96 -0
- package/lib/handler/wrap-handler.js +98 -0
- package/lib/interceptor/cache.js +350 -0
- package/lib/interceptor/dns.js +375 -0
- package/lib/interceptor/response-error.js +15 -7
- package/lib/mock/mock-agent.js +5 -8
- package/lib/mock/mock-client.js +7 -2
- package/lib/mock/mock-errors.js +3 -1
- package/lib/mock/mock-interceptor.js +8 -6
- package/lib/mock/mock-pool.js +7 -2
- package/lib/mock/mock-symbols.js +2 -1
- package/lib/mock/mock-utils.js +33 -5
- package/lib/util/cache.js +360 -0
- package/lib/util/timers.js +50 -6
- package/lib/web/cache/cache.js +25 -21
- package/lib/web/cache/cachestorage.js +3 -1
- package/lib/web/cookies/index.js +18 -5
- package/lib/web/cookies/parse.js +6 -1
- package/lib/web/eventsource/eventsource.js +2 -0
- package/lib/web/fetch/body.js +43 -39
- package/lib/web/fetch/constants.js +45 -29
- package/lib/web/fetch/data-url.js +2 -2
- package/lib/web/fetch/formdata-parser.js +84 -46
- package/lib/web/fetch/formdata.js +42 -20
- package/lib/web/fetch/headers.js +119 -85
- package/lib/web/fetch/index.js +69 -65
- package/lib/web/fetch/request.js +132 -55
- package/lib/web/fetch/response.js +81 -36
- package/lib/web/fetch/util.js +274 -103
- package/lib/web/fetch/webidl.js +54 -18
- package/lib/web/websocket/connection.js +92 -15
- package/lib/web/websocket/constants.js +69 -9
- package/lib/web/websocket/events.js +8 -2
- package/lib/web/websocket/receiver.js +20 -26
- package/lib/web/websocket/stream/websocketerror.js +83 -0
- package/lib/web/websocket/stream/websocketstream.js +485 -0
- package/lib/web/websocket/util.js +115 -10
- package/lib/web/websocket/websocket.js +47 -170
- package/package.json +15 -11
- package/types/agent.d.ts +1 -1
- package/types/cache-interceptor.d.ts +172 -0
- package/types/cookies.d.ts +2 -0
- package/types/dispatcher.d.ts +29 -4
- package/types/env-http-proxy-agent.d.ts +1 -1
- package/types/fetch.d.ts +9 -8
- package/types/handlers.d.ts +4 -4
- package/types/index.d.ts +3 -1
- package/types/interceptors.d.ts +18 -1
- package/types/mock-agent.d.ts +4 -1
- package/types/mock-client.d.ts +1 -1
- package/types/mock-pool.d.ts +1 -1
- package/types/proxy-agent.d.ts +1 -1
- package/types/readable.d.ts +10 -7
- package/types/retry-handler.d.ts +3 -3
- package/types/webidl.d.ts +30 -4
- package/types/websocket.d.ts +33 -0
- package/lib/mock/pluralizer.js +0 -29
- package/lib/web/cache/symbols.js +0 -5
- package/lib/web/fetch/symbols.js +0 -8
package/lib/web/cookies/parse.js
CHANGED
|
@@ -4,6 +4,7 @@ const { maxNameValuePairSize, maxAttributeValueSize } = require('./constants')
|
|
|
4
4
|
const { isCTLExcludingHtab } = require('./util')
|
|
5
5
|
const { collectASequenceOfCodePointsFast } = require('../fetch/data-url')
|
|
6
6
|
const assert = require('node:assert')
|
|
7
|
+
const { unescape } = require('node:querystring')
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* @description Parses the field-value attributes of a set-cookie header string.
|
|
@@ -76,8 +77,12 @@ function parseSetCookie (header) {
|
|
|
76
77
|
|
|
77
78
|
// 6. The cookie-name is the name string, and the cookie-value is the
|
|
78
79
|
// value string.
|
|
80
|
+
// https://datatracker.ietf.org/doc/html/rfc6265
|
|
81
|
+
// To maximize compatibility with user agents, servers that wish to
|
|
82
|
+
// store arbitrary data in a cookie-value SHOULD encode that data, for
|
|
83
|
+
// example, using Base64 [RFC4648].
|
|
79
84
|
return {
|
|
80
|
-
name, value, ...parseUnparsedAttributes(unparsedAttributes)
|
|
85
|
+
name, value: unescape(value), ...parseUnparsedAttributes(unparsedAttributes)
|
|
81
86
|
}
|
|
82
87
|
}
|
|
83
88
|
|
package/lib/web/fetch/body.js
CHANGED
|
@@ -9,8 +9,7 @@ const {
|
|
|
9
9
|
extractMimeType,
|
|
10
10
|
utf8DecodeBytes
|
|
11
11
|
} = require('./util')
|
|
12
|
-
const { FormData } = require('./formdata')
|
|
13
|
-
const { kState } = require('./symbols')
|
|
12
|
+
const { FormData, setFormDataState } = require('./formdata')
|
|
14
13
|
const { webidl } = require('./webidl')
|
|
15
14
|
const { Blob } = require('node:buffer')
|
|
16
15
|
const assert = require('node:assert')
|
|
@@ -40,9 +39,9 @@ function extractBody (object, keepalive = false) {
|
|
|
40
39
|
let stream = null
|
|
41
40
|
|
|
42
41
|
// 2. If object is a ReadableStream object, then set stream to object.
|
|
43
|
-
if (object
|
|
42
|
+
if (webidl.is.ReadableStream(object)) {
|
|
44
43
|
stream = object
|
|
45
|
-
} else if (object
|
|
44
|
+
} else if (webidl.is.Blob(object)) {
|
|
46
45
|
// 3. Otherwise, if object is a Blob object, set stream to the
|
|
47
46
|
// result of running object’s get stream.
|
|
48
47
|
stream = object.stream()
|
|
@@ -65,7 +64,7 @@ function extractBody (object, keepalive = false) {
|
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
// 5. Assert: stream is a ReadableStream object.
|
|
68
|
-
assert(stream
|
|
67
|
+
assert(webidl.is.ReadableStream(stream))
|
|
69
68
|
|
|
70
69
|
// 6. Let action be null.
|
|
71
70
|
let action = null
|
|
@@ -87,7 +86,7 @@ function extractBody (object, keepalive = false) {
|
|
|
87
86
|
|
|
88
87
|
// Set type to `text/plain;charset=UTF-8`.
|
|
89
88
|
type = 'text/plain;charset=UTF-8'
|
|
90
|
-
} else if (object
|
|
89
|
+
} else if (webidl.is.URLSearchParams(object)) {
|
|
91
90
|
// URLSearchParams
|
|
92
91
|
|
|
93
92
|
// spec says to run application/x-www-form-urlencoded on body.list
|
|
@@ -110,7 +109,7 @@ function extractBody (object, keepalive = false) {
|
|
|
110
109
|
|
|
111
110
|
// Set source to a copy of the bytes held by object.
|
|
112
111
|
source = new Uint8Array(object.buffer.slice(object.byteOffset, object.byteOffset + object.byteLength))
|
|
113
|
-
} else if (object
|
|
112
|
+
} else if (webidl.is.FormData(object)) {
|
|
114
113
|
const boundary = `----formdata-undici-0${`${Math.floor(Math.random() * 1e11)}`.padStart(11, '0')}`
|
|
115
114
|
const prefix = `--${boundary}\r\nContent-Disposition: form-data`
|
|
116
115
|
|
|
@@ -152,7 +151,10 @@ function extractBody (object, keepalive = false) {
|
|
|
152
151
|
}
|
|
153
152
|
}
|
|
154
153
|
|
|
155
|
-
|
|
154
|
+
// CRLF is appended to the body to function with legacy servers and match other implementations.
|
|
155
|
+
// https://github.com/curl/curl/blob/3434c6b46e682452973972e8313613dfa58cd690/lib/mime.c#L1029-L1030
|
|
156
|
+
// https://github.com/form-data/form-data/issues/63
|
|
157
|
+
const chunk = textEncoder.encode(`--${boundary}--\r\n`)
|
|
156
158
|
blobParts.push(chunk)
|
|
157
159
|
length += chunk.byteLength
|
|
158
160
|
if (hasUnknownSizeValue) {
|
|
@@ -176,7 +178,7 @@ function extractBody (object, keepalive = false) {
|
|
|
176
178
|
// followed by the multipart/form-data boundary string generated
|
|
177
179
|
// by the multipart/form-data encoding algorithm.
|
|
178
180
|
type = `multipart/form-data; boundary=${boundary}`
|
|
179
|
-
} else if (object
|
|
181
|
+
} else if (webidl.is.Blob(object)) {
|
|
180
182
|
// Blob
|
|
181
183
|
|
|
182
184
|
// Set source to object.
|
|
@@ -204,7 +206,7 @@ function extractBody (object, keepalive = false) {
|
|
|
204
206
|
}
|
|
205
207
|
|
|
206
208
|
stream =
|
|
207
|
-
object
|
|
209
|
+
webidl.is.ReadableStream(object) ? object : ReadableStreamFrom(object)
|
|
208
210
|
}
|
|
209
211
|
|
|
210
212
|
// 11. If source is a byte sequence, then set action to a
|
|
@@ -263,7 +265,7 @@ function safelyExtractBody (object, keepalive = false) {
|
|
|
263
265
|
// a byte sequence or BodyInit object object, run these steps:
|
|
264
266
|
|
|
265
267
|
// 1. If object is a ReadableStream object, then:
|
|
266
|
-
if (object
|
|
268
|
+
if (webidl.is.ReadableStream(object)) {
|
|
267
269
|
// Assert: object is neither disturbed nor locked.
|
|
268
270
|
// istanbul ignore next
|
|
269
271
|
assert(!util.isDisturbed(object), 'The body has already been consumed.')
|
|
@@ -304,7 +306,7 @@ function throwIfAborted (state) {
|
|
|
304
306
|
}
|
|
305
307
|
}
|
|
306
308
|
|
|
307
|
-
function bodyMixinMethods (instance) {
|
|
309
|
+
function bodyMixinMethods (instance, getInternalState) {
|
|
308
310
|
const methods = {
|
|
309
311
|
blob () {
|
|
310
312
|
// The blob() method steps are to return the result of
|
|
@@ -313,7 +315,7 @@ function bodyMixinMethods (instance) {
|
|
|
313
315
|
// contents are bytes and whose type attribute is this’s
|
|
314
316
|
// MIME type.
|
|
315
317
|
return consumeBody(this, (bytes) => {
|
|
316
|
-
let mimeType = bodyMimeType(this)
|
|
318
|
+
let mimeType = bodyMimeType(getInternalState(this))
|
|
317
319
|
|
|
318
320
|
if (mimeType === null) {
|
|
319
321
|
mimeType = ''
|
|
@@ -324,7 +326,7 @@ function bodyMixinMethods (instance) {
|
|
|
324
326
|
// Return a Blob whose contents are bytes and type attribute
|
|
325
327
|
// is mimeType.
|
|
326
328
|
return new Blob([bytes], { type: mimeType })
|
|
327
|
-
}, instance)
|
|
329
|
+
}, instance, getInternalState)
|
|
328
330
|
},
|
|
329
331
|
|
|
330
332
|
arrayBuffer () {
|
|
@@ -334,19 +336,19 @@ function bodyMixinMethods (instance) {
|
|
|
334
336
|
// whose contents are bytes.
|
|
335
337
|
return consumeBody(this, (bytes) => {
|
|
336
338
|
return new Uint8Array(bytes).buffer
|
|
337
|
-
}, instance)
|
|
339
|
+
}, instance, getInternalState)
|
|
338
340
|
},
|
|
339
341
|
|
|
340
342
|
text () {
|
|
341
343
|
// The text() method steps are to return the result of running
|
|
342
344
|
// consume body with this and UTF-8 decode.
|
|
343
|
-
return consumeBody(this, utf8DecodeBytes, instance)
|
|
345
|
+
return consumeBody(this, utf8DecodeBytes, instance, getInternalState)
|
|
344
346
|
},
|
|
345
347
|
|
|
346
348
|
json () {
|
|
347
349
|
// The json() method steps are to return the result of running
|
|
348
350
|
// consume body with this and parse JSON from bytes.
|
|
349
|
-
return consumeBody(this, parseJSONFromBytes, instance)
|
|
351
|
+
return consumeBody(this, parseJSONFromBytes, instance, getInternalState)
|
|
350
352
|
},
|
|
351
353
|
|
|
352
354
|
formData () {
|
|
@@ -354,7 +356,7 @@ function bodyMixinMethods (instance) {
|
|
|
354
356
|
// consume body with this and the following step given a byte sequence bytes:
|
|
355
357
|
return consumeBody(this, (value) => {
|
|
356
358
|
// 1. Let mimeType be the result of get the MIME type with this.
|
|
357
|
-
const mimeType = bodyMimeType(this)
|
|
359
|
+
const mimeType = bodyMimeType(getInternalState(this))
|
|
358
360
|
|
|
359
361
|
// 2. If mimeType is non-null, then switch on mimeType’s essence and run
|
|
360
362
|
// the corresponding steps:
|
|
@@ -362,17 +364,13 @@ function bodyMixinMethods (instance) {
|
|
|
362
364
|
switch (mimeType.essence) {
|
|
363
365
|
case 'multipart/form-data': {
|
|
364
366
|
// 1. ... [long step]
|
|
365
|
-
const parsed = multipartFormDataParser(value, mimeType)
|
|
366
|
-
|
|
367
367
|
// 2. If that fails for some reason, then throw a TypeError.
|
|
368
|
-
|
|
369
|
-
throw new TypeError('Failed to parse body as FormData.')
|
|
370
|
-
}
|
|
368
|
+
const parsed = multipartFormDataParser(value, mimeType)
|
|
371
369
|
|
|
372
370
|
// 3. Return a new FormData object, appending each entry,
|
|
373
371
|
// resulting from the parsing operation, to its entry list.
|
|
374
372
|
const fd = new FormData()
|
|
375
|
-
fd
|
|
373
|
+
setFormDataState(fd, parsed)
|
|
376
374
|
|
|
377
375
|
return fd
|
|
378
376
|
}
|
|
@@ -398,7 +396,7 @@ function bodyMixinMethods (instance) {
|
|
|
398
396
|
throw new TypeError(
|
|
399
397
|
'Content-Type was not one of "multipart/form-data" or "application/x-www-form-urlencoded".'
|
|
400
398
|
)
|
|
401
|
-
}, instance)
|
|
399
|
+
}, instance, getInternalState)
|
|
402
400
|
},
|
|
403
401
|
|
|
404
402
|
bytes () {
|
|
@@ -407,33 +405,36 @@ function bodyMixinMethods (instance) {
|
|
|
407
405
|
// result of creating a Uint8Array from bytes in this’s relevant realm.
|
|
408
406
|
return consumeBody(this, (bytes) => {
|
|
409
407
|
return new Uint8Array(bytes)
|
|
410
|
-
}, instance)
|
|
408
|
+
}, instance, getInternalState)
|
|
411
409
|
}
|
|
412
410
|
}
|
|
413
411
|
|
|
414
412
|
return methods
|
|
415
413
|
}
|
|
416
414
|
|
|
417
|
-
function mixinBody (prototype) {
|
|
418
|
-
Object.assign(prototype.prototype, bodyMixinMethods(prototype))
|
|
415
|
+
function mixinBody (prototype, getInternalState) {
|
|
416
|
+
Object.assign(prototype.prototype, bodyMixinMethods(prototype, getInternalState))
|
|
419
417
|
}
|
|
420
418
|
|
|
421
419
|
/**
|
|
422
420
|
* @see https://fetch.spec.whatwg.org/#concept-body-consume-body
|
|
423
|
-
* @param {
|
|
421
|
+
* @param {any} object internal state
|
|
424
422
|
* @param {(value: unknown) => unknown} convertBytesToJSValue
|
|
425
|
-
* @param {
|
|
423
|
+
* @param {any} instance
|
|
424
|
+
* @param {(target: any) => any} getInternalState
|
|
426
425
|
*/
|
|
427
|
-
async function consumeBody (object, convertBytesToJSValue, instance) {
|
|
426
|
+
async function consumeBody (object, convertBytesToJSValue, instance, getInternalState) {
|
|
428
427
|
webidl.brandCheck(object, instance)
|
|
429
428
|
|
|
429
|
+
const state = getInternalState(object)
|
|
430
|
+
|
|
430
431
|
// 1. If object is unusable, then return a promise rejected
|
|
431
432
|
// with a TypeError.
|
|
432
|
-
if (bodyUnusable(
|
|
433
|
+
if (bodyUnusable(state)) {
|
|
433
434
|
throw new TypeError('Body is unusable: Body has already been read')
|
|
434
435
|
}
|
|
435
436
|
|
|
436
|
-
throwIfAborted(
|
|
437
|
+
throwIfAborted(state)
|
|
437
438
|
|
|
438
439
|
// 2. Let promise be a new promise.
|
|
439
440
|
const promise = createDeferredPromise()
|
|
@@ -455,22 +456,25 @@ async function consumeBody (object, convertBytesToJSValue, instance) {
|
|
|
455
456
|
|
|
456
457
|
// 5. If object’s body is null, then run successSteps with an
|
|
457
458
|
// empty byte sequence.
|
|
458
|
-
if (
|
|
459
|
+
if (state.body == null) {
|
|
459
460
|
successSteps(Buffer.allocUnsafe(0))
|
|
460
461
|
return promise.promise
|
|
461
462
|
}
|
|
462
463
|
|
|
463
464
|
// 6. Otherwise, fully read object’s body given successSteps,
|
|
464
465
|
// errorSteps, and object’s relevant global object.
|
|
465
|
-
|
|
466
|
+
fullyReadBody(state.body, successSteps, errorSteps)
|
|
466
467
|
|
|
467
468
|
// 7. Return promise.
|
|
468
469
|
return promise.promise
|
|
469
470
|
}
|
|
470
471
|
|
|
471
|
-
|
|
472
|
+
/**
|
|
473
|
+
* @see https://fetch.spec.whatwg.org/#body-unusable
|
|
474
|
+
* @param {any} object internal state
|
|
475
|
+
*/
|
|
472
476
|
function bodyUnusable (object) {
|
|
473
|
-
const body = object
|
|
477
|
+
const body = object.body
|
|
474
478
|
|
|
475
479
|
// An object including the Body interface mixin is
|
|
476
480
|
// said to be unusable if its body is non-null and
|
|
@@ -488,14 +492,14 @@ function parseJSONFromBytes (bytes) {
|
|
|
488
492
|
|
|
489
493
|
/**
|
|
490
494
|
* @see https://fetch.spec.whatwg.org/#concept-body-mime-type
|
|
491
|
-
* @param {
|
|
495
|
+
* @param {any} requestOrResponse internal state
|
|
492
496
|
*/
|
|
493
497
|
function bodyMimeType (requestOrResponse) {
|
|
494
498
|
// 1. Let headers be null.
|
|
495
499
|
// 2. If requestOrResponse is a Request object, then set headers to requestOrResponse’s request’s header list.
|
|
496
500
|
// 3. Otherwise, set headers to requestOrResponse’s response’s header list.
|
|
497
501
|
/** @type {import('./headers').HeadersList} */
|
|
498
|
-
const headers = requestOrResponse
|
|
502
|
+
const headers = requestOrResponse.headersList
|
|
499
503
|
|
|
500
504
|
// 4. Let mimeType be the result of extracting a MIME type from headers.
|
|
501
505
|
const mimeType = extractMimeType(headers)
|
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const corsSafeListedMethods = ['GET', 'HEAD', 'POST']
|
|
3
|
+
const corsSafeListedMethods = /** @type {const} */ (['GET', 'HEAD', 'POST'])
|
|
4
4
|
const corsSafeListedMethodsSet = new Set(corsSafeListedMethods)
|
|
5
5
|
|
|
6
|
-
const nullBodyStatus = [101, 204, 205, 304]
|
|
6
|
+
const nullBodyStatus = /** @type {const} */ ([101, 204, 205, 304])
|
|
7
7
|
|
|
8
|
-
const redirectStatus = [301, 302, 303, 307, 308]
|
|
8
|
+
const redirectStatus = /** @type {const} */ ([301, 302, 303, 307, 308])
|
|
9
9
|
const redirectStatusSet = new Set(redirectStatus)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
/**
|
|
12
|
+
* @see https://fetch.spec.whatwg.org/#block-bad-port
|
|
13
|
+
*/
|
|
14
|
+
const badPorts = /** @type {const} */ ([
|
|
13
15
|
'1', '7', '9', '11', '13', '15', '17', '19', '20', '21', '22', '23', '25', '37', '42', '43', '53', '69', '77', '79',
|
|
14
16
|
'87', '95', '101', '102', '103', '104', '109', '110', '111', '113', '115', '117', '119', '123', '135', '137',
|
|
15
17
|
'139', '143', '161', '179', '389', '427', '465', '512', '513', '514', '515', '526', '530', '531', '532',
|
|
16
18
|
'540', '548', '554', '556', '563', '587', '601', '636', '989', '990', '993', '995', '1719', '1720', '1723',
|
|
17
19
|
'2049', '3659', '4045', '4190', '5060', '5061', '6000', '6566', '6665', '6666', '6667', '6668', '6669', '6679',
|
|
18
20
|
'6697', '10080'
|
|
19
|
-
]
|
|
20
|
-
|
|
21
|
+
])
|
|
21
22
|
const badPortsSet = new Set(badPorts)
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
/**
|
|
25
|
+
* @see https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-header
|
|
26
|
+
*/
|
|
27
|
+
const referrerPolicyTokens = /** @type {const} */ ([
|
|
26
28
|
'no-referrer',
|
|
27
29
|
'no-referrer-when-downgrade',
|
|
28
30
|
'same-origin',
|
|
@@ -31,29 +33,39 @@ const referrerPolicy = [
|
|
|
31
33
|
'origin-when-cross-origin',
|
|
32
34
|
'strict-origin-when-cross-origin',
|
|
33
35
|
'unsafe-url'
|
|
34
|
-
]
|
|
35
|
-
|
|
36
|
+
])
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @see https://w3c.github.io/webappsec-referrer-policy/#referrer-policies
|
|
40
|
+
*/
|
|
41
|
+
const referrerPolicy = /** @type {const} */ ([
|
|
42
|
+
'',
|
|
43
|
+
...referrerPolicyTokens
|
|
44
|
+
])
|
|
45
|
+
const referrerPolicyTokensSet = new Set(referrerPolicyTokens)
|
|
36
46
|
|
|
37
|
-
const requestRedirect = ['follow', 'manual', 'error']
|
|
47
|
+
const requestRedirect = /** @type {const} */ (['follow', 'manual', 'error'])
|
|
38
48
|
|
|
39
|
-
const safeMethods = ['GET', 'HEAD', 'OPTIONS', 'TRACE']
|
|
49
|
+
const safeMethods = /** @type {const} */ (['GET', 'HEAD', 'OPTIONS', 'TRACE'])
|
|
40
50
|
const safeMethodsSet = new Set(safeMethods)
|
|
41
51
|
|
|
42
|
-
const requestMode = ['navigate', 'same-origin', 'no-cors', 'cors']
|
|
52
|
+
const requestMode = /** @type {const} */ (['navigate', 'same-origin', 'no-cors', 'cors'])
|
|
43
53
|
|
|
44
|
-
const requestCredentials = ['omit', 'same-origin', 'include']
|
|
54
|
+
const requestCredentials = /** @type {const} */ (['omit', 'same-origin', 'include'])
|
|
45
55
|
|
|
46
|
-
const requestCache = [
|
|
56
|
+
const requestCache = /** @type {const} */ ([
|
|
47
57
|
'default',
|
|
48
58
|
'no-store',
|
|
49
59
|
'reload',
|
|
50
60
|
'no-cache',
|
|
51
61
|
'force-cache',
|
|
52
62
|
'only-if-cached'
|
|
53
|
-
]
|
|
63
|
+
])
|
|
54
64
|
|
|
55
|
-
|
|
56
|
-
|
|
65
|
+
/**
|
|
66
|
+
* @see https://fetch.spec.whatwg.org/#request-body-header-name
|
|
67
|
+
*/
|
|
68
|
+
const requestBodyHeader = /** @type {const} */ ([
|
|
57
69
|
'content-encoding',
|
|
58
70
|
'content-language',
|
|
59
71
|
'content-location',
|
|
@@ -63,18 +75,22 @@ const requestBodyHeader = [
|
|
|
63
75
|
// removed in the Headers implementation. However, undici doesn't
|
|
64
76
|
// filter out headers, so we add it here.
|
|
65
77
|
'content-length'
|
|
66
|
-
]
|
|
78
|
+
])
|
|
67
79
|
|
|
68
|
-
|
|
69
|
-
|
|
80
|
+
/**
|
|
81
|
+
* @see https://fetch.spec.whatwg.org/#enumdef-requestduplex
|
|
82
|
+
*/
|
|
83
|
+
const requestDuplex = /** @type {const} */ ([
|
|
70
84
|
'half'
|
|
71
|
-
]
|
|
85
|
+
])
|
|
72
86
|
|
|
73
|
-
|
|
74
|
-
|
|
87
|
+
/**
|
|
88
|
+
* @see http://fetch.spec.whatwg.org/#forbidden-method
|
|
89
|
+
*/
|
|
90
|
+
const forbiddenMethods = /** @type {const} */ (['CONNECT', 'TRACE', 'TRACK'])
|
|
75
91
|
const forbiddenMethodsSet = new Set(forbiddenMethods)
|
|
76
92
|
|
|
77
|
-
const subresource = [
|
|
93
|
+
const subresource = /** @type {const} */ ([
|
|
78
94
|
'audio',
|
|
79
95
|
'audioworklet',
|
|
80
96
|
'font',
|
|
@@ -87,7 +103,7 @@ const subresource = [
|
|
|
87
103
|
'video',
|
|
88
104
|
'xslt',
|
|
89
105
|
''
|
|
90
|
-
]
|
|
106
|
+
])
|
|
91
107
|
const subresourceSet = new Set(subresource)
|
|
92
108
|
|
|
93
109
|
module.exports = {
|
|
@@ -111,5 +127,5 @@ module.exports = {
|
|
|
111
127
|
corsSafeListedMethodsSet,
|
|
112
128
|
safeMethodsSet,
|
|
113
129
|
forbiddenMethodsSet,
|
|
114
|
-
|
|
130
|
+
referrerPolicyTokens: referrerPolicyTokensSet
|
|
115
131
|
}
|
|
@@ -471,9 +471,9 @@ function forgivingBase64 (data) {
|
|
|
471
471
|
/**
|
|
472
472
|
* @param {string} input
|
|
473
473
|
* @param {{ position: number }} position
|
|
474
|
-
* @param {boolean
|
|
474
|
+
* @param {boolean} [extractValue=false]
|
|
475
475
|
*/
|
|
476
|
-
function collectAnHTTPQuotedString (input, position, extractValue) {
|
|
476
|
+
function collectAnHTTPQuotedString (input, position, extractValue = false) {
|
|
477
477
|
// 1. Let positionStart be position.
|
|
478
478
|
const positionStart = position.position
|
|
479
479
|
|