undici 7.0.0-alpha.9 → 7.0.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.
@@ -27,7 +27,8 @@ const {
27
27
  kResume,
28
28
  kSize,
29
29
  kHTTPContext,
30
- kClosed
30
+ kClosed,
31
+ kBodyTimeout
31
32
  } = require('../core/symbols.js')
32
33
 
33
34
  const kOpenStreams = Symbol('open streams')
@@ -90,7 +91,11 @@ async function connectH2 (client, socket) {
90
91
 
91
92
  const session = http2.connect(client[kUrl], {
92
93
  createConnection: () => socket,
93
- peerMaxConcurrentStreams: client[kMaxConcurrentStreams]
94
+ peerMaxConcurrentStreams: client[kMaxConcurrentStreams],
95
+ settings: {
96
+ // TODO(metcoder95): add support for PUSH
97
+ enablePush: false
98
+ }
94
99
  })
95
100
 
96
101
  session[kOpenStreams] = 0
@@ -129,7 +134,6 @@ async function connectH2 (client, socket) {
129
134
  if (socket[kClosed]) {
130
135
  queueMicrotask(callback)
131
136
  } else {
132
- // Destroying the socket will trigger the session close
133
137
  socket.destroy(err).on('close', callback)
134
138
  }
135
139
  },
@@ -281,6 +285,7 @@ function shouldSendContentLength (method) {
281
285
  }
282
286
 
283
287
  function writeH2 (client, request) {
288
+ const requestTimeout = request.bodyTimeout ?? client[kBodyTimeout]
284
289
  const session = client[kHTTP2Session]
285
290
  const { method, path, host, upgrade, expectContinue, signal, headers: reqHeaders } = request
286
291
  let { body } = request
@@ -379,6 +384,7 @@ function writeH2 (client, request) {
379
384
  session[kOpenStreams] -= 1
380
385
  if (session[kOpenStreams] === 0) session.unref()
381
386
  })
387
+ stream.setTimeout(requestTimeout)
382
388
 
383
389
  return true
384
390
  }
@@ -452,6 +458,7 @@ function writeH2 (client, request) {
452
458
 
453
459
  session.ref()
454
460
 
461
+ // TODO(metcoder95): add support for sending trailers
455
462
  const shouldEndStream = method === 'GET' || method === 'HEAD' || body === null
456
463
  if (expectContinue) {
457
464
  headers[HTTP2_HEADER_EXPECT] = '100-continue'
@@ -469,6 +476,7 @@ function writeH2 (client, request) {
469
476
 
470
477
  // Increment counter as we have new streams open
471
478
  ++session[kOpenStreams]
479
+ stream.setTimeout(requestTimeout)
472
480
 
473
481
  stream.once('response', headers => {
474
482
  const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers
@@ -502,8 +510,9 @@ function writeH2 (client, request) {
502
510
  // Present specially when using pipeline or stream
503
511
  if (stream.state?.state == null || stream.state.state < 6) {
504
512
  // Do not complete the request if it was aborted
505
- if (!request.aborted) {
506
- request.onComplete([])
513
+ // Not prone to happen for as safety net to avoid race conditions with 'trailers'
514
+ if (!request.aborted && !request.completed) {
515
+ request.onComplete({})
507
516
  }
508
517
 
509
518
  client[kQueue][client[kRunningIdx]++] = null
@@ -546,17 +555,25 @@ function writeH2 (client, request) {
546
555
  stream.removeAllListeners('data')
547
556
  })
548
557
 
549
- // stream.on('timeout', () => {
550
- // // TODO(HTTP/2): Support timeout
551
- // })
558
+ stream.on('timeout', () => {
559
+ const err = new InformationalError(`HTTP/2: "stream timeout after ${requestTimeout}"`)
560
+ stream.removeAllListeners('data')
561
+ session[kOpenStreams] -= 1
562
+
563
+ if (session[kOpenStreams] === 0) {
564
+ session.unref()
565
+ }
566
+
567
+ abort(err)
568
+ })
552
569
 
553
- // stream.on('push', headers => {
554
- // // TODO(HTTP/2): Support push
555
- // })
570
+ stream.once('trailers', trailers => {
571
+ if (request.aborted || request.completed) {
572
+ return
573
+ }
556
574
 
557
- // stream.on('trailers', headers => {
558
- // // TODO(HTTP/2): Support trailers
559
- // })
575
+ request.onComplete(trailers)
576
+ })
560
577
 
561
578
  return true
562
579
 
@@ -27,6 +27,10 @@ class ResponseErrorHandler extends DecoratorHandler {
27
27
  return this.#handler.onConnect(abort)
28
28
  }
29
29
 
30
+ #checkContentType (contentType) {
31
+ return this.#contentType.indexOf(contentType) === 0
32
+ }
33
+
30
34
  onHeaders (statusCode, rawHeaders, resume, statusMessage, headers = parseHeaders(rawHeaders)) {
31
35
  this.#statusCode = statusCode
32
36
  this.#headers = headers
@@ -36,7 +40,7 @@ class ResponseErrorHandler extends DecoratorHandler {
36
40
  return this.#handler.onHeaders(statusCode, rawHeaders, resume, statusMessage, headers)
37
41
  }
38
42
 
39
- if (this.#contentType === 'application/json' || this.#contentType === 'text/plain') {
43
+ if (this.#checkContentType('application/json') || this.#checkContentType('text/plain')) {
40
44
  this.#decoder = new TextDecoder('utf-8')
41
45
  }
42
46
  }
@@ -53,7 +57,7 @@ class ResponseErrorHandler extends DecoratorHandler {
53
57
  if (this.#statusCode >= 400) {
54
58
  this.#body += this.#decoder?.decode(undefined, { stream: false }) ?? ''
55
59
 
56
- if (this.#contentType === 'application/json') {
60
+ if (this.#checkContentType('application/json')) {
57
61
  try {
58
62
  this.#body = JSON.parse(this.#body)
59
63
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "undici",
3
- "version": "7.0.0-alpha.9",
3
+ "version": "7.0.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": {