undici 5.27.0 → 5.27.1

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/client.js CHANGED
@@ -1462,23 +1462,7 @@ function _resume (client, sync) {
1462
1462
  return
1463
1463
  }
1464
1464
 
1465
- if (util.isStream(request.body) && util.bodyLength(request.body) === 0) {
1466
- request.body
1467
- .on('data', /* istanbul ignore next */ function () {
1468
- /* istanbul ignore next */
1469
- assert(false)
1470
- })
1471
- .on('error', function (err) {
1472
- errorRequest(client, request, err)
1473
- })
1474
- .on('end', function () {
1475
- util.destroy(this)
1476
- })
1477
-
1478
- request.body = null
1479
- }
1480
-
1481
- if (client[kRunning] > 0 &&
1465
+ if (client[kRunning] > 0 && util.bodyLength(request.body) !== 0 &&
1482
1466
  (util.isStream(request.body) || util.isAsyncIterable(request.body))) {
1483
1467
  // Request with stream or iterator body can error while other requests
1484
1468
  // are inflight and indirectly error those as well.
@@ -1499,6 +1483,11 @@ function _resume (client, sync) {
1499
1483
  }
1500
1484
  }
1501
1485
 
1486
+ // https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2
1487
+ function shouldSendContentLength (method) {
1488
+ return method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS' && method !== 'TRACE' && method !== 'CONNECT'
1489
+ }
1490
+
1502
1491
  function write (client, request) {
1503
1492
  if (client[kHTTPConnVersion] === 'h2') {
1504
1493
  writeH2(client, client[kHTTP2Session], request)
@@ -1527,7 +1516,9 @@ function write (client, request) {
1527
1516
  body.read(0)
1528
1517
  }
1529
1518
 
1530
- let contentLength = util.bodyLength(body)
1519
+ const bodyLength = util.bodyLength(body)
1520
+
1521
+ let contentLength = bodyLength
1531
1522
 
1532
1523
  if (contentLength === null) {
1533
1524
  contentLength = request.contentLength
@@ -1542,7 +1533,9 @@ function write (client, request) {
1542
1533
  contentLength = null
1543
1534
  }
1544
1535
 
1545
- if (request.contentLength !== null && request.contentLength !== contentLength) {
1536
+ // https://github.com/nodejs/undici/issues/2046
1537
+ // A user agent may send a Content-Length header with 0 value, this should be allowed.
1538
+ if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength !== null && request.contentLength !== contentLength) {
1546
1539
  if (client[kStrictContentLength]) {
1547
1540
  errorRequest(client, request, new RequestContentLengthMismatchError())
1548
1541
  return false
@@ -1623,7 +1616,7 @@ function write (client, request) {
1623
1616
  }
1624
1617
 
1625
1618
  /* istanbul ignore else: assertion */
1626
- if (!body) {
1619
+ if (!body || bodyLength === 0) {
1627
1620
  if (contentLength === 0) {
1628
1621
  socket.write(`${header}content-length: 0\r\n\r\n`, 'latin1')
1629
1622
  } else {
@@ -1763,7 +1756,9 @@ function writeH2 (client, session, request) {
1763
1756
  contentLength = null
1764
1757
  }
1765
1758
 
1766
- if (request.contentLength != null && request.contentLength !== contentLength) {
1759
+ // https://github.com/nodejs/undici/issues/2046
1760
+ // A user agent may send a Content-Length header with 0 value, this should be allowed.
1761
+ if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength != null && request.contentLength !== contentLength) {
1767
1762
  if (client[kStrictContentLength]) {
1768
1763
  errorRequest(client, request, new RequestContentLengthMismatchError())
1769
1764
  return false
@@ -112,10 +112,28 @@ class Request {
112
112
 
113
113
  this.method = method
114
114
 
115
+ this.abort = null
116
+
115
117
  if (body == null) {
116
118
  this.body = null
117
119
  } else if (util.isStream(body)) {
118
120
  this.body = body
121
+
122
+ if (!this.body._readableState?.autoDestroy) {
123
+ this.endHandler = function autoDestroy () {
124
+ util.destroy(this)
125
+ }
126
+ this.body.on('end', this.endHandler)
127
+ }
128
+
129
+ this.errorHandler = err => {
130
+ if (this.abort) {
131
+ this.abort(err)
132
+ } else {
133
+ this.error = err
134
+ }
135
+ }
136
+ this.body.on('error', this.errorHandler)
119
137
  } else if (util.isBuffer(body)) {
120
138
  this.body = body.byteLength ? body : null
121
139
  } else if (ArrayBuffer.isView(body)) {
@@ -236,7 +254,12 @@ class Request {
236
254
  assert(!this.aborted)
237
255
  assert(!this.completed)
238
256
 
239
- return this[kHandler].onConnect(abort)
257
+ if (this.error) {
258
+ abort(this.error)
259
+ } else {
260
+ this.abort = abort
261
+ return this[kHandler].onConnect(abort)
262
+ }
240
263
  }
241
264
 
242
265
  onHeaders (statusCode, headers, resume, statusText) {
@@ -265,6 +288,8 @@ class Request {
265
288
  }
266
289
 
267
290
  onComplete (trailers) {
291
+ this.onFinally()
292
+
268
293
  assert(!this.aborted)
269
294
 
270
295
  this.completed = true
@@ -275,6 +300,8 @@ class Request {
275
300
  }
276
301
 
277
302
  onError (error) {
303
+ this.onFinally()
304
+
278
305
  if (channels.error.hasSubscribers) {
279
306
  channels.error.publish({ request: this, error })
280
307
  }
@@ -286,6 +313,18 @@ class Request {
286
313
  return this[kHandler].onError(error)
287
314
  }
288
315
 
316
+ onFinally () {
317
+ if (this.errorHandler) {
318
+ this.body.off('error', this.errorHandler)
319
+ this.errorHandler = null
320
+ }
321
+
322
+ if (this.endHandler) {
323
+ this.body.off('end', this.endHandler)
324
+ this.endHandler = null
325
+ }
326
+ }
327
+
289
328
  // TODO: adjust to support H2
290
329
  addHeader (key, value) {
291
330
  processHeader(this, key, value)
package/lib/core/util.js CHANGED
@@ -190,7 +190,7 @@ function isReadableAborted (stream) {
190
190
  }
191
191
 
192
192
  function destroy (stream, err) {
193
- if (!isStream(stream) || isDestroyed(stream)) {
193
+ if (stream == null || !isStream(stream) || isDestroyed(stream)) {
194
194
  return
195
195
  }
196
196
 
package/lib/pool.js CHANGED
@@ -57,7 +57,7 @@ class Pool extends PoolBase {
57
57
  maxCachedSessions,
58
58
  allowH2,
59
59
  socketPath,
60
- timeout: connectTimeout == null ? 10e3 : connectTimeout,
60
+ timeout: connectTimeout,
61
61
  ...(util.nodeHasAutoSelectFamily && autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined),
62
62
  ...connect
63
63
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "undici",
3
- "version": "5.27.0",
3
+ "version": "5.27.1",
4
4
  "description": "An HTTP/1.1 client, written from scratch for Node.js",
5
5
  "homepage": "https://undici.nodejs.org",
6
6
  "bugs": {