undici 8.8.0 → 8.9.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.
@@ -218,17 +218,62 @@ class MemoryCacheStore extends EventEmitter {
218
218
  }
219
219
 
220
220
  function findEntry (key, entries, now) {
221
- return entries.find((entry) => (
222
- entry.deleteAt > now &&
223
- entry.method === key.method &&
224
- (entry.vary == null || Object.keys(entry.vary).every(headerName => {
225
- if (entry.vary[headerName] === null) {
226
- return key.headers[headerName] === undefined
221
+ for (let i = 0; i < entries.length; i++) {
222
+ const entry = entries[i]
223
+ if (
224
+ entry.deleteAt > now &&
225
+ entry.method === key.method &&
226
+ varyMatches(key, entry)
227
+ ) {
228
+ return entry
229
+ }
230
+ }
231
+ }
232
+
233
+ function varyMatches (key, entry) {
234
+ if (entry.vary == null) {
235
+ return true
236
+ }
237
+
238
+ for (const headerName in entry.vary) {
239
+ if (Object.hasOwn(entry.vary, headerName) && !headerValueEquals(key.headers?.[headerName], entry.vary[headerName])) {
240
+ return false
241
+ }
242
+ }
243
+
244
+ return true
245
+ }
246
+
247
+ /**
248
+ * @param {string|string[]|null|undefined} lhs
249
+ * @param {string|string[]|null|undefined} rhs
250
+ * @returns {boolean}
251
+ */
252
+ function headerValueEquals (lhs, rhs) {
253
+ if (lhs == null && rhs == null) {
254
+ return true
255
+ }
256
+
257
+ if ((lhs == null && rhs != null) ||
258
+ (lhs != null && rhs == null)) {
259
+ return false
260
+ }
261
+
262
+ if (Array.isArray(lhs) && Array.isArray(rhs)) {
263
+ if (lhs.length !== rhs.length) {
264
+ return false
265
+ }
266
+
267
+ for (let i = 0; i < lhs.length; i++) {
268
+ if (lhs[i] !== rhs[i]) {
269
+ return false
227
270
  }
271
+ }
272
+
273
+ return true
274
+ }
228
275
 
229
- return entry.vary[headerName] === key.headers[headerName]
230
- }))
231
- ))
276
+ return lhs === rhs
232
277
  }
233
278
 
234
279
  module.exports = MemoryCacheStore
@@ -456,7 +456,13 @@ function headerValueEquals (lhs, rhs) {
456
456
  return false
457
457
  }
458
458
 
459
- return lhs.every((x, i) => x === rhs[i])
459
+ for (let i = 0; i < lhs.length; i++) {
460
+ if (lhs[i] !== rhs[i]) {
461
+ return false
462
+ }
463
+ }
464
+
465
+ return true
460
466
  }
461
467
 
462
468
  return lhs === rhs
@@ -472,7 +472,13 @@ function processHeader (request, key, val) {
472
472
  } else if (typeof val[i] === 'object') {
473
473
  throw new InvalidArgumentError(`invalid ${key} header`)
474
474
  } else {
475
- arr.push(`${val[i]}`)
475
+ // Coerce primitives (and reject unsafe coercions such as functions
476
+ // with a crafted toString/Symbol.toPrimitive).
477
+ const str = `${val[i]}`
478
+ if (!isValidHeaderValue(str)) {
479
+ throw new InvalidArgumentError(`invalid ${key} header`)
480
+ }
481
+ arr.push(str)
476
482
  }
477
483
  }
478
484
  val = arr
@@ -483,7 +489,12 @@ function processHeader (request, key, val) {
483
489
  } else if (val === null) {
484
490
  val = ''
485
491
  } else {
492
+ // Coerce primitives (and reject unsafe coercions such as functions
493
+ // with a crafted toString/Symbol.toPrimitive).
486
494
  val = `${val}`
495
+ if (!isValidHeaderValue(val)) {
496
+ throw new InvalidArgumentError(`invalid ${key} header`)
497
+ }
487
498
  }
