commit
This commit is contained in:
parent
13ec9babde
commit
68f4b60012
1429 changed files with 2481 additions and 272836 deletions
10
node_modules/undici/lib/fetch/body.js
generated
vendored
10
node_modules/undici/lib/fetch/body.js
generated
vendored
|
@ -123,6 +123,7 @@ function extractBody (object, keepalive = false) {
|
|||
const blobParts = []
|
||||
const rn = new Uint8Array([13, 10]) // '\r\n'
|
||||
length = 0
|
||||
let hasUnknownSizeValue = false
|
||||
|
||||
for (const [name, value] of object) {
|
||||
if (typeof value === 'string') {
|
||||
|
@ -138,13 +139,20 @@ function extractBody (object, keepalive = false) {
|
|||
value.type || 'application/octet-stream'
|
||||
}\r\n\r\n`)
|
||||
blobParts.push(chunk, value, rn)
|
||||
length += chunk.byteLength + value.size + rn.byteLength
|
||||
if (typeof value.size === 'number') {
|
||||
length += chunk.byteLength + value.size + rn.byteLength
|
||||
} else {
|
||||
hasUnknownSizeValue = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const chunk = enc.encode(`--${boundary}--`)
|
||||
blobParts.push(chunk)
|
||||
length += chunk.byteLength
|
||||
if (hasUnknownSizeValue) {
|
||||
length = null
|
||||
}
|
||||
|
||||
// Set source to object.
|
||||
source = object
|
||||
|
|
8
node_modules/undici/lib/fetch/constants.js
generated
vendored
8
node_modules/undici/lib/fetch/constants.js
generated
vendored
|
@ -48,11 +48,17 @@ const requestCache = [
|
|||
'only-if-cached'
|
||||
]
|
||||
|
||||
// https://fetch.spec.whatwg.org/#request-body-header-name
|
||||
const requestBodyHeader = [
|
||||
'content-encoding',
|
||||
'content-language',
|
||||
'content-location',
|
||||
'content-type'
|
||||
'content-type',
|
||||
// See https://github.com/nodejs/undici/issues/2021
|
||||
// 'Content-Length' is a forbidden header name, which is typically
|
||||
// removed in the Headers implementation. However, undici doesn't
|
||||
// filter out headers, so we add it here.
|
||||
'content-length'
|
||||
]
|
||||
|
||||
// https://fetch.spec.whatwg.org/#enumdef-requestduplex
|
||||
|
|
148
node_modules/undici/lib/fetch/dataURL.js
generated
vendored
148
node_modules/undici/lib/fetch/dataURL.js
generated
vendored
|
@ -1,15 +1,18 @@
|
|||
const assert = require('assert')
|
||||
const { atob } = require('buffer')
|
||||
const { format } = require('url')
|
||||
const { isValidHTTPToken, isomorphicDecode } = require('./util')
|
||||
const { isomorphicDecode } = require('./util')
|
||||
|
||||
const encoder = new TextEncoder()
|
||||
|
||||
// Regex
|
||||
const HTTP_TOKEN_CODEPOINTS = /^[!#$%&'*+-.^_|~A-z0-9]+$/
|
||||
/**
|
||||
* @see https://mimesniff.spec.whatwg.org/#http-token-code-point
|
||||
*/
|
||||
const HTTP_TOKEN_CODEPOINTS = /^[!#$%&'*+-.^_|~A-Za-z0-9]+$/
|
||||
const HTTP_WHITESPACE_REGEX = /(\u000A|\u000D|\u0009|\u0020)/ // eslint-disable-line
|
||||
// https://mimesniff.spec.whatwg.org/#http-quoted-string-token-code-point
|
||||
const HTTP_QUOTED_STRING_TOKENS = /^(\u0009|\x{0020}-\x{007E}|\x{0080}-\x{00FF})+$/ // eslint-disable-line
|
||||
/**
|
||||
* @see https://mimesniff.spec.whatwg.org/#http-quoted-string-token-code-point
|
||||
*/
|
||||
const HTTP_QUOTED_STRING_TOKENS = /[\u0009|\u0020-\u007E|\u0080-\u00FF]/ // eslint-disable-line
|
||||
|
||||
// https://fetch.spec.whatwg.org/#data-url-processor
|
||||
/** @param {URL} dataURL */
|
||||
|
@ -31,22 +34,20 @@ function dataURLProcessor (dataURL) {
|
|||
// 5. Let mimeType be the result of collecting a
|
||||
// sequence of code points that are not equal
|
||||
// to U+002C (,), given position.
|
||||
let mimeType = collectASequenceOfCodePoints(
|
||||
(char) => char !== ',',
|
||||
let mimeType = collectASequenceOfCodePointsFast(
|
||||
',',
|
||||
input,
|
||||
position
|
||||
)
|
||||
|
||||
// 6. Strip leading and trailing ASCII whitespace
|
||||
// from mimeType.
|
||||
// Note: This will only remove U+0020 SPACE code
|
||||
// points, if any.
|
||||
// Undici implementation note: we need to store the
|
||||
// length because if the mimetype has spaces removed,
|
||||
// the wrong amount will be sliced from the input in
|
||||
// step #9
|
||||
const mimeTypeLength = mimeType.length
|
||||
mimeType = mimeType.replace(/^(\u0020)+|(\u0020)+$/g, '')
|
||||
mimeType = removeASCIIWhitespace(mimeType, true, true)
|
||||
|
||||
// 7. If position is past the end of input, then
|
||||
// return failure
|
||||
|
@ -118,7 +119,17 @@ function dataURLProcessor (dataURL) {
|
|||
* @param {boolean} excludeFragment
|
||||
*/
|
||||
function URLSerializer (url, excludeFragment = false) {
|
||||
return format(url, { fragment: !excludeFragment })
|
||||
const href = url.href
|
||||
|
||||
if (!excludeFragment) {
|
||||
return href
|
||||
}
|
||||
|
||||
const hash = href.lastIndexOf('#')
|
||||
if (hash === -1) {
|
||||
return href
|
||||
}
|
||||
return href.slice(0, hash)
|
||||
}
|
||||
|
||||
// https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points
|
||||
|
@ -145,6 +156,25 @@ function collectASequenceOfCodePoints (condition, input, position) {
|
|||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* A faster collectASequenceOfCodePoints that only works when comparing a single character.
|
||||
* @param {string} char
|
||||
* @param {string} input
|
||||
* @param {{ position: number }} position
|
||||
*/
|
||||
function collectASequenceOfCodePointsFast (char, input, position) {
|
||||
const idx = input.indexOf(char, position.position)
|
||||
const start = position.position
|
||||
|
||||
if (idx === -1) {
|
||||
position.position = input.length
|
||||
return input.slice(start)
|
||||
}
|
||||
|
||||
position.position = idx
|
||||
return input.slice(start, position.position)
|
||||
}
|
||||
|
||||
// https://url.spec.whatwg.org/#string-percent-decode
|
||||
/** @param {string} input */
|
||||
function stringPercentDecode (input) {
|
||||
|
@ -205,7 +235,7 @@ function percentDecode (input) {
|
|||
function parseMIMEType (input) {
|
||||
// 1. Remove any leading and trailing HTTP whitespace
|
||||
// from input.
|
||||
input = input.trim()
|
||||
input = removeHTTPWhitespace(input, true, true)
|
||||
|
||||
// 2. Let position be a position variable for input,
|
||||
// initially pointing at the start of input.
|
||||
|
@ -214,8 +244,8 @@ function parseMIMEType (input) {
|
|||
// 3. Let type be the result of collecting a sequence
|
||||
// of code points that are not U+002F (/) from
|
||||
// input, given position.
|
||||
const type = collectASequenceOfCodePoints(
|
||||
(char) => char !== '/',
|
||||
const type = collectASequenceOfCodePointsFast(
|
||||
'/',
|
||||
input,
|
||||
position
|
||||
)
|
||||
|
@ -239,14 +269,14 @@ function parseMIMEType (input) {
|
|||
// 7. Let subtype be the result of collecting a sequence of
|
||||
// code points that are not U+003B (;) from input, given
|
||||
// position.
|
||||
let subtype = collectASequenceOfCodePoints(
|
||||
(char) => char !== ';',
|
||||
let subtype = collectASequenceOfCodePointsFast(
|
||||
';',
|
||||
input,
|
||||
position
|
||||
)
|
||||
|
||||
// 8. Remove any trailing HTTP whitespace from subtype.
|
||||
subtype = subtype.trimEnd()
|
||||
subtype = removeHTTPWhitespace(subtype, false, true)
|
||||
|
||||
// 9. If subtype is the empty string or does not solely
|
||||
// contain HTTP token code points, then return failure.
|
||||
|
@ -254,17 +284,20 @@ function parseMIMEType (input) {
|
|||
return 'failure'
|
||||
}
|
||||
|
||||
const typeLowercase = type.toLowerCase()
|
||||
const subtypeLowercase = subtype.toLowerCase()
|
||||
|
||||
// 10. Let mimeType be a new MIME type record whose type
|
||||
// is type, in ASCII lowercase, and subtype is subtype,
|
||||
// in ASCII lowercase.
|
||||
// https://mimesniff.spec.whatwg.org/#mime-type
|
||||
const mimeType = {
|
||||
type: type.toLowerCase(),
|
||||
subtype: subtype.toLowerCase(),
|
||||
type: typeLowercase,
|
||||
subtype: subtypeLowercase,
|
||||
/** @type {Map<string, string>} */
|
||||
parameters: new Map(),
|
||||
// https://mimesniff.spec.whatwg.org/#mime-type-essence
|
||||
essence: `${type}/${subtype}`
|
||||
essence: `${typeLowercase}/${subtypeLowercase}`
|
||||
}
|
||||
|
||||
// 11. While position is not past the end of input:
|
||||
|
@ -324,8 +357,8 @@ function parseMIMEType (input) {
|
|||
|
||||
// 2. Collect a sequence of code points that are not
|
||||
// U+003B (;) from input, given position.
|
||||
collectASequenceOfCodePoints(
|
||||
(char) => char !== ';',
|
||||
collectASequenceOfCodePointsFast(
|
||||
';',
|
||||
input,
|
||||
position
|
||||
)
|
||||
|
@ -335,15 +368,14 @@ function parseMIMEType (input) {
|
|||
// 1. Set parameterValue to the result of collecting
|
||||
// a sequence of code points that are not U+003B (;)
|
||||
// from input, given position.
|
||||
parameterValue = collectASequenceOfCodePoints(
|
||||
(char) => char !== ';',
|
||||
parameterValue = collectASequenceOfCodePointsFast(
|
||||
';',
|
||||
input,
|
||||
position
|
||||
)
|
||||
|
||||
// 2. Remove any trailing HTTP whitespace from parameterValue.
|
||||
// Note: it says "trailing" whitespace; leading is fine.
|
||||
parameterValue = parameterValue.trimEnd()
|
||||
parameterValue = removeHTTPWhitespace(parameterValue, false, true)
|
||||
|
||||
// 3. If parameterValue is the empty string, then continue.
|
||||
if (parameterValue.length === 0) {
|
||||
|
@ -360,7 +392,7 @@ function parseMIMEType (input) {
|
|||
if (
|
||||
parameterName.length !== 0 &&
|
||||
HTTP_TOKEN_CODEPOINTS.test(parameterName) &&
|
||||
!HTTP_QUOTED_STRING_TOKENS.test(parameterValue) &&
|
||||
(parameterValue.length === 0 || HTTP_QUOTED_STRING_TOKENS.test(parameterValue)) &&
|
||||
!mimeType.parameters.has(parameterName)
|
||||
) {
|
||||
mimeType.parameters.set(parameterName, parameterValue)
|
||||
|
@ -494,11 +526,11 @@ function collectAnHTTPQuotedString (input, position, extractValue) {
|
|||
*/
|
||||
function serializeAMimeType (mimeType) {
|
||||
assert(mimeType !== 'failure')
|
||||
const { type, subtype, parameters } = mimeType
|
||||
const { parameters, essence } = mimeType
|
||||
|
||||
// 1. Let serialization be the concatenation of mimeType’s
|
||||
// type, U+002F (/), and mimeType’s subtype.
|
||||
let serialization = `${type}/${subtype}`
|
||||
let serialization = essence
|
||||
|
||||
// 2. For each name → value of mimeType’s parameters:
|
||||
for (let [name, value] of parameters.entries()) {
|
||||
|
@ -513,7 +545,7 @@ function serializeAMimeType (mimeType) {
|
|||
|
||||
// 4. If value does not solely contain HTTP token code
|
||||
// points or value is the empty string, then:
|
||||
if (!isValidHTTPToken(value)) {
|
||||
if (!HTTP_TOKEN_CODEPOINTS.test(value)) {
|
||||
// 1. Precede each occurence of U+0022 (") or
|
||||
// U+005C (\) in value with U+005C (\).
|
||||
value = value.replace(/(\\|")/g, '\\$1')
|
||||
|
@ -533,10 +565,64 @@ function serializeAMimeType (mimeType) {
|
|||
return serialization
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://fetch.spec.whatwg.org/#http-whitespace
|
||||
* @param {string} char
|
||||
*/
|
||||
function isHTTPWhiteSpace (char) {
|
||||
return char === '\r' || char === '\n' || char === '\t' || char === ' '
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://fetch.spec.whatwg.org/#http-whitespace
|
||||
* @param {string} str
|
||||
*/
|
||||
function removeHTTPWhitespace (str, leading = true, trailing = true) {
|
||||
let lead = 0
|
||||
let trail = str.length - 1
|
||||
|
||||
if (leading) {
|
||||
for (; lead < str.length && isHTTPWhiteSpace(str[lead]); lead++);
|
||||
}
|
||||
|
||||
if (trailing) {
|
||||
for (; trail > 0 && isHTTPWhiteSpace(str[trail]); trail--);
|
||||
}
|
||||
|
||||
return str.slice(lead, trail + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://infra.spec.whatwg.org/#ascii-whitespace
|
||||
* @param {string} char
|
||||
*/
|
||||
function isASCIIWhitespace (char) {
|
||||
return char === '\r' || char === '\n' || char === '\t' || char === '\f' || char === ' '
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace
|
||||
*/
|
||||
function removeASCIIWhitespace (str, leading = true, trailing = true) {
|
||||
let lead = 0
|
||||
let trail = str.length - 1
|
||||
|
||||
if (leading) {
|
||||
for (; lead < str.length && isASCIIWhitespace(str[lead]); lead++);
|
||||
}
|
||||
|
||||
if (trailing) {
|
||||
for (; trail > 0 && isASCIIWhitespace(str[trail]); trail--);
|
||||
}
|
||||
|
||||
return str.slice(lead, trail + 1)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
dataURLProcessor,
|
||||
URLSerializer,
|
||||
collectASequenceOfCodePoints,
|
||||
collectASequenceOfCodePointsFast,
|
||||
stringPercentDecode,
|
||||
parseMIMEType,
|
||||
collectAnHTTPQuotedString,
|
||||
|
|
9
node_modules/undici/lib/fetch/formdata.js
generated
vendored
9
node_modules/undici/lib/fetch/formdata.js
generated
vendored
|
@ -61,14 +61,7 @@ class FormData {
|
|||
|
||||
// The delete(name) method steps are to remove all entries whose name
|
||||
// is name from this’s entry list.
|
||||
const next = []
|
||||
for (const entry of this[kState]) {
|
||||
if (entry.name !== name) {
|
||||
next.push(entry)
|
||||
}
|
||||
}
|
||||
|
||||
this[kState] = next
|
||||
this[kState] = this[kState].filter(entry => entry.name !== name)
|
||||
}
|
||||
|
||||
get (name) {
|
||||
|
|
109
node_modules/undici/lib/fetch/headers.js
generated
vendored
109
node_modules/undici/lib/fetch/headers.js
generated
vendored
|
@ -3,7 +3,7 @@
|
|||
'use strict'
|
||||
|
||||
const { kHeadersList } = require('../core/symbols')
|
||||
const { kGuard, kHeadersCaseInsensitive } = require('./symbols')
|
||||
const { kGuard } = require('./symbols')
|
||||
const { kEnumerableProperty } = require('../core/util')
|
||||
const {
|
||||
makeIterator,
|
||||
|
@ -11,6 +11,7 @@ const {
|
|||
isValidHeaderValue
|
||||
} = require('./util')
|
||||
const { webidl } = require('./webidl')
|
||||
const assert = require('assert')
|
||||
|
||||
const kHeadersMap = Symbol('headers map')
|
||||
const kHeadersSortedMap = Symbol('headers map sorted')
|
||||
|
@ -23,10 +24,12 @@ function headerValueNormalize (potentialValue) {
|
|||
// To normalize a byte sequence potentialValue, remove
|
||||
// any leading and trailing HTTP whitespace bytes from
|
||||
// potentialValue.
|
||||
return potentialValue.replace(
|
||||
/^[\r\n\t ]+|[\r\n\t ]+$/g,
|
||||
''
|
||||
)
|
||||
|
||||
// Trimming the end with `.replace()` and a RegExp is typically subject to
|
||||
// ReDoS. This is safer and faster.
|
||||
let i = potentialValue.length
|
||||
while (/[\r\n\t ]/.test(potentialValue.charAt(--i)));
|
||||
return potentialValue.slice(0, i + 1).replace(/^[\r\n\t ]+/, '')
|
||||
}
|
||||
|
||||
function fill (headers, object) {
|
||||
|
@ -72,6 +75,7 @@ class HeadersList {
|
|||
if (init instanceof HeadersList) {
|
||||
this[kHeadersMap] = new Map(init[kHeadersMap])
|
||||
this[kHeadersSortedMap] = init[kHeadersSortedMap]
|
||||
this.cookies = init.cookies
|
||||
} else {
|
||||
this[kHeadersMap] = new Map(init)
|
||||
this[kHeadersSortedMap] = null
|
||||
|
@ -91,6 +95,7 @@ class HeadersList {
|
|||
clear () {
|
||||
this[kHeadersMap].clear()
|
||||
this[kHeadersSortedMap] = null
|
||||
this.cookies = null
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-header-list-append
|
||||
|
@ -104,14 +109,18 @@ class HeadersList {
|
|||
|
||||
// 2. Append (name, value) to list.
|
||||
if (exists) {
|
||||
this[kHeadersMap].set(lowercaseName, { name: exists.name, value: `${exists.value}, ${value}` })
|
||||
const delimiter = lowercaseName === 'cookie' ? '; ' : ', '
|
||||
this[kHeadersMap].set(lowercaseName, {
|
||||
name: exists.name,
|
||||
value: `${exists.value}${delimiter}${value}`
|
||||
})
|
||||
} else {
|
||||
this[kHeadersMap].set(lowercaseName, { name, value })
|
||||
}
|
||||
|
||||
if (lowercaseName === 'set-cookie') {
|
||||
this.cookies ??= []
|
||||
this.cookies.push([name, value])
|
||||
this.cookies.push(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,7 +130,7 @@ class HeadersList {
|
|||
const lowercaseName = name.toLowerCase()
|
||||
|
||||
if (lowercaseName === 'set-cookie') {
|
||||
this.cookies = [[name, value]]
|
||||
this.cookies = [value]
|
||||
}
|
||||
|
||||
// 1. If list contains name, then set the value of
|
||||
|
@ -164,15 +173,16 @@ class HeadersList {
|
|||
}
|
||||
}
|
||||
|
||||
get [kHeadersCaseInsensitive] () {
|
||||
/** @type {string[]} */
|
||||
const flatList = []
|
||||
get entries () {
|
||||
const headers = {}
|
||||
|
||||
for (const { name, value } of this[kHeadersMap].values()) {
|
||||
flatList.push(name, value)
|
||||
if (this[kHeadersMap].size) {
|
||||
for (const { name, value } of this[kHeadersMap].values()) {
|
||||
headers[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
return flatList
|
||||
return headers
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,18 +389,74 @@ class Headers {
|
|||
return this[kHeadersList].set(name, value)
|
||||
}
|
||||
|
||||
get [kHeadersSortedMap] () {
|
||||
if (!this[kHeadersList][kHeadersSortedMap]) {
|
||||
this[kHeadersList][kHeadersSortedMap] = new Map([...this[kHeadersList]].sort((a, b) => a[0] < b[0] ? -1 : 1))
|
||||
// https://fetch.spec.whatwg.org/#dom-headers-getsetcookie
|
||||
getSetCookie () {
|
||||
webidl.brandCheck(this, Headers)
|
||||
|
||||
// 1. If this’s header list does not contain `Set-Cookie`, then return « ».
|
||||
// 2. Return the values of all headers in this’s header list whose name is
|
||||
// a byte-case-insensitive match for `Set-Cookie`, in order.
|
||||
|
||||
const list = this[kHeadersList].cookies
|
||||
|
||||
if (list) {
|
||||
return [...list]
|
||||
}
|
||||
return this[kHeadersList][kHeadersSortedMap]
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine
|
||||
get [kHeadersSortedMap] () {
|
||||
if (this[kHeadersList][kHeadersSortedMap]) {
|
||||
return this[kHeadersList][kHeadersSortedMap]
|
||||
}
|
||||
|
||||
// 1. Let headers be an empty list of headers with the key being the name
|
||||
// and value the value.
|
||||
const headers = []
|
||||
|
||||
// 2. Let names be the result of convert header names to a sorted-lowercase
|
||||
// set with all the names of the headers in list.
|
||||
const names = [...this[kHeadersList]].sort((a, b) => a[0] < b[0] ? -1 : 1)
|
||||
const cookies = this[kHeadersList].cookies
|
||||
|
||||
// 3. For each name of names:
|
||||
for (const [name, value] of names) {
|
||||
// 1. If name is `set-cookie`, then:
|
||||
if (name === 'set-cookie') {
|
||||
// 1. Let values be a list of all values of headers in list whose name
|
||||
// is a byte-case-insensitive match for name, in order.
|
||||
|
||||
// 2. For each value of values:
|
||||
// 1. Append (name, value) to headers.
|
||||
for (const value of cookies) {
|
||||
headers.push([name, value])
|
||||
}
|
||||
} else {
|
||||
// 2. Otherwise:
|
||||
|
||||
// 1. Let value be the result of getting name from list.
|
||||
|
||||
// 2. Assert: value is non-null.
|
||||
assert(value !== null)
|
||||
|
||||
// 3. Append (name, value) to headers.
|
||||
headers.push([name, value])
|
||||
}
|
||||
}
|
||||
|
||||
this[kHeadersList][kHeadersSortedMap] = headers
|
||||
|
||||
// 4. Return headers.
|
||||
return headers
|
||||
}
|
||||
|
||||
keys () {
|
||||
webidl.brandCheck(this, Headers)
|
||||
|
||||
return makeIterator(
|
||||
() => [...this[kHeadersSortedMap].entries()],
|
||||
() => [...this[kHeadersSortedMap].values()],
|
||||
'Headers',
|
||||
'key'
|
||||
)
|
||||
|
@ -400,7 +466,7 @@ class Headers {
|
|||
webidl.brandCheck(this, Headers)
|
||||
|
||||
return makeIterator(
|
||||
() => [...this[kHeadersSortedMap].entries()],
|
||||
() => [...this[kHeadersSortedMap].values()],
|
||||
'Headers',
|
||||
'value'
|
||||
)
|
||||
|
@ -410,7 +476,7 @@ class Headers {
|
|||
webidl.brandCheck(this, Headers)
|
||||
|
||||
return makeIterator(
|
||||
() => [...this[kHeadersSortedMap].entries()],
|
||||
() => [...this[kHeadersSortedMap].values()],
|
||||
'Headers',
|
||||
'key+value'
|
||||
)
|
||||
|
@ -451,6 +517,7 @@ Object.defineProperties(Headers.prototype, {
|
|||
get: kEnumerableProperty,
|
||||
has: kEnumerableProperty,
|
||||
set: kEnumerableProperty,
|
||||
getSetCookie: kEnumerableProperty,
|
||||
keys: kEnumerableProperty,
|
||||
values: kEnumerableProperty,
|
||||
entries: kEnumerableProperty,
|
||||
|
|
50
node_modules/undici/lib/fetch/index.js
generated
vendored
50
node_modules/undici/lib/fetch/index.js
generated
vendored
|
@ -37,9 +37,12 @@ const {
|
|||
isErrorLike,
|
||||
fullyReadBody,
|
||||
readableStreamClose,
|
||||
isomorphicEncode
|
||||
isomorphicEncode,
|
||||
urlIsLocal,
|
||||
urlIsHttpHttpsScheme,
|
||||
urlHasHttpsScheme
|
||||
} = require('./util')
|
||||
const { kState, kHeaders, kGuard, kRealm, kHeadersCaseInsensitive } = require('./symbols')
|
||||
const { kState, kHeaders, kGuard, kRealm } = require('./symbols')
|
||||
const assert = require('assert')
|
||||
const { safelyExtractBody } = require('./body')
|
||||
const {
|
||||
|
@ -53,7 +56,7 @@ const {
|
|||
const { kHeadersList } = require('../core/symbols')
|
||||
const EE = require('events')
|
||||
const { Readable, pipeline } = require('stream')
|
||||
const { isErrored, isReadable } = require('../core/util')
|
||||
const { isErrored, isReadable, nodeMajor, nodeMinor } = require('../core/util')
|
||||
const { dataURLProcessor, serializeAMimeType } = require('./dataURL')
|
||||
const { TransformStream } = require('stream/web')
|
||||
const { getGlobalDispatcher } = require('../global')
|
||||
|
@ -64,10 +67,6 @@ const { STATUS_CODES } = require('http')
|
|||
let resolveObjectURL
|
||||
let ReadableStream = globalThis.ReadableStream
|
||||
|
||||
const nodeVersion = process.versions.node.split('.')
|
||||
const nodeMajor = Number(nodeVersion[0])
|
||||
const nodeMinor = Number(nodeVersion[1])
|
||||
|
||||
class Fetch extends EE {
|
||||
constructor (dispatcher) {
|
||||
super()
|
||||
|
@ -276,7 +275,7 @@ function finalizeAndReportTiming (response, initiatorType = 'other') {
|
|||
let cacheState = response.cacheState
|
||||
|
||||
// 6. If originalURL’s scheme is not an HTTP(S) scheme, then return.
|
||||
if (!/^https?:/.test(originalURL.protocol)) {
|
||||
if (!urlIsHttpHttpsScheme(originalURL)) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -301,7 +300,7 @@ function finalizeAndReportTiming (response, initiatorType = 'other') {
|
|||
// capability.
|
||||
// TODO: given global’s relevant settings object’s cross-origin isolated
|
||||
// capability?
|
||||
response.timingInfo.endTime = coarsenedSharedCurrentTime()
|
||||
timingInfo.endTime = coarsenedSharedCurrentTime()
|
||||
|
||||
// 10. Set response’s timing info to timingInfo.
|
||||
response.timingInfo = timingInfo
|
||||
|
@ -319,7 +318,7 @@ function finalizeAndReportTiming (response, initiatorType = 'other') {
|
|||
|
||||
// https://w3c.github.io/resource-timing/#dfn-mark-resource-timing
|
||||
function markResourceTiming (timingInfo, originalURL, initiatorType, globalThis, cacheState) {
|
||||
if (nodeMajor >= 18 && nodeMinor >= 2) {
|
||||
if (nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 2)) {
|
||||
performance.markResourceTiming(timingInfo, originalURL, initiatorType, globalThis, cacheState)
|
||||
}
|
||||
}
|
||||
|
@ -534,10 +533,7 @@ async function mainFetch (fetchParams, recursive = false) {
|
|||
|
||||
// 3. If request’s local-URLs-only flag is set and request’s current URL is
|
||||
// not local, then set response to a network error.
|
||||
if (
|
||||
request.localURLsOnly &&
|
||||
!/^(about|blob|data):/.test(requestCurrentURL(request).protocol)
|
||||
) {
|
||||
if (request.localURLsOnly && !urlIsLocal(requestCurrentURL(request))) {
|
||||
response = makeNetworkError('local URLs only')
|
||||
}
|
||||
|
||||
|
@ -627,7 +623,7 @@ async function mainFetch (fetchParams, recursive = false) {
|
|||
}
|
||||
|
||||
// request’s current URL’s scheme is not an HTTP(S) scheme
|
||||
if (!/^https?:/.test(requestCurrentURL(request).protocol)) {
|
||||
if (!urlIsHttpHttpsScheme(requestCurrentURL(request))) {
|
||||
// Return a network error.
|
||||
return makeNetworkError('URL scheme must be a HTTP(S) scheme')
|
||||
}
|
||||
|
@ -1134,7 +1130,7 @@ async function httpRedirectFetch (fetchParams, response) {
|
|||
|
||||
// 6. If locationURL’s scheme is not an HTTP(S) scheme, then return a network
|
||||
// error.
|
||||
if (!/^https?:/.test(locationURL.protocol)) {
|
||||
if (!urlIsHttpHttpsScheme(locationURL)) {
|
||||
return makeNetworkError('URL scheme must be a HTTP(S) scheme')
|
||||
}
|
||||
|
||||
|
@ -1209,7 +1205,7 @@ async function httpRedirectFetch (fetchParams, response) {
|
|||
// 14. If request’s body is non-null, then set request’s body to the first return
|
||||
// value of safely extracting request’s body’s source.
|
||||
if (request.body != null) {
|
||||
assert(request.body.source)
|
||||
assert(request.body.source != null)
|
||||
request.body = safelyExtractBody(request.body.source)[0]
|
||||
}
|
||||
|
||||
|
@ -1403,7 +1399,7 @@ async function httpNetworkOrCacheFetch (
|
|||
// header if httpRequest’s header list contains that header’s name.
|
||||
// TODO: https://github.com/whatwg/fetch/issues/1285#issuecomment-896560129
|
||||
if (!httpRequest.headersList.contains('accept-encoding')) {
|
||||
if (/^https:/.test(requestCurrentURL(httpRequest).protocol)) {
|
||||
if (urlHasHttpsScheme(requestCurrentURL(httpRequest))) {
|
||||
httpRequest.headersList.append('accept-encoding', 'br, gzip, deflate')
|
||||
} else {
|
||||
httpRequest.headersList.append('accept-encoding', 'gzip, deflate')
|
||||
|
@ -1849,6 +1845,7 @@ async function httpNetworkFetch (
|
|||
// 4. Set bytes to the result of handling content codings given
|
||||
// codings and bytes.
|
||||
let bytes
|
||||
let isFailure
|
||||
try {
|
||||
const { done, value } = await fetchParams.controller.next()
|
||||
|
||||
|
@ -1863,6 +1860,10 @@ async function httpNetworkFetch (
|
|||
bytes = undefined
|
||||
} else {
|
||||
bytes = err
|
||||
|
||||
// err may be propagated from the result of calling readablestream.cancel,
|
||||
// which might not be an error. https://github.com/nodejs/undici/issues/2009
|
||||
isFailure = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1882,7 +1883,7 @@ async function httpNetworkFetch (
|
|||
timingInfo.decodedBodySize += bytes?.byteLength ?? 0
|
||||
|
||||
// 6. If bytes is failure, then terminate fetchParams’s controller.
|
||||
if (isErrorLike(bytes)) {
|
||||
if (isFailure) {
|
||||
fetchParams.controller.terminate(bytes)
|
||||
return
|
||||
}
|
||||
|
@ -1949,7 +1950,7 @@ async function httpNetworkFetch (
|
|||
origin: url.origin,
|
||||
method: request.method,
|
||||
body: fetchParams.controller.dispatcher.isMockActive ? request.body && request.body.source : body,
|
||||
headers: request.headersList[kHeadersCaseInsensitive],
|
||||
headers: request.headersList.entries,
|
||||
maxRedirections: 0,
|
||||
upgrade: request.mode === 'websocket' ? 'websocket' : undefined
|
||||
},
|
||||
|
@ -1983,7 +1984,9 @@ async function httpNetworkFetch (
|
|||
const val = headersList[n + 1].toString('latin1')
|
||||
|
||||
if (key.toLowerCase() === 'content-encoding') {
|
||||
codings = val.split(',').map((x) => x.trim())
|
||||
// https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.1
|
||||
// "All content-coding values are case-insensitive..."
|
||||
codings = val.toLowerCase().split(',').map((x) => x.trim())
|
||||
} else if (key.toLowerCase() === 'location') {
|
||||
location = val
|
||||
}
|
||||
|
@ -2002,9 +2005,10 @@ async function httpNetworkFetch (
|
|||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
|
||||
if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) {
|
||||
for (const coding of codings) {
|
||||
if (/(x-)?gzip/.test(coding)) {
|
||||
// https://www.rfc-editor.org/rfc/rfc9112.html#section-7.2
|
||||
if (coding === 'x-gzip' || coding === 'gzip') {
|
||||
decoders.push(zlib.createGunzip())
|
||||
} else if (/(x-)?deflate/.test(coding)) {
|
||||
} else if (coding === 'deflate') {
|
||||
decoders.push(zlib.createInflate())
|
||||
} else if (coding === 'br') {
|
||||
decoders.push(zlib.createBrotliDecompress())
|
||||
|
|
47
node_modules/undici/lib/fetch/request.js
generated
vendored
47
node_modules/undici/lib/fetch/request.js
generated
vendored
|
@ -9,7 +9,8 @@ const util = require('../core/util')
|
|||
const {
|
||||
isValidHTTPToken,
|
||||
sameOrigin,
|
||||
normalizeMethod
|
||||
normalizeMethod,
|
||||
makePolicyContainer
|
||||
} = require('./util')
|
||||
const {
|
||||
forbiddenMethods,
|
||||
|
@ -28,10 +29,12 @@ const { getGlobalOrigin } = require('./global')
|
|||
const { URLSerializer } = require('./dataURL')
|
||||
const { kHeadersList } = require('../core/symbols')
|
||||
const assert = require('assert')
|
||||
const { getMaxListeners, setMaxListeners, getEventListeners, defaultMaxListeners } = require('events')
|
||||
|
||||
let TransformStream = globalThis.TransformStream
|
||||
|
||||
const kInit = Symbol('init')
|
||||
const kAbortController = Symbol('abortController')
|
||||
|
||||
const requestFinalizer = new FinalizationRegistry(({ signal, abort }) => {
|
||||
signal.removeEventListener('abort', abort)
|
||||
|
@ -50,10 +53,14 @@ class Request {
|
|||
input = webidl.converters.RequestInfo(input)
|
||||
init = webidl.converters.RequestInit(init)
|
||||
|
||||
// TODO
|
||||
// https://html.spec.whatwg.org/multipage/webappapis.html#environment-settings-object
|
||||
this[kRealm] = {
|
||||
settingsObject: {
|
||||
baseUrl: getGlobalOrigin()
|
||||
baseUrl: getGlobalOrigin(),
|
||||
get origin () {
|
||||
return this.baseUrl?.origin
|
||||
},
|
||||
policyContainer: makePolicyContainer()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,12 +129,12 @@ class Request {
|
|||
}
|
||||
|
||||
// 10. If init["window"] exists and is non-null, then throw a TypeError.
|
||||
if (init.window !== undefined && init.window != null) {
|
||||
if (init.window != null) {
|
||||
throw new TypeError(`'window' option '${window}' must be null`)
|
||||
}
|
||||
|
||||
// 11. If init["window"] exists, then set window to "no-window".
|
||||
if (init.window !== undefined) {
|
||||
if ('window' in init) {
|
||||
window = 'no-window'
|
||||
}
|
||||
|
||||
|
@ -348,12 +355,34 @@ class Request {
|
|||
if (signal.aborted) {
|
||||
ac.abort(signal.reason)
|
||||
} else {
|
||||
// Keep a strong ref to ac while request object
|
||||
// is alive. This is needed to prevent AbortController
|
||||
// from being prematurely garbage collected.
|
||||
// See, https://github.com/nodejs/undici/issues/1926.
|
||||
this[kAbortController] = ac
|
||||
|
||||
const acRef = new WeakRef(ac)
|
||||
const abort = function () {
|
||||
acRef.deref()?.abort(this.reason)
|
||||
const ac = acRef.deref()
|
||||
if (ac !== undefined) {
|
||||
ac.abort(this.reason)
|
||||
}
|
||||
}
|
||||
|
||||
// Third-party AbortControllers may not work with these.
|
||||
// See, https://github.com/nodejs/undici/pull/1910#issuecomment-1464495619.
|
||||
try {
|
||||
// If the max amount of listeners is equal to the default, increase it
|
||||
// This is only available in node >= v19.9.0
|
||||
if (typeof getMaxListeners === 'function' && getMaxListeners(signal) === defaultMaxListeners) {
|
||||
setMaxListeners(100, signal)
|
||||
} else if (getEventListeners(signal, 'abort').length >= defaultMaxListeners) {
|
||||
setMaxListeners(100, signal)
|
||||
}
|
||||
} catch {}
|
||||
|
||||
signal.addEventListener('abort', abort, { once: true })
|
||||
requestFinalizer.register(this, { signal, abort })
|
||||
requestFinalizer.register(ac, { signal, abort })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -413,7 +442,7 @@ class Request {
|
|||
// non-null, and request’s method is `GET` or `HEAD`, then throw a
|
||||
// TypeError.
|
||||
if (
|
||||
((init.body !== undefined && init.body != null) || inputBody != null) &&
|
||||
(init.body != null || inputBody != null) &&
|
||||
(request.method === 'GET' || request.method === 'HEAD')
|
||||
) {
|
||||
throw new TypeError('Request with GET/HEAD method cannot have body.')
|
||||
|
@ -423,7 +452,7 @@ class Request {
|
|||
let initBody = null
|
||||
|
||||
// 36. If init["body"] exists and is non-null, then:
|
||||
if (init.body !== undefined && init.body != null) {
|
||||
if (init.body != null) {
|
||||
// 1. Let Content-Type be null.
|
||||
// 2. Set initBody and Content-Type to the result of extracting
|
||||
// init["body"], with keepalive set to request’s keepalive.
|
||||
|
|
9
node_modules/undici/lib/fetch/response.js
generated
vendored
9
node_modules/undici/lib/fetch/response.js
generated
vendored
|
@ -348,9 +348,7 @@ function makeNetworkError (reason) {
|
|||
status: 0,
|
||||
error: isError
|
||||
? reason
|
||||
: new Error(reason ? String(reason) : reason, {
|
||||
cause: isError ? reason : undefined
|
||||
}),
|
||||
: new Error(reason ? String(reason) : reason),
|
||||
aborted: reason && reason.name === 'AbortError'
|
||||
})
|
||||
}
|
||||
|
@ -469,7 +467,7 @@ function initializeResponse (response, init, body) {
|
|||
|
||||
// 5. If init["headers"] exists, then fill response’s headers with init["headers"].
|
||||
if ('headers' in init && init.headers != null) {
|
||||
fill(response[kState].headersList, init.headers)
|
||||
fill(response[kHeaders], init.headers)
|
||||
}
|
||||
|
||||
// 6. If body was given, then:
|
||||
|
@ -571,5 +569,6 @@ module.exports = {
|
|||
makeResponse,
|
||||
makeAppropriateNetworkError,
|
||||
filterResponse,
|
||||
Response
|
||||
Response,
|
||||
cloneResponse
|
||||
}
|
||||
|
|
3
node_modules/undici/lib/fetch/symbols.js
generated
vendored
3
node_modules/undici/lib/fetch/symbols.js
generated
vendored
|
@ -6,6 +6,5 @@ module.exports = {
|
|||
kSignal: Symbol('signal'),
|
||||
kState: Symbol('state'),
|
||||
kGuard: Symbol('guard'),
|
||||
kRealm: Symbol('realm'),
|
||||
kHeadersCaseInsensitive: Symbol('headers case insensitive')
|
||||
kRealm: Symbol('realm')
|
||||
}
|
||||
|
|
238
node_modules/undici/lib/fetch/util.js
generated
vendored
238
node_modules/undici/lib/fetch/util.js
generated
vendored
|
@ -1,6 +1,7 @@
|
|||
'use strict'
|
||||
|
||||
const { redirectStatus, badPorts, referrerPolicy: referrerPolicyTokens } = require('./constants')
|
||||
const { getGlobalOrigin } = require('./global')
|
||||
const { performance } = require('perf_hooks')
|
||||
const { isBlobLike, toUSVString, ReadableStreamFrom } = require('../core/util')
|
||||
const assert = require('assert')
|
||||
|
@ -36,9 +37,11 @@ function responseLocationURL (response, requestFragment) {
|
|||
// `Location` and response’s header list.
|
||||
let location = response.headersList.get('location')
|
||||
|
||||
// 3. If location is a value, then set location to the result of parsing
|
||||
// location with response’s URL.
|
||||
location = location ? new URL(location, responseURL(response)) : null
|
||||
// 3. If location is a header value, then set location to the result of
|
||||
// parsing location with response’s URL.
|
||||
if (location !== null && isValidHeaderValue(location)) {
|
||||
location = new URL(location, responseURL(response))
|
||||
}
|
||||
|
||||
// 4. If location is a URL whose fragment is null, then set location’s
|
||||
// fragment to requestFragment.
|
||||
|
@ -61,7 +64,7 @@ function requestBadPort (request) {
|
|||
|
||||
// 2. If url’s scheme is an HTTP(S) scheme and url’s port is a bad port,
|
||||
// then return blocked.
|
||||
if (/^https?:/.test(url.protocol) && badPorts.includes(url.port)) {
|
||||
if (urlIsHttpHttpsScheme(url) && badPorts.includes(url.port)) {
|
||||
return 'blocked'
|
||||
}
|
||||
|
||||
|
@ -267,7 +270,7 @@ function appendRequestOriginHeader (request) {
|
|||
// 2. If request’s response tainting is "cors" or request’s mode is "websocket", then append (`Origin`, serializedOrigin) to request’s header list.
|
||||
if (request.responseTainting === 'cors' || request.mode === 'websocket') {
|
||||
if (serializedOrigin) {
|
||||
request.headersList.append('Origin', serializedOrigin)
|
||||
request.headersList.append('origin', serializedOrigin)
|
||||
}
|
||||
|
||||
// 3. Otherwise, if request’s method is neither `GET` nor `HEAD`, then:
|
||||
|
@ -282,7 +285,7 @@ function appendRequestOriginHeader (request) {
|
|||
case 'strict-origin':
|
||||
case 'strict-origin-when-cross-origin':
|
||||
// If request’s origin is a tuple origin, its scheme is "https", and request’s current URL’s scheme is not "https", then set serializedOrigin to `null`.
|
||||
if (/^https:/.test(request.origin) && !/^https:/.test(requestCurrentURL(request))) {
|
||||
if (request.origin && urlHasHttpsScheme(request.origin) && !urlHasHttpsScheme(requestCurrentURL(request))) {
|
||||
serializedOrigin = null
|
||||
}
|
||||
break
|
||||
|
@ -298,7 +301,7 @@ function appendRequestOriginHeader (request) {
|
|||
|
||||
if (serializedOrigin) {
|
||||
// 2. Append (`Origin`, serializedOrigin) to request’s header list.
|
||||
request.headersList.append('Origin', serializedOrigin)
|
||||
request.headersList.append('origin', serializedOrigin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -327,14 +330,17 @@ function createOpaqueTimingInfo (timingInfo) {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/origin.html#policy-container
|
||||
function makePolicyContainer () {
|
||||
// TODO
|
||||
return {}
|
||||
// Note: the fetch spec doesn't make use of embedder policy or CSP list
|
||||
return {
|
||||
referrerPolicy: 'strict-origin-when-cross-origin'
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/origin.html#clone-a-policy-container
|
||||
function clonePolicyContainer () {
|
||||
// TODO
|
||||
return {}
|
||||
function clonePolicyContainer (policyContainer) {
|
||||
return {
|
||||
referrerPolicy: policyContainer.referrerPolicy
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
|
||||
|
@ -342,104 +348,76 @@ function determineRequestsReferrer (request) {
|
|||
// 1. Let policy be request's referrer policy.
|
||||
const policy = request.referrerPolicy
|
||||
|
||||
// Return no-referrer when empty or policy says so
|
||||
if (policy == null || policy === '' || policy === 'no-referrer') {
|
||||
return 'no-referrer'
|
||||
}
|
||||
// Note: policy cannot (shouldn't) be null or an empty string.
|
||||
assert(policy)
|
||||
|
||||
// 2. Let environment be request’s client.
|
||||
|
||||
// 2. Let environment be the request client
|
||||
const environment = request.client
|
||||
let referrerSource = null
|
||||
|
||||
/**
|
||||
* 3, Switch on request’s referrer:
|
||||
"client"
|
||||
If environment’s global object is a Window object, then
|
||||
Let document be the associated Document of environment’s global object.
|
||||
If document’s origin is an opaque origin, return no referrer.
|
||||
While document is an iframe srcdoc document,
|
||||
let document be document’s browsing context’s browsing context container’s node document.
|
||||
Let referrerSource be document’s URL.
|
||||
|
||||
Otherwise, let referrerSource be environment’s creation URL.
|
||||
|
||||
a URL
|
||||
Let referrerSource be request’s referrer.
|
||||
*/
|
||||
// 3. Switch on request’s referrer:
|
||||
if (request.referrer === 'client') {
|
||||
// Not defined in Node but part of the spec
|
||||
if (request.client?.globalObject?.constructor?.name === 'Window' ) { // eslint-disable-line
|
||||
const origin = environment.globalObject.self?.origin ?? environment.globalObject.location?.origin
|
||||
// Note: node isn't a browser and doesn't implement document/iframes,
|
||||
// so we bypass this step and replace it with our own.
|
||||
|
||||
// If document’s origin is an opaque origin, return no referrer.
|
||||
if (origin == null || origin === 'null') return 'no-referrer'
|
||||
const globalOrigin = getGlobalOrigin()
|
||||
|
||||
// Let referrerSource be document’s URL.
|
||||
referrerSource = new URL(environment.globalObject.location.href)
|
||||
} else {
|
||||
// 3(a)(II) If environment's global object is not Window,
|
||||
// Let referrerSource be environments creationURL
|
||||
if (environment?.globalObject?.location == null) {
|
||||
return 'no-referrer'
|
||||
}
|
||||
|
||||
referrerSource = new URL(environment.globalObject.location.href)
|
||||
if (!globalOrigin || globalOrigin.origin === 'null') {
|
||||
return 'no-referrer'
|
||||
}
|
||||
|
||||
// note: we need to clone it as it's mutated
|
||||
referrerSource = new URL(globalOrigin)
|
||||
} else if (request.referrer instanceof URL) {
|
||||
// 3(b) If requests's referrer is a URL instance, then make
|
||||
// referrerSource be requests's referrer.
|
||||
// Let referrerSource be request’s referrer.
|
||||
referrerSource = request.referrer
|
||||
} else {
|
||||
// If referrerSource neither client nor instance of URL
|
||||
// then return "no-referrer".
|
||||
return 'no-referrer'
|
||||
}
|
||||
|
||||
const urlProtocol = referrerSource.protocol
|
||||
// 4. Let request’s referrerURL be the result of stripping referrerSource for
|
||||
// use as a referrer.
|
||||
let referrerURL = stripURLForReferrer(referrerSource)
|
||||
|
||||
// If url's scheme is a local scheme (i.e. one of "about", "data", "javascript", "file")
|
||||
// then return "no-referrer".
|
||||
if (
|
||||
urlProtocol === 'about:' || urlProtocol === 'data:' ||
|
||||
urlProtocol === 'blob:'
|
||||
) {
|
||||
return 'no-referrer'
|
||||
// 5. Let referrerOrigin be the result of stripping referrerSource for use as
|
||||
// a referrer, with the origin-only flag set to true.
|
||||
const referrerOrigin = stripURLForReferrer(referrerSource, true)
|
||||
|
||||
// 6. If the result of serializing referrerURL is a string whose length is
|
||||
// greater than 4096, set referrerURL to referrerOrigin.
|
||||
if (referrerURL.toString().length > 4096) {
|
||||
referrerURL = referrerOrigin
|
||||
}
|
||||
|
||||
let temp
|
||||
let referrerOrigin
|
||||
// 4. Let requests's referrerURL be the result of stripping referrer
|
||||
// source for use as referrer (using util function, without origin only)
|
||||
const referrerUrl = (temp = stripURLForReferrer(referrerSource)).length > 4096
|
||||
// 5. Let referrerOrigin be the result of stripping referrer
|
||||
// source for use as referrer (using util function, with originOnly true)
|
||||
? (referrerOrigin = stripURLForReferrer(referrerSource, true))
|
||||
// 6. If result of seralizing referrerUrl is a string whose length is greater than
|
||||
// 4096, then set referrerURL to referrerOrigin
|
||||
: temp
|
||||
const areSameOrigin = sameOrigin(request, referrerUrl)
|
||||
const isNonPotentiallyTrustWorthy = isURLPotentiallyTrustworthy(referrerUrl) &&
|
||||
const areSameOrigin = sameOrigin(request, referrerURL)
|
||||
const isNonPotentiallyTrustWorthy = isURLPotentiallyTrustworthy(referrerURL) &&
|
||||
!isURLPotentiallyTrustworthy(request.url)
|
||||
|
||||
// NOTE: How to treat step 7?
|
||||
// 8. Execute the switch statements corresponding to the value of policy:
|
||||
switch (policy) {
|
||||
case 'origin': return referrerOrigin != null ? referrerOrigin : stripURLForReferrer(referrerSource, true)
|
||||
case 'unsafe-url': return referrerUrl
|
||||
case 'unsafe-url': return referrerURL
|
||||
case 'same-origin':
|
||||
return areSameOrigin ? referrerOrigin : 'no-referrer'
|
||||
case 'origin-when-cross-origin':
|
||||
return areSameOrigin ? referrerUrl : referrerOrigin
|
||||
case 'strict-origin-when-cross-origin':
|
||||
/**
|
||||
* 1. If the origin of referrerURL and the origin of request’s current URL are the same,
|
||||
* then return referrerURL.
|
||||
* 2. If referrerURL is a potentially trustworthy URL and request’s current URL is not a
|
||||
* potentially trustworthy URL, then return no referrer.
|
||||
* 3. Return referrerOrigin
|
||||
*/
|
||||
if (areSameOrigin) return referrerOrigin
|
||||
// else return isNonPotentiallyTrustWorthy ? 'no-referrer' : referrerOrigin
|
||||
return areSameOrigin ? referrerURL : referrerOrigin
|
||||
case 'strict-origin-when-cross-origin': {
|
||||
const currentURL = requestCurrentURL(request)
|
||||
|
||||
// 1. If the origin of referrerURL and the origin of request’s current
|
||||
// URL are the same, then return referrerURL.
|
||||
if (sameOrigin(referrerURL, currentURL)) {
|
||||
return referrerURL
|
||||
}
|
||||
|
||||
// 2. If referrerURL is a potentially trustworthy URL and request’s
|
||||
// current URL is not a potentially trustworthy URL, then return no
|
||||
// referrer.
|
||||
if (isURLPotentiallyTrustworthy(referrerURL) && !isURLPotentiallyTrustworthy(currentURL)) {
|
||||
return 'no-referrer'
|
||||
}
|
||||
|
||||
// 3. Return referrerOrigin.
|
||||
return referrerOrigin
|
||||
}
|
||||
case 'strict-origin': // eslint-disable-line
|
||||
/**
|
||||
* 1. If referrerURL is a potentially trustworthy URL and
|
||||
|
@ -458,15 +436,42 @@ function determineRequestsReferrer (request) {
|
|||
default: // eslint-disable-line
|
||||
return isNonPotentiallyTrustWorthy ? 'no-referrer' : referrerOrigin
|
||||
}
|
||||
}
|
||||
|
||||
function stripURLForReferrer (url, originOnly = false) {
|
||||
const urlObject = new URL(url.href)
|
||||
urlObject.username = ''
|
||||
urlObject.password = ''
|
||||
urlObject.hash = ''
|
||||
/**
|
||||
* @see https://w3c.github.io/webappsec-referrer-policy/#strip-url
|
||||
* @param {URL} url
|
||||
* @param {boolean|undefined} originOnly
|
||||
*/
|
||||
function stripURLForReferrer (url, originOnly) {
|
||||
// 1. Assert: url is a URL.
|
||||
assert(url instanceof URL)
|
||||
|
||||
return originOnly ? urlObject.origin : urlObject.href
|
||||
// 2. If url’s scheme is a local scheme, then return no referrer.
|
||||
if (url.protocol === 'file:' || url.protocol === 'about:' || url.protocol === 'blank:') {
|
||||
return 'no-referrer'
|
||||
}
|
||||
|
||||
// 3. Set url’s username to the empty string.
|
||||
url.username = ''
|
||||
|
||||
// 4. Set url’s password to the empty string.
|
||||
url.password = ''
|
||||
|
||||
// 5. Set url’s fragment to null.
|
||||
url.hash = ''
|
||||
|
||||
// 6. If the origin-only flag is true, then:
|
||||
if (originOnly) {
|
||||
// 1. Set url’s path to « the empty string ».
|
||||
url.pathname = ''
|
||||
|
||||
// 2. Set url’s query to null.
|
||||
url.search = ''
|
||||
}
|
||||
|
||||
// 7. Return url.
|
||||
return url
|
||||
}
|
||||
|
||||
function isURLPotentiallyTrustworthy (url) {
|
||||
|
@ -633,7 +638,9 @@ function tryUpgradeRequestToAPotentiallyTrustworthyURL (request) {
|
|||
*/
|
||||
function sameOrigin (A, B) {
|
||||
// 1. If A and B are the same opaque origin, then return true.
|
||||
// "opaque origin" is an internal value we cannot access, ignore.
|
||||
if (A.origin === B.origin && A.origin === 'null') {
|
||||
return true
|
||||
}
|
||||
|
||||
// 2. If A and B are both tuple origins and their schemes,
|
||||
// hosts, and port are identical, then return true.
|
||||
|
@ -939,6 +946,41 @@ async function readAllBytes (reader, successSteps, failureSteps) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://fetch.spec.whatwg.org/#is-local
|
||||
* @param {URL} url
|
||||
*/
|
||||
function urlIsLocal (url) {
|
||||
assert('protocol' in url) // ensure it's a url object
|
||||
|
||||
const protocol = url.protocol
|
||||
|
||||
return protocol === 'about:' || protocol === 'blob:' || protocol === 'data:'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|URL} url
|
||||
*/
|
||||
function urlHasHttpsScheme (url) {
|
||||
if (typeof url === 'string') {
|
||||
return url.startsWith('https:')
|
||||
}
|
||||
|
||||
return url.protocol === 'https:'
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://fetch.spec.whatwg.org/#http-scheme
|
||||
* @param {URL} url
|
||||
*/
|
||||
function urlIsHttpHttpsScheme (url) {
|
||||
assert('protocol' in url) // ensure it's a url object
|
||||
|
||||
const protocol = url.protocol
|
||||
|
||||
return protocol === 'http:' || protocol === 'https:'
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch supports node >= 16.8.0, but Object.hasOwn was added in v16.9.0.
|
||||
*/
|
||||
|
@ -983,5 +1025,9 @@ module.exports = {
|
|||
isReadableStreamLike,
|
||||
readableStreamClose,
|
||||
isomorphicEncode,
|
||||
isomorphicDecode
|
||||
isomorphicDecode,
|
||||
urlIsLocal,
|
||||
urlHasHttpsScheme,
|
||||
urlIsHttpHttpsScheme,
|
||||
readAllBytes
|
||||
}
|
||||
|
|
7
node_modules/undici/lib/fetch/webidl.js
generated
vendored
7
node_modules/undici/lib/fetch/webidl.js
generated
vendored
|
@ -51,6 +51,13 @@ webidl.argumentLengthCheck = function ({ length }, min, ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
webidl.illegalConstructor = function () {
|
||||
throw webidl.errors.exception({
|
||||
header: 'TypeError',
|
||||
message: 'Illegal constructor'
|
||||
})
|
||||
}
|
||||
|
||||
// https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values
|
||||
webidl.util.Type = function (V) {
|
||||
switch (typeof V) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue