undici 8.0.3 → 8.2.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.
Files changed (54) hide show
  1. package/docs/docs/api/Client.md +2 -0
  2. package/docs/docs/api/Dispatcher.md +2 -2
  3. package/lib/api/api-connect.js +1 -1
  4. package/lib/api/api-pipeline.js +2 -2
  5. package/lib/api/api-request.js +2 -2
  6. package/lib/api/api-stream.js +1 -1
  7. package/lib/api/api-upgrade.js +8 -2
  8. package/lib/api/readable.js +3 -2
  9. package/lib/cache/memory-cache-store.js +1 -1
  10. package/lib/cache/sqlite-cache-store.js +6 -4
  11. package/lib/core/connect.js +16 -0
  12. package/lib/core/constants.js +1 -24
  13. package/lib/core/errors.js +2 -2
  14. package/lib/core/request.js +17 -2
  15. package/lib/core/socks5-client.js +24 -9
  16. package/lib/core/socks5-utils.js +32 -23
  17. package/lib/core/util.js +28 -3
  18. package/lib/dispatcher/agent.js +38 -40
  19. package/lib/dispatcher/balanced-pool.js +21 -23
  20. package/lib/dispatcher/client-h1.js +34 -16
  21. package/lib/dispatcher/client-h2.js +400 -147
  22. package/lib/dispatcher/client.js +3 -2
  23. package/lib/dispatcher/dispatcher-base.js +18 -0
  24. package/lib/dispatcher/h2c-client.js +4 -4
  25. package/lib/dispatcher/pool-base.js +6 -6
  26. package/lib/dispatcher/pool.js +8 -3
  27. package/lib/dispatcher/proxy-agent.js +2 -0
  28. package/lib/dispatcher/round-robin-pool.js +5 -6
  29. package/lib/dispatcher/socks5-proxy-agent.js +23 -14
  30. package/lib/handler/cache-handler.js +1 -1
  31. package/lib/handler/redirect-handler.js +4 -0
  32. package/lib/interceptor/redirect.js +3 -3
  33. package/lib/llhttp/llhttp-wasm.js +1 -1
  34. package/lib/llhttp/llhttp_simd-wasm.js +1 -1
  35. package/lib/mock/mock-agent.js +8 -8
  36. package/lib/mock/mock-call-history.js +15 -15
  37. package/lib/util/cache.js +1 -1
  38. package/lib/web/eventsource/eventsource-stream.js +245 -150
  39. package/lib/web/fetch/formdata-parser.js +17 -6
  40. package/lib/web/fetch/index.js +38 -28
  41. package/lib/web/webidl/index.js +5 -5
  42. package/lib/web/websocket/frame.js +1 -7
  43. package/lib/web/websocket/permessage-deflate.js +13 -31
  44. package/lib/web/websocket/receiver.js +62 -22
  45. package/lib/web/websocket/stream/websocketstream.js +6 -5
  46. package/lib/web/websocket/websocket.js +6 -1
  47. package/package.json +1 -1
  48. package/types/client.d.ts +11 -0
  49. package/types/dispatcher.d.ts +4 -4
  50. package/types/header.d.ts +5 -0
  51. package/types/interceptors.d.ts +1 -1
  52. package/types/proxy-agent.d.ts +2 -2
  53. package/types/socks5-proxy-agent.d.ts +2 -2
  54. package/lib/llhttp/.gitkeep +0 -0
@@ -164,35 +164,14 @@ class BalancedPool extends PoolBase {
164
164
  throw new BalancedPoolMissingUpstreamError()
165
165
  }
166
166
 
167
- const dispatcher = this[kClients].find(dispatcher => (
168
- !dispatcher[kNeedDrain] &&
169
- dispatcher.closed !== true &&
170
- dispatcher.destroyed !== true
171
- ))
172
-
173
- if (!dispatcher) {
174
- return
175
- }
176
-
177
- const allClientsBusy = this[kClients].map(pool => pool[kNeedDrain]).reduce((a, b) => a && b, true)
178
-
179
- if (allClientsBusy) {
180
- return
181
- }
182
-
183
167
  let counter = 0
184
168
 
185
- let maxWeightIndex = this[kClients].findIndex(pool => !pool[kNeedDrain])
169
+ let maxWeightIndex = -1
186
170
 