488
499
 
489
500
  if (headerName === 'host') {
@@ -10,6 +10,7 @@ const {
10
10
  RequestContentLengthMismatchError,
11
11
  ResponseContentLengthMismatchError,
12
12
  RequestAbortedError,
13
+ InvalidArgumentError,
13
14
  HeadersTimeoutError,
14
15
  HeadersOverflowError,
15
16
  SocketError,
@@ -1200,8 +1201,16 @@ function writeH1 (client, request) {
1200
1201
  }
1201
1202
  body = bodyStream.stream
1202
1203
  contentLength = bodyStream.length
1203
- } else if (util.isBlobLike(body) && request.contentType == null && body.type) {
1204
- headers.push('content-type', body.type)
1204
+ } else if (util.isBlobLike(body) && request.contentType == null) {
1205
+ const contentType = body.type
1206
+ if (contentType) {
1207
+ const contentTypeValue = `${contentType}`
1208
+ if (!util.isValidHeaderValue(contentTypeValue)) {
1209
+ util.errorRequest(client, request, new InvalidArgumentError('invalid content-type header'))
1210
+ return false
1211
+ }
1212
+ headers.push('content-type', contentTypeValue)
1213
+ }
1205
1214
  }
1206
1215
 
1207
1216
  if (body && typeof body.read === 'function') {
package/lib/global.js CHANGED
@@ -8,6 +8,9 @@ const { InvalidArgumentError } = require('./core/errors')
8
8
  const Agent = require('./dispatcher/agent')
9
9
  const Dispatcher1Wrapper = require('./dispatcher/dispatcher1-wrapper')
10
10
 
11
+ // Fallback storage for when globalThis is not extensible (e.g. frozen)
12
+ let fallbackDispatcher
13
+
11
14
  if (getGlobalDispatcher() === undefined) {
12
15
  setGlobalDispatcher(new Agent())
13
16
  }
@@ -17,25 +20,42 @@ function setGlobalDispatcher (agent) {
17
20
  throw new InvalidArgumentError('Argument agent must implement Agent')
18
21
  }
19
22
 
20
- Object.defineProperty(globalThis, globalDispatcher, {
21
- value: agent,
22
- writable: true,
23
- enumerable: false,
24
- configurable: false
25
- })
26
-
27
- const legacyAgent = agent instanceof Dispatcher1Wrapper ? agent : new Dispatcher1Wrapper(agent)
28
-
29
- Object.defineProperty(globalThis, legacyGlobalDispatcher, {
30
- value: legacyAgent,
31
- writable: true,
32
- enumerable: false,
33
- configurable: false
34
- })
23
+ try {
24
+ Object.defineProperty(globalThis, globalDispatcher, {
25
+ value: agent,
26
+ writable: true,
27
+ enumerable: false,
28
+ configurable: false
29
+ })
30
+ } catch (err) {
31
+ // globalThis is not extensible (e.g. Object.freeze(globalThis))
32
+ // Use fallback storage instead
33
+ if (err instanceof TypeError) {
34
+ fallbackDispatcher = agent
35
+ return
36
+ }
37
+ throw err
38
+ }
39
+
40
+ try {
41
+ const legacyAgent = agent instanceof Dispatcher1Wrapper ? agent : new Dispatcher1Wrapper(agent)
42
+
43
+ Object.defineProperty(globalThis, legacyGlobalDispatcher, {
44
+ value: legacyAgent,
45
+ writable: true,
46
+ enumerable: false,
47
+ configurable: false
48
+ })
49
+ } catch (err) {
50
+ // globalThis is not extensible; fallback storage is already set
51
+ if (!(err instanceof TypeError)) {
52
+ throw err
53
+ }
54
+ }
35
55
  }
36
56
 
37
57
  function getGlobalDispatcher () {
38
- return globalThis[globalDispatcher]
58
+ return globalThis[globalDispatcher] ?? fallbackDispatcher
39
59
  }
40
60
 
41
61
  // These are the globals that can be installed by undici.install().