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 +3 -22
- package/lib/dispatcher/client-h2.js +10 -16
- package/lib/interceptor/decompress.js +2 -5
- package/lib/web/fetch/index.js +2 -2
- package/package.json +1 -1
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('
|
|
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('
|
|
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('
|
|
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', (
|
|
674
|
+
stream.once('end', () => {
|
|
671
675
|
stream.removeAllListeners('data')
|
|
672
|
-
//
|
|
673
|
-
|
|
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
|
|
686
|
-
//
|
|
687
|
-
|
|
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
|
-
|
|
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
|
/**
|
package/lib/web/fetch/index.js
CHANGED
|
@@ -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
|
|
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
|
|
1682
|
+
return response
|
|
1683
1683
|
}
|
|
1684
1684
|
|
|
1685
1685
|
// 4. Set response to the result of running HTTP-network-or-cache fetch given
|