1 | # undici
|
2 |
|
3 | ![Node CI](https://github.com/mcollina/undici/workflows/Node%20CI/badge.svg) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](http://standardjs.com/) [![npm version](https://badge.fury.io/js/undici.svg)](https://badge.fury.io/js/undici)
|
4 |
|
5 | A HTTP/1.1 client, written from scratch for Node.js.
|
6 |
|
7 | > Undici means eleven in Italian. 1.1 -> 11 -> Eleven -> Undici.
|
8 | It is also a Stranger Things reference.
|
9 |
|
10 |
|
11 | Picture of Eleven
|
12 | -->
|
13 |
|
14 | ## Install
|
15 |
|
16 | ```
|
17 | npm i undici
|
18 | ```
|
19 |
|
20 | ## Benchmarks
|
21 |
|
22 | Machine: AMD EPYC 7502P<br/>
|
23 |
|
24 | Node 15
|
25 | ```
|
26 | http - keepalive x 12,028 ops/sec ±2.60% (265 runs sampled)
|
27 | undici - pipeline x 31,321 ops/sec ±0.77% (276 runs sampled)
|
28 | undici - request x 36,612 ops/sec ±0.71% (277 runs sampled)
|
29 | undici - stream x 41,291 ops/sec ±0.90% (268 runs sampled)
|
30 | undici - dispatch x 47,319 ops/sec ±1.17% (263 runs sampled)
|
31 | ```
|
32 |
|
33 | The benchmark is a simple `hello world` [example](benchmarks/index.js) using a
|
34 | single unix socket with pipelining.
|
35 |
|
36 | ## API
|
37 |
|
38 | <a name='client'></a>
|
39 | ### `new undici.Client(url, opts)`
|
40 |
|
41 | A basic HTTP/1.1 client, mapped on top a single TCP/TLS connection. Pipelining is disabled
|
42 | by default.
|
43 |
|
44 | `url` can be a string or a [`URL`](https://nodejs.org/api/url.html#url_class_url) object.
|
45 | It should only include the protocol, hostname, and the port.
|
46 |
|
47 | Options:
|
48 |
|
49 | - `socketTimeout: Number`, the timeout after which a socket with active requests
|
50 | will time out. Monitors time between activity on a connected socket.
|
51 | Use `0` to disable it entirely. Default: `30e3` milliseconds (30s).
|
52 |
|
53 | - `socketPath: String|Null`, an IPC endpoint, either Unix domain socket or Windows named pipe.
|
54 | Default: `null`.
|
55 |
|
56 | - `idleTimeout: Number`, the timeout after which a socket without active requests
|
57 | will time out. Monitors time between activity on a connected socket.
|
58 | This value may be overriden by *keep-alive* hints from the server.
|
59 | Default: `4e3` milliseconds (4s).
|
60 |
|
61 | - `keepAlive: Boolean`, enable or disable keep alive connections.
|
62 | Default: `true`.
|
63 |
|
64 | - `keepAliveMaxTimeout: Number`, the maximum allowed `idleTimeout` when overriden by
|
65 | *keep-alive* hints from the server.
|
66 | Default: `600e3` milliseconds (10min).
|
67 |
|
68 | - `keepAliveTimeoutThreshold: Number`, a number subtracted from server *keep-alive* hints
|
69 | when overriding `idleTimeout` to account for timing inaccuries caused by e.g.
|
70 | transport latency.
|
71 | Default: `1e3` milliseconds (1s).
|
72 |
|
73 | - `pipelining: Number`, the amount of concurrent requests to be sent over the
|
74 | single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2).
|
75 | Carefully consider your workload and environment before enabling concurrent requests
|
76 | as pipelining may reduce performance if used incorrectly. Pipelining is sensitive
|
77 | to network stack settings as well as head of line blocking caused by e.g. long running requests.
|
78 | Default: `1`.
|
79 |
|
80 | - `tls: Object|Null`, an options object which in the case of `https` will be passed to
|
81 | [`tls.connect`](https://nodejs.org/api/tls.html#tls_tls_connect_options_callback).
|
82 | Default: `null`.
|
83 |
|
84 | - `maxHeaderSize: Number`, the maximum length of request headers in bytes.
|
85 | Default: `16384` (16KiB).
|
86 |
|
87 | - `headersTimeout: Number`, the amount of time the parser will wait to receive the complete
|
88 | HTTP headers (Node 14 and above only).
|
89 | Default: `30e3` milliseconds (30s).
|
90 |
|
91 | <a name='request'></a>
|
92 | #### `client.request(opts[, callback(err, data)]): Promise|Void`
|
93 |
|
94 | Performs a HTTP request.
|
95 |
|
96 | Options:
|
97 |
|
98 | * `path: String`
|
99 | * `method: String`
|
100 | * `opaque: Any`
|
101 | * `body: String|Buffer|Uint8Array|stream.Readable|Null`
|
102 | Default: `null`.
|
103 | * `headers: Object|Array|Null`, an object with header-value pairs or an array with header-value pairs bi-indexed (`['header1', 'value1', 'header2', 'value2']`).
|
104 | Default: `null`.
|
105 | * `signal: AbortSignal|EventEmitter|Null`
|
106 | Default: `null`.
|
107 | * `requestTimeout: Number`, the timeout after which a request will time out, in
|
108 | milliseconds. Monitors time between request being enqueued and receiving
|
109 | a response. Use `0` to disable it entirely.
|
110 | Default: `30e3` milliseconds (30s).
|
111 | * `idempotent: Boolean`, whether the requests can be safely retried or not.
|
112 | If `false` the request won't be sent until all preceeding
|
113 | requests in the pipeline has completed.
|
114 | Default: `true` if `method` is `HEAD` or `GET`.
|
115 |
|
116 | Headers are represented by an object like this:
|
117 |
|
118 | ```js
|
119 | {
|
120 | 'content-length': '123',
|
121 | 'content-type': 'text/plain',
|
122 | connection: 'keep-alive',
|
123 | host: 'mysite.com',
|
124 | accept: '*/*'
|
125 | }
|
126 | ```
|
127 |
|
128 | Or an array like this:
|
129 |
|
130 | ```js
|
131 | [
|
132 | 'content-length', '123',
|
133 | 'content-type', 'text/plain',
|
134 | 'connection', 'keep-alive',
|
135 | 'host', 'mysite.com',
|
136 | 'accept', '*/*'
|
137 | ]
|
138 | ```
|
139 |
|
140 | Keys are lowercased. Values are not modified.
|
141 | If you don't specify a `host` header, it will be derived from the `url` of the client instance.
|
142 |
|
143 | The `data` parameter in `callback` is defined as follow:
|
144 |
|
145 | * `statusCode: Number`
|
146 | * `opaque: Any`
|
147 | * `headers: Object`, an object where all keys have been lowercased.
|
148 | * `body: stream.Readable` response payload. A user **must**
|
149 | either fully consume or destroy the body unless there is an error, or no further requests
|
150 | will be processed.
|
151 |
|
152 | Returns a promise if no callback is provided.
|
153 |
|
154 | Example:
|
155 |
|
156 | ```js
|
157 | const { Client } = require('undici')
|
158 | const client = new Client(`http://localhost:3000`)
|
159 |
|
160 | client.request({
|
161 | path: '/',
|
162 | method: 'GET'
|
163 | }, function (err, data) {
|
164 | if (err) {
|
165 | // handle this in some way!
|
166 | return
|
167 | }
|
168 |
|
169 | const {
|
170 | statusCode,
|
171 | headers,
|
172 | body
|
173 | } = data
|
174 |
|
175 | console.log('response received', statusCode)
|
176 | console.log('headers', headers)
|
177 |
|
178 | body.setEncoding('utf8')
|
179 | body.on('data', console.log)
|
180 |
|
181 | client.close()
|
182 | })
|
183 | ```
|
184 |
|
185 | Non-idempotent requests will not be pipelined in order
|
186 | to avoid indirect failures.
|
187 |
|
188 | Idempotent requests will be automatically retried if
|
189 | they fail due to indirect failure from the request
|
190 | at the head of the pipeline. This does not apply to
|
191 | idempotent requests with a stream request body.
|
192 |
|
193 | ##### Aborting a request
|
194 |
|
195 | A request can may be aborted using either an `AbortController` or an `EventEmitter`.
|
196 | To use `AbortController` in Node.js versions earlier than 15, you will need to
|
197 | install a shim - `npm i abort-controller`.
|
198 |
|
199 | ```js
|
200 | const { Client } = require('undici')
|
201 |
|
202 | const client = new Client('http://localhost:3000')
|
203 | const abortController = new AbortController()
|
204 |
|
205 | client.request({
|
206 | path: '/',
|
207 | method: 'GET',
|
208 | signal: abortController.signal
|
209 | }, function (err, data) {
|
210 | console.log(err) // RequestAbortedError
|
211 | client.close()
|
212 | })
|
213 |
|
214 | abortController.abort()
|
215 | ```
|
216 |
|
217 | Alternatively, any `EventEmitter` that emits an `'abort'` event may be used as an abort controller:
|
218 |
|
219 | ```js
|
220 | const EventEmitter = require('events')
|
221 | const { Client } = require('undici')
|
222 |
|
223 | const client = new Client('http://localhost:3000')
|
224 | const ee = new EventEmitter()
|
225 |
|
226 | client.request({
|
227 | path: '/',
|
228 | method: 'GET',
|
229 | signal: ee
|
230 | }, function (err, data) {
|
231 | console.log(err) // RequestAbortedError
|
232 | client.close()
|
233 | })
|
234 |
|
235 | ee.emit('abort')
|
236 | ```
|
237 |
|
238 | Destroying the request or response body will have the same effect.
|
239 |
|
240 | <a name='stream'></a>
|
241 | #### `client.stream(opts, factory(data)[, callback(err)]): Promise|Void`
|
242 |
|
243 | A faster version of [`request`][request].
|
244 |
|
245 | Unlike [`request`][request] this method expects `factory`
|
246 | to return a [`Writable`](https://nodejs.org/api/stream.html#stream_class_stream_writable) which the response will be
|
247 | written to. This improves performance by avoiding
|
248 | creating an intermediate [`Readable`](https://nodejs.org/api/stream.html#stream_readable_streams) when the user
|
249 | expects to directly pipe the response body to a
|
250 | [`Writable`](https://nodejs.org/api/stream.html#stream_class_stream_writable).
|
251 |
|
252 | Options:
|
253 |
|
254 | * ... same as [`client.request(opts[, callback])`][request].
|
255 |
|
256 | The `data` parameter in `factory` is defined as follow:
|
257 |
|
258 | * `statusCode: Number`
|
259 | * `headers: Object`, an object where all keys have been lowercased.
|
260 | * `opaque: Any`
|
261 |
|
262 | The `data` parameter in `callback` is defined as follow:
|
263 |
|
264 | * `opaque: Any`
|
265 | * `trailers: Object`, an object where all keys have been lowercased.
|
266 |
|
267 | Returns a promise if no callback is provided.
|
268 |
|
269 | ```js
|
270 | const { Client } = require('undici')
|
271 | const client = new Client(`http://localhost:3000`)
|
272 | const fs = require('fs')
|
273 |
|
274 | client.stream({
|
275 | path: '/',
|
276 | method: 'GET',
|
277 | opaque: filename
|
278 | }, ({ statusCode, headers, opaque: filename }) => {
|
279 | console.log('response received', statusCode)
|
280 | console.log('headers', headers)
|
281 | return fs.createWriteStream(filename)
|
282 | }, (err) => {
|
283 | if (err) {
|
284 | console.error('failure', err)
|
285 | } else {
|
286 | console.log('success')
|
287 | }
|
288 | })
|
289 | ```
|
290 |
|
291 | `opaque` makes it possible to avoid creating a closure
|
292 | for the `factory` method:
|
293 |
|
294 | ```js
|
295 | function (req, res) {
|
296 | return client.stream({ ...opts, opaque: res }, proxy)
|
297 | }
|
298 | ```
|
299 |
|
300 | Instead of:
|
301 |
|
302 | ```js
|
303 | function (req, res) {
|
304 | return client.stream(opts, (data) => {
|
305 | // Creates closure to capture `res`.
|
306 | proxy({ ...data, opaque: res })
|
307 | }
|
308 | }
|
309 | ```
|
310 |
|
311 | <a name='pipeline'></a>
|
312 | #### `client.pipeline(opts, handler(data)): Duplex`
|
313 |
|
314 | For easy use with [`stream.pipeline`](https://nodejs.org/api/stream.html#stream_stream_pipeline_source_transforms_destination_callback).
|
315 |
|
316 | Options:
|
317 |
|
318 | * ... same as [`client.request(opts, callback)`][request].
|
319 | * `objectMode: Boolean`, `true` if the `handler` will return an object stream.
|
320 | Default: `false`
|
321 |
|
322 | The `data` parameter in `handler` is defined as follow:
|
323 |
|
324 | * `statusCode: Number`
|
325 | * `headers: Object`, an object where all keys have been lowercased.
|
326 | * `opaque: Any`
|
327 | * `body: stream.Readable` response payload. A user **must**
|
328 | either fully consume or destroy the body unless there is an error, or no further requests
|
329 | will be processed.
|
330 |
|
331 | `handler` should return a [`Readable`](https://nodejs.org/api/stream.html#stream_class_stream_readable) from which the result will be
|
332 | read. Usually it should just return the `body` argument unless
|
333 | some kind of transformation needs to be performed based on e.g.
|
334 | `headers` or `statusCode`.
|
335 |
|
336 | The `handler` should validate the response and save any
|
337 | required state. If there is an error it should be thrown.
|
338 |
|
339 | Returns a `Duplex` which writes to the request and reads from
|
340 | the response.
|
341 |
|
342 | ```js
|
343 | const { Client } = require('undici')
|
344 | const client = new Client(`http://localhost:3000`)
|
345 | const fs = require('fs')
|
346 | const stream = require('stream')
|
347 |
|
348 | stream.pipeline(
|
349 | fs.createReadStream('source.raw'),
|
350 | client.pipeline({
|
351 | path: '/',
|
352 | method: 'PUT',
|
353 | }, ({ statusCode, headers, body }) => {
|
354 | if (statusCode !== 201) {
|
355 | throw new Error('invalid response')
|
356 | }
|
357 |
|
358 | if (isZipped(headers)) {
|
359 | return pipeline(body, unzip(), () => {})
|
360 | }
|
361 |
|
362 | return body
|
363 | }),
|
364 | fs.createWriteStream('response.raw'),
|
365 | (err) => {
|
366 | if (err) {
|
367 | console.error('failed')
|
368 | } else {
|
369 | console.log('succeeded')
|
370 | }
|
371 | }
|
372 | )
|
373 | ```
|
374 |
|
375 | <a name='upgrade'></a>
|
376 | #### `client.upgrade(opts[, callback(err, data)]): Promise|Void`
|
377 |
|
378 | Upgrade to a different protocol.
|
379 |
|
380 | Options:
|
381 |
|
382 | * `path: String`
|
383 | * `opaque: Any`
|
384 | * `method: String`
|
385 | Default: `GET`
|
386 | * `headers: Object|Null`, an object with header-value pairs.
|
387 | Default: `null`
|
388 | * `signal: AbortSignal|EventEmitter|Null`.
|
389 | Default: `null`
|
390 | * `requestTimeout: Number`, the timeout after which a request will time out, in
|
391 | milliseconds. Monitors time between request being enqueued and receiving
|
392 | a response. Use `0` to disable it entirely.
|
393 | Default: `30e3` milliseconds (30s).
|
394 | * `protocol: String`, a string of comma separated protocols, in descending preference order.
|
395 | Default: `Websocket`.
|
396 |
|
397 | The `data` parameter in `callback` is defined as follow:
|
398 |
|
399 | * `headers: Object`, an object where all keys have been lowercased.
|
400 | * `socket: Duplex`
|
401 | * `opaque`
|
402 |
|
403 | Returns a promise if no callback is provided.
|
404 |
|
405 | <a name='connect'></a>
|
406 | #### `client.connect(opts[, callback(err, data)]): Promise|Void`
|
407 |
|
408 | Starts two-way communications with the requested resource.
|
409 |
|
410 | Options:
|
411 |
|
412 | * `path: String`
|
413 | * `opaque: Any`
|
414 | * `headers: Object|Null`, an object with header-value pairs.
|
415 | Default: `null`
|
416 | * `signal: AbortSignal|EventEmitter|Null`.
|
417 | Default: `null`
|
418 | * `requestTimeout: Number`, the timeout after which a request will time out, in
|
419 | milliseconds. Monitors time between request being enqueued and receiving
|
420 | a response. Use `0` to disable it entirely.
|
421 | Default: `30e3` milliseconds (30s).
|
422 |
|
423 | The `data` parameter in `callback` is defined as follow:
|
424 |
|
425 | * `statusCode: Number`
|
426 | * `headers: Object`, an object where all keys have been lowercased.
|
427 | * `socket: Duplex`
|
428 | * `opaque: Any`
|
429 |
|
430 | Returns a promise if no callback is provided.
|
431 |
|
432 | <a name='dispatch'></a>
|
433 | #### `client.dispatch(opts, handler): Void`
|
434 |
|
435 | This is the low level API which all the preceeding APIs are implemented on top of.
|
436 |
|
437 | This API is expected to evolve through semver-major versions and is less stable
|
438 | than the preceeding higher level APIs. It is primarily intended for library developers
|
439 | who implement higher level APIs on top of this.
|
440 |
|
441 | Options:
|
442 |
|
443 | * `path: String`
|
444 | * `method: String`
|
445 | * `body: String|Buffer|Uint8Array|stream.Readable|Null`
|
446 | Default: `null`.
|
447 | * `headers: Object|Null`, an object with header-value pairs.
|
448 | Default: `null`.
|
449 | * `requestTimeout: Number`, the timeout after which a request will time out, in
|
450 | milliseconds. Monitors time between request being enqueued and receiving
|
451 | a response. Use `0` to disable it entirely.
|
452 | Default: `30e3` milliseconds (30s).
|
453 | * `idempotent: Boolean`, whether the requests can be safely retried or not.
|
454 | If `false` the request won't be sent until all preceeding
|
455 | requests in the pipeline has completed.
|
456 | Default: `true` if `method` is `HEAD` or `GET`.
|
457 |
|
458 | The `handler` parameter is defined as follow:
|
459 |
|
460 | * `onConnect(abort)`, invoked before request is dispatched on socket.
|
461 | May be invoked multiple times when a request is retried when the request at the head of the pipeline fails.
|
462 | * `abort(): Void`, abort request.
|
463 | * `onUpgrade(statusCode, headers, socket): Void`, invoked when request is upgraded either due to a `Upgrade` header or `CONNECT` method.
|
464 | * `statusCode: Number`
|
465 | * `headers: Array|Null`
|
466 | * `socket: Duplex`
|
467 | * `onHeaders(statusCode, headers, resume): Boolean`, invoked when statusCode and headers have been received.
|
468 | May be invoked multiple times due to 1xx informational headers.
|
469 | * `statusCode: Number`
|
470 | * `headers: Array|Null`, an array of key-value pairs. Keys are not automatically lowercased.
|
471 | * `resume(): Void`, resume `onData` after returning `false`.
|
472 | * `onData(chunk): Boolean`, invoked when response payload data is received.
|
473 | * `chunk: Buffer`
|
474 | * `onComplete(trailers): Void`, invoked when response payload and trailers have been received and the request has completed.
|
475 | * `trailers: Array|Null`
|
476 | * `onError(err): Void`, invoked when an error has occured.
|
477 | * `err: Error`
|
478 |
|
479 | The caller is responsible for handling the `body` argument, in terms of `'error'` events and `destroy()`:ing up until
|
480 | the `onConnect` handler has been invoked.
|
481 |
|
482 | <a name='close'></a>
|
483 | #### `client.close([callback]): Promise|Void`
|
484 |
|
485 | Closes the client and gracefully waits for enqueued requests to
|
486 | complete before invoking the callback.
|
487 |
|
488 | Returns a promise if no callback is provided.
|
489 |
|
490 | <a name='destroy'></a>
|
491 | #### `client.destroy([err][, callback]): Promise|Void`
|
492 |
|
493 | Destroy the client abruptly with the given `err`. All the pending and running
|
494 | requests will be asynchronously aborted and error. Waits until socket is closed
|
495 | before invoking the callback. Since this operation is asynchronously dispatched
|
496 | there might still be some progress on dispatched requests.
|
497 |
|
498 | Returns a promise if no callback is provided.
|
499 |
|
500 | #### `client.pipelining: Number`
|
501 |
|
502 | Property to get and set the pipelining factor.
|
503 |
|
504 | #### `client.pending: Number`
|
505 |
|
506 | Number of queued requests.
|
507 |
|
508 | #### `client.running: Number`
|
509 |
|
510 | Number of inflight requests.
|
511 |
|
512 | #### `client.size: Number`
|
513 |
|
514 | Number of pending and running requests.
|
515 |
|
516 | #### `client.connected: Boolean`
|
517 |
|
518 | True if the client has an active connection. The client will lazily
|
519 | create a connection when it receives a request and will destroy it
|
520 | if there is no activity for the duration of the `timeout` value.
|
521 |
|
522 | #### `client.busy: Boolean`
|
523 |
|
524 | True if pipeline is saturated or blocked. Indicicates whether dispatching
|
525 | further requests is meaningful.
|
526 |
|
527 | #### `client.closed: Boolean`
|
528 |
|
529 | True after `client.close()` has been called.
|
530 |
|
531 | #### `client.destroyed: Boolean`
|
532 |
|
533 | True after `client.destroyed()` has been called or `client.close()` has been
|
534 | called and the client shutdown has completed.
|
535 |
|
536 | #### Events
|
537 |
|
538 | * `'drain'`, emitted when pipeline is no longer fully
|
539 | saturated.
|
540 |
|
541 | * `'connect'`, emitted when a socket has been created and
|
542 | connected. The client will connect once `client.size > 0`.
|
543 |
|
544 | * `'disconnect'`, emitted when socket has disconnected. The
|
545 | first argument of the event is the error which caused the
|
546 | socket to disconnect. The client will reconnect if or once
|
547 | `client.size > 0`.
|
548 |
|
549 | <a name='pool'></a>
|
550 | ### `new undici.Pool(url, opts)`
|
551 |
|
552 | A pool of [`Client`][] connected to the same upstream target.
|
553 |
|
554 | Options:
|
555 |
|
556 | * ... same as [`Client`][].
|
557 | * `connections`, the number of clients to create.
|
558 | Default `10`.
|
559 |
|
560 | `Pool` does not guarantee that requests are dispatched in
|
561 | order of invocation.
|
562 |
|
563 | #### `pool.request(opts[, callback]): Promise|Void`
|
564 |
|
565 | Calls [`client.request(opts, callback)`][request] on one of the clients.
|
566 |
|
567 | #### `pool.stream(opts, factory[, callback]): Promise|Void`
|
568 |
|
569 | Calls [`client.stream(opts, factory, callback)`][stream] on one of the clients.
|
570 |
|
571 | #### `pool.pipeline(opts, handler): Duplex`
|
572 |
|
573 | Calls [`client.pipeline(opts, handler)`][pipeline] on one of the clients.
|
574 |
|
575 | #### `pool.upgrade(opts[, callback]): Promise|Void`
|
576 |
|
577 | Calls [`client.upgrade(opts, callback)`][upgrade] on one of the clients.
|
578 |
|
579 | #### `pool.connect(opts[, callback]): Promise|Void`
|
580 |
|
581 | Calls [`client.connect(opts, callback)`][connect] on one of the clients.
|
582 |
|
583 | #### `pool.dispatch(opts, handler): Void`
|
584 |
|
585 | Calls [`client.dispatch(opts, handler)`][dispatch] on one of the clients.
|
586 |
|
587 | #### `pool.close([callback]): Promise|Void`
|
588 |
|
589 | Calls [`client.close(callback)`](#close) on all the clients.
|
590 |
|
591 | #### `pool.destroy([err][, callback]): Promise|Void`
|
592 |
|
593 | Calls [`client.destroy(err, callback)`](#destroy) on all the clients.
|
594 |
|
595 | <a name='errors'></a>
|
596 | ### `undici.errors`
|
597 |
|
598 | Undici exposes a variety of error objects that you can use to enhance your error handling.
|
599 | You can find all the error objects inside the `errors` key.
|
600 |
|
601 | ```js
|
602 | const { errors } = require('undici')
|
603 | ```
|
604 |
|
605 | | Error | Error Codes | Description |
|
606 | | -----------------------------|-----------------------------------|------------------------------------------------|
|
607 | | `InvalidArgumentError` | `UND_ERR_INVALID_ARG` | passed an invalid argument. |
|
608 | | `InvalidReturnValueError` | `UND_ERR_INVALID_RETURN_VALUE` | returned an invalid value. |
|
609 | | `SocketTimeoutError` | `UND_ERR_SOCKET_TIMEOUT` | a socket exceeds the `socketTimeout` option. |
|
610 | | `RequestTimeoutError` | `UND_ERR_REQUEST_TIMEOUT` | a request exceeds the `requestTimeout` option. |
|
611 | | `RequestAbortedError` | `UND_ERR_ABORTED` | the request has been aborted by the user |
|
612 | | `ClientDestroyedError` | `UND_ERR_DESTROYED` | trying to use a destroyed client. |
|
613 | | `ClientClosedError` | `UND_ERR_CLOSED` | trying to use a closed client. |
|
614 | | `SocketError` | `UND_ERR_SOCKET` | there is an error with the socket. |
|
615 | | `NotSupportedError` | `UND_ERR_NOT_SUPPORTED` | encountered unsupported functionality. |
|
616 | | `ContentLengthMismatchError` | `UND_ERR_CONTENT_LENGTH_MISMATCH`| body does not match content-length header |
|
617 | | `InformationalError` | `UND_ERR_INFO` | expected error with reason |
|
618 | | `TrailerMismatchError` | `UND_ERR_TRAILER_MISMATCH` | trailers did not match specification |
|
619 |
|
620 | ## Specification Compliance
|
621 |
|
622 | This section documents parts of the HTTP/1.1 specification which Undici does
|
623 | not support or does not fully implement.
|
624 |
|
625 | #### Expect
|
626 |
|
627 | Undici does not support the `Expect` request header field. The request
|
628 | body is always immediately sent and the `100 Continue` response will be
|
629 | ignored.
|
630 |
|
631 | Refs: https://tools.ietf.org/html/rfc7231#section-5.1.1
|
632 |
|
633 | ### Pipelining
|
634 |
|
635 | Uncidi will only use pipelining if configured with a `pipelining` factor
|
636 | greater than `1`.
|
637 |
|
638 | Undici always assumes that connections are persistent and will immediatly
|
639 | pipeline requests, without checking whether the connection is persistent.
|
640 | Hence, automatic fallback to HTTP/1.0 or HTTP/1.1 without pipelining is
|
641 | not supported.
|
642 |
|
643 | Undici will immediately pipeline when retrying requests afters a failed
|
644 | connection. However, Undici will not retry the first remaining requests in
|
645 | the prior pipeline and instead error the corresponding callback/promise/stream.
|
646 |
|
647 | Refs: https://tools.ietf.org/html/rfc2616#section-8.1.2.2<br/>
|
648 | Refs: https://tools.ietf.org/html/rfc7230#section-6.3.2
|
649 |
|
650 | ## Collaborators
|
651 |
|
652 | * [__Robert Nagy__](https://github.com/ronag), <https://www.npmjs.com/~ronag>
|
653 |
|
654 | ## License
|
655 |
|
656 | MIT
|
657 |
|
658 | [`Client`]: #client
|
659 | [request]: #request
|
660 | [stream]: #stream
|
661 | [pipeline]: #pipeline
|
662 | [upgrade]: #upgrade
|
663 | [connect]: #connect
|
664 | [dispatch]: #dispatch
|