undici 6.20.0 → 7.0.0-alpha.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/README.md +6 -10
- package/docs/docs/api/Agent.md +0 -3
- package/docs/docs/api/Client.md +1 -3
- package/docs/docs/api/Debug.md +1 -1
- package/docs/docs/api/Dispatcher.md +60 -8
- package/docs/docs/api/EnvHttpProxyAgent.md +0 -1
- package/docs/docs/api/Fetch.md +1 -0
- package/docs/docs/api/MockAgent.md +2 -0
- package/docs/docs/api/MockPool.md +2 -1
- package/docs/docs/api/Pool.md +0 -1
- package/docs/docs/api/RetryAgent.md +1 -1
- package/docs/docs/api/RetryHandler.md +1 -1
- package/docs/docs/api/WebSocket.md +45 -3
- package/index.js +6 -6
- package/lib/api/abort-signal.js +2 -0
- package/lib/api/api-connect.js +3 -1
- package/lib/api/api-pipeline.js +7 -6
- package/lib/api/api-request.js +32 -47
- package/lib/api/api-stream.js +39 -50
- package/lib/api/api-upgrade.js +5 -3
- package/lib/api/readable.js +261 -64
- package/lib/api/util.js +2 -0
- package/lib/core/constants.js +11 -9
- package/lib/core/diagnostics.js +122 -128
- package/lib/core/errors.js +4 -4
- package/lib/core/request.js +11 -9
- package/lib/core/symbols.js +2 -1
- package/lib/core/tree.js +9 -1
- package/lib/core/util.js +219 -48
- package/lib/dispatcher/agent.js +3 -17
- package/lib/dispatcher/balanced-pool.js +5 -8
- package/lib/dispatcher/client-h1.js +278 -54
- package/lib/dispatcher/client-h2.js +1 -1
- package/lib/dispatcher/client.js +23 -34
- package/lib/dispatcher/dispatcher-base.js +2 -34
- package/lib/dispatcher/dispatcher.js +3 -24
- package/lib/dispatcher/fixed-queue.js +91 -49
- package/lib/dispatcher/pool-stats.js +2 -0
- package/lib/dispatcher/pool.js +3 -6
- package/lib/dispatcher/proxy-agent.js +6 -7
- package/lib/handler/decorator-handler.js +24 -0
- package/lib/handler/redirect-handler.js +11 -2
- package/lib/handler/retry-handler.js +12 -3
- package/lib/interceptor/dns.js +346 -0
- package/lib/interceptor/dump.js +2 -2
- package/lib/interceptor/redirect.js +11 -14
- package/lib/interceptor/response-error.js +4 -1
- package/lib/llhttp/constants.d.ts +97 -0
- package/lib/llhttp/constants.js +412 -192
- package/lib/llhttp/constants.js.map +1 -0
- package/lib/llhttp/llhttp-wasm.js +11 -1
- package/lib/llhttp/llhttp_simd-wasm.js +11 -1
- package/lib/llhttp/utils.d.ts +2 -0
- package/lib/llhttp/utils.js +9 -9
- package/lib/llhttp/utils.js.map +1 -0
- package/lib/mock/mock-agent.js +5 -8
- package/lib/mock/mock-client.js +9 -4
- package/lib/mock/mock-errors.js +3 -1
- package/lib/mock/mock-interceptor.js +8 -6
- package/lib/mock/mock-pool.js +9 -4
- package/lib/mock/mock-symbols.js +3 -1
- package/lib/mock/mock-utils.js +29 -5
- package/lib/web/cache/cache.js +24 -21
- package/lib/web/cache/cachestorage.js +1 -1
- package/lib/web/cookies/index.js +17 -13
- package/lib/web/cookies/parse.js +2 -2
- package/lib/web/eventsource/eventsource-stream.js +9 -8
- package/lib/web/eventsource/eventsource.js +10 -6
- package/lib/web/fetch/body.js +42 -36
- package/lib/web/fetch/constants.js +35 -26
- package/lib/web/fetch/data-url.js +1 -1
- package/lib/web/fetch/formdata-parser.js +2 -2
- package/lib/web/fetch/formdata.js +65 -54
- package/lib/web/fetch/headers.js +117 -85
- package/lib/web/fetch/index.js +55 -62
- package/lib/web/fetch/request.js +135 -77
- package/lib/web/fetch/response.js +86 -56
- package/lib/web/fetch/util.js +90 -64
- package/lib/web/fetch/webidl.js +99 -64
- package/lib/web/websocket/connection.js +76 -147
- package/lib/web/websocket/constants.js +3 -4
- package/lib/web/websocket/events.js +4 -2
- package/lib/web/websocket/frame.js +45 -3
- package/lib/web/websocket/receiver.js +29 -33
- package/lib/web/websocket/sender.js +18 -13
- package/lib/web/websocket/stream/websocketerror.js +83 -0
- package/lib/web/websocket/stream/websocketstream.js +485 -0
- package/lib/web/websocket/util.js +128 -77
- package/lib/web/websocket/websocket.js +234 -135
- package/package.json +20 -33
- package/scripts/strip-comments.js +3 -1
- package/types/agent.d.ts +7 -7
- package/types/api.d.ts +24 -24
- package/types/balanced-pool.d.ts +11 -11
- package/types/client.d.ts +11 -12
- package/types/diagnostics-channel.d.ts +10 -10
- package/types/dispatcher.d.ts +96 -97
- package/types/env-http-proxy-agent.d.ts +2 -2
- package/types/errors.d.ts +53 -47
- package/types/fetch.d.ts +8 -8
- package/types/formdata.d.ts +7 -7
- package/types/global-dispatcher.d.ts +4 -4
- package/types/global-origin.d.ts +5 -5
- package/types/handlers.d.ts +4 -4
- package/types/header.d.ts +157 -1
- package/types/index.d.ts +42 -46
- package/types/interceptors.d.ts +22 -8
- package/types/mock-agent.d.ts +21 -18
- package/types/mock-client.d.ts +4 -4
- package/types/mock-errors.d.ts +3 -3
- package/types/mock-interceptor.d.ts +19 -19
- package/types/mock-pool.d.ts +4 -4
- package/types/patch.d.ts +0 -4
- package/types/pool-stats.d.ts +8 -8
- package/types/pool.d.ts +12 -12
- package/types/proxy-agent.d.ts +4 -4
- package/types/readable.d.ts +22 -14
- package/types/retry-agent.d.ts +1 -1
- package/types/retry-handler.d.ts +8 -8
- package/types/util.d.ts +3 -3
- package/types/utility.d.ts +7 -0
- package/types/webidl.d.ts +44 -6
- package/types/websocket.d.ts +34 -1
- package/docs/docs/api/DispatchInterceptor.md +0 -60
- package/lib/interceptor/redirect-interceptor.js +0 -21
- package/lib/mock/pluralizer.js +0 -29
- package/lib/web/cache/symbols.js +0 -5
- package/lib/web/fetch/file.js +0 -126
- package/lib/web/fetch/symbols.js +0 -9
- package/lib/web/fileapi/encoding.js +0 -290
- package/lib/web/fileapi/filereader.js +0 -344
- package/lib/web/fileapi/progressevent.js +0 -78
- package/lib/web/fileapi/symbols.js +0 -10
- package/lib/web/fileapi/util.js +0 -391
- package/lib/web/websocket/symbols.js +0 -12
- package/types/file.d.ts +0 -39
- package/types/filereader.d.ts +0 -54
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# undici
|
|
2
2
|
|
|
3
|
-
[](https://github.com/nodejs/undici/actions/workflows/nodejs.yml) [](https://github.com/nodejs/undici/actions/workflows/nodejs.yml) [](https://github.com/neostandard/neostandard) [](https://badge.fury.io/js/undici) [](https://codecov.io/gh/nodejs/undici)
|
|
4
4
|
|
|
5
5
|
An HTTP/1.1 client, written from scratch for Node.js.
|
|
6
6
|
|
|
@@ -84,6 +84,7 @@ The `body` mixins are the most common way to format the request/response body. M
|
|
|
84
84
|
|
|
85
85
|
- [`.arrayBuffer()`](https://fetch.spec.whatwg.org/#dom-body-arraybuffer)
|
|
86
86
|
- [`.blob()`](https://fetch.spec.whatwg.org/#dom-body-blob)
|
|
87
|
+
- [`.bytes()`](https://fetch.spec.whatwg.org/#dom-body-bytes)
|
|
87
88
|
- [`.json()`](https://fetch.spec.whatwg.org/#dom-body-json)
|
|
88
89
|
- [`.text()`](https://fetch.spec.whatwg.org/#dom-body-text)
|
|
89
90
|
|
|
@@ -126,7 +127,6 @@ Arguments:
|
|
|
126
127
|
* **options** [`RequestOptions`](./docs/docs/api/Dispatcher.md#parameter-requestoptions)
|
|
127
128
|
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
|
|
128
129
|
* **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
|
|
129
|
-
* **maxRedirections** `Integer` - Default: `0`
|
|
130
130
|
|
|
131
131
|
Returns a promise with the result of the `Dispatcher.request` method.
|
|
132
132
|
|
|
@@ -142,7 +142,6 @@ Arguments:
|
|
|
142
142
|
* **options** [`StreamOptions`](./docs/docs/api/Dispatcher.md#parameter-streamoptions)
|
|
143
143
|
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
|
|
144
144
|
* **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
|
|
145
|
-
* **maxRedirections** `Integer` - Default: `0`
|
|
146
145
|
* **factory** `Dispatcher.stream.factory`
|
|
147
146
|
|
|
148
147
|
Returns a promise with the result of the `Dispatcher.stream` method.
|
|
@@ -159,7 +158,6 @@ Arguments:
|
|
|
159
158
|
* **options** [`PipelineOptions`](./docs/docs/api/Dispatcher.md#parameter-pipelineoptions)
|
|
160
159
|
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
|
|
161
160
|
* **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
|
|
162
|
-
* **maxRedirections** `Integer` - Default: `0`
|
|
163
161
|
* **handler** `Dispatcher.pipeline.handler`
|
|
164
162
|
|
|
165
163
|
Returns: `stream.Duplex`
|
|
@@ -177,7 +175,6 @@ Arguments:
|
|
|
177
175
|
* **url** `string | URL | UrlObject`
|
|
178
176
|
* **options** [`ConnectOptions`](./docs/docs/api/Dispatcher.md#parameter-connectoptions)
|
|
179
177
|
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
|
|
180
|
-
* **maxRedirections** `Integer` - Default: `0`
|
|
181
178
|
* **callback** `(err: Error | null, data: ConnectData | null) => void` (optional)
|
|
182
179
|
|
|
183
180
|
Returns a promise with the result of the `Dispatcher.connect` method.
|
|
@@ -233,7 +230,7 @@ A body can be of the following types:
|
|
|
233
230
|
- URLSearchParams
|
|
234
231
|
- FormData
|
|
235
232
|
|
|
236
|
-
In this implementation of fetch, ```request.body``` now accepts ```Async Iterables```. It is not present in the [Fetch Standard
|
|
233
|
+
In this implementation of fetch, ```request.body``` now accepts ```Async Iterables```. It is not present in the [Fetch Standard](https://fetch.spec.whatwg.org).
|
|
237
234
|
|
|
238
235
|
```js
|
|
239
236
|
import { fetch } from 'undici'
|
|
@@ -262,13 +259,13 @@ await fetch('http://example.com', { method: 'POST', body })
|
|
|
262
259
|
|
|
263
260
|
#### `request.duplex`
|
|
264
261
|
|
|
265
|
-
- half
|
|
262
|
+
- `'half'`
|
|
266
263
|
|
|
267
|
-
In this implementation of fetch, `request.duplex` must be set if `request.body` is `ReadableStream` or `Async Iterables`, however,
|
|
264
|
+
In this implementation of fetch, `request.duplex` must be set if `request.body` is `ReadableStream` or `Async Iterables`, however, even though the value must be set to `'half'`, it is actually a _full_ duplex. For more detail refer to the [Fetch Standard](https://fetch.spec.whatwg.org/#dom-requestinit-duplex).
|
|
268
265
|
|
|
269
266
|
#### `response.body`
|
|
270
267
|
|
|
271
|
-
Nodejs has two kinds of streams: [web streams](https://nodejs.org/
|
|
268
|
+
Nodejs has two kinds of streams: [web streams](https://nodejs.org/api/webstreams.html), which follow the API of the WHATWG web standard found in browsers, and an older Node-specific [streams API](https://nodejs.org/api/stream.html). `response.body` returns a readable web stream. If you would prefer to work with a Node stream you can convert a web stream using `.fromWeb()`.
|
|
272
269
|
|
|
273
270
|
```js
|
|
274
271
|
import { fetch } from 'undici'
|
|
@@ -337,7 +334,6 @@ Arguments:
|
|
|
337
334
|
* **url** `string | URL | UrlObject`
|
|
338
335
|
* **options** [`UpgradeOptions`](./docs/docs/api/Dispatcher.md#parameter-upgradeoptions)
|
|
339
336
|
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
|
|
340
|
-
* **maxRedirections** `Integer` - Default: `0`
|
|
341
337
|
* **callback** `(error: Error | null, data: UpgradeData) => void` (optional)
|
|
342
338
|
|
|
343
339
|
Returns a promise with the result of the `Dispatcher.upgrade` method.
|
package/docs/docs/api/Agent.md
CHANGED
|
@@ -19,8 +19,6 @@ Returns: `Agent`
|
|
|
19
19
|
Extends: [`PoolOptions`](Pool.md#parameter-pooloptions)
|
|
20
20
|
|
|
21
21
|
* **factory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Pool(origin, opts)`
|
|
22
|
-
* **maxRedirections** `Integer` - Default: `0`. The number of HTTP redirection to follow unless otherwise specified in `DispatchOptions`.
|
|
23
|
-
* **interceptors** `{ Agent: DispatchInterceptor[] }` - Default: `[RedirectInterceptor]` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching). Note that the behavior of interceptors is Experimental and might change at any given time.
|
|
24
22
|
|
|
25
23
|
## Instance Properties
|
|
26
24
|
|
|
@@ -51,7 +49,6 @@ Implements [`Dispatcher.dispatch(options, handler)`](Dispatcher.md#dispatcherdis
|
|
|
51
49
|
Extends: [`DispatchOptions`](Dispatcher.md#parameter-dispatchoptions)
|
|
52
50
|
|
|
53
51
|
* **origin** `string | URL`
|
|
54
|
-
* **maxRedirections** `Integer`.
|
|
55
52
|
|
|
56
53
|
Implements [`Dispatcher.destroy([error, callback])`](Dispatcher.md#dispatcherdestroyerror-callback-promise).
|
|
57
54
|
|
package/docs/docs/api/Client.md
CHANGED
|
@@ -19,7 +19,7 @@ Returns: `Client`
|
|
|
19
19
|
|
|
20
20
|
> ⚠️ Warning: The `H2` support is experimental.
|
|
21
21
|
|
|
22
|
-
* **bodyTimeout** `number | null` (optional) - Default: `300e3` - The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Defaults to 300 seconds. Please note the `timeout` will be reset if you keep writing data to the
|
|
22
|
+
* **bodyTimeout** `number | null` (optional) - Default: `300e3` - The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Defaults to 300 seconds. Please note the `timeout` will be reset if you keep writing data to the socket everytime.
|
|
23
23
|
* **headersTimeout** `number | null` (optional) - Default: `300e3` - The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers while not sending the request. Defaults to 300 seconds.
|
|
24
24
|
* **keepAliveMaxTimeout** `number | null` (optional) - Default: `600e3` - The maximum allowed `keepAliveTimeout`, in milliseconds, when overridden by *keep-alive* hints from the server. Defaults to 10 minutes.
|
|
25
25
|
* **keepAliveTimeout** `number | null` (optional) - Default: `4e3` - The timeout, in milliseconds, after which a socket without active requests will time out. Monitors time between activity on a connected socket. This value may be overridden by *keep-alive* hints from the server. See [MDN: HTTP - Headers - Keep-Alive directives](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive#directives) for more details. Defaults to 4 seconds.
|
|
@@ -29,8 +29,6 @@ Returns: `Client`
|
|
|
29
29
|
* **pipelining** `number | null` (optional) - Default: `1` - The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Carefully consider your workload and environment before enabling concurrent requests as pipelining may reduce performance if used incorrectly. Pipelining is sensitive to network stack settings as well as head of line blocking caused by e.g. long running requests. Set to `0` to disable keep-alive connections.
|
|
30
30
|
* **connect** `ConnectOptions | Function | null` (optional) - Default: `null`.
|
|
31
31
|
* **strictContentLength** `Boolean` (optional) - Default: `true` - Whether to treat request content length mismatches as errors. If true, an error is thrown when the request content-length header doesn't match the length of the request body.
|
|
32
|
-
<!-- TODO: Remove once we drop its support -->
|
|
33
|
-
* **interceptors** `{ Client: DispatchInterceptor[] }` - Default: `[RedirectInterceptor]` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching). Note that the behavior of interceptors is Experimental and might change at any given time. **Note: this is deprecated in favor of [Dispatcher#compose](./Dispatcher.md#dispatcher). Support will be droped in next major.**
|
|
34
32
|
* **autoSelectFamily**: `boolean` (optional) - Default: depends on local Node version, on Node 18.13.0 and above is `false`. Enables a family autodetection algorithm that loosely implements section 5 of [RFC 8305](https://tools.ietf.org/html/rfc8305#section-5). See [here](https://nodejs.org/api/net.html#socketconnectoptions-connectlistener) for more details. This option is ignored if not supported by the current Node version.
|
|
35
33
|
* **autoSelectFamilyAttemptTimeout**: `number` - Default: depends on local Node version, on Node 18.13.0 and above is `250`. The amount of time in milliseconds to wait for a connection attempt to finish before trying the next address when using the `autoSelectFamily` option. See [here](https://nodejs.org/api/net.html#socketconnectoptions-connectlistener) for more details.
|
|
36
34
|
* **allowH2**: `boolean` - Default: `false`. Enables support for H2 if the server has assigned bigger priority to it through ALPN negotiation.
|
package/docs/docs/api/Debug.md
CHANGED
|
@@ -201,7 +201,6 @@ Returns: `Boolean` - `false` if dispatcher is busy and further dispatch calls wo
|
|
|
201
201
|
* **upgrade** `string | null` (optional) - Default: `null` - Upgrade the request. Should be used to specify the kind of upgrade i.e. `'Websocket'`.
|
|
202
202
|
* **bodyTimeout** `number | null` (optional) - The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Defaults to 300 seconds.
|
|
203
203
|
* **headersTimeout** `number | null` (optional) - The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers while not sending the request. Defaults to 300 seconds.
|
|
204
|
-
* **throwOnError** `boolean` (optional) - Default: `false` - Whether Undici should throw an error upon receiving a 4xx or 5xx response from the server.
|
|
205
204
|
* **expectContinue** `boolean` (optional) - Default: `false` - For H2, it appends the expect: 100-continue header, and halts the request body until a 100-continue is received from the remote server
|
|
206
205
|
|
|
207
206
|
#### Parameter: `DispatchHandler`
|
|
@@ -479,7 +478,7 @@ The `RequestOptions.method` property should not be value `'CONNECT'`.
|
|
|
479
478
|
#### Parameter: `ResponseData`
|
|
480
479
|
|
|
481
480
|
* **statusCode** `number`
|
|
482
|
-
* **headers** `Record<string, string | string[]>` - Note that all header keys are lower-cased, e.
|
|
481
|
+
* **headers** `Record<string, string | string[]>` - Note that all header keys are lower-cased, e.g. `content-type`.
|
|
483
482
|
* **body** `stream.Readable` which also implements [the body mixin from the Fetch Standard](https://fetch.spec.whatwg.org/#body-mixin).
|
|
484
483
|
* **trailers** `Record<string, string>` - This object starts out
|
|
485
484
|
as empty and will be mutated to contain trailers after `body` has emitted `'end'`.
|
|
@@ -488,11 +487,13 @@ The `RequestOptions.method` property should not be value `'CONNECT'`.
|
|
|
488
487
|
|
|
489
488
|
`body` contains the following additional [body mixin](https://fetch.spec.whatwg.org/#body-mixin) methods and properties:
|
|
490
489
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
490
|
+
* [`.arrayBuffer()`](https://fetch.spec.whatwg.org/#dom-body-arraybuffer)
|
|
491
|
+
* [`.blob()`](https://fetch.spec.whatwg.org/#dom-body-blob)
|
|
492
|
+
* [`.bytes()`](https://fetch.spec.whatwg.org/#dom-body-bytes)
|
|
493
|
+
* [`.json()`](https://fetch.spec.whatwg.org/#dom-body-json)
|
|
494
|
+
* [`.text()`](https://fetch.spec.whatwg.org/#dom-body-text)
|
|
495
|
+
* `body`
|
|
496
|
+
* `bodyUsed`
|
|
496
497
|
|
|
497
498
|
`body` can not be consumed twice. For example, calling `text()` after `json()` throws `TypeError`.
|
|
498
499
|
|
|
@@ -973,7 +974,7 @@ const client = new Client("http://example.com").compose(
|
|
|
973
974
|
})
|
|
974
975
|
);
|
|
975
976
|
|
|
976
|
-
// or
|
|
977
|
+
// or
|
|
977
978
|
client.dispatch(
|
|
978
979
|
{
|
|
979
980
|
path: "/",
|
|
@@ -984,6 +985,57 @@ client.dispatch(
|
|
|
984
985
|
);
|
|
985
986
|
```
|
|
986
987
|
|
|
988
|
+
##### `dns`
|
|
989
|
+
|
|
990
|
+
The `dns` interceptor enables you to cache DNS lookups for a given duration, per origin.
|
|
991
|
+
|
|
992
|
+
>It is well suited for scenarios where you want to cache DNS lookups to avoid the overhead of resolving the same domain multiple times
|
|
993
|
+
|
|
994
|
+
**Options**
|
|
995
|
+
- `maxTTL` - The maximum time-to-live (in milliseconds) of the DNS cache. It should be a positive integer. Default: `10000`.
|
|
996
|
+
- Set `0` to disable TTL.
|
|
997
|
+
- `maxItems` - The maximum number of items to cache. It should be a positive integer. Default: `Infinity`.
|
|
998
|
+
- `dualStack` - Whether to resolve both IPv4 and IPv6 addresses. Default: `true`.
|
|
999
|
+
- It will also attempt a happy-eyeballs-like approach to connect to the available addresses in case of a connection failure.
|
|
1000
|
+
- `affinity` - Whether to use IPv4 or IPv6 addresses. Default: `4`.
|
|
1001
|
+
- It can be either `'4` or `6`.
|
|
1002
|
+
- It will only take effect if `dualStack` is `false`.
|
|
1003
|
+
- `lookup: (hostname: string, options: LookupOptions, callback: (err: NodeJS.ErrnoException | null, addresses: DNSInterceptorRecord[]) => void) => void` - Custom lookup function. Default: `dns.lookup`.
|
|
1004
|
+
- For more info see [dns.lookup](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback).
|
|
1005
|
+
- `pick: (origin: URL, records: DNSInterceptorRecords, affinity: 4 | 6) => DNSInterceptorRecord` - Custom pick function. Default: `RoundRobin`.
|
|
1006
|
+
- The function should return a single record from the records array.
|
|
1007
|
+
- By default a simplified version of Round Robin is used.
|
|
1008
|
+
- The `records` property can be mutated to store the state of the balancing algorithm.
|
|
1009
|
+
|
|
1010
|
+
> The `Dispatcher#options` also gets extended with the options `dns.affinity`, `dns.dualStack`, `dns.lookup` and `dns.pick` which can be used to configure the interceptor at a request-per-request basis.
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
**DNSInterceptorRecord**
|
|
1014
|
+
It represents a DNS record.
|
|
1015
|
+
- `family` - (`number`) The IP family of the address. It can be either `4` or `6`.
|
|
1016
|
+
- `address` - (`string`) The IP address.
|
|
1017
|
+
|
|
1018
|
+
**DNSInterceptorOriginRecords**
|
|
1019
|
+
It represents a map of DNS IP addresses records for a single origin.
|
|
1020
|
+
- `4.ips` - (`DNSInterceptorRecord[] | null`) The IPv4 addresses.
|
|
1021
|
+
- `6.ips` - (`DNSInterceptorRecord[] | null`) The IPv6 addresses.
|
|
1022
|
+
|
|
1023
|
+
**Example - Basic DNS Interceptor**
|
|
1024
|
+
|
|
1025
|
+
```js
|
|
1026
|
+
const { Client, interceptors } = require("undici");
|
|
1027
|
+
const { dns } = interceptors;
|
|
1028
|
+
|
|
1029
|
+
const client = new Agent().compose([
|
|
1030
|
+
dns({ ...opts })
|
|
1031
|
+
])
|
|
1032
|
+
|
|
1033
|
+
const response = await client.request({
|
|
1034
|
+
origin: `http://localhost:3030`,
|
|
1035
|
+
...requestOpts
|
|
1036
|
+
})
|
|
1037
|
+
```
|
|
1038
|
+
|
|
987
1039
|
##### `Response Error Interceptor`
|
|
988
1040
|
|
|
989
1041
|
**Introduction**
|
|
@@ -133,7 +133,6 @@ Implements [`Dispatcher.dispatch(options, handler)`](Dispatcher.md#dispatcherdis
|
|
|
133
133
|
Extends: [`DispatchOptions`](Dispatcher.md#parameter-dispatchoptions)
|
|
134
134
|
|
|
135
135
|
* **origin** `string | URL`
|
|
136
|
-
* **maxRedirections** `Integer`.
|
|
137
136
|
|
|
138
137
|
Implements [`Dispatcher.destroy([error, callback])`](Dispatcher.md#dispatcherdestroyerror-callback-promise).
|
|
139
138
|
|
package/docs/docs/api/Fetch.md
CHANGED
|
@@ -28,6 +28,7 @@ This API is implemented as per the standard, you can find documentation on [MDN]
|
|
|
28
28
|
|
|
29
29
|
- [`.arrayBuffer()`](https://fetch.spec.whatwg.org/#dom-body-arraybuffer)
|
|
30
30
|
- [`.blob()`](https://fetch.spec.whatwg.org/#dom-body-blob)
|
|
31
|
+
- [`.bytes()`](https://fetch.spec.whatwg.org/#dom-body-bytes)
|
|
31
32
|
- [`.formData()`](https://fetch.spec.whatwg.org/#dom-body-formdata)
|
|
32
33
|
- [`.json()`](https://fetch.spec.whatwg.org/#dom-body-json)
|
|
33
34
|
- [`.text()`](https://fetch.spec.whatwg.org/#dom-body-text)
|
|
@@ -18,6 +18,8 @@ Extends: [`AgentOptions`](Agent.md#parameter-agentoptions)
|
|
|
18
18
|
|
|
19
19
|
* **agent** `Agent` (optional) - Default: `new Agent([options])` - a custom agent encapsulated by the MockAgent.
|
|
20
20
|
|
|
21
|
+
* **ignoreTrailingSlash** `boolean` (optional) - Default: `false` - set the default value for `ignoreTrailingSlash` for interceptors.
|
|
22
|
+
|
|
21
23
|
### Example - Basic MockAgent instantiation
|
|
22
24
|
|
|
23
25
|
This will instantiate the MockAgent. It will not do anything until registered as the agent to use with requests and mock interceptions are added.
|
|
@@ -58,6 +58,7 @@ Returns: `MockInterceptor` corresponding to the input options.
|
|
|
58
58
|
* **body** `string | RegExp | (body: string) => boolean` - (optional) - a matcher for the HTTP request body.
|
|
59
59
|
* **headers** `Record<string, string | RegExp | (body: string) => boolean`> - (optional) - a matcher for the HTTP request headers. To be intercepted, a request must match all defined headers. Extra headers not defined here may (or may not) be included in the request and do not affect the interception in any way.
|
|
60
60
|
* **query** `Record<string, any> | null` - (optional) - a matcher for the HTTP request query string params. Only applies when a `string` was provided for `MockPoolInterceptOptions.path`.
|
|
61
|
+
* **ignoreTrailingSlash** `boolean` - (optional) - set to `true` if the matcher should also match by ignoring potential trailing slashes in `MockPoolInterceptOptions.path`.
|
|
61
62
|
|
|
62
63
|
### Return: `MockInterceptor`
|
|
63
64
|
|
|
@@ -81,7 +82,7 @@ By default, `reply` and `replyWithError` define the behaviour for the first matc
|
|
|
81
82
|
|
|
82
83
|
### Return: `MockScope`
|
|
83
84
|
|
|
84
|
-
A `MockScope` is associated with a single `MockInterceptor`. With this, we can configure the default behaviour of
|
|
85
|
+
A `MockScope` is associated with a single `MockInterceptor`. With this, we can configure the default behaviour of an intercepted reply.
|
|
85
86
|
|
|
86
87
|
* **delay** `(waitInMs: number) => MockScope` - delay the associated reply by a set amount in ms.
|
|
87
88
|
* **persist** `() => MockScope` - any matching request will always reply with the defined response indefinitely.
|
package/docs/docs/api/Pool.md
CHANGED
|
@@ -19,7 +19,6 @@ Extends: [`ClientOptions`](Client.md#parameter-clientoptions)
|
|
|
19
19
|
|
|
20
20
|
* **factory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Client(origin, opts)`
|
|
21
21
|
* **connections** `number | null` (optional) - Default: `null` - The number of `Client` instances to create. When set to `null`, the `Pool` instance will create an unlimited amount of `Client` instances.
|
|
22
|
-
* **interceptors** `{ Pool: DispatchInterceptor[] } }` - Default: `{ Pool: [] }` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching).
|
|
23
22
|
|
|
24
23
|
## Instance Properties
|
|
25
24
|
|
|
@@ -46,7 +46,7 @@ It represents the retry state for a given request.
|
|
|
46
46
|
- **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandlers) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every retry.
|
|
47
47
|
- **handler** Extends [`Dispatch.DispatchHandlers`](Dispatcher.md#dispatcherdispatchoptions-handler) (required) - Handler function to be called after the request is successful or the retries are exhausted.
|
|
48
48
|
|
|
49
|
-
>__Note__: The `RetryHandler` does not retry over stateful bodies (e.g. streams, AsyncIterable) as those, once consumed, are left in
|
|
49
|
+
>__Note__: The `RetryHandler` does not retry over stateful bodies (e.g. streams, AsyncIterable) as those, once consumed, are left in a state that cannot be reutilized. For these situations the `RetryHandler` will identify
|
|
50
50
|
>the body as stateful and will not retry the request rejecting with the error `UND_ERR_REQ_RETRY`.
|
|
51
51
|
|
|
52
52
|
Examples:
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Class: WebSocket
|
|
2
2
|
|
|
3
|
-
> ⚠️ Warning: the WebSocket API is experimental.
|
|
4
|
-
|
|
5
3
|
Extends: [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)
|
|
6
4
|
|
|
7
5
|
The WebSocket object provides a way to manage a WebSocket connection to a server, allowing bidirectional communication. The API follows the [WebSocket spec](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) and [RFC 6455](https://datatracker.ietf.org/doc/html/rfc6455).
|
|
@@ -10,7 +8,7 @@ The WebSocket object provides a way to manage a WebSocket connection to a server
|
|
|
10
8
|
|
|
11
9
|
Arguments:
|
|
12
10
|
|
|
13
|
-
* **url** `URL | string`
|
|
11
|
+
* **url** `URL | string`
|
|
14
12
|
* **protocol** `string | string[] | WebSocketInit` (optional) - Subprotocol(s) to request the server use, or a [`Dispatcher`](./Dispatcher.md).
|
|
15
13
|
|
|
16
14
|
### Example:
|
|
@@ -36,6 +34,50 @@ import { WebSocket } from 'undici'
|
|
|
36
34
|
const ws = new WebSocket('wss://echo.websocket.events', ['echo', 'chat'])
|
|
37
35
|
```
|
|
38
36
|
|
|
37
|
+
# Class: WebSocketStream
|
|
38
|
+
|
|
39
|
+
> ⚠️ Warning: the WebSocketStream API has not been finalized and is likely to change.
|
|
40
|
+
|
|
41
|
+
See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebSocketStream) for more information.
|
|
42
|
+
|
|
43
|
+
## `new WebSocketStream(url[, protocol])`
|
|
44
|
+
|
|
45
|
+
Arguments:
|
|
46
|
+
|
|
47
|
+
* **url** `URL | string`
|
|
48
|
+
* **options** `WebSocketStreamOptions` (optional)
|
|
49
|
+
|
|
50
|
+
### WebSocketStream Example
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
const stream = new WebSocketStream('https://echo.websocket.org/')
|
|
54
|
+
const { readable, writable } = await stream.opened
|
|
55
|
+
|
|
56
|
+
async function read () {
|
|
57
|
+
/** @type {ReadableStreamReader} */
|
|
58
|
+
const reader = readable.getReader()
|
|
59
|
+
|
|
60
|
+
while (true) {
|
|
61
|
+
const { done, value } = await reader.read()
|
|
62
|
+
if (done) break
|
|
63
|
+
|
|
64
|
+
// do something with value
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function write () {
|
|
69
|
+
/** @type {WritableStreamDefaultWriter} */
|
|
70
|
+
const writer = writable.getWriter()
|
|
71
|
+
writer.write('Hello, world!')
|
|
72
|
+
writer.releaseLock()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
read()
|
|
76
|
+
|
|
77
|
+
setInterval(() => write(), 5000)
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
|
|
39
81
|
## Read More
|
|
40
82
|
|
|
41
83
|
- [MDN - WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
|
package/index.js
CHANGED
|
@@ -21,7 +21,6 @@ const RetryHandler = require('./lib/handler/retry-handler')
|
|
|
21
21
|
const { getGlobalDispatcher, setGlobalDispatcher } = require('./lib/global')
|
|
22
22
|
const DecoratorHandler = require('./lib/handler/decorator-handler')
|
|
23
23
|
const RedirectHandler = require('./lib/handler/redirect-handler')
|
|
24
|
-
const createRedirectInterceptor = require('./lib/interceptor/redirect-interceptor')
|
|
25
24
|
|
|
26
25
|
Object.assign(Dispatcher.prototype, api)
|
|
27
26
|
|
|
@@ -37,11 +36,11 @@ module.exports.RetryHandler = RetryHandler
|
|
|
37
36
|
|
|
38
37
|
module.exports.DecoratorHandler = DecoratorHandler
|
|
39
38
|
module.exports.RedirectHandler = RedirectHandler
|
|
40
|
-
module.exports.createRedirectInterceptor = createRedirectInterceptor
|
|
41
39
|
module.exports.interceptors = {
|
|
42
40
|
redirect: require('./lib/interceptor/redirect'),
|
|
43
41
|
retry: require('./lib/interceptor/retry'),
|
|
44
|
-
dump: require('./lib/interceptor/dump')
|
|
42
|
+
dump: require('./lib/interceptor/dump'),
|
|
43
|
+
dns: require('./lib/interceptor/dns')
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
module.exports.buildConnector = buildConnector
|
|
@@ -119,8 +118,6 @@ module.exports.Headers = require('./lib/web/fetch/headers').Headers
|
|
|
119
118
|
module.exports.Response = require('./lib/web/fetch/response').Response
|
|
120
119
|
module.exports.Request = require('./lib/web/fetch/request').Request
|
|
121
120
|
module.exports.FormData = require('./lib/web/fetch/formdata').FormData
|
|
122
|
-
module.exports.File = globalThis.File ?? require('node:buffer').File
|
|
123
|
-
module.exports.FileReader = require('./lib/web/fileapi/filereader').FileReader
|
|
124
121
|
|
|
125
122
|
const { setGlobalOrigin, getGlobalOrigin } = require('./lib/web/fetch/global')
|
|
126
123
|
|
|
@@ -128,7 +125,7 @@ module.exports.setGlobalOrigin = setGlobalOrigin
|
|
|
128
125
|
module.exports.getGlobalOrigin = getGlobalOrigin
|
|
129
126
|
|
|
130
127
|
const { CacheStorage } = require('./lib/web/cache/cachestorage')
|
|
131
|
-
const { kConstruct } = require('./lib/
|
|
128
|
+
const { kConstruct } = require('./lib/core/symbols')
|
|
132
129
|
|
|
133
130
|
// Cache & CacheStorage are tightly coupled with fetch. Even if it may run
|
|
134
131
|
// in an older version of Node, it doesn't have any use without fetch.
|
|
@@ -152,6 +149,9 @@ module.exports.CloseEvent = CloseEvent
|
|
|
152
149
|
module.exports.ErrorEvent = ErrorEvent
|
|
153
150
|
module.exports.MessageEvent = MessageEvent
|
|
154
151
|
|
|
152
|
+
module.exports.WebSocketStream = require('./lib/web/websocket/stream/websocketstream').WebSocketStream
|
|
153
|
+
module.exports.WebSocketError = require('./lib/web/websocket/stream/websocketerror').WebSocketError
|
|
154
|
+
|
|
155
155
|
module.exports.request = makeDispatcher(api.request)
|
|
156
156
|
module.exports.stream = makeDispatcher(api.stream)
|
|
157
157
|
module.exports.pipeline = makeDispatcher(api.pipeline)
|
package/lib/api/abort-signal.js
CHANGED
package/lib/api/api-connect.js
CHANGED
|
@@ -95,7 +95,9 @@ function connect (opts, callback) {
|
|
|
95
95
|
|
|
96
96
|
try {
|
|
97
97
|
const connectHandler = new ConnectHandler(opts, callback)
|
|
98
|
-
|
|
98
|
+
const connectOptions = { ...opts, method: 'CONNECT' }
|
|
99
|
+
|
|
100
|
+
this.dispatch(connectOptions, connectHandler)
|
|
99
101
|
} catch (err) {
|
|
100
102
|
if (typeof callback !== 'function') {
|
|
101
103
|
throw err
|
package/lib/api/api-pipeline.js
CHANGED
|
@@ -5,15 +5,17 @@ const {
|
|
|
5
5
|
Duplex,
|
|
6
6
|
PassThrough
|
|
7
7
|
} = require('node:stream')
|
|
8
|
+
const assert = require('node:assert')
|
|
9
|
+
const { AsyncResource } = require('node:async_hooks')
|
|
8
10
|
const {
|
|
9
11
|
InvalidArgumentError,
|
|
10
12
|
InvalidReturnValueError,
|
|
11
13
|
RequestAbortedError
|
|
12
14
|
} = require('../core/errors')
|
|
13
15
|
const util = require('../core/util')
|
|
14
|
-
const { AsyncResource } = require('node:async_hooks')
|
|
15
16
|
const { addSignal, removeSignal } = require('./abort-signal')
|
|
16
|
-
|
|
17
|
+
|
|
18
|
+
function noop () {}
|
|
17
19
|
|
|
18
20
|
const kResume = Symbol('resume')
|
|
19
21
|
|
|
@@ -92,7 +94,7 @@ class PipelineHandler extends AsyncResource {
|
|
|
92
94
|
this.context = null
|
|
93
95
|
this.onInfo = onInfo || null
|
|
94
96
|
|
|
95
|
-
this.req = new PipelineRequest().on('error',
|
|
97
|
+
this.req = new PipelineRequest().on('error', noop)
|
|
96
98
|
|
|
97
99
|
this.ret = new Duplex({
|
|
98
100
|
readableObjectMode: opts.objectMode,
|
|
@@ -145,7 +147,7 @@ class PipelineHandler extends AsyncResource {
|
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
onConnect (abort, context) {
|
|
148
|
-
const {
|
|
150
|
+
const { res } = this
|
|
149
151
|
|
|
150
152
|
if (this.reason) {
|
|
151
153
|
abort(this.reason)
|
|
@@ -153,7 +155,6 @@ class PipelineHandler extends AsyncResource {
|
|
|
153
155
|
}
|
|
154
156
|
|
|
155
157
|
assert(!res, 'pipeline cannot be retried')
|
|
156
|
-
assert(!ret.destroyed)
|
|
157
158
|
|
|
158
159
|
this.abort = abort
|
|
159
160
|
this.context = context
|
|
@@ -184,7 +185,7 @@ class PipelineHandler extends AsyncResource {
|
|
|
184
185
|
context
|
|
185
186
|
})
|
|
186
187
|
} catch (err) {
|
|
187
|
-
this.res.on('error',
|
|
188
|
+
this.res.on('error', noop)
|
|
188
189
|
throw err
|
|
189
190
|
}
|
|
190
191
|
|
package/lib/api/api-request.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const assert = require('node:assert')
|
|
4
|
+
const { AsyncResource } = require('node:async_hooks')
|
|
4
5
|
const { Readable } = require('./readable')
|
|
5
6
|
const { InvalidArgumentError, RequestAbortedError } = require('../core/errors')
|
|
6
7
|
const util = require('../core/util')
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
function noop () {}
|
|
9
10
|
|
|
10
11
|
class RequestHandler extends AsyncResource {
|
|
11
12
|
constructor (opts, callback) {
|
|
@@ -13,7 +14,7 @@ class RequestHandler extends AsyncResource {
|
|
|
13
14
|
throw new InvalidArgumentError('invalid opts')
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
const { signal, method, opaque, body, onInfo, responseHeaders,
|
|
17
|
+
const { signal, method, opaque, body, onInfo, responseHeaders, highWaterMark } = opts
|
|
17
18
|
|
|
18
19
|
try {
|
|
19
20
|
if (typeof callback !== 'function') {
|
|
@@ -39,7 +40,7 @@ class RequestHandler extends AsyncResource {
|
|
|
39
40
|
super('UNDICI_REQUEST')
|
|
40
41
|
} catch (err) {
|
|
41
42
|
if (util.isStream(body)) {
|
|
42
|
-
util.destroy(body.on('error',
|
|
43
|
+
util.destroy(body.on('error', noop), err)
|
|
43
44
|
}
|
|
44
45
|
throw err
|
|
45
46
|
}
|
|
@@ -54,38 +55,22 @@ class RequestHandler extends AsyncResource {
|
|
|
54
55
|
this.trailers = {}
|
|
55
56
|
this.context = null
|
|
56
57
|
this.onInfo = onInfo || null
|
|
57
|
-
this.throwOnError = throwOnError
|
|
58
58
|
this.highWaterMark = highWaterMark
|
|
59
|
-
this.signal = signal
|
|
60
59
|
this.reason = null
|
|
61
60
|
this.removeAbortListener = null
|
|
62
61
|
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
if (signal?.aborted) {
|
|
63
|
+
this.reason = signal.reason ?? new RequestAbortedError()
|
|
64
|
+
} else if (signal) {
|
|
65
|
+
this.removeAbortListener = util.addAbortListener(signal, () => {
|
|
66
|
+
this.reason = signal.reason ?? new RequestAbortedError()
|
|
67
|
+
if (this.res) {
|
|
68
|
+
util.destroy(this.res, this.reason)
|
|
69
|
+
} else if (this.abort) {
|
|
70
|
+
this.abort(this.reason)
|
|
71
|
+
}
|
|
66
72
|
})
|
|
67
73
|
}
|
|
68
|
-
|
|
69
|
-
if (this.signal) {
|
|
70
|
-
if (this.signal.aborted) {
|
|
71
|
-
this.reason = this.signal.reason ?? new RequestAbortedError()
|
|
72
|
-
} else {
|
|
73
|
-
this.removeAbortListener = util.addAbortListener(this.signal, () => {
|
|
74
|
-
this.reason = this.signal.reason ?? new RequestAbortedError()
|
|
75
|
-
if (this.res) {
|
|
76
|
-
util.destroy(this.res, this.reason)
|
|
77
|
-
} else if (this.abort) {
|
|
78
|
-
this.abort(this.reason)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (this.removeAbortListener) {
|
|
82
|
-
this.res?.off('close', this.removeAbortListener)
|
|
83
|
-
this.removeAbortListener()
|
|
84
|
-
this.removeAbortListener = null
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
74
|
}
|
|
90
75
|
|
|
91
76
|
onConnect (abort, context) {
|
|
@@ -127,25 +112,20 @@ class RequestHandler extends AsyncResource {
|
|
|
127
112
|
|
|
128
113
|
if (this.removeAbortListener) {
|
|
129
114
|
res.on('close', this.removeAbortListener)
|
|
115
|
+
this.removeAbortListener = null
|
|
130
116
|
}
|
|
131
117
|
|
|
132
118
|
this.callback = null
|
|
133
119
|
this.res = res
|
|
134
120
|
if (callback !== null) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
trailers: this.trailers,
|
|
144
|
-
opaque,
|
|
145
|
-
body: res,
|
|
146
|
-
context
|
|
147
|
-
})
|
|
148
|
-
}
|
|
121
|
+
this.runInAsyncScope(callback, null, null, {
|
|
122
|
+
statusCode,
|
|
123
|
+
headers,
|
|
124
|
+
trailers: this.trailers,
|
|
125
|
+
opaque,
|
|
126
|
+
body: res,
|
|
127
|
+
context
|
|
128
|
+
})
|
|
149
129
|
}
|
|
150
130
|
}
|
|
151
131
|
|
|
@@ -179,11 +159,14 @@ class RequestHandler extends AsyncResource {
|
|
|
179
159
|
|
|
180
160
|
if (body) {
|
|
181
161
|
this.body = null
|
|
182
|
-
|
|
162
|
+
|
|
163
|
+
if (util.isStream(body)) {
|
|
164
|
+
body.on('error', noop)
|
|
165
|
+
util.destroy(body, err)
|
|
166
|
+
}
|
|
183
167
|
}
|
|
184
168
|
|
|
185
169
|
if (this.removeAbortListener) {
|
|
186
|
-
res?.off('close', this.removeAbortListener)
|
|
187
170
|
this.removeAbortListener()
|
|
188
171
|
this.removeAbortListener = null
|
|
189
172
|
}
|
|
@@ -200,7 +183,9 @@ function request (opts, callback) {
|
|
|
200
183
|
}
|
|
201
184
|
|
|
202
185
|
try {
|
|
203
|
-
|
|
186
|
+
const handler = new RequestHandler(opts, callback)
|
|
187
|
+
|
|
188
|
+
this.dispatch(opts, handler)
|
|
204
189
|
} catch (err) {
|
|
205
190
|
if (typeof callback !== 'function') {
|
|
206
191
|
throw err
|