Comparing version 4.2.2 to 4.3.0
@@ -32,4 +32,9 @@ # Class: Client | ||
Every Tls option, see [here](https://nodejs.org/api/tls.html#tls_tls_connect_options_callback). | ||
Furthermore, the following options can be passed: | ||
* **socketPath** `string | null` (optional) - Default: `null` - An IPC endpoint, either Unix domain socket or Windows named pipe. | ||
* **maxCachedSessions** `number | null` (optional) - Default: `100` - Maximum number of TLS cached sessions. Use 0 to disable TLS session caching. Default: 100. | ||
* **timeout** `number | null` (optional) - Default `10e3` | ||
* **servername** `string | null` (optional) | ||
@@ -47,2 +52,27 @@ ### Example - Basic Client instantiation | ||
### Example - Custom connector | ||
This will allow you to perform some additional check on the socket that will be used for the next request. | ||
```js | ||
'use strict' | ||
import { Client, buildConnector } from 'undici' | ||
const connector = buildConnector({ rejectUnauthorized: false }) | ||
const client = new Client('https://localhost:3000', { | ||
connect (opts, cb) { | ||
connector(opts, (err, socket) => { | ||
if (err) { | ||
cb(err) | ||
} else if (/* assertion */) { | ||
socket.destroy() | ||
cb(new Error('kaboom')) | ||
} else { | ||
cb(null, socket) | ||
} | ||
}) | ||
} | ||
}) | ||
``` | ||
## Instance Methods | ||
@@ -49,0 +79,0 @@ |
@@ -421,3 +421,3 @@ # Dispatcher | ||
* **headers** `http.IncomingHttpHeaders` | ||
* **body** `stream.Readable` | ||
* **body** `stream.Readable` which also implements [the body mixin from the Fetch Standard](https://fetch.spec.whatwg.org/#body-mixin). | ||
* **trailers** `Record<string, string>` - This object starts out | ||
@@ -428,2 +428,10 @@ as empty and will be mutated to contain trailers after `body` has emitted `'end'`. | ||
`body` contains the following additional [body mixin](https://fetch.spec.whatwg.org/#body-mixin) methods and properties: | ||
- `text()` | ||
- `json()` | ||
- `arrayBuffer()` | ||
- `body` | ||
- `bodyUsed` | ||
#### Example 1 - Basic GET Request | ||
@@ -430,0 +438,0 @@ |
@@ -5,2 +5,3 @@ import Dispatcher from './types/dispatcher' | ||
import Client from './types/client' | ||
import buildConnector from './types/connector' | ||
import errors from './types/errors' | ||
@@ -14,3 +15,3 @@ import Agent from './types/agent' | ||
export { Dispatcher, Pool, Client, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, MockClient, MockPool, MockAgent, mockErrors } | ||
export { Dispatcher, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, MockClient, MockPool, MockAgent, mockErrors } | ||
export default Undici | ||
@@ -24,2 +25,3 @@ | ||
var Client: typeof import('./types/client'); | ||
var buildConnector: typeof import('./types/connector'); | ||
var errors: typeof import('./types/errors'); | ||
@@ -26,0 +28,0 @@ var Agent: typeof import('./types/agent'); |
@@ -11,2 +11,3 @@ 'use strict' | ||
const api = require('./lib/api') | ||
const buildConnector = require('./lib/core/connect') | ||
const MockClient = require('./lib/mock/mock-client') | ||
@@ -24,2 +25,3 @@ const MockAgent = require('./lib/mock/mock-agent') | ||
module.exports.buildConnector = buildConnector | ||
module.exports.errors = errors | ||
@@ -26,0 +28,0 @@ |
'use strict' | ||
const { Readable } = require('stream') | ||
const Readable = require('./readable') | ||
const { | ||
@@ -12,23 +12,2 @@ InvalidArgumentError, | ||
const kAbort = Symbol('abort') | ||
class RequestResponse extends Readable { | ||
constructor (resume, abort) { | ||
super({ autoDestroy: true, read: resume }) | ||
this[kAbort] = abort | ||
} | ||
_destroy (err, callback) { | ||
if (!err && !this._readableState.endEmitted) { | ||
err = new RequestAbortedError() | ||
} | ||
if (err) { | ||
this[kAbort]() | ||
} | ||
callback(err) | ||
} | ||
} | ||
class RequestHandler extends AsyncResource { | ||
@@ -96,3 +75,3 @@ constructor (opts, callback) { | ||
const body = new RequestResponse(resume, abort) | ||
const body = new Readable(resume, abort) | ||
@@ -99,0 +78,0 @@ this.callback = null |
@@ -26,3 +26,3 @@ 'use strict' | ||
} = require('./core/errors') | ||
const makeConnect = require('./core/connect') | ||
const buildConnector = require('./core/connect') | ||
@@ -153,3 +153,3 @@ const { | ||
if (typeof connect !== 'function') { | ||
connect = makeConnect({ | ||
connect = buildConnector({ | ||
...tls, | ||
@@ -156,0 +156,0 @@ maxCachedSessions, |
@@ -14,23 +14,21 @@ 'use strict' | ||
class Connector { | ||
constructor ({ maxCachedSessions, socketPath, timeout, ...opts }) { | ||
if (maxCachedSessions != null && (!Number.isInteger(maxCachedSessions) || maxCachedSessions < 0)) { | ||
throw new InvalidArgumentError('maxCachedSessions must be a positive integer or zero') | ||
} | ||
this.opts = { path: socketPath, ...opts } | ||
this.timeout = timeout == null ? 10e3 : timeout | ||
this.sessionCache = new Map() | ||
this.maxCachedSessions = maxCachedSessions == null ? 100 : maxCachedSessions | ||
function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) { | ||
if (maxCachedSessions != null && (!Number.isInteger(maxCachedSessions) || maxCachedSessions < 0)) { | ||
throw new InvalidArgumentError('maxCachedSessions must be a positive integer or zero') | ||
} | ||
connect ({ hostname, host, protocol, port, servername }, callback) { | ||
const options = { path: socketPath, ...opts } | ||
const sessionCache = new Map() | ||
timeout = timeout == null ? 10e3 : timeout | ||
maxCachedSessions = maxCachedSessions == null ? 100 : maxCachedSessions | ||
return function connect ({ hostname, host, protocol, port, servername }, callback) { | ||
let socket | ||
if (protocol === 'https:') { | ||
servername = servername || this.opts.servername || util.getServerName(host) | ||
servername = servername || options.servername || util.getServerName(host) | ||
const session = this.sessionCache.get(servername) || null | ||
const session = sessionCache.get(servername) || null | ||
socket = tls.connect({ | ||
...this.opts, | ||
...options, | ||
servername, | ||
@@ -42,5 +40,2 @@ session, | ||
const cache = this.sessionCache | ||
const maxCachedSessions = this.maxCachedSessions | ||
socket | ||
@@ -55,9 +50,9 @@ .on('session', function (session) { | ||
if (cache.size >= maxCachedSessions) { | ||
if (sessionCache.size >= maxCachedSessions) { | ||
// remove the oldest session | ||
const { value: oldestKey } = cache.keys().next() | ||
cache.delete(oldestKey) | ||
const { value: oldestKey } = sessionCache.keys().next() | ||
sessionCache.delete(oldestKey) | ||
} | ||
cache.set(this.servername, session) | ||
sessionCache.set(this.servername, session) | ||
}) | ||
@@ -67,3 +62,3 @@ .on('error', function (err) { | ||
// TODO (fix): Only delete for session related errors. | ||
cache.delete(this.servername) | ||
sessionCache.delete(this.servername) | ||
} | ||
@@ -73,3 +68,3 @@ }) | ||
socket = net.connect({ | ||
...this.opts, | ||
...options, | ||
port: port || 80, | ||
@@ -80,4 +75,4 @@ host: hostname | ||
const timeout = this.timeout | ||
? setTimeout(onConnectTimeout, this.timeout, socket) | ||
const timeoutId = timeout | ||
? setTimeout(onConnectTimeout, timeout, socket) | ||
: null | ||
@@ -88,3 +83,3 @@ | ||
.once(protocol === 'https:' ? 'secureConnect' : 'connect', function () { | ||
clearTimeout(timeout) | ||
clearTimeout(timeoutId) | ||
@@ -98,3 +93,3 @@ if (callback) { | ||
.on('error', function (err) { | ||
clearTimeout(timeout) | ||
clearTimeout(timeoutId) | ||
@@ -116,4 +111,2 @@ if (callback) { | ||
module.exports = (opts) => { | ||
return Connector.prototype.connect.bind(new Connector(opts)) | ||
} | ||
module.exports = buildConnector |
@@ -14,3 +14,3 @@ 'use strict' | ||
const assert = require('assert') | ||
const makeConnect = require('./core/connect') | ||
const buildConnector = require('./core/connect') | ||
@@ -62,3 +62,3 @@ const kClients = Symbol('clients') | ||
if (typeof connect !== 'function') { | ||
connect = makeConnect({ | ||
connect = buildConnector({ | ||
...tls, | ||
@@ -65,0 +65,0 @@ maxCachedSessions, |
{ | ||
"name": "undici", | ||
"version": "4.2.2", | ||
"version": "4.3.0", | ||
"description": "An HTTP/1.1 client, written from scratch for Node.js", | ||
@@ -5,0 +5,0 @@ "homepage": "https://undici.nodejs.org", |
@@ -68,2 +68,20 @@ # undici | ||
Using [the body mixin from the Fetch Standard](https://fetch.spec.whatwg.org/#body-mixin). | ||
```js | ||
import { request } from 'undici' | ||
const { | ||
statusCode, | ||
headers, | ||
trailers, | ||
body | ||
} = await request('http://localhost:3000/foo') | ||
console.log('response received', statusCode) | ||
console.log('headers', headers) | ||
console.log('data', await body.json()) | ||
console.log('trailers', trailers) | ||
``` | ||
## Common API Methods | ||
@@ -70,0 +88,0 @@ |
import { URL } from 'url' | ||
import Dispatcher from './dispatcher' | ||
import { TlsOptions } from 'tls' | ||
import Dispatcher, { DispatchOptions, RequestOptions } from './dispatcher' | ||
import buildConnector from './connector' | ||
@@ -15,2 +17,7 @@ export = Client | ||
destroyed: boolean; | ||
/** Dispatches a request. This API is expected to evolve through semver-major versions and is less stable than the preceding higher level APIs. It is primarily intended for library developers who implement higher level APIs on top of this. */ | ||
dispatch(options: Client.ClientDispatchOptions, handler: Dispatcher.DispatchHandlers): void; | ||
/** Performs an HTTP request. */ | ||
request(options: Client.ClientRequestOptions): Promise<Dispatcher.ResponseData>; | ||
request(options: Client.ClientRequestOptions, callback: (err: Error | null, data: Dispatcher.ResponseData) => void): void; | ||
} | ||
@@ -29,3 +36,3 @@ | ||
/** **/ | ||
connect?: object | Function | null; | ||
connect?: buildConnector.BuildOptions | Function | null; | ||
/** The maximum length of request headers in bytes. Default: `16384` (16KiB). */ | ||
@@ -38,4 +45,14 @@ maxHeaderSize?: number | null; | ||
/** If `true`, an error is thrown when the request content-length header doesn't match the length of the request body. Default: `true`. */ | ||
strictContentLength?: boolean | ||
strictContentLength?: boolean; | ||
/** @deprecated use the connect option instead */ | ||
tls?: TlsOptions | null; | ||
} | ||
export interface ClientDispatchOptions extends Partial<DispatchOptions> { | ||
origin?: string | URL; | ||
} | ||
export interface ClientRequestOptions extends Partial<RequestOptions> { | ||
origin?: string | URL; | ||
} | ||
} |
import Client from './client' | ||
import Dispatcher from './dispatcher' | ||
import Dispatcher, { DispatchOptions, RequestOptions } from './dispatcher' | ||
import { URL } from 'url' | ||
@@ -13,2 +13,7 @@ | ||
destroyed: boolean; | ||
/** Dispatches a request. This API is expected to evolve through semver-major versions and is less stable than the preceding higher level APIs. It is primarily intended for library developers who implement higher level APIs on top of this. */ | ||
dispatch(options: Pool.PoolDispatchOptions, handler: Dispatcher.DispatchHandlers): void; | ||
/** Performs an HTTP request. */ | ||
request(options: Pool.PoolRequestOptions): Promise<Dispatcher.ResponseData>; | ||
request(options: Pool.PoolRequestOptions, callback: (err: Error | null, data: Dispatcher.ResponseData) => void): void; | ||
} | ||
@@ -23,2 +28,10 @@ | ||
} | ||
export interface PoolDispatchOptions extends Partial<DispatchOptions> { | ||
origin?: string | URL; | ||
} | ||
export interface PoolRequestOptions extends Partial<RequestOptions> { | ||
origin?: string | URL; | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
443807
68
5371
237