undici 6.21.0 → 7.0.0-alpha.10
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 +27 -46
- package/docs/docs/api/Agent.md +14 -17
- package/docs/docs/api/BalancedPool.md +16 -16
- package/docs/docs/api/CacheStore.md +131 -0
- package/docs/docs/api/Client.md +12 -14
- package/docs/docs/api/Debug.md +1 -1
- package/docs/docs/api/Dispatcher.md +98 -194
- package/docs/docs/api/EnvHttpProxyAgent.md +12 -13
- package/docs/docs/api/MockAgent.md +5 -3
- package/docs/docs/api/MockClient.md +5 -5
- package/docs/docs/api/MockPool.md +4 -3
- package/docs/docs/api/Pool.md +15 -16
- package/docs/docs/api/PoolStats.md +1 -1
- package/docs/docs/api/ProxyAgent.md +3 -3
- package/docs/docs/api/RedirectHandler.md +1 -1
- package/docs/docs/api/RetryAgent.md +1 -1
- package/docs/docs/api/RetryHandler.md +4 -4
- package/docs/docs/api/WebSocket.md +46 -4
- package/docs/docs/api/api-lifecycle.md +11 -11
- package/docs/docs/best-practices/mocking-request.md +2 -2
- package/docs/docs/best-practices/proxy.md +1 -1
- package/index.d.ts +1 -1
- package/index.js +23 -7
- 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 +33 -48
- package/lib/api/api-stream.js +39 -50
- package/lib/api/api-upgrade.js +5 -3
- package/lib/api/readable.js +235 -62
- package/lib/api/util.js +2 -0
- package/lib/cache/memory-cache-store.js +177 -0
- package/lib/cache/sqlite-cache-store.js +446 -0
- package/lib/core/constants.js +35 -10
- package/lib/core/diagnostics.js +122 -128
- package/lib/core/errors.js +6 -6
- package/lib/core/request.js +13 -11
- package/lib/core/symbols.js +2 -1
- package/lib/core/tree.js +9 -1
- package/lib/core/util.js +237 -49
- package/lib/dispatcher/agent.js +3 -17
- package/lib/dispatcher/balanced-pool.js +5 -8
- package/lib/dispatcher/client-h1.js +379 -134
- package/lib/dispatcher/client-h2.js +173 -107
- package/lib/dispatcher/client.js +19 -32
- package/lib/dispatcher/dispatcher-base.js +6 -35
- package/lib/dispatcher/dispatcher.js +7 -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 +3 -6
- package/lib/handler/cache-handler.js +393 -0
- package/lib/handler/cache-revalidation-handler.js +124 -0
- package/lib/handler/decorator-handler.js +27 -0
- package/lib/handler/redirect-handler.js +54 -59
- package/lib/handler/retry-handler.js +77 -109
- package/lib/handler/unwrap-handler.js +96 -0
- package/lib/handler/wrap-handler.js +98 -0
- package/lib/interceptor/cache.js +350 -0
- package/lib/interceptor/dns.js +375 -0
- package/lib/interceptor/dump.js +2 -2
- package/lib/interceptor/redirect.js +11 -14
- package/lib/interceptor/response-error.js +18 -7
- 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/util/cache.js +360 -0
- package/lib/web/cache/cache.js +24 -21
- package/lib/web/cache/cachestorage.js +1 -1
- package/lib/web/cookies/index.js +29 -14
- package/lib/web/cookies/parse.js +8 -3
- package/lib/web/eventsource/eventsource-stream.js +9 -8
- package/lib/web/eventsource/eventsource.js +10 -6
- package/lib/web/fetch/body.js +43 -41
- package/lib/web/fetch/constants.js +12 -5
- package/lib/web/fetch/data-url.js +3 -3
- package/lib/web/fetch/formdata-parser.js +72 -45
- package/lib/web/fetch/formdata.js +65 -54
- package/lib/web/fetch/headers.js +118 -86
- package/lib/web/fetch/index.js +58 -67
- package/lib/web/fetch/request.js +136 -77
- package/lib/web/fetch/response.js +87 -56
- package/lib/web/fetch/util.js +259 -109
- package/lib/web/fetch/webidl.js +113 -68
- package/lib/web/websocket/connection.js +76 -147
- package/lib/web/websocket/constants.js +70 -10
- 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 +24 -36
- 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/cache-interceptor.d.ts +172 -0
- package/types/client.d.ts +11 -12
- package/types/cookies.d.ts +2 -0
- package/types/diagnostics-channel.d.ts +10 -10
- package/types/dispatcher.d.ts +113 -90
- package/types/env-http-proxy-agent.d.ts +2 -2
- package/types/errors.d.ts +53 -47
- package/types/fetch.d.ts +17 -16
- 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 +7 -7
- package/types/header.d.ts +157 -1
- package/types/index.d.ts +44 -46
- package/types/interceptors.d.ts +25 -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 +18 -15
- package/types/retry-agent.d.ts +1 -1
- package/types/retry-handler.d.ts +10 -10
- 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/docs/docs/api/Pool.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Extends: `undici.Dispatcher`
|
|
4
4
|
|
|
5
|
-
A pool of [Client](Client.md) instances connected to the same upstream target.
|
|
5
|
+
A pool of [Client](/docs/docs/api/Client.md) instances connected to the same upstream target.
|
|
6
6
|
|
|
7
7
|
Requests are not guaranteed to be dispatched in order of invocation.
|
|
8
8
|
|
|
@@ -15,21 +15,20 @@ Arguments:
|
|
|
15
15
|
|
|
16
16
|
### Parameter: `PoolOptions`
|
|
17
17
|
|
|
18
|
-
Extends: [`ClientOptions`](Client.md#parameter-clientoptions)
|
|
18
|
+
Extends: [`ClientOptions`](/docs/docs/api/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
|
|
|
26
25
|
### `Pool.closed`
|
|
27
26
|
|
|
28
|
-
Implements [Client.closed](Client.md#clientclosed)
|
|
27
|
+
Implements [Client.closed](/docs/docs/api/Client.md#clientclosed)
|
|
29
28
|
|
|
30
29
|
### `Pool.destroyed`
|
|
31
30
|
|
|
32
|
-
Implements [Client.destroyed](Client.md#clientdestroyed)
|
|
31
|
+
Implements [Client.destroyed](/docs/docs/api/Client.md#clientdestroyed)
|
|
33
32
|
|
|
34
33
|
### `Pool.stats`
|
|
35
34
|
|
|
@@ -39,46 +38,46 @@ Returns [`PoolStats`](PoolStats.md) instance for this pool.
|
|
|
39
38
|
|
|
40
39
|
### `Pool.close([callback])`
|
|
41
40
|
|
|
42
|
-
Implements [`Dispatcher.close([callback])`](Dispatcher.md#dispatcherclosecallback-promise).
|
|
41
|
+
Implements [`Dispatcher.close([callback])`](/docs/docs/api/Dispatcher.md#dispatcherclosecallback-promise).
|
|
43
42
|
|
|
44
43
|
### `Pool.destroy([error, callback])`
|
|
45
44
|
|
|
46
|
-
Implements [`Dispatcher.destroy([error, callback])`](Dispatcher.md#dispatcherdestroyerror-callback-promise).
|
|
45
|
+
Implements [`Dispatcher.destroy([error, callback])`](/docs/docs/api/Dispatcher.md#dispatcherdestroyerror-callback-promise).
|
|
47
46
|
|
|
48
47
|
### `Pool.connect(options[, callback])`
|
|
49
48
|
|
|
50
|
-
See [`Dispatcher.connect(options[, callback])`](Dispatcher.md#dispatcherconnectoptions-callback).
|
|
49
|
+
See [`Dispatcher.connect(options[, callback])`](/docs/docs/api/Dispatcher.md#dispatcherconnectoptions-callback).
|
|
51
50
|
|
|
52
51
|
### `Pool.dispatch(options, handler)`
|
|
53
52
|
|
|
54
|
-
Implements [`Dispatcher.dispatch(options, handler)`](Dispatcher.md#dispatcherdispatchoptions-handler).
|
|
53
|
+
Implements [`Dispatcher.dispatch(options, handler)`](/docs/docs/api/Dispatcher.md#dispatcherdispatchoptions-handler).
|
|
55
54
|
|
|
56
55
|
### `Pool.pipeline(options, handler)`
|
|
57
56
|
|
|
58
|
-
See [`Dispatcher.pipeline(options, handler)`](Dispatcher.md#dispatcherpipelineoptions-handler).
|
|
57
|
+
See [`Dispatcher.pipeline(options, handler)`](/docs/docs/api/Dispatcher.md#dispatcherpipelineoptions-handler).
|
|
59
58
|
|
|
60
59
|
### `Pool.request(options[, callback])`
|
|
61
60
|
|
|
62
|
-
See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
|
|
61
|
+
See [`Dispatcher.request(options [, callback])`](/docs/docs/api/Dispatcher.md#dispatcherrequestoptions-callback).
|
|
63
62
|
|
|
64
63
|
### `Pool.stream(options, factory[, callback])`
|
|
65
64
|
|
|
66
|
-
See [`Dispatcher.stream(options, factory[, callback])`](Dispatcher.md#dispatcherstreamoptions-factory-callback).
|
|
65
|
+
See [`Dispatcher.stream(options, factory[, callback])`](/docs/docs/api/Dispatcher.md#dispatcherstreamoptions-factory-callback).
|
|
67
66
|
|
|
68
67
|
### `Pool.upgrade(options[, callback])`
|
|
69
68
|
|
|
70
|
-
See [`Dispatcher.upgrade(options[, callback])`](Dispatcher.md#dispatcherupgradeoptions-callback).
|
|
69
|
+
See [`Dispatcher.upgrade(options[, callback])`](/docs/docs/api/Dispatcher.md#dispatcherupgradeoptions-callback).
|
|
71
70
|
|
|
72
71
|
## Instance Events
|
|
73
72
|
|
|
74
73
|
### Event: `'connect'`
|
|
75
74
|
|
|
76
|
-
See [Dispatcher Event: `'connect'`](Dispatcher.md#event-connect).
|
|
75
|
+
See [Dispatcher Event: `'connect'`](/docs/docs/api/Dispatcher.md#event-connect).
|
|
77
76
|
|
|
78
77
|
### Event: `'disconnect'`
|
|
79
78
|
|
|
80
|
-
See [Dispatcher Event: `'disconnect'`](Dispatcher.md#event-disconnect).
|
|
79
|
+
See [Dispatcher Event: `'disconnect'`](/docs/docs/api/Dispatcher.md#event-disconnect).
|
|
81
80
|
|
|
82
81
|
### Event: `'drain'`
|
|
83
82
|
|
|
84
|
-
See [Dispatcher Event: `'drain'`](Dispatcher.md#event-drain).
|
|
83
|
+
See [Dispatcher Event: `'drain'`](/docs/docs/api/Dispatcher.md#event-drain).
|
|
@@ -14,7 +14,7 @@ Returns: `ProxyAgent`
|
|
|
14
14
|
|
|
15
15
|
### Parameter: `ProxyAgentOptions`
|
|
16
16
|
|
|
17
|
-
Extends: [`AgentOptions`](Agent.md#parameter-agentoptions)
|
|
17
|
+
Extends: [`AgentOptions`](/docs/docs/api/Agent.md#parameter-agentoptions)
|
|
18
18
|
|
|
19
19
|
* **uri** `string | URL` (required) - The URI of the proxy server. This can be provided as a string, as an instance of the URL class, or as an object with a `uri` property of type string.
|
|
20
20
|
If the `uri` is provided as a string or `uri` is an object with an `uri` property of type string, then it will be parsed into a `URL` object according to the [WHATWG URL Specification](https://url.spec.whatwg.org).
|
|
@@ -123,8 +123,8 @@ await proxyAgent.close()
|
|
|
123
123
|
|
|
124
124
|
### `ProxyAgent.dispatch(options, handlers)`
|
|
125
125
|
|
|
126
|
-
Implements [`Agent.dispatch(options, handlers)`](Agent.md#parameter-agentdispatchoptions).
|
|
126
|
+
Implements [`Agent.dispatch(options, handlers)`](/docs/docs/api/Agent.md#parameter-agentdispatchoptions).
|
|
127
127
|
|
|
128
128
|
### `ProxyAgent.request(options[, callback])`
|
|
129
129
|
|
|
130
|
-
See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
|
|
130
|
+
See [`Dispatcher.request(options [, callback])`](/docs/docs/api/Dispatcher.md#dispatcherrequestoptions-callback).
|
|
@@ -16,7 +16,7 @@ Returns: `RedirectHandler`
|
|
|
16
16
|
|
|
17
17
|
### Parameters
|
|
18
18
|
|
|
19
|
-
- **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.
|
|
19
|
+
- **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandler) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every redirection.
|
|
20
20
|
- **maxRedirections** `number` (required) - Maximum number of redirections allowed.
|
|
21
21
|
- **opts** `object` (required) - Options for handling redirection.
|
|
22
22
|
- **handler** `object` (required) - Handlers for different stages of the request lifecycle.
|
|
@@ -15,7 +15,7 @@ Returns: `retryHandler`
|
|
|
15
15
|
|
|
16
16
|
### Parameter: `Dispatch.DispatchOptions & RetryOptions`
|
|
17
17
|
|
|
18
|
-
Extends: [`Dispatch.DispatchOptions`](Dispatcher.md#parameter-dispatchoptions).
|
|
18
|
+
Extends: [`Dispatch.DispatchOptions`](/docs/docs/api/Dispatcher.md#parameter-dispatchoptions).
|
|
19
19
|
|
|
20
20
|
#### `RetryOptions`
|
|
21
21
|
|
|
@@ -43,10 +43,10 @@ It represents the retry state for a given request.
|
|
|
43
43
|
|
|
44
44
|
### Parameter `RetryHandlers`
|
|
45
45
|
|
|
46
|
-
- **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.
|
|
47
|
-
- **handler** Extends [`Dispatch.
|
|
46
|
+
- **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandler) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every retry.
|
|
47
|
+
- **handler** Extends [`Dispatch.DispatchHandler`](/docs/docs/api/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,8 +8,8 @@ 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`
|
|
14
|
-
* **protocol** `string | string[] | WebSocketInit` (optional) - Subprotocol(s) to request the server use, or a [`Dispatcher`](
|
|
11
|
+
* **url** `URL | string`
|
|
12
|
+
* **protocol** `string | string[] | WebSocketInit` (optional) - Subprotocol(s) to request the server use, or a [`Dispatcher`](/docs/docs/api/Dispatcher.md).
|
|
15
13
|
|
|
16
14
|
### Example:
|
|
17
15
|
|
|
@@ -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)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Client Lifecycle
|
|
2
2
|
|
|
3
|
-
An Undici [Client](Client.md) can be best described as a state machine. The following list is a summary of the various state transitions the `Client` will go through in its lifecycle. This document also contains detailed breakdowns of each state.
|
|
3
|
+
An Undici [Client](/docs/docs/api/Client.md) can be best described as a state machine. The following list is a summary of the various state transitions the `Client` will go through in its lifecycle. This document also contains detailed breakdowns of each state.
|
|
4
4
|
|
|
5
5
|
> This diagram is not a perfect representation of the undici Client. Since the Client class is not actually implemented as a state-machine, actual execution may deviate slightly from what is described below. Consider this as a general resource for understanding the inner workings of the Undici client rather than some kind of formal specification.
|
|
6
6
|
|
|
@@ -28,7 +28,7 @@ stateDiagram-v2
|
|
|
28
28
|
[*] --> idle
|
|
29
29
|
idle --> pending : connect
|
|
30
30
|
idle --> destroyed : destroy/close
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
pending --> idle : timeout
|
|
33
33
|
pending --> destroyed : destroy
|
|
34
34
|
|
|
@@ -58,33 +58,33 @@ stateDiagram-v2
|
|
|
58
58
|
|
|
59
59
|
### idle
|
|
60
60
|
|
|
61
|
-
The **idle** state is the initial state of a `Client` instance. While an `origin` is required for instantiating a `Client` instance, the underlying socket connection will not be established until a request is queued using [`Client.dispatch()`](Client.md#clientdispatchoptions-handlers). By calling `Client.dispatch()` directly or using one of the multiple implementations ([`Client.connect()`](Client.md#clientconnectoptions-callback), [`Client.pipeline()`](Client.md#clientpipelineoptions-handler), [`Client.request()`](Client.md#clientrequestoptions-callback), [`Client.stream()`](Client.md#clientstreamoptions-factory-callback), and [`Client.upgrade()`](Client.md#clientupgradeoptions-callback)), the `Client` instance will transition from **idle** to [**pending**](#pending) and then most likely directly to [**processing**](#processing).
|
|
61
|
+
The **idle** state is the initial state of a `Client` instance. While an `origin` is required for instantiating a `Client` instance, the underlying socket connection will not be established until a request is queued using [`Client.dispatch()`](/docs/docs/api/Client.md#clientdispatchoptions-handlers). By calling `Client.dispatch()` directly or using one of the multiple implementations ([`Client.connect()`](Client.md#clientconnectoptions-callback), [`Client.pipeline()`](Client.md#clientpipelineoptions-handler), [`Client.request()`](Client.md#clientrequestoptions-callback), [`Client.stream()`](Client.md#clientstreamoptions-factory-callback), and [`Client.upgrade()`](/docs/docs/api/Client.md#clientupgradeoptions-callback)), the `Client` instance will transition from **idle** to [**pending**](/docs/docs/api/Client.md#pending) and then most likely directly to [**processing**](/docs/docs/api/Client.md#processing).
|
|
62
62
|
|
|
63
|
-
Calling [`Client.close()`](Client.md#clientclosecallback) or [`Client.destroy()`](Client.md#clientdestroyerror-callback) transitions directly to the [**destroyed**](#destroyed) state since the `Client` instance will have no queued requests in this state.
|
|
63
|
+
Calling [`Client.close()`](/docs/docs/api/Client.md#clientclosecallback) or [`Client.destroy()`](Client.md#clientdestroyerror-callback) transitions directly to the [**destroyed**](/docs/docs/api/Client.md#destroyed) state since the `Client` instance will have no queued requests in this state.
|
|
64
64
|
|
|
65
65
|
### pending
|
|
66
66
|
|
|
67
|
-
The **pending** state signifies a non-processing `Client`. Upon entering this state, the `Client` establishes a socket connection and emits the [`'connect'`](Client.md#event-connect) event signalling a connection was successfully established with the `origin` provided during `Client` instantiation. The internal queue is initially empty, and requests can start queueing.
|
|
67
|
+
The **pending** state signifies a non-processing `Client`. Upon entering this state, the `Client` establishes a socket connection and emits the [`'connect'`](/docs/docs/api/Client.md#event-connect) event signalling a connection was successfully established with the `origin` provided during `Client` instantiation. The internal queue is initially empty, and requests can start queueing.
|
|
68
68
|
|
|
69
|
-
Calling [`Client.close()`](Client.md#clientclosecallback) with queued requests, transitions the `Client` to the [**processing**](#processing) state. Without queued requests, it transitions to the [**destroyed**](#destroyed) state.
|
|
69
|
+
Calling [`Client.close()`](/docs/docs/api/Client.md#clientclosecallback) with queued requests, transitions the `Client` to the [**processing**](/docs/docs/api/Client.md#processing) state. Without queued requests, it transitions to the [**destroyed**](/docs/docs/api/Client.md#destroyed) state.
|
|
70
70
|
|
|
71
|
-
Calling [`Client.destroy()`](Client.md#clientdestroyerror-callback) transitions directly to the [**destroyed**](#destroyed) state regardless of existing requests.
|
|
71
|
+
Calling [`Client.destroy()`](/docs/docs/api/Client.md#clientdestroyerror-callback) transitions directly to the [**destroyed**](/docs/docs/api/Client.md#destroyed) state regardless of existing requests.
|
|
72
72
|
|
|
73
73
|
### processing
|
|
74
74
|
|
|
75
|
-
The **processing** state is a state machine within itself. It initializes to the [**processing.running**](#running) state. The [`Client.dispatch()`](Client.md#clientdispatchoptions-handlers), [`Client.close()`](Client.md#clientclosecallback), and [`Client.destroy()`](Client.md#clientdestroyerror-callback) can be called at any time while the `Client` is in this state. `Client.dispatch()` will add more requests to the queue while existing requests continue to be processed. `Client.close()` will transition to the [**processing.closing**](#closing) state. And `Client.destroy()` will transition to [**destroyed**](#destroyed).
|
|
75
|
+
The **processing** state is a state machine within itself. It initializes to the [**processing.running**](/docs/docs/api/Client.md#running) state. The [`Client.dispatch()`](/docs/docs/api/Client.md#clientdispatchoptions-handlers), [`Client.close()`](Client.md#clientclosecallback), and [`Client.destroy()`](Client.md#clientdestroyerror-callback) can be called at any time while the `Client` is in this state. `Client.dispatch()` will add more requests to the queue while existing requests continue to be processed. `Client.close()` will transition to the [**processing.closing**](/docs/docs/api/Client.md#closing) state. And `Client.destroy()` will transition to [**destroyed**](/docs/docs/api/Client.md#destroyed).
|
|
76
76
|
|
|
77
77
|
#### running
|
|
78
78
|
|
|
79
|
-
In the **processing.running** sub-state, queued requests are being processed in a FIFO order. If a request body requires draining, the *needDrain* event transitions to the [**processing.busy**](#busy) sub-state. The *close* event transitions the Client to the [**process.closing**](#closing) sub-state. If all queued requests are processed and neither [`Client.close()`](Client.md#clientclosecallback) nor [`Client.destroy()`](Client.md#clientdestroyerror-callback) are called, then the [**processing**](#processing) machine will trigger a *keepalive* event transitioning the `Client` back to the [**pending**](#pending) state. During this time, the `Client` is waiting for the socket connection to timeout, and once it does, it triggers the *timeout* event and transitions to the [**idle**](#idle) state.
|
|
79
|
+
In the **processing.running** sub-state, queued requests are being processed in a FIFO order. If a request body requires draining, the *needDrain* event transitions to the [**processing.busy**](/docs/docs/api/Client.md#busy) sub-state. The *close* event transitions the Client to the [**process.closing**](/docs/docs/api/Client.md#closing) sub-state. If all queued requests are processed and neither [`Client.close()`](/docs/docs/api/Client.md#clientclosecallback) nor [`Client.destroy()`](Client.md#clientdestroyerror-callback) are called, then the [**processing**](/docs/docs/api/Client.md#processing) machine will trigger a *keepalive* event transitioning the `Client` back to the [**pending**](/docs/docs/api/Client.md#pending) state. During this time, the `Client` is waiting for the socket connection to timeout, and once it does, it triggers the *timeout* event and transitions to the [**idle**](/docs/docs/api/Client.md#idle) state.
|
|
80
80
|
|
|
81
81
|
#### busy
|
|
82
82
|
|
|
83
|
-
This sub-state is only entered when a request body is an instance of [Stream](https://nodejs.org/api/stream.html) and requires draining. The `Client` cannot process additional requests while in this state and must wait until the currently processing request body is completely drained before transitioning back to [**processing.running**](#running).
|
|
83
|
+
This sub-state is only entered when a request body is an instance of [Stream](https://nodejs.org/api/stream.html) and requires draining. The `Client` cannot process additional requests while in this state and must wait until the currently processing request body is completely drained before transitioning back to [**processing.running**](/docs/docs/api/Client.md#running).
|
|
84
84
|
|
|
85
85
|
#### closing
|
|
86
86
|
|
|
87
|
-
This sub-state is only entered when a `Client` instance has queued requests and the [`Client.close()`](Client.md#clientclosecallback) method is called. In this state, the `Client` instance continues to process requests as usual, with the one exception that no additional requests can be queued. Once all of the queued requests are processed, the `Client` will trigger the *done* event gracefully entering the [**destroyed**](#destroyed) state without an error.
|
|
87
|
+
This sub-state is only entered when a `Client` instance has queued requests and the [`Client.close()`](/docs/docs/api/Client.md#clientclosecallback) method is called. In this state, the `Client` instance continues to process requests as usual, with the one exception that no additional requests can be queued. Once all of the queued requests are processed, the `Client` will trigger the *done* event gracefully entering the [**destroyed**](/docs/docs/api/Client.md#destroyed) state without an error.
|
|
88
88
|
|
|
89
89
|
### destroyed
|
|
90
90
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Mocking Request
|
|
2
2
|
|
|
3
|
-
Undici has its own mocking [utility](
|
|
3
|
+
Undici has its own mocking [utility](/docs/docs/api/MockAgent.md). It allow us to intercept undici HTTP requests and return mocked values instead. It can be useful for testing purposes.
|
|
4
4
|
|
|
5
5
|
Example:
|
|
6
6
|
|
|
@@ -73,7 +73,7 @@ const badRequest = await bankTransfer('1234567890', '100')
|
|
|
73
73
|
assert.deepEqual(badRequest, { message: 'bank account not found' })
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
Explore other MockAgent functionality [here](
|
|
76
|
+
Explore other MockAgent functionality [here](/docs/docs/api/MockAgent.md)
|
|
77
77
|
|
|
78
78
|
## Debug Mock Value
|
|
79
79
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Connecting through a proxy is possible by:
|
|
4
4
|
|
|
5
|
-
- Using [ProxyAgent](
|
|
5
|
+
- Using [ProxyAgent](/docs/docs/api/ProxyAgent.md).
|
|
6
6
|
- Configuring `Client` or `Pool` constructor.
|
|
7
7
|
|
|
8
8
|
The proxy url should be passed to the `Client` or `Pool` constructor, while the upstream server url
|
package/index.d.ts
CHANGED
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,26 @@ 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'),
|
|
41
|
+
responseError: require('./lib/interceptor/response-error'),
|
|
43
42
|
retry: require('./lib/interceptor/retry'),
|
|
44
|
-
dump: require('./lib/interceptor/dump')
|
|
43
|
+
dump: require('./lib/interceptor/dump'),
|
|
44
|
+
dns: require('./lib/interceptor/dns'),
|
|
45
|
+
cache: require('./lib/interceptor/cache')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports.cacheStores = {
|
|
49
|
+
MemoryCacheStore: require('./lib/cache/memory-cache-store')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const SqliteCacheStore = require('./lib/cache/sqlite-cache-store')
|
|
54
|
+
module.exports.cacheStores.SqliteCacheStore = SqliteCacheStore
|
|
55
|
+
} catch (err) {
|
|
56
|
+
if (err.code !== 'ERR_UNKNOWN_BUILTIN_MODULE') {
|
|
57
|
+
throw err
|
|
58
|
+
}
|
|
45
59
|
}
|
|
46
60
|
|
|
47
61
|
module.exports.buildConnector = buildConnector
|
|
@@ -119,8 +133,6 @@ module.exports.Headers = require('./lib/web/fetch/headers').Headers
|
|
|
119
133
|
module.exports.Response = require('./lib/web/fetch/response').Response
|
|
120
134
|
module.exports.Request = require('./lib/web/fetch/request').Request
|
|
121
135
|
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
136
|
|
|
125
137
|
const { setGlobalOrigin, getGlobalOrigin } = require('./lib/web/fetch/global')
|
|
126
138
|
|
|
@@ -128,18 +140,19 @@ module.exports.setGlobalOrigin = setGlobalOrigin
|
|
|
128
140
|
module.exports.getGlobalOrigin = getGlobalOrigin
|
|
129
141
|
|
|
130
142
|
const { CacheStorage } = require('./lib/web/cache/cachestorage')
|
|
131
|
-
const { kConstruct } = require('./lib/
|
|
143
|
+
const { kConstruct } = require('./lib/core/symbols')
|
|
132
144
|
|
|
133
145
|
// Cache & CacheStorage are tightly coupled with fetch. Even if it may run
|
|
134
146
|
// in an older version of Node, it doesn't have any use without fetch.
|
|
135
147
|
module.exports.caches = new CacheStorage(kConstruct)
|
|
136
148
|
|
|
137
|
-
const { deleteCookie, getCookies, getSetCookies, setCookie } = require('./lib/web/cookies')
|
|
149
|
+
const { deleteCookie, getCookies, getSetCookies, setCookie, parseCookie } = require('./lib/web/cookies')
|
|
138
150
|
|
|
139
151
|
module.exports.deleteCookie = deleteCookie
|
|
140
152
|
module.exports.getCookies = getCookies
|
|
141
153
|
module.exports.getSetCookies = getSetCookies
|
|
142
154
|
module.exports.setCookie = setCookie
|
|
155
|
+
module.exports.parseCookie = parseCookie
|
|
143
156
|
|
|
144
157
|
const { parseMIMEType, serializeAMimeType } = require('./lib/web/fetch/data-url')
|
|
145
158
|
|
|
@@ -152,6 +165,9 @@ module.exports.CloseEvent = CloseEvent
|
|
|
152
165
|
module.exports.ErrorEvent = ErrorEvent
|
|
153
166
|
module.exports.MessageEvent = MessageEvent
|
|
154
167
|
|
|
168
|
+
module.exports.WebSocketStream = require('./lib/web/websocket/stream/websocketstream').WebSocketStream
|
|
169
|
+
module.exports.WebSocketError = require('./lib/web/websocket/stream/websocketerror').WebSocketError
|
|
170
|
+
|
|
155
171
|
module.exports.request = makeDispatcher(api.request)
|
|
156
172
|
module.exports.stream = makeDispatcher(api.stream)
|
|
157
173
|
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.on('error', noop), 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
|
|
|
@@ -173,17 +153,20 @@ class RequestHandler extends AsyncResource {
|
|
|
173
153
|
this.res = null
|
|
174
154
|
// Ensure all queued handlers are invoked before destroying res.
|
|
175
155
|
queueMicrotask(() => {
|
|
176
|
-
util.destroy(res, err)
|
|
156
|
+
util.destroy(res.on('error', noop), err)
|
|
177
157
|
})
|
|
178
158
|
}
|
|
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
|