pnpm 11.28.2 → 11.28.4

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.
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const assert = require('node:assert')
4
+ const { errorMonitor } = require('node:events')
4
5
  const { pipeline } = require('node:stream')
5
6
  const util = require('../core/util.js')
6
7
  const {
@@ -77,6 +78,15 @@ function parseH2Headers (headers) {
77
78
  return result
78
79
  }
79
80
 
81
+ /**
82
+ * @param {import('node:http2').IncomingHttpHeaders} headers
83
+ * @returns {Buffer[]}
84
+ */
85
+ function parseH2ResponseHeaders (headers) {
86
+ const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers
87
+ return parseH2Headers(realHeaders)
88
+ }
89
+
80
90
  async function connectH2 (client, socket) {
81
91
  client[kSocket] = socket
82
92
 
@@ -297,22 +307,32 @@ function writeH2 (client, request) {
297
307
  headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ''}`
298
308
  headers[HTTP2_HEADER_METHOD] = method
299
309
 
300
- const abort = (err) => {
301
- if (request.aborted || request.completed) {
310
+ /**
311
+ * @param {Error} [error]
312
+ */
313
+ const abort = (error) => {
314
+ if (request.aborted) {
315
+ return
316
+ }
317
+
318
+ if (request.completed) {
319
+ if (method === 'CONNECT' && stream != null) {
320
+ util.destroy(stream, error || new RequestAbortedError())
321
+ }
302
322
  return
303
323
  }
304
324
 
305
- err = err || new RequestAbortedError()
325
+ error = error || new RequestAbortedError()
306
326
 
307
- util.errorRequest(client, request, err)
327
+ util.errorRequest(client, request, error)
308
328
 
309
329
  if (stream != null) {
310
- util.destroy(stream, err)
330
+ util.destroy(stream, error)
311
331
  }
312
332
 
313
333
  // We do not destroy the socket as we can continue using the session
314
334
  // the stream get's destroyed and the session remains to create new streams
315
- util.destroy(body, err)
335
+ util.destroy(body, error)
316
336
  client[kQueue][client[kRunningIdx]++] = null
317
337
  client[kResume]()
318
338
  }
@@ -331,25 +351,57 @@ function writeH2 (client, request) {
331
351
 
332
352
  if (method === 'CONNECT') {
333
353
  session.ref()
334
- // We are already connected, streams are pending, first request
335
- // will create a new stream. We trigger a request to create the stream and wait until
336
- // `ready` event is triggered
337
354
  // We disabled endStream to allow the user to write to the stream
338
355
  stream = session.request(headers, { endStream: false, signal })
356
+ let upgradeResponseFinished = false
357
+
358
+ /**
359
+ * @param {import('node:http2').IncomingHttpHeaders} headers
360
+ */
361
+ const onResponse = (headers) => {
362
+ upgradeResponseFinished = true
363
+ stream.off(errorMonitor, onUpgradeError)
364
+ request.onUpgradeResponse(Number(headers[HTTP2_HEADER_STATUS]), headers, parseH2ResponseHeaders)
365
+ }
339
366
 
340
- if (stream.id && !stream.pending) {
341
- request.onUpgrade(null, null, stream)
342
- ++session[kOpenStreams]
343
- client[kQueue][client[kRunningIdx]++] = null
344
- } else {
345
- stream.once('ready', () => {
367
+ /**
368
+ * @param {Error} error
369
+ */
370
+ const onUpgradeError = (error) => {
371
+ upgradeResponseFinished = true
372
+ stream.off('response', onResponse)
373
+ request.onUpgradeError(error)
374
+ }
375
+
376
+ const onReady = () => {
377
+ try {
346
378
  request.onUpgrade(null, null, stream)
347
- ++session[kOpenStreams]
348
- client[kQueue][client[kRunningIdx]++] = null
349
- })
379
+ } catch (error) {
380
+ stream.off('response', onResponse)
381
+ abort(error)
382
+ return
383
+ }
384
+
385
+ if (request.aborted) {
386
+ return
387
+ }
388
+
389
+ stream.off('error', abort)
390
+ stream.once(errorMonitor, onUpgradeError)
391
+ client[kQueue][client[kRunningIdx]++] = null
350
392
  }
351
393
 
394
+ stream.once('response', onResponse)
395
+ stream.once('error', abort)
396
+ ++session[kOpenStreams]
397
+ onReady()
398
+
352
399
  stream.once('close', () => {
400
+ if (!upgradeResponseFinished && request.completed) {
401
+ stream.off('response', onResponse)
402
+ stream.off(errorMonitor, onUpgradeError)
403
+ request.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`))
404
+ }
353
405
  session[kOpenStreams] -= 1
354
406
  if (session[kOpenStreams] === 0) session.unref()
355
407
  })
@@ -205,7 +205,10 @@ class RetryHandler {
205
205
  this.retryCount += 1
206
206
 
207
207
  if (statusCode >= 300) {
208
- if (this.retryOpts.statusCodes.includes(statusCode) === false) {
208
+ // Only expose a response if no earlier attempt has reached the caller.
209
+ // Otherwise abort this attempt so the error settles the existing body
210
+ // instead of replacing it with a new response.
211
+ if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) {
209
212
  this.headersSent = true
210
213
  this.checkpointResponseEnd(headers, resume)
211
214
  return this.handler.onHeaders(
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "undici",
3
- "version": "6.28.1",
3
+ "version": "6.29.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": {