undici 5.26.4 → 5.27.0

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/index-fetch.js CHANGED
@@ -2,13 +2,11 @@
2
2
 
3
3
  const fetchImpl = require('./lib/fetch').fetch
4
4
 
5
- module.exports.fetch = async function fetch (resource, init = undefined) {
6
- try {
7
- return await fetchImpl(resource, init)
8
- } catch (err) {
5
+ module.exports.fetch = function fetch (resource, init = undefined) {
6
+ return fetchImpl(resource, init).catch((err) => {
9
7
  Error.captureStackTrace(err, this)
10
8
  throw err
11
- }
9
+ })
12
10
  }
13
11
  module.exports.FormData = require('./lib/fetch/formdata').FormData
14
12
  module.exports.Headers = require('./lib/fetch/headers').Headers
@@ -222,6 +222,14 @@ class Request {
222
222
  if (channels.bodySent.hasSubscribers) {
223
223
  channels.bodySent.publish({ request: this })
224
224
  }
225
+
226
+ if (this[kHandler].onRequestSent) {
227
+ try {
228
+ this[kHandler].onRequestSent()
229
+ } catch (err) {
230
+ this.onError(err)
231
+ }
232
+ }
225
233
  }
226
234
 
227
235
  onConnect (abort) {
package/lib/fetch/body.js CHANGED
@@ -26,6 +26,8 @@ let ReadableStream = globalThis.ReadableStream
26
26
 
27
27
  /** @type {globalThis['File']} */
28
28
  const File = NativeFile ?? UndiciFile
29
+ const textEncoder = new TextEncoder()
30
+ const textDecoder = new TextDecoder()
29
31
 
30
32
  // https://fetch.spec.whatwg.org/#concept-bodyinit-extract
31
33
  function extractBody (object, keepalive = false) {
@@ -49,7 +51,7 @@ function extractBody (object, keepalive = false) {
49
51
  stream = new ReadableStream({
50
52
  async pull (controller) {
51
53
  controller.enqueue(
52
- typeof source === 'string' ? new TextEncoder().encode(source) : source
54
+ typeof source === 'string' ? textEncoder.encode(source) : source
53
55
  )
54
56
  queueMicrotask(() => readableStreamClose(controller))
55
57
  },
@@ -119,7 +121,6 @@ function extractBody (object, keepalive = false) {
119
121
  // - That the content-length is calculated in advance.
120
122
  // - And that all parts are pre-encoded and ready to be sent.
121
123
 
122
- const enc = new TextEncoder()
123
124
  const blobParts = []
124
125
  const rn = new Uint8Array([13, 10]) // '\r\n'
125
126
  length = 0
@@ -127,13 +128,13 @@ function extractBody (object, keepalive = false) {
127
128
 
128
129
  for (const [name, value] of object) {
129
130
  if (typeof value === 'string') {
130
- const chunk = enc.encode(prefix +
131
+ const chunk = textEncoder.encode(prefix +
131
132
  `; name="${escape(normalizeLinefeeds(name))}"` +
132
133
  `\r\n\r\n${normalizeLinefeeds(value)}\r\n`)
133
134
  blobParts.push(chunk)
134
135
  length += chunk.byteLength
135
136
  } else {
136
- const chunk = enc.encode(`${prefix}; name="${escape(normalizeLinefeeds(name))}"` +
137
+ const chunk = textEncoder.encode(`${prefix}; name="${escape(normalizeLinefeeds(name))}"` +
137
138
  (value.name ? `; filename="${escape(value.name)}"` : '') + '\r\n' +
138
139
  `Content-Type: ${
139
140
  value.type || 'application/octet-stream'
@@ -147,7 +148,7 @@ function extractBody (object, keepalive = false) {
147
148
  }
148
149
  }
149
150
 
150
- const chunk = enc.encode(`--${boundary}--`)
151
+ const chunk = textEncoder.encode(`--${boundary}--`)
151
152
  blobParts.push(chunk)
152
153
  length += chunk.byteLength
153
154
  if (hasUnknownSizeValue) {
@@ -443,14 +444,16 @@ function bodyMixinMethods (instance) {
443
444
  let text = ''
444
445
  // application/x-www-form-urlencoded parser will keep the BOM.
445
446
  // https://url.spec.whatwg.org/#concept-urlencoded-parser
446
- const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true })
447
+ // Note that streaming decoder is stateful and cannot be reused
448
+ const streamingDecoder = new TextDecoder('utf-8', { ignoreBOM: true })
449
+
447
450
  for await (const chunk of consumeBody(this[kState].body)) {
448
451
  if (!isUint8Array(chunk)) {
449
452
  throw new TypeError('Expected Uint8Array chunk')
450
453
  }
451
- text += textDecoder.decode(chunk, { stream: true })
454
+ text += streamingDecoder.decode(chunk, { stream: true })
452
455
  }
453
- text += textDecoder.decode()
456
+ text += streamingDecoder.decode()
454
457
  entries = new URLSearchParams(text)
455
458
  } catch (err) {
456
459
  // istanbul ignore next: Unclear when new URLSearchParams can fail on a string.
@@ -565,7 +568,7 @@ function utf8DecodeBytes (buffer) {
565
568
 
566
569
  // 3. Process a queue with an instance of UTF-8’s
567
570
  // decoder, ioQueue, output, and "replacement".
568
- const output = new TextDecoder().decode(buffer)
571
+ const output = textDecoder.decode(buffer)
569
572
 
570
573
  // 4. Return output.
571
574
  return output
@@ -3,10 +3,12 @@
3
3
  const { MessageChannel, receiveMessageOnPort } = require('worker_threads')
4
4
 
5
5
  const corsSafeListedMethods = ['GET', 'HEAD', 'POST']
6
+ const corsSafeListedMethodsSet = new Set(corsSafeListedMethods)
6
7
 
7
8
  const nullBodyStatus = [101, 204, 205, 304]
8
9
 
9
10
  const redirectStatus = [301, 302, 303, 307, 308]
11
+ const redirectStatusSet = new Set(redirectStatus)
10
12
 
11
13
  // https://fetch.spec.whatwg.org/#block-bad-port
12
14
  const badPorts = [
@@ -18,6 +20,8 @@ const badPorts = [
18
20
  '10080'
19
21
  ]
20
22
 
23
+ const badPortsSet = new Set(badPorts)
24
+
21
25
  // https://w3c.github.io/webappsec-referrer-policy/#referrer-policies
22
26
  const referrerPolicy = [
23
27
  '',
@@ -30,10 +34,12 @@ const referrerPolicy = [
30
34
  'strict-origin-when-cross-origin',
31
35
  'unsafe-url'
32
36
  ]
37
+ const referrerPolicySet = new Set(referrerPolicy)
33
38
 
34
39
  const requestRedirect = ['follow', 'manual', 'error']
35
40
 
36
41
  const safeMethods = ['GET', 'HEAD', 'OPTIONS', 'TRACE']
42
+ const safeMethodsSet = new Set(safeMethods)
37
43
 
38
44
  const requestMode = ['navigate', 'same-origin', 'no-cors', 'cors']
39
45
 
@@ -68,6 +74,7 @@ const requestDuplex = [
68
74
 
69
75
  // http://fetch.spec.whatwg.org/#forbidden-method
70
76
  const forbiddenMethods = ['CONNECT', 'TRACE', 'TRACK']
77
+ const forbiddenMethodsSet = new Set(forbiddenMethods)
71
78
 
72
79
  const subresource = [
73
80
  'audio',
@@ -83,6 +90,7 @@ const subresource = [
83
90
  'xslt',
84
91
  ''
85
92
  ]
93
+ const subresourceSet = new Set(subresource)
86
94
 
87
95
  /** @type {globalThis['DOMException']} */
88
96
  const DOMException = globalThis.DOMException ?? (() => {
@@ -132,5 +140,12 @@ module.exports = {
132
140
  nullBodyStatus,
133
141
  safeMethods,
134
142
  badPorts,
135
- requestDuplex
143
+ requestDuplex,
144
+ subresourceSet,
145
+ badPortsSet,
146
+ redirectStatusSet,
147
+ corsSafeListedMethodsSet,
148
+ safeMethodsSet,
149
+ forbiddenMethodsSet,
150
+ referrerPolicySet
136
151
  }
package/lib/fetch/file.js CHANGED
@@ -7,6 +7,7 @@ const { isBlobLike } = require('./util')
7
7
  const { webidl } = require('./webidl')
8
8
  const { parseMIMEType, serializeAMimeType } = require('./dataURL')
9
9
  const { kEnumerableProperty } = require('../core/util')
10
+ const encoder = new TextEncoder()
10
11
 
11
12
  class File extends Blob {
12
13
  constructor (fileBits, fileName, options = {}) {
@@ -280,7 +281,7 @@ function processBlobParts (parts, options) {
280
281
  }
281
282
 
282
283
  // 3. Append the result of UTF-8 encoding s to bytes.
283
- bytes.push(new TextEncoder().encode(s))
284
+ bytes.push(encoder.encode(s))
284
285
  } else if (
285
286
  types.isAnyArrayBuffer(element) ||
286
287
  types.isTypedArray(element)
@@ -46,11 +46,11 @@ const { kState, kHeaders, kGuard, kRealm } = require('./symbols')
46
46
  const assert = require('assert')
47
47
  const { safelyExtractBody } = require('./body')
48
48
  const {
49
- redirectStatus,
49
+ redirectStatusSet,
50
50
  nullBodyStatus,
51
- safeMethods,
51
+ safeMethodsSet,
52
52
  requestBodyHeader,
53
- subresource,
53
+ subresourceSet,
54
54
  DOMException
55
55
  } = require('./constants')
56
56
  const { kHeadersList } = require('../core/symbols')
@@ -62,6 +62,7 @@ const { TransformStream } = require('stream/web')
62
62
  const { getGlobalDispatcher } = require('../global')
63
63
  const { webidl } = require('./webidl')
64
64
  const { STATUS_CODES } = require('http')
65
+ const GET_OR_HEAD = ['GET', 'HEAD']
65
66
 
66
67
  /** @type {import('buffer').resolveObjectURL} */
67
68
  let resolveObjectURL
@@ -121,7 +122,7 @@ class Fetch extends EE {
121
122
  }
122
123
 
123
124
  // https://fetch.spec.whatwg.org/#fetch-method
124
- async function fetch (input, init = {}) {
125
+ function fetch (input, init = {}) {
125
126
  webidl.argumentLengthCheck(arguments, 1, { header: 'globalThis.fetch' })
126
127
 
127
128
  // 1. Let p be a new promise.
@@ -204,7 +205,7 @@ async function fetch (input, init = {}) {
204
205
  const processResponse = (response) => {
205
206
  // 1. If locallyAborted is true, terminate these substeps.
206
207
  if (locallyAborted) {
207
- return
208
+ return Promise.resolve()
208
209
  }
209
210
 
210
211
  // 2. If response’s aborted flag is set, then:
@@ -217,7 +218,7 @@ async function fetch (input, init = {}) {
217
218
  // deserializedError.
218
219
 
219
220
  abortFetch(p, request, responseObject, controller.serializedAbortReason)
220
- return
221
+ return Promise.resolve()
221
222
  }
222
223
 
223
224
  // 3. If response is a network error, then reject p with a TypeError
@@ -226,7 +227,7 @@ async function fetch (input, init = {}) {
226
227
  p.reject(
227
228
  Object.assign(new TypeError('fetch failed'), { cause: response.error })
228
229
  )
229
- return
230
+ return Promise.resolve()
230
231
  }
231
232
 
232
233
  // 4. Set responseObject to the result of creating a Response object,
@@ -509,7 +510,7 @@ function fetching ({
509
510
  }
510
511
 
511
512
  // 15. If request is a subresource request, then:
512
- if (subresource.includes(request.destination)) {
513
+ if (subresourceSet.has(request.destination)) {
513
514
  // TODO
514
515
  }
515
516
 
@@ -776,13 +777,13 @@ async function mainFetch (fetchParams, recursive = false) {
776
777
 
777
778
  // https://fetch.spec.whatwg.org/#concept-scheme-fetch
778
779
  // given a fetch params fetchParams
779
- async function schemeFetch (fetchParams) {
780
+ function schemeFetch (fetchParams) {
780
781
  // Note: since the connection is destroyed on redirect, which sets fetchParams to a
781
782
  // cancelled state, we do not want this condition to trigger *unless* there have been
782
783
  // no redirects. See https://github.com/nodejs/undici/issues/1776
783
784
  // 1. If fetchParams is canceled, then return the appropriate network error for fetchParams.
784
785
  if (isCancelled(fetchParams) && fetchParams.request.redirectCount === 0) {
785
- return makeAppropriateNetworkError(fetchParams)
786
+ return Promise.resolve(makeAppropriateNetworkError(fetchParams))
786
787
  }
787
788
 
788
789
  // 2. Let request be fetchParams’s request.
@@ -798,7 +799,7 @@ async function schemeFetch (fetchParams) {
798
799
  // and body is the empty byte sequence as a body.
799
800
 
800
801
  // Otherwise, return a network error.
801
- return makeNetworkError('about scheme is not supported')
802
+ return Promise.resolve(makeNetworkError('about scheme is not supported'))
802
803
  }
803
804
  case 'blob:': {
804
805
  if (!resolveObjectURL) {
@@ -811,7 +812,7 @@ async function schemeFetch (fetchParams) {
811
812
  // https://github.com/web-platform-tests/wpt/blob/7b0ebaccc62b566a1965396e5be7bb2bc06f841f/FileAPI/url/resources/fetch-tests.js#L52-L56
812
813
  // Buffer.resolveObjectURL does not ignore URL queries.
813
814
  if (blobURLEntry.search.length !== 0) {
814
- return makeNetworkError('NetworkError when attempting to fetch resource.')
815
+ return Promise.resolve(makeNetworkError('NetworkError when attempting to fetch resource.'))
815
816
  }
816
817
 
817
818
  const blobURLEntryObject = resolveObjectURL(blobURLEntry.toString())
@@ -819,7 +820,7 @@ async function schemeFetch (fetchParams) {
819
820
  // 2. If request’s method is not `GET`, blobURLEntry is null, or blobURLEntry’s
820
821
  // object is not a Blob object, then return a network error.
821
822
  if (request.method !== 'GET' || !isBlobLike(blobURLEntryObject)) {
822
- return makeNetworkError('invalid method')
823
+ return Promise.resolve(makeNetworkError('invalid method'))
823
824
  }
824
825
 
825
826
  // 3. Let bodyWithType be the result of safely extracting blobURLEntry’s object.
@@ -846,7 +847,7 @@ async function schemeFetch (fetchParams) {
846
847
 
847
848
  response.body = body
848
849
 
849
- return response
850
+ return Promise.resolve(response)
850
851
  }
851
852
  case 'data:': {
852
853
  // 1. Let dataURLStruct be the result of running the
@@ -857,7 +858,7 @@ async function schemeFetch (fetchParams) {
857
858
  // 2. If dataURLStruct is failure, then return a
858
859
  // network error.
859
860
  if (dataURLStruct === 'failure') {
860
- return makeNetworkError('failed to fetch the data URL')
861
+ return Promise.resolve(makeNetworkError('failed to fetch the data URL'))
861
862
  }
862
863
 
863
864
  // 3. Let mimeType be dataURLStruct’s MIME type, serialized.
@@ -866,28 +867,28 @@ async function schemeFetch (fetchParams) {
866
867
  // 4. Return a response whose status message is `OK`,
867
868
  // header list is « (`Content-Type`, mimeType) »,
868
869
  // and body is dataURLStruct’s body as a body.
869
- return makeResponse({
870
+ return Promise.resolve(makeResponse({
870
871
  statusText: 'OK',
871
872
  headersList: [
872
873
  ['content-type', { name: 'Content-Type', value: mimeType }]
873
874
  ],
874
875
  body: safelyExtractBody(dataURLStruct.body)[0]
875
- })
876
+ }))
876
877
  }
877
878
  case 'file:': {
878
879
  // For now, unfortunate as it is, file URLs are left as an exercise for the reader.
879
880
  // When in doubt, return a network error.
880
- return makeNetworkError('not implemented... yet...')
881
+ return Promise.resolve(makeNetworkError('not implemented... yet...'))
881
882
  }
882
883
  case 'http:':
883
884
  case 'https:': {
884
885
  // Return the result of running HTTP fetch given fetchParams.
885
886
 
886
- return await httpFetch(fetchParams)
887
+ return httpFetch(fetchParams)
887
888
  .catch((err) => makeNetworkError(err))
888
889
  }
889
890
  default: {
890
- return makeNetworkError('unknown scheme')
891
+ return Promise.resolve(makeNetworkError('unknown scheme'))
891
892
  }
892
893
  }
893
894
  }
@@ -906,7 +907,7 @@ function finalizeResponse (fetchParams, response) {
906
907
  }
907
908
 
908
909
  // https://fetch.spec.whatwg.org/#fetch-finale
909
- async function fetchFinale (fetchParams, response) {
910
+ function fetchFinale (fetchParams, response) {
910
911
  // 1. If response is a network error, then:
911
912
  if (response.type === 'error') {
912
913
  // 1. Set response’s URL list to « fetchParams’s request’s URL list[0] ».
@@ -990,8 +991,9 @@ async function fetchFinale (fetchParams, response) {
990
991
  } else {
991
992
  // 4. Otherwise, fully read response’s body given processBody, processBodyError,
992
993
  // and fetchParams’s task destination.
993
- await fullyReadBody(response.body, processBody, processBodyError)
994
+ return fullyReadBody(response.body, processBody, processBodyError)
994
995
  }
996
+ return Promise.resolve()
995
997
  }
996
998
  }
997
999
 
@@ -1062,7 +1064,7 @@ async function httpFetch (fetchParams) {
1062
1064
  }
1063
1065
 
1064
1066
  // 8. If actualResponse’s status is a redirect status, then:
1065
- if (redirectStatus.includes(actualResponse.status)) {
1067
+ if (redirectStatusSet.has(actualResponse.status)) {
1066
1068
  // 1. If actualResponse’s status is not 303, request’s body is not null,
1067
1069
  // and the connection uses HTTP/2, then user agents may, and are even
1068
1070
  // encouraged to, transmit an RST_STREAM frame.
@@ -1099,7 +1101,7 @@ async function httpFetch (fetchParams) {
1099
1101
  }
1100
1102
 
1101
1103
  // https://fetch.spec.whatwg.org/#http-redirect-fetch
1102
- async function httpRedirectFetch (fetchParams, response) {
1104
+ function httpRedirectFetch (fetchParams, response) {
1103
1105
  // 1. Let request be fetchParams’s request.
1104
1106
  const request = fetchParams.request
1105
1107
 
@@ -1125,18 +1127,18 @@ async function httpRedirectFetch (fetchParams, response) {
1125
1127
  }
1126
1128
  } catch (err) {
1127
1129
  // 5. If locationURL is failure, then return a network error.
1128
- return makeNetworkError(err)
1130
+ return Promise.resolve(makeNetworkError(err))
1129
1131
  }
1130
1132
 
1131
1133
  // 6. If locationURL’s scheme is not an HTTP(S) scheme, then return a network
1132
1134
  // error.
1133
1135
  if (!urlIsHttpHttpsScheme(locationURL)) {
1134
- return makeNetworkError('URL scheme must be a HTTP(S) scheme')
1136
+ return Promise.resolve(makeNetworkError('URL scheme must be a HTTP(S) scheme'))
1135
1137
  }
1136
1138
 
1137
1139
  // 7. If request’s redirect count is 20, then return a network error.
1138
1140
  if (request.redirectCount === 20) {
1139
- return makeNetworkError('redirect count exceeded')
1141
+ return Promise.resolve(makeNetworkError('redirect count exceeded'))
1140
1142
  }
1141
1143
 
1142
1144
  // 8. Increase request’s redirect count by 1.
@@ -1150,7 +1152,7 @@ async function httpRedirectFetch (fetchParams, response) {
1150
1152
  (locationURL.username || locationURL.password) &&
1151
1153
  !sameOrigin(request, locationURL)
1152
1154
  ) {
1153
- return makeNetworkError('cross origin not allowed for request mode "cors"')
1155
+ return Promise.resolve(makeNetworkError('cross origin not allowed for request mode "cors"'))
1154
1156
  }
1155
1157
 
1156
1158
  // 10. If request’s response tainting is "cors" and locationURL includes
@@ -1159,9 +1161,9 @@ async function httpRedirectFetch (fetchParams, response) {
1159
1161
  request.responseTainting === 'cors' &&
1160
1162
  (locationURL.username || locationURL.password)
1161
1163
  ) {
1162
- return makeNetworkError(
1164
+ return Promise.resolve(makeNetworkError(
1163
1165
  'URL cannot contain credentials for request mode "cors"'
1164
- )
1166
+ ))
1165
1167
  }
1166
1168
 
1167
1169
  // 11. If actualResponse’s status is not 303, request’s body is non-null,
@@ -1171,7 +1173,7 @@ async function httpRedirectFetch (fetchParams, response) {
1171
1173
  request.body != null &&
1172
1174
  request.body.source == null
1173
1175
  ) {
1174
- return makeNetworkError()
1176
+ return Promise.resolve(makeNetworkError())
1175
1177
  }
1176
1178
 
1177
1179
  // 12. If one of the following is true
@@ -1180,7 +1182,7 @@ async function httpRedirectFetch (fetchParams, response) {
1180
1182
  if (
1181
1183
  ([301, 302].includes(actualResponse.status) && request.method === 'POST') ||
1182
1184
  (actualResponse.status === 303 &&
1183
- !['GET', 'HEAD'].includes(request.method))
1185
+ !GET_OR_HEAD.includes(request.method))
1184
1186
  ) {
1185
1187
  // then:
1186
1188
  // 1. Set request’s method to `GET` and request’s body to null.
@@ -1464,7 +1466,7 @@ async function httpNetworkOrCacheFetch (
1464
1466
  // responses in httpCache, as per the "Invalidation" chapter of HTTP
1465
1467
  // Caching, and set storedResponse to null. [HTTP-CACHING]
1466
1468
  if (
1467
- !safeMethods.includes(httpRequest.method) &&
1469
+ !safeMethodsSet.has(httpRequest.method) &&
1468
1470
  forwardResponse.status >= 200 &&
1469
1471
  forwardResponse.status <= 399
1470
1472
  ) {
@@ -2024,7 +2026,7 @@ async function httpNetworkFetch (
2024
2026
 
2025
2027
  const willFollow = request.redirect === 'follow' &&
2026
2028
  location &&
2027
- redirectStatus.includes(status)
2029
+ redirectStatusSet.has(status)
2028
2030
 
2029
2031
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
2030
2032
  if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) {
@@ -13,8 +13,8 @@ const {
13
13
  makePolicyContainer
14
14
  } = require('./util')
15
15
  const {
16
- forbiddenMethods,
17
- corsSafeListedMethods,
16
+ forbiddenMethodsSet,
17
+ corsSafeListedMethodsSet,
18
18
  referrerPolicy,
19
19
  requestRedirect,
20
20
  requestMode,
@@ -319,7 +319,7 @@ class Request {
319
319
  throw TypeError(`'${init.method}' is not a valid HTTP method.`)
320
320
  }
321
321
 
322
- if (forbiddenMethods.indexOf(method.toUpperCase()) !== -1) {
322
+ if (forbiddenMethodsSet.has(method.toUpperCase())) {
323
323
  throw TypeError(`'${init.method}' HTTP method is unsupported.`)
324
324
  }
325
325
 
@@ -404,7 +404,7 @@ class Request {
404
404
  if (mode === 'no-cors') {
405
405
  // 1. If this’s request’s method is not a CORS-safelisted method,
406
406
  // then throw a TypeError.
407
- if (!corsSafeListedMethods.includes(request.method)) {
407
+ if (!corsSafeListedMethodsSet.has(request.method)) {
408
408
  throw new TypeError(
409
409
  `'${request.method} is unsupported in no-cors mode.`
410
410
  )
@@ -14,7 +14,7 @@ const {
14
14
  isomorphicEncode
15
15
  } = require('./util')
16
16
  const {
17
- redirectStatus,
17
+ redirectStatusSet,
18
18
  nullBodyStatus,
19
19
  DOMException
20
20
  } = require('./constants')
@@ -28,6 +28,7 @@ const assert = require('assert')
28
28
  const { types } = require('util')
29
29
 
30
30
  const ReadableStream = globalThis.ReadableStream || require('stream/web').ReadableStream
31
+ const textEncoder = new TextEncoder('utf-8')
31
32
 
32
33
  // https://fetch.spec.whatwg.org/#response-class
33
34
  class Response {
@@ -57,7 +58,7 @@ class Response {
57
58
  }
58
59
 
59
60
  // 1. Let bytes the result of running serialize a JavaScript value to JSON bytes on data.
60
- const bytes = new TextEncoder('utf-8').encode(
61
+ const bytes = textEncoder.encode(
61
62
  serializeJavascriptValueToJSONString(data)
62
63
  )
63
64
 
@@ -102,7 +103,7 @@ class Response {
102
103
  }
103
104
 
104
105
  // 3. If status is not a redirect status, then throw a RangeError.
105
- if (!redirectStatus.includes(status)) {
106
+ if (!redirectStatusSet.has(status)) {
106
107
  throw new RangeError('Invalid status code ' + status)
107
108
  }
108
109
 
package/lib/fetch/util.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { redirectStatus, badPorts, referrerPolicy: referrerPolicyTokens } = require('./constants')
3
+ const { redirectStatusSet, referrerPolicySet: referrerPolicyTokens, badPortsSet } = require('./constants')
4
4
  const { getGlobalOrigin } = require('./global')
5
5
  const { performance } = require('perf_hooks')
6
6
  const { isBlobLike, toUSVString, ReadableStreamFrom } = require('../core/util')
@@ -29,7 +29,7 @@ function responseURL (response) {
29
29
  // https://fetch.spec.whatwg.org/#concept-response-location-url
30
30
  function responseLocationURL (response, requestFragment) {
31
31
  // 1. If response’s status is not a redirect status, then return null.
32
- if (!redirectStatus.includes(response.status)) {
32
+ if (!redirectStatusSet.has(response.status)) {
33
33
  return null
34
34
  }
35
35
 
@@ -64,7 +64,7 @@ function requestBadPort (request) {
64
64
 
65
65
  // 2. If url’s scheme is an HTTP(S) scheme and url’s port is a bad port,
66
66
  // then return blocked.
67
- if (urlIsHttpHttpsScheme(url) && badPorts.includes(url.port)) {
67
+ if (urlIsHttpHttpsScheme(url) && badPortsSet.has(url.port)) {
68
68
  return 'blocked'
69
69
  }
70
70
 
@@ -206,7 +206,7 @@ function setRequestReferrerPolicyOnRedirect (request, actualResponse) {
206
206
  // The left-most policy is the fallback.
207
207
  for (let i = policyHeader.length; i !== 0; i--) {
208
208
  const token = policyHeader[i - 1].trim()
209
- if (referrerPolicyTokens.includes(token)) {
209
+ if (referrerPolicyTokens.has(token)) {
210
210
  policy = token
211
211
  break
212
212
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "undici",
3
- "version": "5.26.4",
3
+ "version": "5.27.0",
4
4
  "description": "An HTTP/1.1 client, written from scratch for Node.js",
5
5
  "homepage": "https://undici.nodejs.org",
6
6
  "bugs": {
@@ -84,7 +84,7 @@
84
84
  "test:tdd": "tap test/*.js test/diagnostics-channel/*.js -w",
85
85
  "test:typescript": "node scripts/verifyVersion.js 14 || tsd && tsc --skipLibCheck test/imports/undici-import.ts",
86
86
  "test:websocket": "node scripts/verifyVersion.js 18 || tap test/websocket/*.js",
87
- "test:wpt": "node scripts/verifyVersion 18 || (node test/wpt/start-fetch.mjs && node test/wpt/start-FileAPI.mjs && node test/wpt/start-mimesniff.mjs && node test/wpt/start-xhr.mjs && node --no-warnings --expose-internals test/wpt/start-websockets.mjs)",
87
+ "test:wpt": "node scripts/verifyVersion 18 || (node test/wpt/start-fetch.mjs && node test/wpt/start-FileAPI.mjs && node test/wpt/start-mimesniff.mjs && node test/wpt/start-xhr.mjs && node test/wpt/start-websockets.mjs)",
88
88
  "coverage": "nyc --reporter=text --reporter=html npm run test",
89
89
  "coverage:ci": "nyc --reporter=lcov npm run test",
90
90
  "bench": "PORT=3042 concurrently -k -s first npm:bench:server npm:bench:run",
package/types/index.d.ts CHANGED
@@ -53,5 +53,11 @@ declare namespace Undici {
53
53
  var MockAgent: typeof import('./mock-agent').default;
54
54
  var mockErrors: typeof import('./mock-errors').default;
55
55
  var fetch: typeof import('./fetch').fetch;
56
+ var Headers: typeof import('./fetch').Headers;
57
+ var Response: typeof import('./fetch').Response;
58
+ var Request: typeof import('./fetch').Request;
59
+ var FormData: typeof import('./formdata').FormData;
60
+ var File: typeof import('./file').File;
61
+ var FileReader: typeof import('./filereader').FileReader;
56
62
  var caches: typeof import('./cache').caches;
57
63
  }