187
171
  while (counter++ < this[kClients].length) {
188
172
  this[kIndex] = (this[kIndex] + 1) % this[kClients].length
189
173
  const pool = this[kClients][this[kIndex]]
190
174
 
191
- // find pool index with the largest weight
192
- if (pool[kWeight] > this[kClients][maxWeightIndex][kWeight] && !pool[kNeedDrain]) {
193
- maxWeightIndex = this[kIndex]
194
- }
195
-
196
175
  // decrease the current weight every `this[kClients].length`.
197
176
  if (this[kIndex] === 0) {
198
177
  // Set the current weight to the next lower weight.
@@ -202,11 +181,30 @@ class BalancedPool extends PoolBase {
202
181
  this[kCurrentWeight] = this[kMaxWeightPerServer]
203
182
  }
204
183
  }
205
- if (pool[kWeight] >= this[kCurrentWeight] && (!pool[kNeedDrain])) {
184
+
185
+ // Skip unavailable pools after updating the current weight for this cycle.
186
+ if (
187
+ pool[kNeedDrain] ||
188
+ pool.closed === true ||
189
+ pool.destroyed === true
190
+ ) {
191
+ continue
192
+ }
193
+
194
+ // Track the best fallback if no pool matches the current weight.
195
+ if (maxWeightIndex === -1 || pool[kWeight] > this[kClients][maxWeightIndex][kWeight]) {
196
+ maxWeightIndex = this[kIndex]
197
+ }
198
+
199
+ if (pool[kWeight] >= this[kCurrentWeight]) {
206
200
  return pool
207
201
  }
208
202
  }
209
203
 
204
+ if (maxWeightIndex === -1) {
205
+ return
206
+ }
207
+
210
208
  this[kCurrentWeight] = this[kClients][maxWeightIndex][kWeight]
211
209
  this[kIndex] = maxWeightIndex
212
210
  return this[kClients][maxWeightIndex]
@@ -69,9 +69,9 @@ function lazyllhttp () {
69
69
  let useWasmSIMD = process.arch !== 'ppc64'
70
70
  // The Env Variable UNDICI_NO_WASM_SIMD allows explicitly overriding the default behavior
71
71
  if (process.env.UNDICI_NO_WASM_SIMD === '1') {
72
- useWasmSIMD = true
73
- } else if (process.env.UNDICI_NO_WASM_SIMD === '0') {
74
72
  useWasmSIMD = false
73
+ } else if (process.env.UNDICI_NO_WASM_SIMD === '0') {
74
+ useWasmSIMD = true
75
75
  }
76
76
 
77
77
  if (useWasmSIMD) {
@@ -188,6 +188,7 @@ let currentBufferRef = null
188
188
  */
189
189
  let currentBufferSize = 0
190
190
  let currentBufferPtr = null
191
+ let currentBuffer = null
191
192
 
192
193
  const USE_NATIVE_TIMER = 0
193
194
  const USE_FAST_TIMER = 1
@@ -216,6 +217,7 @@ class Parser {
216
217
  */
217
218
  this.socket = socket
218
219
  this.timeout = null
220
+ this.timeoutWeakRef = new WeakRef(this)
219
221
  this.timeoutValue = null
220
222
  this.timeoutType = null
221
223
  this.statusCode = 0
@@ -231,8 +233,8 @@ class Parser {
231
233
  this.bytesRead = 0
232
234
 
233
235
  this.keepAlive = ''
234
- this.contentLength = ''
235
- this.connection = ''
236
+ this.contentLength = -1
237
+ this.connectionKeepAlive = false
236
238
  this.maxResponseSize = client[kMaxResponseSize]
237
239
  }
238
240
 
@@ -253,9 +255,9 @@ class Parser {
253
255
 
254
256
  if (delay) {
255
257
  if (type & USE_FAST_TIMER) {
256
- this.timeout = timers.setFastTimeout(onParserTimeout, delay, new WeakRef(this))
258
+ this.timeout = timers.setFastTimeout(onParserTimeout, delay, this.timeoutWeakRef)
257
259
  } else {
258
- this.timeout = setTimeout(onParserTimeout, delay, new WeakRef(this))
260
+ this.timeout = setTimeout(onParserTimeout, delay, this.timeoutWeakRef)
259
261
  this.timeout?.unref()
260
262
  }
261
263
  }
@@ -322,7 +324,16 @@ class Parser {
322
324
  currentBufferPtr = llhttp.malloc(currentBufferSize)
323
325
  }
324
326
 
325
- new Uint8Array(llhttp.memory.buffer, currentBufferPtr, currentBufferSize).set(chunk)
327
+ if (
328
+ currentBuffer === null ||
329
+ currentBuffer.buffer !== llhttp.memory.buffer ||
330
+ currentBuffer.byteOffset !== currentBufferPtr ||
331
+ currentBuffer.byteLength !== currentBufferSize
332
+ ) {
333
+ currentBuffer = new Uint8Array(llhttp.memory.buffer, currentBufferPtr, currentBufferSize)
334
+ }
335
+
336
+ currentBuffer.set(chunk)
326
337
 
327
338
  // Call `execute` on the wasm parser.
328
339
  // We pass the `llhttp_parser` pointer address, the pointer address of buffer view data,
@@ -447,10 +458,17 @@ class Parser {
447
458
  if (headerName === 'keep-alive') {
448
459
  this.keepAlive += buf.toString()
449
460
  } else if (headerName === 'connection') {
450
- this.connection += buf.toString()
461
+ this.connectionKeepAlive =
462
+ this.headers[len - 1].length === 10 &&
463
+ util.bufferToLowerCasedHeaderName(this.headers[len - 1]) === 'keep-alive'
451
464
  }
452
465
  } else if (key.length === 14 && util.bufferToLowerCasedHeaderName(key) === 'content-length') {
453
- this.contentLength += buf.toString()
466
+ if (this.contentLength === -1) {
467
+ this.contentLength = 0
468
+ }
469
+ for (let i = 0; i < buf.length; i++) {
470
+ this.contentLength = (this.contentLength * 10) + (buf[i] - 0x30)
471
+ }
454
472
  }
455
473
 
456
474
  this.trackHeader(buf.length)
@@ -554,7 +572,7 @@ class Parser {
554
572
  this.shouldKeepAlive = (
555
573
  shouldKeepAlive ||
556
574
  // Override llhttp value which does not allow keepAlive for HEAD.
557
- (request.method === 'HEAD' && !socket[kReset] && this.connection.toLowerCase() === 'keep-alive')
575
+ (request.method === 'HEAD' && !socket[kReset] && this.connectionKeepAlive)
558
576
  )
559
577
 
560
578
  if (this.statusCode >= 200) {
@@ -687,9 +705,9 @@ class Parser {
687
705
  this.statusCode = 0
688
706
  this.statusText = ''
689
707
  this.bytesRead = 0
690
- this.contentLength = ''
708
+ this.contentLength = -1
691
709
  this.keepAlive = ''
692
- this.connection = ''
710
+ this.connectionKeepAlive = false
693
711
 
694
712
  this.headers = []
695
713
  this.headersSize = 0
@@ -698,7 +716,7 @@ class Parser {
698
716
  return 0
699
717
  }
700
718
 
701
- if (request.method !== 'HEAD' && contentLength && bytesRead !== parseInt(contentLength, 10)) {
719
+ if (request.method !== 'HEAD' && contentLength !== -1 && bytesRead !== contentLength) {
702
720
  util.destroy(socket, new ResponseContentLengthMismatchError())
703
721
  return -1
704
722
  }
@@ -1106,7 +1124,7 @@ function writeH1 (client, request) {
1106
1124
  socket[kReset] = reset
1107
1125
  }
1108
1126
 
1109
- if (client[kMaxRequests] && socket[kCounter]++ >= client[kMaxRequests]) {
1127
+ if (client[kMaxRequests] && ++socket[kCounter] >= client[kMaxRequests]) {
1110
1128
  socket[kReset] = true
1111
1129
  }
1112
1130
 
@@ -1477,7 +1495,7 @@ class AsyncWriter {
1477
1495
  }
1478
1496
 
1479
1497
  /**
1480
- * @param {Buffer} chunk
1498
+ * @param {string|Uint8Array} chunk
1481
1499
  * @returns
1482
1500
  */
1483
1501
  write (chunk) {
@@ -1491,7 +1509,7 @@ class AsyncWriter {
1491
1509
  return false
1492
1510
  }
1493
1511
 
1494
- const len = Buffer.byteLength(chunk)
1512
+ const len = chunk instanceof Uint8Array ? chunk.byteLength : Buffer.byteLength(chunk)
1495
1513
  if (!len) {
1496
1514
  return true
1497
1515
  }