undici 7.19.1 → 7.19.2

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/lib/core/util.js CHANGED
@@ -431,22 +431,17 @@ function parseHeaders (headers, obj) {
431
431
  val = [val]
432
432
  obj[key] = val
433
433
  }
434
- val.push(headers[i + 1].toString('utf8'))
434
+ val.push(headers[i + 1].toString('latin1'))
435
435
  } else {
436
436
  const headersValue = headers[i + 1]
437
437
  if (typeof headersValue === 'string') {
438
438
  obj[key] = headersValue
439
439
  } else {
440
- obj[key] = Array.isArray(headersValue) ? headersValue.map(x => x.toString('utf8')) : headersValue.toString('utf8')
440
+ obj[key] = Array.isArray(headersValue) ? headersValue.map(x => x.toString('latin1')) : headersValue.toString('latin1')
441
441
  }
442
442
  }
443
443
  }
444
444
 
445
- // See https://github.com/nodejs/node/pull/46528
446
- if ('content-length' in obj && 'content-disposition' in obj) {
447
- obj['content-disposition'] = Buffer.from(obj['content-disposition']).toString('latin1')
448
- }
449
-
450
445
  return obj
451
446
  }
452
447
 
@@ -461,34 +456,20 @@ function parseRawHeaders (headers) {
461
456
  */
462
457
  const ret = new Array(headersLength)
463
458
 
464
- let hasContentLength = false
465
- let contentDispositionIdx = -1
466
459
  let key
467
460
  let val
468
- let kLen = 0
469
461
 
470
462
  for (let n = 0; n < headersLength; n += 2) {
471
463
  key = headers[n]
472
464
  val = headers[n + 1]
473
465
 
474
466
  typeof key !== 'string' && (key = key.toString())
475
- typeof val !== 'string' && (val = val.toString('utf8'))
467
+ typeof val !== 'string' && (val = val.toString('latin1'))
476
468
 
477
- kLen = key.length
478
- if (kLen === 14 && key[7] === '-' && (key === 'content-length' || key.toLowerCase() === 'content-length')) {
479
- hasContentLength = true
480
- } else if (kLen === 19 && key[7] === '-' && (key === 'content-disposition' || key.toLowerCase() === 'content-disposition')) {
481
- contentDispositionIdx = n + 1
482
- }
483
469
  ret[n] = key
484
470
  ret[n + 1] = val
485
471
  }
486
472
 
487
- // See https://github.com/nodejs/node/pull/46528
488
- if (hasContentLength && contentDispositionIdx !== -1) {
489
- ret[contentDispositionIdx] = Buffer.from(ret[contentDispositionIdx]).toString('latin1')
490
- }
491
-
492
473
  return ret
493
474
  }
494
475
 
@@ -642,9 +642,13 @@ function writeH2 (client, request) {
642
642
  ++session[kOpenStreams]
643
643
  stream.setTimeout(requestTimeout)
644
644
 
645
+ // Track whether we received a response (headers)
646
+ let responseReceived = false
647
+
645
648
  stream.once('response', headers => {
646
649
  const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers
647
650
  request.onResponseStarted()
651
+ responseReceived = true
648
652
 
649
653
  // Due to the stream nature, it is possible we face a race condition
650
654
  // where the stream has been assigned, but the request has been aborted
@@ -667,14 +671,10 @@ function writeH2 (client, request) {
667
671
  }
668
672
  })
669
673
 
670
- stream.once('end', (err) => {
674
+ stream.once('end', () => {
671
675
  stream.removeAllListeners('data')
672
- // When state is null, it means we haven't consumed body and the stream still do not have
673
- // a state.
674
- // Present specially when using pipeline or stream
675
- if (stream.state?.state == null || stream.state.state < 6) {
676
- // Do not complete the request if it was aborted
677
- // Not prone to happen for as safety net to avoid race conditions with 'trailers'
676
+ // If we received a response, this is a normal completion
677
+ if (responseReceived) {
678
678
  if (!request.aborted && !request.completed) {
679
679
  request.onComplete({})
680
680
  }
@@ -682,15 +682,9 @@ function writeH2 (client, request) {
682
682
  client[kQueue][client[kRunningIdx]++] = null
683
683
  client[kResume]()
684
684
  } else {
685
- // Stream is closed or half-closed-remote (6), decrement counter and cleanup
686
- // It does not have sense to continue working with the stream as we do not
687
- // have yet RST_STREAM support on client-side
688
- --session[kOpenStreams]
689
- if (session[kOpenStreams] === 0) {
690
- session.unref()
691
- }
692
-
693
- abort(err ?? new InformationalError('HTTP/2: stream half-closed (remote)'))
685
+ // Stream ended without receiving a response - this is an error
686
+ // (e.g., server destroyed the stream before sending headers)
687
+ abort(new InformationalError('HTTP/2: stream half-closed (remote)'))
694
688
  client[kQueue][client[kRunningIdx]++] = null
695
689
  client[kPendingIdx] = client[kRunningIdx]
696
690
  client[kResume]()
@@ -33,8 +33,6 @@ let warningEmitted = /** @type {boolean} */ (false)
33
33
  class DecompressHandler extends DecoratorHandler {
34
34
  /** @type {Transform[]} */
35
35
  #decompressors = []
36
- /** @type {NodeJS.WritableStream&NodeJS.ReadableStream|null} */
37
- #pipelineStream
38
36
  /** @type {Readonly<number[]>} */
39
37
  #skipStatusCodes
40
38
  /** @type {boolean} */
@@ -139,7 +137,7 @@ class DecompressHandler extends DecoratorHandler {
139
137
  const lastDecompressor = this.#decompressors[this.#decompressors.length - 1]
140
138
  this.#setupDecompressorEvents(lastDecompressor, controller)
141
139
 
142
- this.#pipelineStream = pipeline(this.#decompressors, (err) => {
140
+ pipeline(this.#decompressors, (err) => {
143
141
  if (err) {
144
142
  super.onResponseError(controller, err)
145
143
  return
@@ -154,7 +152,6 @@ class DecompressHandler extends DecoratorHandler {
154
152
  */
155
153
  #cleanupDecompressors () {
156
154
  this.#decompressors.length = 0
157
- this.#pipelineStream = null
158
155
  }
159
156
 
160
157
  /**
@@ -190,7 +187,7 @@ class DecompressHandler extends DecoratorHandler {
190
187
  this.#setupMultipleDecompressors(controller)
191
188
  }
192
189
 
193
- super.onResponseStart(controller, statusCode, newHeaders, statusMessage)
190
+ return super.onResponseStart(controller, statusCode, newHeaders, statusMessage)
194
191
  }
195
192
 
196
193
  /**
@@ -1677,9 +1677,9 @@ async function httpNetworkOrCacheFetch (
1677
1677
  // requestCurrentURL(request).password = TODO
1678
1678
 
1679
1679
  // In browsers, the user will be prompted to enter a username/password before the request
1680
- // is re-sent. To prevent an infinite 401 loop, return a network error for now.
1680
+ // is re-sent. To prevent an infinite 401 loop, return the response for now.
1681
1681
  // https://github.com/nodejs/undici/pull/4756
1682
- return makeNetworkError()
1682
+ return response
1683
1683
  }
1684
1684
 
1685
1685
  // 4. Set response to the result of running HTTP-network-or-cache fetch given
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "undici",
3
- "version": "7.19.1",
3
+ "version": "7.19.2",
4
4
  "description": "An HTTP/1.1 client, written from scratch for Node.js",
5
5
  "homepage": "https://undici.nodejs.org",
6
6
  "bugs": {