undici 7.15.0 → 7.16.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.
Files changed (45) hide show
  1. package/README.md +1 -1
  2. package/docs/docs/api/Agent.md +1 -0
  3. package/docs/docs/api/Errors.md +0 -1
  4. package/index-fetch.js +2 -2
  5. package/index.js +4 -8
  6. package/lib/api/api-request.js +22 -8
  7. package/lib/api/readable.js +7 -5
  8. package/lib/core/errors.js +217 -13
  9. package/lib/core/request.js +5 -1
  10. package/lib/core/util.js +32 -10
  11. package/lib/dispatcher/agent.js +19 -7
  12. package/lib/dispatcher/client-h1.js +20 -9
  13. package/lib/dispatcher/client-h2.js +13 -3
  14. package/lib/dispatcher/client.js +57 -57
  15. package/lib/dispatcher/dispatcher-base.js +12 -7
  16. package/lib/dispatcher/env-http-proxy-agent.js +12 -16
  17. package/lib/dispatcher/fixed-queue.js +15 -39
  18. package/lib/dispatcher/h2c-client.js +6 -6
  19. package/lib/dispatcher/pool-base.js +60 -43
  20. package/lib/dispatcher/pool.js +2 -2
  21. package/lib/dispatcher/proxy-agent.js +14 -9
  22. package/lib/global.js +19 -1
  23. package/lib/interceptor/cache.js +61 -0
  24. package/lib/mock/mock-agent.js +4 -4
  25. package/lib/mock/mock-errors.js +10 -0
  26. package/lib/mock/mock-utils.js +12 -10
  27. package/lib/util/date.js +534 -140
  28. package/lib/web/cookies/index.js +1 -1
  29. package/lib/web/eventsource/eventsource-stream.js +2 -2
  30. package/lib/web/eventsource/eventsource.js +34 -29
  31. package/lib/web/eventsource/util.js +1 -9
  32. package/lib/web/fetch/body.js +16 -22
  33. package/lib/web/fetch/index.js +14 -15
  34. package/lib/web/fetch/response.js +2 -4
  35. package/lib/web/fetch/util.js +8 -14
  36. package/lib/web/webidl/index.js +203 -42
  37. package/lib/web/websocket/connection.js +4 -3
  38. package/lib/web/websocket/events.js +1 -1
  39. package/lib/web/websocket/stream/websocketerror.js +22 -1
  40. package/lib/web/websocket/stream/websocketstream.js +16 -7
  41. package/lib/web/websocket/websocket.js +32 -42
  42. package/package.json +7 -6
  43. package/types/agent.d.ts +1 -0
  44. package/types/errors.d.ts +5 -15
  45. package/types/webidl.d.ts +82 -21
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # undici
2
2
 
