agent-base
Advanced tools
Comparing version
/// <reference types="node" /> | ||
import net from 'net'; | ||
import http from 'http'; | ||
import https from 'https'; | ||
import { Duplex } from 'stream'; | ||
import { EventEmitter } from 'events'; | ||
declare function createAgent(opts?: createAgent.AgentOptions): createAgent.Agent; | ||
declare namespace createAgent { | ||
var prototype: Agent; | ||
} | ||
declare function createAgent(callback: createAgent.AgentCallback, opts?: createAgent.AgentOptions): createAgent.Agent; | ||
declare namespace createAgent { | ||
var prototype: Agent; | ||
} | ||
declare namespace createAgent { | ||
type ClientRequest = http.ClientRequest & { | ||
interface ClientRequest extends http.ClientRequest { | ||
_last?: boolean; | ||
_hadError?: boolean; | ||
method: string; | ||
}; | ||
type AgentCallbackReturn = net.Socket | createAgent.Agent | http.Agent; | ||
} | ||
interface AgentRequestOptions { | ||
host?: string; | ||
path?: string; | ||
port: number; | ||
} | ||
interface HttpRequestOptions extends AgentRequestOptions, Omit<http.RequestOptions, keyof AgentRequestOptions> { | ||
secureEndpoint: false; | ||
} | ||
interface HttpsRequestOptions extends AgentRequestOptions, Omit<https.RequestOptions, keyof AgentRequestOptions> { | ||
secureEndpoint: true; | ||
} | ||
type RequestOptions = HttpRequestOptions | HttpsRequestOptions; | ||
type AgentLike = Pick<createAgent.Agent, 'addRequest'> | http.Agent; | ||
type AgentCallbackReturn = Duplex | AgentLike; | ||
type AgentCallbackCallback = (err: Error | null | undefined, socket: createAgent.AgentCallbackReturn) => void; | ||
type AgentCallbackPromise = (req: createAgent.ClientRequest, opts: createAgent.RequestOptions) => createAgent.AgentCallbackReturn | Promise<createAgent.AgentCallbackReturn>; | ||
type AgentCallback = typeof Agent.prototype.callback; | ||
type AgentOptions = http.AgentOptions & {}; | ||
type RequestOptions = http.RequestOptions & { | ||
port: number; | ||
secureEndpoint: boolean; | ||
type AgentOptions = { | ||
timeout?: number; | ||
}; | ||
@@ -37,7 +44,10 @@ /** | ||
timeout: number | null; | ||
options?: createAgent.AgentOptions; | ||
maxFreeSockets: number; | ||
maxSockets: number; | ||
sockets: net.Socket[]; | ||
requests: http.ClientRequest[]; | ||
sockets: { | ||
[key: string]: net.Socket[]; | ||
}; | ||
requests: { | ||
[key: string]: http.IncomingMessage[]; | ||
}; | ||
private promisifiedCallback?; | ||
@@ -44,0 +54,0 @@ private explicitDefaultPort?; |
@@ -6,9 +6,8 @@ "use strict"; | ||
const events_1 = require("events"); | ||
const debug_1 = __importDefault(require("debug")); | ||
const promisify_1 = __importDefault(require("./promisify")); | ||
function isAgentBase(v) { | ||
const debug = debug_1.default('agent-base'); | ||
function isAgent(v) { | ||
return Boolean(v) && typeof v.addRequest === 'function'; | ||
} | ||
function isHttpAgent(v) { | ||
return Boolean(v) && typeof v.addRequest === 'function'; | ||
} | ||
function isSecureEndpoint() { | ||
@@ -34,4 +33,2 @@ const { stack } = new Error(); | ||
super(); | ||
// The callback gets promisified lazily | ||
this.promisifiedCallback = undefined; | ||
let opts = _opts; | ||
@@ -44,3 +41,3 @@ if (typeof callback === 'function') { | ||
} | ||
// timeout for the socket to be returned from the callback | ||
// Timeout for the socket to be returned from the callback | ||
this.timeout = null; | ||
@@ -50,7 +47,8 @@ if (opts && typeof opts.timeout === 'number') { | ||
} | ||
this.options = opts || {}; | ||
// These aren't actually used by `agent-base`, but are required | ||
// for the TypeScript definition files in `@types/node` :/ | ||
this.maxFreeSockets = 1; | ||
this.maxSockets = 1; | ||
this.sockets = []; | ||
this.requests = []; | ||
this.sockets = {}; | ||
this.requests = {}; | ||
} | ||
@@ -61,5 +59,3 @@ get defaultPort() { | ||
} | ||
else { | ||
return isSecureEndpoint() ? 443 : 80; | ||
} | ||
return isSecureEndpoint() ? 443 : 80; | ||
} | ||
@@ -73,5 +69,3 @@ set defaultPort(v) { | ||
} | ||
else { | ||
return isSecureEndpoint() ? 'https:' : 'http:'; | ||
} | ||
return isSecureEndpoint() ? 'https:' : 'http:'; | ||
} | ||
@@ -91,19 +85,20 @@ set protocol(v) { | ||
addRequest(req, _opts) { | ||
const ownOpts = Object.assign({}, _opts); | ||
if (typeof ownOpts.secureEndpoint !== 'boolean') { | ||
ownOpts.secureEndpoint = isSecureEndpoint(); | ||
const opts = Object.assign({}, _opts); | ||
if (typeof opts.secureEndpoint !== 'boolean') { | ||
opts.secureEndpoint = isSecureEndpoint(); | ||
} | ||
// Set default `host` for HTTP to localhost | ||
if (ownOpts.host == null) { | ||
ownOpts.host = 'localhost'; | ||
if (opts.host == null) { | ||
opts.host = 'localhost'; | ||
} | ||
// Set default `port` for HTTP if none was explicitly specified | ||
if (ownOpts.port == null) { | ||
ownOpts.port = ownOpts.secureEndpoint ? 443 : 80; | ||
if (opts.port == null) { | ||
opts.port = opts.secureEndpoint ? 443 : 80; | ||
} | ||
const opts = Object.assign(Object.assign({}, this.options), ownOpts); | ||
if (opts.protocol == null) { | ||
opts.protocol = opts.secureEndpoint ? 'https:' : 'http:'; | ||
} | ||
if (opts.host && opts.path) { | ||
// If both a `host` and `path` are specified then it's most likely the | ||
// result of a `url.parse()` call... we need to remove the `path` portion so | ||
// that `net.connect()` doesn't attempt to open that as a unix socket file. | ||
// If both a `host` and `path` are specified then it's most | ||
// likely the result of a `url.parse()` call... we need to | ||
// remove the `path` portion so that `net.connect()` doesn't | ||
// attempt to open that as a unix socket file. | ||
delete opts.path; | ||
@@ -120,8 +115,6 @@ } | ||
req.shouldKeepAlive = false; | ||
// Create the `stream.Duplex` instance | ||
let timedOut = false; | ||
let timeout = null; | ||
const timeoutMs = this.timeout; | ||
const freeSocket = this.freeSocket; | ||
function onerror(err) { | ||
let timeoutId = null; | ||
const timeoutMs = opts.timeout || this.timeout; | ||
const onerror = (err) => { | ||
if (req._hadError) | ||
@@ -133,5 +126,5 @@ return; | ||
req._hadError = true; | ||
} | ||
function ontimeout() { | ||
timeout = null; | ||
}; | ||
const ontimeout = () => { | ||
timeoutId = null; | ||
timedOut = true; | ||
@@ -141,27 +134,24 @@ const err = new Error(`A "socket" was not created for HTTP request before ${timeoutMs}ms`); | ||
onerror(err); | ||
} | ||
function callbackError(err) { | ||
}; | ||
const callbackError = (err) => { | ||
if (timedOut) | ||
return; | ||
if (timeout !== null) { | ||
clearTimeout(timeout); | ||
timeout = null; | ||
if (timeoutId !== null) { | ||
clearTimeout(timeoutId); | ||
timeoutId = null; | ||
} | ||
onerror(err); | ||
} | ||
function onsocket(socket) { | ||
let sock; | ||
function onfree() { | ||
freeSocket(sock, opts); | ||
} | ||
}; | ||
const onsocket = (socket) => { | ||
if (timedOut) | ||
return; | ||
if (timeout != null) { | ||
clearTimeout(timeout); | ||
timeout = null; | ||
if (timeoutId != null) { | ||
clearTimeout(timeoutId); | ||
timeoutId = null; | ||
} | ||
if (isAgentBase(socket) || isHttpAgent(socket)) { | ||
if (isAgent(socket)) { | ||
// `socket` is actually an `http.Agent` instance, so | ||
// relinquish responsibility for this `req` to the Agent | ||
// from here on | ||
debug('Callback returned another Agent instance %o', socket.constructor.name); | ||
socket.addRequest(req, opts); | ||
@@ -171,5 +161,6 @@ return; | ||
if (socket) { | ||
sock = socket; | ||
sock.on('free', onfree); | ||
req.onSocket(sock); | ||
socket.once('free', () => { | ||
this.freeSocket(socket, opts); | ||
}); | ||
req.onSocket(socket); | ||
return; | ||
@@ -179,3 +170,3 @@ } | ||
onerror(err); | ||
} | ||
}; | ||
if (typeof this.callback !== 'function') { | ||
@@ -187,3 +178,3 @@ onerror(new Error('`callback` is not defined')); | ||
if (this.callback.length >= 3) { | ||
// Legacy callback function - convert to a Promise | ||
debug('Converting legacy callback function to promise'); | ||
this.promisifiedCallback = promisify_1.default(this.callback); | ||
@@ -196,3 +187,3 @@ } | ||
if (typeof timeoutMs === 'number' && timeoutMs > 0) { | ||
timeout = setTimeout(ontimeout, timeoutMs); | ||
timeoutId = setTimeout(ontimeout, timeoutMs); | ||
} | ||
@@ -203,2 +194,3 @@ if ('port' in opts && typeof opts.port !== 'number') { | ||
try { | ||
debug('Resolving socket for %o request: %o', opts.protocol, `${req.method} ${req.path}`); | ||
Promise.resolve(this.promisifiedCallback(req, opts)).then(onsocket, callbackError); | ||
@@ -211,12 +203,14 @@ } | ||
freeSocket(socket, opts) { | ||
// TODO reuse sockets | ||
debug('Freeing socket %o %o', socket.constructor.name, opts); | ||
socket.destroy(); | ||
} | ||
destroy() { } | ||
destroy() { | ||
debug('Destroying agent %o', this.constructor.name); | ||
} | ||
} | ||
createAgent.Agent = Agent; | ||
// So that `instanceof` works correctly | ||
createAgent.prototype = createAgent.Agent.prototype; | ||
})(createAgent || (createAgent = {})); | ||
// So that `instanceof` works correctly | ||
createAgent.prototype = createAgent.Agent.prototype; | ||
module.exports = createAgent; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "agent-base", | ||
"version": "5.1.1", | ||
"version": "6.0.0", | ||
"description": "Turn a function into an `http.Agent` instance", | ||
@@ -34,5 +34,9 @@ "main": "dist/src/index", | ||
}, | ||
"dependencies": { | ||
"debug": "4" | ||
}, | ||
"devDependencies": { | ||
"@types/debug": "4", | ||
"@types/mocha": "^5.2.7", | ||
"@types/node": "^10.5.3", | ||
"@types/node": "^12.12.17", | ||
"@types/ws": "^6.0.3", | ||
@@ -39,0 +43,0 @@ "@typescript-eslint/eslint-plugin": "1.6.0", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
24416
3.06%293
1.38%1
Infinity%19
5.56%+ Added
+ Added
+ Added