[d24f17c] | 1 | // https://github.com/Ethan-Arrowood/undici-fetch
|
---|
| 2 |
|
---|
| 3 | 'use strict'
|
---|
| 4 |
|
---|
| 5 | const { kHeadersList, kConstruct } = require('../core/symbols')
|
---|
| 6 | const { kGuard } = require('./symbols')
|
---|
| 7 | const { kEnumerableProperty } = require('../core/util')
|
---|
| 8 | const {
|
---|
| 9 | makeIterator,
|
---|
| 10 | isValidHeaderName,
|
---|
| 11 | isValidHeaderValue
|
---|
| 12 | } = require('./util')
|
---|
| 13 | const { webidl } = require('./webidl')
|
---|
| 14 | const assert = require('assert')
|
---|
| 15 |
|
---|
| 16 | const kHeadersMap = Symbol('headers map')
|
---|
| 17 | const kHeadersSortedMap = Symbol('headers map sorted')
|
---|
| 18 |
|
---|
| 19 | /**
|
---|
| 20 | * @param {number} code
|
---|
| 21 | */
|
---|
| 22 | function isHTTPWhiteSpaceCharCode (code) {
|
---|
| 23 | return code === 0x00a || code === 0x00d || code === 0x009 || code === 0x020
|
---|
| 24 | }
|
---|
| 25 |
|
---|
| 26 | /**
|
---|
| 27 | * @see https://fetch.spec.whatwg.org/#concept-header-value-normalize
|
---|
| 28 | * @param {string} potentialValue
|
---|
| 29 | */
|
---|
| 30 | function headerValueNormalize (potentialValue) {
|
---|
| 31 | // To normalize a byte sequence potentialValue, remove
|
---|
| 32 | // any leading and trailing HTTP whitespace bytes from
|
---|
| 33 | // potentialValue.
|
---|
| 34 | let i = 0; let j = potentialValue.length
|
---|
| 35 |
|
---|
| 36 | while (j > i && isHTTPWhiteSpaceCharCode(potentialValue.charCodeAt(j - 1))) --j
|
---|
| 37 | while (j > i && isHTTPWhiteSpaceCharCode(potentialValue.charCodeAt(i))) ++i
|
---|
| 38 |
|
---|
| 39 | return i === 0 && j === potentialValue.length ? potentialValue : potentialValue.substring(i, j)
|
---|
| 40 | }
|
---|
| 41 |
|
---|
| 42 | function fill (headers, object) {
|
---|
| 43 | // To fill a Headers object headers with a given object object, run these steps:
|
---|
| 44 |
|
---|
| 45 | // 1. If object is a sequence, then for each header in object:
|
---|
| 46 | // Note: webidl conversion to array has already been done.
|
---|
| 47 | if (Array.isArray(object)) {
|
---|
| 48 | for (let i = 0; i < object.length; ++i) {
|
---|
| 49 | const header = object[i]
|
---|
| 50 | // 1. If header does not contain exactly two items, then throw a TypeError.
|
---|
| 51 | if (header.length !== 2) {
|
---|
| 52 | throw webidl.errors.exception({
|
---|
| 53 | header: 'Headers constructor',
|
---|
| 54 | message: `expected name/value pair to be length 2, found ${header.length}.`
|
---|
| 55 | })
|
---|
| 56 | }
|
---|
| 57 |
|
---|
| 58 | // 2. Append (header’s first item, header’s second item) to headers.
|
---|
| 59 | appendHeader(headers, header[0], header[1])
|
---|
| 60 | }
|
---|
| 61 | } else if (typeof object === 'object' && object !== null) {
|
---|
| 62 | // Note: null should throw
|
---|
| 63 |
|
---|
| 64 | // 2. Otherwise, object is a record, then for each key → value in object,
|
---|
| 65 | // append (key, value) to headers
|
---|
| 66 | const keys = Object.keys(object)
|
---|
| 67 | for (let i = 0; i < keys.length; ++i) {
|
---|
| 68 | appendHeader(headers, keys[i], object[keys[i]])
|
---|
| 69 | }
|
---|
| 70 | } else {
|
---|
| 71 | throw webidl.errors.conversionFailed({
|
---|
| 72 | prefix: 'Headers constructor',
|
---|
| 73 | argument: 'Argument 1',
|
---|
| 74 | types: ['sequence<sequence<ByteString>>', 'record<ByteString, ByteString>']
|
---|
| 75 | })
|
---|
| 76 | }
|
---|
| 77 | }
|
---|
| 78 |
|
---|
| 79 | /**
|
---|
| 80 | * @see https://fetch.spec.whatwg.org/#concept-headers-append
|
---|
| 81 | */
|
---|
| 82 | function appendHeader (headers, name, value) {
|
---|
| 83 | // 1. Normalize value.
|
---|
| 84 | value = headerValueNormalize(value)
|
---|
| 85 |
|
---|
| 86 | // 2. If name is not a header name or value is not a
|
---|
| 87 | // header value, then throw a TypeError.
|
---|
| 88 | if (!isValidHeaderName(name)) {
|
---|
| 89 | throw webidl.errors.invalidArgument({
|
---|
| 90 | prefix: 'Headers.append',
|
---|
| 91 | value: name,
|
---|
| 92 | type: 'header name'
|
---|
| 93 | })
|
---|
| 94 | } else if (!isValidHeaderValue(value)) {
|
---|
| 95 | throw webidl.errors.invalidArgument({
|
---|
| 96 | prefix: 'Headers.append',
|
---|
| 97 | value,
|
---|
| 98 | type: 'header value'
|
---|
| 99 | })
|
---|
| 100 | }
|
---|
| 101 |
|
---|
| 102 | // 3. If headers’s guard is "immutable", then throw a TypeError.
|
---|
| 103 | // 4. Otherwise, if headers’s guard is "request" and name is a
|
---|
| 104 | // forbidden header name, return.
|
---|
| 105 | // Note: undici does not implement forbidden header names
|
---|
| 106 | if (headers[kGuard] === 'immutable') {
|
---|
| 107 | throw new TypeError('immutable')
|
---|
| 108 | } else if (headers[kGuard] === 'request-no-cors') {
|
---|
| 109 | // 5. Otherwise, if headers’s guard is "request-no-cors":
|
---|
| 110 | // TODO
|
---|
| 111 | }
|
---|
| 112 |
|
---|
| 113 | // 6. Otherwise, if headers’s guard is "response" and name is a
|
---|
| 114 | // forbidden response-header name, return.
|
---|
| 115 |
|
---|
| 116 | // 7. Append (name, value) to headers’s header list.
|
---|
| 117 | return headers[kHeadersList].append(name, value)
|
---|
| 118 |
|
---|
| 119 | // 8. If headers’s guard is "request-no-cors", then remove
|
---|
| 120 | // privileged no-CORS request headers from headers
|
---|
| 121 | }
|
---|
| 122 |
|
---|
| 123 | class HeadersList {
|
---|
| 124 | /** @type {[string, string][]|null} */
|
---|
| 125 | cookies = null
|
---|
| 126 |
|
---|
| 127 | constructor (init) {
|
---|
| 128 | if (init instanceof HeadersList) {
|
---|
| 129 | this[kHeadersMap] = new Map(init[kHeadersMap])
|
---|
| 130 | this[kHeadersSortedMap] = init[kHeadersSortedMap]
|
---|
| 131 | this.cookies = init.cookies === null ? null : [...init.cookies]
|
---|
| 132 | } else {
|
---|
| 133 | this[kHeadersMap] = new Map(init)
|
---|
| 134 | this[kHeadersSortedMap] = null
|
---|
| 135 | }
|
---|
| 136 | }
|
---|
| 137 |
|
---|
| 138 | // https://fetch.spec.whatwg.org/#header-list-contains
|
---|
| 139 | contains (name) {
|
---|
| 140 | // A header list list contains a header name name if list
|
---|
| 141 | // contains a header whose name is a byte-case-insensitive
|
---|
| 142 | // match for name.
|
---|
| 143 | name = name.toLowerCase()
|
---|
| 144 |
|
---|
| 145 | return this[kHeadersMap].has(name)
|
---|
| 146 | }
|
---|
| 147 |
|
---|
| 148 | clear () {
|
---|
| 149 | this[kHeadersMap].clear()
|
---|
| 150 | this[kHeadersSortedMap] = null
|
---|
| 151 | this.cookies = null
|
---|
| 152 | }
|
---|
| 153 |
|
---|
| 154 | // https://fetch.spec.whatwg.org/#concept-header-list-append
|
---|
| 155 | append (name, value) {
|
---|
| 156 | this[kHeadersSortedMap] = null
|
---|
| 157 |
|
---|
| 158 | // 1. If list contains name, then set name to the first such
|
---|
| 159 | // header’s name.
|
---|
| 160 | const lowercaseName = name.toLowerCase()
|
---|
| 161 | const exists = this[kHeadersMap].get(lowercaseName)
|
---|
| 162 |
|
---|
| 163 | // 2. Append (name, value) to list.
|
---|
| 164 | if (exists) {
|
---|
| 165 | const delimiter = lowercaseName === 'cookie' ? '; ' : ', '
|
---|
| 166 | this[kHeadersMap].set(lowercaseName, {
|
---|
| 167 | name: exists.name,
|
---|
| 168 | value: `${exists.value}${delimiter}${value}`
|
---|
| 169 | })
|
---|
| 170 | } else {
|
---|
| 171 | this[kHeadersMap].set(lowercaseName, { name, value })
|
---|
| 172 | }
|
---|
| 173 |
|
---|
| 174 | if (lowercaseName === 'set-cookie') {
|
---|
| 175 | this.cookies ??= []
|
---|
| 176 | this.cookies.push(value)
|
---|
| 177 | }
|
---|
| 178 | }
|
---|
| 179 |
|
---|
| 180 | // https://fetch.spec.whatwg.org/#concept-header-list-set
|
---|
| 181 | set (name, value) {
|
---|
| 182 | this[kHeadersSortedMap] = null
|
---|
| 183 | const lowercaseName = name.toLowerCase()
|
---|
| 184 |
|
---|
| 185 | if (lowercaseName === 'set-cookie') {
|
---|
| 186 | this.cookies = [value]
|
---|
| 187 | }
|
---|
| 188 |
|
---|
| 189 | // 1. If list contains name, then set the value of
|
---|
| 190 | // the first such header to value and remove the
|
---|
| 191 | // others.
|
---|
| 192 | // 2. Otherwise, append header (name, value) to list.
|
---|
| 193 | this[kHeadersMap].set(lowercaseName, { name, value })
|
---|
| 194 | }
|
---|
| 195 |
|
---|
| 196 | // https://fetch.spec.whatwg.org/#concept-header-list-delete
|
---|
| 197 | delete (name) {
|
---|
| 198 | this[kHeadersSortedMap] = null
|
---|
| 199 |
|
---|
| 200 | name = name.toLowerCase()
|
---|
| 201 |
|
---|
| 202 | if (name === 'set-cookie') {
|
---|
| 203 | this.cookies = null
|
---|
| 204 | }
|
---|
| 205 |
|
---|
| 206 | this[kHeadersMap].delete(name)
|
---|
| 207 | }
|
---|
| 208 |
|
---|
| 209 | // https://fetch.spec.whatwg.org/#concept-header-list-get
|
---|
| 210 | get (name) {
|
---|
| 211 | const value = this[kHeadersMap].get(name.toLowerCase())
|
---|
| 212 |
|
---|
| 213 | // 1. If list does not contain name, then return null.
|
---|
| 214 | // 2. Return the values of all headers in list whose name
|
---|
| 215 | // is a byte-case-insensitive match for name,
|
---|
| 216 | // separated from each other by 0x2C 0x20, in order.
|
---|
| 217 | return value === undefined ? null : value.value
|
---|
| 218 | }
|
---|
| 219 |
|
---|
| 220 | * [Symbol.iterator] () {
|
---|
| 221 | // use the lowercased name
|
---|
| 222 | for (const [name, { value }] of this[kHeadersMap]) {
|
---|
| 223 | yield [name, value]
|
---|
| 224 | }
|
---|
| 225 | }
|
---|
| 226 |
|
---|
| 227 | get entries () {
|
---|
| 228 | const headers = {}
|
---|
| 229 |
|
---|
| 230 | if (this[kHeadersMap].size) {
|
---|
| 231 | for (const { name, value } of this[kHeadersMap].values()) {
|
---|
| 232 | headers[name] = value
|
---|
| 233 | }
|
---|
| 234 | }
|
---|
| 235 |
|
---|
| 236 | return headers
|
---|
| 237 | }
|
---|
| 238 | }
|
---|
| 239 |
|
---|
| 240 | // https://fetch.spec.whatwg.org/#headers-class
|
---|
| 241 | class Headers {
|
---|
| 242 | constructor (init = undefined) {
|
---|
| 243 | if (init === kConstruct) {
|
---|
| 244 | return
|
---|
| 245 | }
|
---|
| 246 | this[kHeadersList] = new HeadersList()
|
---|
| 247 |
|
---|
| 248 | // The new Headers(init) constructor steps are:
|
---|
| 249 |
|
---|
| 250 | // 1. Set this’s guard to "none".
|
---|
| 251 | this[kGuard] = 'none'
|
---|
| 252 |
|
---|
| 253 | // 2. If init is given, then fill this with init.
|
---|
| 254 | if (init !== undefined) {
|
---|
| 255 | init = webidl.converters.HeadersInit(init)
|
---|
| 256 | fill(this, init)
|
---|
| 257 | }
|
---|
| 258 | }
|
---|
| 259 |
|
---|
| 260 | // https://fetch.spec.whatwg.org/#dom-headers-append
|
---|
| 261 | append (name, value) {
|
---|
| 262 | webidl.brandCheck(this, Headers)
|
---|
| 263 |
|
---|
| 264 | webidl.argumentLengthCheck(arguments, 2, { header: 'Headers.append' })
|
---|
| 265 |
|
---|
| 266 | name = webidl.converters.ByteString(name)
|
---|
| 267 | value = webidl.converters.ByteString(value)
|
---|
| 268 |
|
---|
| 269 | return appendHeader(this, name, value)
|
---|
| 270 | }
|
---|
| 271 |
|
---|
| 272 | // https://fetch.spec.whatwg.org/#dom-headers-delete
|
---|
| 273 | delete (name) {
|
---|
| 274 | webidl.brandCheck(this, Headers)
|
---|
| 275 |
|
---|
| 276 | webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.delete' })
|
---|
| 277 |
|
---|
| 278 | name = webidl.converters.ByteString(name)
|
---|
| 279 |
|
---|
| 280 | // 1. If name is not a header name, then throw a TypeError.
|
---|
| 281 | if (!isValidHeaderName(name)) {
|
---|
| 282 | throw webidl.errors.invalidArgument({
|
---|
| 283 | prefix: 'Headers.delete',
|
---|
| 284 | value: name,
|
---|
| 285 | type: 'header name'
|
---|
| 286 | })
|
---|
| 287 | }
|
---|
| 288 |
|
---|
| 289 | // 2. If this’s guard is "immutable", then throw a TypeError.
|
---|
| 290 | // 3. Otherwise, if this’s guard is "request" and name is a
|
---|
| 291 | // forbidden header name, return.
|
---|
| 292 | // 4. Otherwise, if this’s guard is "request-no-cors", name
|
---|
| 293 | // is not a no-CORS-safelisted request-header name, and
|
---|
| 294 | // name is not a privileged no-CORS request-header name,
|
---|
| 295 | // return.
|
---|
| 296 | // 5. Otherwise, if this’s guard is "response" and name is
|
---|
| 297 | // a forbidden response-header name, return.
|
---|
| 298 | // Note: undici does not implement forbidden header names
|
---|
| 299 | if (this[kGuard] === 'immutable') {
|
---|
| 300 | throw new TypeError('immutable')
|
---|
| 301 | } else if (this[kGuard] === 'request-no-cors') {
|
---|
| 302 | // TODO
|
---|
| 303 | }
|
---|
| 304 |
|
---|
| 305 | // 6. If this’s header list does not contain name, then
|
---|
| 306 | // return.
|
---|
| 307 | if (!this[kHeadersList].contains(name)) {
|
---|
| 308 | return
|
---|
| 309 | }
|
---|
| 310 |
|
---|
| 311 | // 7. Delete name from this’s header list.
|
---|
| 312 | // 8. If this’s guard is "request-no-cors", then remove
|
---|
| 313 | // privileged no-CORS request headers from this.
|
---|
| 314 | this[kHeadersList].delete(name)
|
---|
| 315 | }
|
---|
| 316 |
|
---|
| 317 | // https://fetch.spec.whatwg.org/#dom-headers-get
|
---|
| 318 | get (name) {
|
---|
| 319 | webidl.brandCheck(this, Headers)
|
---|
| 320 |
|
---|
| 321 | webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.get' })
|
---|
| 322 |
|
---|
| 323 | name = webidl.converters.ByteString(name)
|
---|
| 324 |
|
---|
| 325 | // 1. If name is not a header name, then throw a TypeError.
|
---|
| 326 | if (!isValidHeaderName(name)) {
|
---|
| 327 | throw webidl.errors.invalidArgument({
|
---|
| 328 | prefix: 'Headers.get',
|
---|
| 329 | value: name,
|
---|
| 330 | type: 'header name'
|
---|
| 331 | })
|
---|
| 332 | }
|
---|
| 333 |
|
---|
| 334 | // 2. Return the result of getting name from this’s header
|
---|
| 335 | // list.
|
---|
| 336 | return this[kHeadersList].get(name)
|
---|
| 337 | }
|
---|
| 338 |
|
---|
| 339 | // https://fetch.spec.whatwg.org/#dom-headers-has
|
---|
| 340 | has (name) {
|
---|
| 341 | webidl.brandCheck(this, Headers)
|
---|
| 342 |
|
---|
| 343 | webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.has' })
|
---|
| 344 |
|
---|
| 345 | name = webidl.converters.ByteString(name)
|
---|
| 346 |
|
---|
| 347 | // 1. If name is not a header name, then throw a TypeError.
|
---|
| 348 | if (!isValidHeaderName(name)) {
|
---|
| 349 | throw webidl.errors.invalidArgument({
|
---|
| 350 | prefix: 'Headers.has',
|
---|
| 351 | value: name,
|
---|
| 352 | type: 'header name'
|
---|
| 353 | })
|
---|
| 354 | }
|
---|
| 355 |
|
---|
| 356 | // 2. Return true if this’s header list contains name;
|
---|
| 357 | // otherwise false.
|
---|
| 358 | return this[kHeadersList].contains(name)
|
---|
| 359 | }
|
---|
| 360 |
|
---|
| 361 | // https://fetch.spec.whatwg.org/#dom-headers-set
|
---|
| 362 | set (name, value) {
|
---|
| 363 | webidl.brandCheck(this, Headers)
|
---|
| 364 |
|
---|
| 365 | webidl.argumentLengthCheck(arguments, 2, { header: 'Headers.set' })
|
---|
| 366 |
|
---|
| 367 | name = webidl.converters.ByteString(name)
|
---|
| 368 | value = webidl.converters.ByteString(value)
|
---|
| 369 |
|
---|
| 370 | // 1. Normalize value.
|
---|
| 371 | value = headerValueNormalize(value)
|
---|
| 372 |
|
---|
| 373 | // 2. If name is not a header name or value is not a
|
---|
| 374 | // header value, then throw a TypeError.
|
---|
| 375 | if (!isValidHeaderName(name)) {
|
---|
| 376 | throw webidl.errors.invalidArgument({
|
---|
| 377 | prefix: 'Headers.set',
|
---|
| 378 | value: name,
|
---|
| 379 | type: 'header name'
|
---|
| 380 | })
|
---|
| 381 | } else if (!isValidHeaderValue(value)) {
|
---|
| 382 | throw webidl.errors.invalidArgument({
|
---|
| 383 | prefix: 'Headers.set',
|
---|
| 384 | value,
|
---|
| 385 | type: 'header value'
|
---|
| 386 | })
|
---|
| 387 | }
|
---|
| 388 |
|
---|
| 389 | // 3. If this’s guard is "immutable", then throw a TypeError.
|
---|
| 390 | // 4. Otherwise, if this’s guard is "request" and name is a
|
---|
| 391 | // forbidden header name, return.
|
---|
| 392 | // 5. Otherwise, if this’s guard is "request-no-cors" and
|
---|
| 393 | // name/value is not a no-CORS-safelisted request-header,
|
---|
| 394 | // return.
|
---|
| 395 | // 6. Otherwise, if this’s guard is "response" and name is a
|
---|
| 396 | // forbidden response-header name, return.
|
---|
| 397 | // Note: undici does not implement forbidden header names
|
---|
| 398 | if (this[kGuard] === 'immutable') {
|
---|
| 399 | throw new TypeError('immutable')
|
---|
| 400 | } else if (this[kGuard] === 'request-no-cors') {
|
---|
| 401 | // TODO
|
---|
| 402 | }
|
---|
| 403 |
|
---|
| 404 | // 7. Set (name, value) in this’s header list.
|
---|
| 405 | // 8. If this’s guard is "request-no-cors", then remove
|
---|
| 406 | // privileged no-CORS request headers from this
|
---|
| 407 | this[kHeadersList].set(name, value)
|
---|
| 408 | }
|
---|
| 409 |
|
---|
| 410 | // https://fetch.spec.whatwg.org/#dom-headers-getsetcookie
|
---|
| 411 | getSetCookie () {
|
---|
| 412 | webidl.brandCheck(this, Headers)
|
---|
| 413 |
|
---|
| 414 | // 1. If this’s header list does not contain `Set-Cookie`, then return « ».
|
---|
| 415 | // 2. Return the values of all headers in this’s header list whose name is
|
---|
| 416 | // a byte-case-insensitive match for `Set-Cookie`, in order.
|
---|
| 417 |
|
---|
| 418 | const list = this[kHeadersList].cookies
|
---|
| 419 |
|
---|
| 420 | if (list) {
|
---|
| 421 | return [...list]
|
---|
| 422 | }
|
---|
| 423 |
|
---|
| 424 | return []
|
---|
| 425 | }
|
---|
| 426 |
|
---|
| 427 | // https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine
|
---|
| 428 | get [kHeadersSortedMap] () {
|
---|
| 429 | if (this[kHeadersList][kHeadersSortedMap]) {
|
---|
| 430 | return this[kHeadersList][kHeadersSortedMap]
|
---|
| 431 | }
|
---|
| 432 |
|
---|
| 433 | // 1. Let headers be an empty list of headers with the key being the name
|
---|
| 434 | // and value the value.
|
---|
| 435 | const headers = []
|
---|
| 436 |
|
---|
| 437 | // 2. Let names be the result of convert header names to a sorted-lowercase
|
---|
| 438 | // set with all the names of the headers in list.
|
---|
| 439 | const names = [...this[kHeadersList]].sort((a, b) => a[0] < b[0] ? -1 : 1)
|
---|
| 440 | const cookies = this[kHeadersList].cookies
|
---|
| 441 |
|
---|
| 442 | // 3. For each name of names:
|
---|
| 443 | for (let i = 0; i < names.length; ++i) {
|
---|
| 444 | const [name, value] = names[i]
|
---|
| 445 | // 1. If name is `set-cookie`, then:
|
---|
| 446 | if (name === 'set-cookie') {
|
---|
| 447 | // 1. Let values be a list of all values of headers in list whose name
|
---|
| 448 | // is a byte-case-insensitive match for name, in order.
|
---|
| 449 |
|
---|
| 450 | // 2. For each value of values:
|
---|
| 451 | // 1. Append (name, value) to headers.
|
---|
| 452 | for (let j = 0; j < cookies.length; ++j) {
|
---|
| 453 | headers.push([name, cookies[j]])
|
---|
| 454 | }
|
---|
| 455 | } else {
|
---|
| 456 | // 2. Otherwise:
|
---|
| 457 |
|
---|
| 458 | // 1. Let value be the result of getting name from list.
|
---|
| 459 |
|
---|
| 460 | // 2. Assert: value is non-null.
|
---|
| 461 | assert(value !== null)
|
---|
| 462 |
|
---|
| 463 | // 3. Append (name, value) to headers.
|
---|
| 464 | headers.push([name, value])
|
---|
| 465 | }
|
---|
| 466 | }
|
---|
| 467 |
|
---|
| 468 | this[kHeadersList][kHeadersSortedMap] = headers
|
---|
| 469 |
|
---|
| 470 | // 4. Return headers.
|
---|
| 471 | return headers
|
---|
| 472 | }
|
---|
| 473 |
|
---|
| 474 | keys () {
|
---|
| 475 | webidl.brandCheck(this, Headers)
|
---|
| 476 |
|
---|
| 477 | if (this[kGuard] === 'immutable') {
|
---|
| 478 | const value = this[kHeadersSortedMap]
|
---|
| 479 | return makeIterator(() => value, 'Headers',
|
---|
| 480 | 'key')
|
---|
| 481 | }
|
---|
| 482 |
|
---|
| 483 | return makeIterator(
|
---|
| 484 | () => [...this[kHeadersSortedMap].values()],
|
---|
| 485 | 'Headers',
|
---|
| 486 | 'key'
|
---|
| 487 | )
|
---|
| 488 | }
|
---|
| 489 |
|
---|
| 490 | values () {
|
---|
| 491 | webidl.brandCheck(this, Headers)
|
---|
| 492 |
|
---|
| 493 | if (this[kGuard] === 'immutable') {
|
---|
| 494 | const value = this[kHeadersSortedMap]
|
---|
| 495 | return makeIterator(() => value, 'Headers',
|
---|
| 496 | 'value')
|
---|
| 497 | }
|
---|
| 498 |
|
---|
| 499 | return makeIterator(
|
---|
| 500 | () => [...this[kHeadersSortedMap].values()],
|
---|
| 501 | 'Headers',
|
---|
| 502 | 'value'
|
---|
| 503 | )
|
---|
| 504 | }
|
---|
| 505 |
|
---|
| 506 | entries () {
|
---|
| 507 | webidl.brandCheck(this, Headers)
|
---|
| 508 |
|
---|
| 509 | if (this[kGuard] === 'immutable') {
|
---|
| 510 | const value = this[kHeadersSortedMap]
|
---|
| 511 | return makeIterator(() => value, 'Headers',
|
---|
| 512 | 'key+value')
|
---|
| 513 | }
|
---|
| 514 |
|
---|
| 515 | return makeIterator(
|
---|
| 516 | () => [...this[kHeadersSortedMap].values()],
|
---|
| 517 | 'Headers',
|
---|
| 518 | 'key+value'
|
---|
| 519 | )
|
---|
| 520 | }
|
---|
| 521 |
|
---|
| 522 | /**
|
---|
| 523 | * @param {(value: string, key: string, self: Headers) => void} callbackFn
|
---|
| 524 | * @param {unknown} thisArg
|
---|
| 525 | */
|
---|
| 526 | forEach (callbackFn, thisArg = globalThis) {
|
---|
| 527 | webidl.brandCheck(this, Headers)
|
---|
| 528 |
|
---|
| 529 | webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.forEach' })
|
---|
| 530 |
|
---|
| 531 | if (typeof callbackFn !== 'function') {
|
---|
| 532 | throw new TypeError(
|
---|
| 533 | "Failed to execute 'forEach' on 'Headers': parameter 1 is not of type 'Function'."
|
---|
| 534 | )
|
---|
| 535 | }
|
---|
| 536 |
|
---|
| 537 | for (const [key, value] of this) {
|
---|
| 538 | callbackFn.apply(thisArg, [value, key, this])
|
---|
| 539 | }
|
---|
| 540 | }
|
---|
| 541 |
|
---|
| 542 | [Symbol.for('nodejs.util.inspect.custom')] () {
|
---|
| 543 | webidl.brandCheck(this, Headers)
|
---|
| 544 |
|
---|
| 545 | return this[kHeadersList]
|
---|
| 546 | }
|
---|
| 547 | }
|
---|
| 548 |
|
---|
| 549 | Headers.prototype[Symbol.iterator] = Headers.prototype.entries
|
---|
| 550 |
|
---|
| 551 | Object.defineProperties(Headers.prototype, {
|
---|
| 552 | append: kEnumerableProperty,
|
---|
| 553 | delete: kEnumerableProperty,
|
---|
| 554 | get: kEnumerableProperty,
|
---|
| 555 | has: kEnumerableProperty,
|
---|
| 556 | set: kEnumerableProperty,
|
---|
| 557 | getSetCookie: kEnumerableProperty,
|
---|
| 558 | keys: kEnumerableProperty,
|
---|
| 559 | values: kEnumerableProperty,
|
---|
| 560 | entries: kEnumerableProperty,
|
---|
| 561 | forEach: kEnumerableProperty,
|
---|
| 562 | [Symbol.iterator]: { enumerable: false },
|
---|
| 563 | [Symbol.toStringTag]: {
|
---|
| 564 | value: 'Headers',
|
---|
| 565 | configurable: true
|
---|
| 566 | }
|
---|
| 567 | })
|
---|
| 568 |
|
---|
| 569 | webidl.converters.HeadersInit = function (V) {
|
---|
| 570 | if (webidl.util.Type(V) === 'Object') {
|
---|
| 571 | if (V[Symbol.iterator]) {
|
---|
| 572 | return webidl.converters['sequence<sequence<ByteString>>'](V)
|
---|
| 573 | }
|
---|
| 574 |
|
---|
| 575 | return webidl.converters['record<ByteString, ByteString>'](V)
|
---|
| 576 | }
|
---|
| 577 |
|
---|
| 578 | throw webidl.errors.conversionFailed({
|
---|
| 579 | prefix: 'Headers constructor',
|
---|
| 580 | argument: 'Argument 1',
|
---|
| 581 | types: ['sequence<sequence<ByteString>>', 'record<ByteString, ByteString>']
|
---|
| 582 | })
|
---|
| 583 | }
|
---|
| 584 |
|
---|
| 585 | module.exports = {
|
---|
| 586 | fill,
|
---|
| 587 | Headers,
|
---|
| 588 | HeadersList
|
---|
| 589 | }
|
---|