3
- [![Node CI](https://github.com/nodejs/undici/actions/workflows/nodejs.yml/badge.svg)](https://github.com/nodejs/undici/actions/workflows/nodejs.yml) [![neostandard javascript style](https://img.shields.io/badge/neo-standard-7fffff?style=flat\&labelColor=ff80ff)](https://github.com/neostandard/neostandard) [![npm version](https://badge.fury.io/js/undici.svg)](https://badge.fury.io/js/undici) [![codecov](https://codecov.io/gh/nodejs/undici/branch/main/graph/badge.svg?token=yZL6LtXkOA)](https://codecov.io/gh/nodejs/undici)
3
+ [![Node CI](https://github.com/nodejs/undici/actions/workflows/ci.yml/badge.svg)](https://github.com/nodejs/undici/actions/workflows/nodejs.yml) [![neostandard javascript style](https://img.shields.io/badge/neo-standard-7fffff?style=flat\&labelColor=ff80ff)](https://github.com/neostandard/neostandard) [![npm version](https://badge.fury.io/js/undici.svg)](https://badge.fury.io/js/undici) [![codecov](https://codecov.io/gh/nodejs/undici/branch/main/graph/badge.svg?token=yZL6LtXkOA)](https://codecov.io/gh/nodejs/undici)
4
4
 
5
5
  An HTTP/1.1 client, written from scratch for Node.js.
6
6
 
@@ -19,6 +19,7 @@ Returns: `Agent`
19
19
  Extends: [`PoolOptions`](/docs/docs/api/Pool.md#parameter-pooloptions)
20
20
 
21
21
  * **factory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Pool(origin, opts)`
22
+ * **maxOrigins** `number` (optional) - Default: `Infinity` - Limits the total number of origins that can receive requests at a time, throwing an `MaxOriginsReachedError` error when attempting to dispatch when the max is reached. If `Infinity`, no limit is enforced.
22
23
 
23
24
  ## Instance Properties
24
25
 
@@ -14,7 +14,6 @@ import { errors } from 'undici'
14
14
  | `HeadersTimeoutError` | `UND_ERR_HEADERS_TIMEOUT` | socket is destroyed due to headers timeout. |
15
15
  | `HeadersOverflowError` | `UND_ERR_HEADERS_OVERFLOW` | socket is destroyed due to headers' max size being exceeded. |
16
16
  | `BodyTimeoutError` | `UND_ERR_BODY_TIMEOUT` | socket is destroyed due to body timeout. |
17
- | `ResponseStatusCodeError` | `UND_ERR_RESPONSE_STATUS_CODE` | an error is thrown when `throwOnError` is `true` for status codes >= 400. |
18
17
  | `InvalidArgumentError` | `UND_ERR_INVALID_ARG` | passed an invalid argument. |
19
18
  | `InvalidReturnValueError` | `UND_ERR_INVALID_RETURN_VALUE` | returned an invalid value. |
20
19
  | `RequestAbortedError` | `UND_ERR_ABORTED` | the request has been aborted by the user |
package/index-fetch.js CHANGED
@@ -4,8 +4,8 @@ const { getGlobalDispatcher, setGlobalDispatcher } = require('./lib/global')
4
4
  const EnvHttpProxyAgent = require('./lib/dispatcher/env-http-proxy-agent')
5
5
  const fetchImpl = require('./lib/web/fetch').fetch
6
6
 
7
- module.exports.fetch = function fetch (resource, init = undefined) {
8
- return fetchImpl(resource, init).catch((err) => {
7
+ module.exports.fetch = function fetch (init, options = undefined) {
8
+ return fetchImpl(init, options).catch(err => {
9
9
  if (err && typeof err === 'object') {
10
10
  Error.captureStackTrace(err)
11
11
  }
package/index.js CHANGED
@@ -117,16 +117,14 @@ module.exports.setGlobalDispatcher = setGlobalDispatcher
117
117
  module.exports.getGlobalDispatcher = getGlobalDispatcher
118
118
 
119
119
  const fetchImpl = require('./lib/web/fetch').fetch
120
- module.exports.fetch = async function fetch (init, options = undefined) {
121
- try {
122
- return await fetchImpl(init, options)
123
- } catch (err) {
120
+
121
+ module.exports.fetch = function fetch (init, options = undefined) {
122
+ return fetchImpl(init, options).catch(err => {
124
123
  if (err && typeof err === 'object') {
125
124
  Error.captureStackTrace(err)
126
125
  }
127
-
128
126
  throw err
129
- }
127
+ })
130
128
  }
131
129
  module.exports.Headers = require('./lib/web/fetch/headers').Headers
132
130
  module.exports.Response = require('./lib/web/fetch/response').Response
@@ -141,8 +139,6 @@ module.exports.getGlobalOrigin = getGlobalOrigin
141
139
  const { CacheStorage } = require('./lib/web/cache/cachestorage')
142
140
  const { kConstruct } = require('./lib/core/symbols')
143
141
 
144
- // Cache & CacheStorage are tightly coupled with fetch. Even if it may run
145
- // in an older version of Node, it doesn't have any use without fetch.
146
142
  module.exports.caches = new CacheStorage(kConstruct)
147
143
 
148
144
  const { deleteCookie, getCookies, getSetCookies, setCookie, parseCookie } = require('./lib/web/cookies')
@@ -118,14 +118,28 @@ class RequestHandler extends AsyncResource {
118
118
  this.callback = null
119
119
  this.res = res
120
120
  if (callback !== null) {
121
- this.runInAsyncScope(callback, null, null, {
122
- statusCode,
123
- headers,
124
- trailers: this.trailers,
125
- opaque,
126
- body: res,
127
- context
128
- })
121
+ try {
122
+ this.runInAsyncScope(callback, null, null, {
123
+ statusCode,
124
+ headers,
125
+ trailers: this.trailers,
126
+ opaque,
127
+ body: res,
128
+ context
129
+ })
130
+ } catch (err) {
131
+ // If the callback throws synchronously, we need to handle it
132
+ // Remove reference to res to allow res being garbage collected
133
+ this.res = null
134
+
135
+ // Destroy the response stream
136
+ util.destroy(res.on('error', noop), err)
137
+
138
+ // Use queueMicrotask to re-throw the error so it reaches uncaughtException
139
+ queueMicrotask(() => {
140
+ throw err
141
+ })
142
+ }
129
143
  }
130
144
  }
131
145
 
@@ -262,24 +262,26 @@ class BodyReadable extends Readable {
262
262
  * @param {AbortSignal} [opts.signal] An AbortSignal to cancel the dump.
263
263
  * @returns {Promise<null>}
264
264
  */
265
- async dump (opts) {
265
+ dump (opts) {
266
266
  const signal = opts?.signal
267
267
 
268
268
  if (signal != null && (typeof signal !== 'object' || !('aborted' in signal))) {
269
- throw new InvalidArgumentError('signal must be an AbortSignal')
269
+ return Promise.reject(new InvalidArgumentError('signal must be an AbortSignal'))
270
270
  }
271
271
 
272
272
  const limit = opts?.limit && Number.isFinite(opts.limit)
273
273
  ? opts.limit
274
274
  : 128 * 1024
275
275
 
276
- signal?.throwIfAborted()
276
+ if (signal?.aborted) {
277
+ return Promise.reject(signal.reason ?? new AbortError())
278
+ }
277
279
 
278
280
  if (this._readableState.closeEmitted) {
279
- return null
281
+ return Promise.resolve(null)
280
282
  }
281
283
 
282
- return await new Promise((resolve, reject) => {
284
+ return new Promise((resolve, reject) => {
283
285
  if (
284
286
  (this[kContentLength] && (this[kContentLength] > limit)) ||
285
287
  this[kBytesRead] > limit
@@ -1,13 +1,23 @@
1
1
  'use strict'
2
2
 
3
+ const kUndiciError = Symbol.for('undici.error.UND_ERR')
3
4
  class UndiciError extends Error {
4
5
  constructor (message, options) {
5
6
  super(message, options)
6
7
  this.name = 'UndiciError'
7
8
  this.code = 'UND_ERR'
8
9
  }
10
+
11
+ static [Symbol.hasInstance] (instance) {
12
+ return instance && instance[kUndiciError] === true
13
+ }
14
+
15
+ get [kUndiciError] () {
16
+ return true
17
+ }
9
18
  }
10
19
 
20
+ const kConnectTimeoutError = Symbol.for('undici.error.UND_ERR_CONNECT_TIMEOUT')
11
21
  class ConnectTimeoutError extends UndiciError {
12
22
  constructor (message) {
13
23
  super(message)
@@ -15,8 +25,17 @@ class ConnectTimeoutError extends UndiciError {
15
25
  this.message = message || 'Connect Timeout Error'
16
26
  this.code = 'UND_ERR_CONNECT_TIMEOUT'
17
27
  }
28
+
29
+ static [Symbol.hasInstance] (instance) {
30
+ return instance && instance[kConnectTimeoutError] === true
31
+ }
32
+
33
+ get [kConnectTimeoutError] () {
34
+ return true
35
+ }
18
36
  }
19
37
 
38
+ const kHeadersTimeoutError = Symbol.for('undici.error.UND_ERR_HEADERS_TIMEOUT')
20
39
  class HeadersTimeoutError extends UndiciError {
21
40
  constructor (message) {
22
41
  super(message)
@@ -24,8 +43,17 @@ class HeadersTimeoutError extends UndiciError {
24
43
  this.message = message || 'Headers Timeout Error'
25
44
  this.code = 'UND_ERR_HEADERS_TIMEOUT'
26
45
  }
46
+
47
+ static [Symbol.hasInstance] (instance) {
48
+ return instance && instance[kHeadersTimeoutError] === true
49
+ }
50
+
51
+ get [kHeadersTimeoutError] () {
52
+ return true
53
+ }
27
54
  }
28
55
 
56
+ const kHeadersOverflowError = Symbol.for('undici.error.UND_ERR_HEADERS_OVERFLOW')
29
57
  class HeadersOverflowError extends UndiciError {
30
58
  constructor (message) {
31
59
  super(message)
@@ -33,8 +61,17 @@ class HeadersOverflowError extends UndiciError {
33
61
  this.message = message || 'Headers Overflow Error'
34
62
  this.code = 'UND_ERR_HEADERS_OVERFLOW'
35
63
  }
64
+
65
+ static [Symbol.hasInstance] (instance) {
66
+ return instance && instance[kHeadersOverflowError] === true
67
+ }
68
+
69
+ get [kHeadersOverflowError] () {
70
+ return true
71
+ }
36
72
  }
37
73
 
74
+ const kBodyTimeoutError = Symbol.for('undici.error.UND_ERR_BODY_TIMEOUT')
38
75
  class BodyTimeoutError extends UndiciError {
39
76
  constructor (message) {
40
77
  super(message)
@@ -42,21 +79,17 @@ class BodyTimeoutError extends UndiciError {
42
79
  this.message = message || 'Body Timeout Error'
43
80
  this.code = 'UND_ERR_BODY_TIMEOUT'
44
81
  }
45
- }
46
82
 
47
- class ResponseStatusCodeError extends UndiciError {
48
- constructor (message, statusCode, headers, body) {
49
- super(message)
50
- this.name = 'ResponseStatusCodeError'
51
- this.message = message || 'Response Status Code Error'
52
- this.code = 'UND_ERR_RESPONSE_STATUS_CODE'
53
- this.body = body
54
- this.status = statusCode
55
- this.statusCode = statusCode
56
- this.headers = headers
83
+ static [Symbol.hasInstance] (instance) {
84
+ return instance && instance[kBodyTimeoutError] === true
85
+ }
86
+
87
+ get [kBodyTimeoutError] () {
88
+ return true
57
89
  }
58
90
  }
59
91
 
92
+ const kInvalidArgumentError = Symbol.for('undici.error.UND_ERR_INVALID_ARG')
60
93
  class InvalidArgumentError extends UndiciError {
61
94
  constructor (message) {
62
95
  super(message)
@@ -64,8 +97,17 @@ class InvalidArgumentError extends UndiciError {
64
97
  this.message = message || 'Invalid Argument Error'
65
98
  this.code = 'UND_ERR_INVALID_ARG'
66
99
  }
100
+
101
+ static [Symbol.hasInstance] (instance) {
102
+ return instance && instance[kInvalidArgumentError] === true
103
+ }
104
+
105
+ get [kInvalidArgumentError] () {
106
+ return true
107
+ }
67
108
  }
68
109
 
110
+ const kInvalidReturnValueError = Symbol.for('undici.error.UND_ERR_INVALID_RETURN_VALUE')
69
111
  class InvalidReturnValueError extends UndiciError {
70
112
  constructor (message) {
71
113
  super(message)
@@ -73,16 +115,35 @@ class InvalidReturnValueError extends UndiciError {
73
115
  this.message = message || 'Invalid Return Value Error'
74
116
  this.code = 'UND_ERR_INVALID_RETURN_VALUE'
75
117
  }
118
+
119
+ static [Symbol.hasInstance] (instance) {
120
+ return instance && instance[kInvalidReturnValueError] === true
121
+ }
122
+
123
+ get [kInvalidReturnValueError] () {
124
+ return true
125
+ }
76
126
  }
77
127
 
128
+ const kAbortError = Symbol.for('undici.error.UND_ERR_ABORT')
78
129
  class AbortError extends UndiciError {
79
130
  constructor (message) {
80
131
  super(message)
81
132
  this.name = 'AbortError'
82
133
  this.message = message || 'The operation was aborted'
134
+ this.code = 'UND_ERR_ABORT'
135
+ }
136
+
137
+ static [Symbol.hasInstance] (instance) {
138
+ return instance && instance[kAbortError] === true
139
+ }
140
+
141
+ get [kAbortError] () {
142
+ return true
83
143
  }
84
144
  }
85
145
 
146
+ const kRequestAbortedError = Symbol.for('undici.error.UND_ERR_ABORTED')
86
147
  class RequestAbortedError extends AbortError {
87
148
  constructor (message) {
88
149
  super(message)
@@ -90,8 +151,17 @@ class RequestAbortedError extends AbortError {
90
151
  this.message = message || 'Request aborted'
91
152
  this.code = 'UND_ERR_ABORTED'
92
153
  }
154
+
155
+ static [Symbol.hasInstance] (instance) {
156
+ return instance && instance[kRequestAbortedError] === true
157
+ }
158
+
159
+ get [kRequestAbortedError] () {
160
+ return true
161
+ }
93
162
  }
94
163
 
164
+ const kInformationalError = Symbol.for('undici.error.UND_ERR_INFO')
95
165
  class InformationalError extends UndiciError {
96
166
  constructor (message) {
97
167
  super(message)
@@ -99,8 +169,17 @@ class InformationalError extends UndiciError {
99
169
  this.message = message || 'Request information'
100
170
  this.code = 'UND_ERR_INFO'
101
171
  }
172
+
173
+ static [Symbol.hasInstance] (instance) {
174
+ return instance && instance[kInformationalError] === true
175
+ }
176
+
177
+ get [kInformationalError] () {
178
+ return true
179
+ }
102
180
  }
103
181
 
182
+ const kRequestContentLengthMismatchError = Symbol.for('undici.error.UND_ERR_REQ_CONTENT_LENGTH_MISMATCH')
104
183
  class RequestContentLengthMismatchError extends UndiciError {
105
184
  constructor (message) {
106
185
  super(message)
@@ -108,8 +187,17 @@ class RequestContentLengthMismatchError extends UndiciError {
108
187
  this.message = message || 'Request body length does not match content-length header'
109
188
  this.code = 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH'
110
189
  }
190
+
191
+ static [Symbol.hasInstance] (instance) {
192
+ return instance && instance[kRequestContentLengthMismatchError] === true
193
+ }
194
+
195
+ get [kRequestContentLengthMismatchError] () {
196
+ return true
197
+ }
111
198
  }
112
199
 
200
+ const kResponseContentLengthMismatchError = Symbol.for('undici.error.UND_ERR_RES_CONTENT_LENGTH_MISMATCH')
113
201
  class ResponseContentLengthMismatchError extends UndiciError {
114
202
  constructor (message) {
115
203
  super(message)
@@ -117,8 +205,17 @@ class ResponseContentLengthMismatchError extends UndiciError {
117
205
  this.message = message || 'Response body length does not match content-length header'
118
206
  this.code = 'UND_ERR_RES_CONTENT_LENGTH_MISMATCH'
119
207
  }
208
+
209
+ static [Symbol.hasInstance] (instance) {
210
+ return instance && instance[kResponseContentLengthMismatchError] === true
211
+ }
212
+
213
+ get [kResponseContentLengthMismatchError] () {
214
+ return true
215
+ }
120
216
  }
121
217
 
218
+ const kClientDestroyedError = Symbol.for('undici.error.UND_ERR_DESTROYED')
122
219
  class ClientDestroyedError extends UndiciError {
123
220
  constructor (message) {
124
221
  super(message)
@@ -126,8 +223,17 @@ class ClientDestroyedError extends UndiciError {
126
223
  this.message = message || 'The client is destroyed'
127
224
  this.code = 'UND_ERR_DESTROYED'
128
225
  }
226
+
227
+ static [Symbol.hasInstance] (instance) {
228
+ return instance && instance[kClientDestroyedError] === true
229
+ }
230
+
231
+ get [kClientDestroyedError] () {
232
+ return true
233
+ }
129
234
  }
130
235
 
236
+ const kClientClosedError = Symbol.for('undici.error.UND_ERR_CLOSED')
131
237
  class ClientClosedError extends UndiciError {
132
238
  constructor (message) {
133
239
  super(message)
@@ -135,8 +241,17 @@ class ClientClosedError extends UndiciError {
135
241
  this.message = message || 'The client is closed'
136
242
  this.code = 'UND_ERR_CLOSED'
137
243
  }
244
+
245
+ static [Symbol.hasInstance] (instance) {
246
+ return instance && instance[kClientClosedError] === true
247
+ }
248
+
249
+ get [kClientClosedError] () {
250
+ return true
251
+ }
138
252
  }
139
253
 
254
+ const kSocketError = Symbol.for('undici.error.UND_ERR_SOCKET')
140
255
  class SocketError extends UndiciError {
141
256
  constructor (message, socket) {
142
257
  super(message)
@@ -145,8 +260,17 @@ class SocketError extends UndiciError {
145
260
  this.code = 'UND_ERR_SOCKET'
146
261
  this.socket = socket
147
262
  }
263
+
264
+ static [Symbol.hasInstance] (instance) {
265
+ return instance && instance[kSocketError] === true
266
+ }
267
+
268
+ get [kSocketError] () {
269
+ return true
270
+ }
148
271
  }
149
272
 
273
+ const kNotSupportedError = Symbol.for('undici.error.UND_ERR_NOT_SUPPORTED')
150
274
  class NotSupportedError extends UndiciError {
151
275
  constructor (message) {
152
276
  super(message)
@@ -154,8 +278,17 @@ class NotSupportedError extends UndiciError {
154
278
  this.message = message || 'Not supported error'
155
279
  this.code = 'UND_ERR_NOT_SUPPORTED'
156
280
  }
281
+
282
+ static [Symbol.hasInstance] (instance) {
283
+ return instance && instance[kNotSupportedError] === true
284
+ }
285
+
286
+ get [kNotSupportedError] () {
287
+ return true
288
+ }
157
289
  }
158
290
 
291
+ const kBalancedPoolMissingUpstreamError = Symbol.for('undici.error.UND_ERR_BPL_MISSING_UPSTREAM')
159
292
  class BalancedPoolMissingUpstreamError extends UndiciError {
160
293
  constructor (message) {
161
294
  super(message)
@@ -163,8 +296,17 @@ class BalancedPoolMissingUpstreamError extends UndiciError {
163
296
  this.message = message || 'No upstream has been added to the BalancedPool'
164
297
  this.code = 'UND_ERR_BPL_MISSING_UPSTREAM'
165
298
  }
299
+
300
+ static [Symbol.hasInstance] (instance) {
301
+ return instance && instance[kBalancedPoolMissingUpstreamError] === true
302
+ }
303
+
304
+ get [kBalancedPoolMissingUpstreamError] () {
305
+ return true
306
+ }
166
307
  }
167
308
 
309
+ const kHTTPParserError = Symbol.for('undici.error.UND_ERR_HTTP_PARSER')
168
310
  class HTTPParserError extends Error {
169
311
  constructor (message, code, data) {
170
312
  super(message)
@@ -172,8 +314,17 @@ class HTTPParserError extends Error {
172
314
  this.code = code ? `HPE_${code}` : undefined
173
315
  this.data = data ? data.toString() : undefined
174
316
  }
317
+
318
+ static [Symbol.hasInstance] (instance) {
319
+ return instance && instance[kHTTPParserError] === true
320
+ }
321
+
322
+ get [kHTTPParserError] () {
323
+ return true
324
+ }
175
325
  }
176
326
 
327
+ const kResponseExceededMaxSizeError = Symbol.for('undici.error.UND_ERR_RES_EXCEEDED_MAX_SIZE')
177
328
  class ResponseExceededMaxSizeError extends UndiciError {
178
329
  constructor (message) {
179
330
  super(message)
@@ -181,8 +332,17 @@ class ResponseExceededMaxSizeError extends UndiciError {
181
332
  this.message = message || 'Response content exceeded max size'
182
333
  this.code = 'UND_ERR_RES_EXCEEDED_MAX_SIZE'
183
334
  }
335
+
336
+ static [Symbol.hasInstance] (instance) {
337
+ return instance && instance[kResponseExceededMaxSizeError] === true
338
+ }
339
+
340
+ get [kResponseExceededMaxSizeError] () {
341
+ return true
342
+ }
184
343
  }
185
344
 
345
+ const kRequestRetryError = Symbol.for('undici.error.UND_ERR_REQ_RETRY')
186
346
  class RequestRetryError extends UndiciError {
187
347
  constructor (message, code, { headers, data }) {
188
348
  super(message)
@@ -193,8 +353,17 @@ class RequestRetryError extends UndiciError {
193
353
  this.data = data
194
354
  this.headers = headers
195
355
  }
356
+
357
+ static [Symbol.hasInstance] (instance) {
358
+ return instance && instance[kRequestRetryError] === true
359
+ }
360
+
361
+ get [kRequestRetryError] () {
362
+ return true
363
+ }
196
364
  }
197
365
 
366
+ const kResponseError = Symbol.for('undici.error.UND_ERR_RESPONSE')
198
367
  class ResponseError extends UndiciError {
199
368
  constructor (message, code, { headers, body }) {
200
369
  super(message)
@@ -205,8 +374,17 @@ class ResponseError extends UndiciError {
205
374
  this.body = body
206
375
  this.headers = headers
207
376
  }
377
+
378
+ static [Symbol.hasInstance] (instance) {
379
+ return instance && instance[kResponseError] === true
380
+ }
381
+
382
+ get [kResponseError] () {
383
+ return true
384
+ }
208
385
  }
209
386
 
387
+ const kSecureProxyConnectionError = Symbol.for('undici.error.UND_ERR_PRX_TLS')
210
388
  class SecureProxyConnectionError extends UndiciError {
211
389
  constructor (cause, message, options = {}) {
212
390
  super(message, { cause, ...options })
@@ -215,6 +393,32 @@ class SecureProxyConnectionError extends UndiciError {
215
393
  this.code = 'UND_ERR_PRX_TLS'
216
394
  this.cause = cause
217
395
  }
396
+
397
+ static [Symbol.hasInstance] (instance) {
398
+ return instance && instance[kSecureProxyConnectionError] === true
399
+ }
400
+
401
+ get [kSecureProxyConnectionError] () {
402
+ return true
403
+ }
404
+ }
405
+
406
+ const kMaxOriginsReachedError = Symbol.for('undici.error.UND_ERR_MAX_ORIGINS_REACHED')
407
+ class MaxOriginsReachedError extends UndiciError {
408
+ constructor (message) {
409
+ super(message)
410
+ this.name = 'MaxOriginsReachedError'
411
+ this.message = message || 'Maximum allowed origins reached'
412
+ this.code = 'UND_ERR_MAX_ORIGINS_REACHED'
413
+ }
414
+
415
+ static [Symbol.hasInstance] (instance) {
416
+ return instance && instance[kMaxOriginsReachedError] === true
417
+ }
418
+
419
+ get [kMaxOriginsReachedError] () {
420
+ return true
421
+ }
218
422
  }
219
423
 
220
424
  module.exports = {
@@ -226,7 +430,6 @@ module.exports = {
226
430
  BodyTimeoutError,
227
431
  RequestContentLengthMismatchError,
228
432
  ConnectTimeoutError,
229
- ResponseStatusCodeError,
230
433
  InvalidArgumentError,
231
434
  InvalidReturnValueError,
232
435
  RequestAbortedError,
@@ -240,5 +443,6 @@ module.exports = {
240
443
  ResponseExceededMaxSizeError,
241
444
  RequestRetryError,
242
445
  ResponseError,
243
- SecureProxyConnectionError
446
+ SecureProxyConnectionError,
447
+ MaxOriginsReachedError
244
448
  }
@@ -17,7 +17,8 @@ const {
17
17
  serializePathWithQuery,
18
18
  assertRequestHandler,
19
19
  getServerName,
20
- normalizedMethodRecords
20
+ normalizedMethodRecords,
21
+ getProtocolFromUrlString
21
22
  } = require('./util')
22
23
  const { channels } = require('./diagnostics.js')
23
24
  const { headerNameLowerCasedRecord } = require('./constants')
@@ -141,8 +142,11 @@ class Request {
141
142
 
142
143
  this.path = query ? serializePathWithQuery(path, query) : path
143
144
 
145
+ // TODO: shall we maybe standardize it to an URL object?
144
146
  this.origin = origin
145
147
 
148
+ this.protocol = getProtocolFromUrlString(origin)
149
+
146
150
  this.idempotent = idempotent == null
147
151
  ? method === 'HEAD' || method === 'GET'
148
152
  : idempotent
package/lib/core/util.js CHANGED
@@ -609,12 +609,11 @@ function ReadableStreamFrom (iterable) {
609
609
  let iterator
610
610
  return new ReadableStream(
611
611
  {
612
- async start () {
612
+ start () {
613
613
  iterator = iterable[Symbol.asyncIterator]()
614
614
  },
615
615
  pull (controller) {
616
- async function pull () {
617
- const { done, value } = await iterator.next()
616
+ return iterator.next().then(({ done, value }) => {
618
617
  if (done) {
619
618
  queueMicrotask(() => {
620
619
  controller.close()
@@ -625,15 +624,13 @@ function ReadableStreamFrom (iterable) {
625
624
  if (buf.byteLength) {
626
625
  controller.enqueue(new Uint8Array(buf))
627
626
  } else {
628
- return await pull()
627
+ return this.pull(controller)
629
628
  }
630
629
  }
631
- }
632
-
633
- return pull()
630
+ })
634
631
  },
635
- async cancel () {
636
- await iterator.return()
632
+ cancel () {
633
+ return iterator.return()
637
634
  },
638
635
  type: 'bytes'
639
636
  }
@@ -879,6 +876,30 @@ function onConnectTimeout (socket, opts) {
879
876
  destroy(socket, new ConnectTimeoutError(message))
880
877
  }
881
878
 
879
+ /**
880
+ * @param {string} urlString
881
+ * @returns {string}
882
+ */
883
+ function getProtocolFromUrlString (urlString) {
884
+ if (
885
+ urlString[0] === 'h' &&
886
+ urlString[1] === 't' &&
887
+ urlString[2] === 't' &&
888
+ urlString[3] === 'p'
889
+ ) {
890
+ switch (urlString[4]) {
891
+ case ':':
892
+ return 'http:'
893
+ case 's':
894
+ if (urlString[5] === ':') {
895
+ return 'https:'
896
+ }
897
+ }
898
+ }
899
+ // fallback if none of the usual suspects
900
+ return urlString.slice(0, urlString.indexOf(':') + 1)
901
+ }
902
+
882
903
  const kEnumerableProperty = Object.create(null)
883
904
  kEnumerableProperty.enumerable = true
884
905
 
@@ -950,5 +971,6 @@ module.exports = {
950
971
  nodeMinor,
951
972
  safeHTTPMethods: Object.freeze(['GET', 'HEAD', 'OPTIONS', 'TRACE']),
952
973
  wrapRequestBody,
953
- setupConnectTimeout
974
+ setupConnectTimeout,
975
+ getProtocolFromUrlString
954
976
  }