You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					203 lines
				
				7.7 KiB
			
		
		
			
		
	
	
					203 lines
				
				7.7 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								"use strict";
							 | 
						||
| 
								 | 
							
								var __importDefault = (this && this.__importDefault) || function (mod) {
							 | 
						||
| 
								 | 
							
								    return (mod && mod.__esModule) ? mod : { "default": mod };
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								const events_1 = require("events");
							 | 
						||
| 
								 | 
							
								const debug_1 = __importDefault(require("debug"));
							 | 
						||
| 
								 | 
							
								const promisify_1 = __importDefault(require("./promisify"));
							 | 
						||
| 
								 | 
							
								const debug = debug_1.default('agent-base');
							 | 
						||
| 
								 | 
							
								function isAgent(v) {
							 | 
						||
| 
								 | 
							
								    return Boolean(v) && typeof v.addRequest === 'function';
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function isSecureEndpoint() {
							 | 
						||
| 
								 | 
							
								    const { stack } = new Error();
							 | 
						||
| 
								 | 
							
								    if (typeof stack !== 'string')
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    return stack.split('\n').some(l => l.indexOf('(https.js:') !== -1 || l.indexOf('node:https:') !== -1);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function createAgent(callback, opts) {
							 | 
						||
| 
								 | 
							
								    return new createAgent.Agent(callback, opts);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								(function (createAgent) {
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Base `http.Agent` implementation.
							 | 
						||
| 
								 | 
							
								     * No pooling/keep-alive is implemented by default.
							 | 
						||
| 
								 | 
							
								     *
							 | 
						||
| 
								 | 
							
								     * @param {Function} callback
							 | 
						||
| 
								 | 
							
								     * @api public
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    class Agent extends events_1.EventEmitter {
							 | 
						||
| 
								 | 
							
								        constructor(callback, _opts) {
							 | 
						||
| 
								 | 
							
								            super();
							 | 
						||
| 
								 | 
							
								            let opts = _opts;
							 | 
						||
| 
								 | 
							
								            if (typeof callback === 'function') {
							 | 
						||
| 
								 | 
							
								                this.callback = callback;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if (callback) {
							 | 
						||
| 
								 | 
							
								                opts = callback;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            // Timeout for the socket to be returned from the callback
							 | 
						||
| 
								 | 
							
								            this.timeout = null;
							 | 
						||
| 
								 | 
							
								            if (opts && typeof opts.timeout === 'number') {
							 | 
						||
| 
								 | 
							
								                this.timeout = opts.timeout;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            // 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.maxTotalSockets = Infinity;
							 | 
						||
| 
								 | 
							
								            this.sockets = {};
							 | 
						||
| 
								 | 
							
								            this.freeSockets = {};
							 | 
						||
| 
								 | 
							
								            this.requests = {};
							 | 
						||
| 
								 | 
							
								            this.options = {};
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        get defaultPort() {
							 | 
						||
| 
								 | 
							
								            if (typeof this.explicitDefaultPort === 'number') {
							 | 
						||
| 
								 | 
							
								                return this.explicitDefaultPort;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return isSecureEndpoint() ? 443 : 80;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        set defaultPort(v) {
							 | 
						||
| 
								 | 
							
								            this.explicitDefaultPort = v;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        get protocol() {
							 | 
						||
| 
								 | 
							
								            if (typeof this.explicitProtocol === 'string') {
							 | 
						||
| 
								 | 
							
								                return this.explicitProtocol;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return isSecureEndpoint() ? 'https:' : 'http:';
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        set protocol(v) {
							 | 
						||
| 
								 | 
							
								            this.explicitProtocol = v;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        callback(req, opts, fn) {
							 | 
						||
| 
								 | 
							
								            throw new Error('"agent-base" has no default implementation, you must subclass and override `callback()`');
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Called by node-core's "_http_client.js" module when creating
							 | 
						||
| 
								 | 
							
								         * a new HTTP request with this Agent instance.
							 | 
						||
| 
								 | 
							
								         *
							 | 
						||
| 
								 | 
							
								         * @api public
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        addRequest(req, _opts) {
							 | 
						||
| 
								 | 
							
								            const opts = Object.assign({}, _opts);
							 | 
						||
| 
								 | 
							
								            if (typeof opts.secureEndpoint !== 'boolean') {
							 | 
						||
| 
								 | 
							
								                opts.secureEndpoint = isSecureEndpoint();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (opts.host == null) {
							 | 
						||
| 
								 | 
							
								                opts.host = 'localhost';
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (opts.port == null) {
							 | 
						||
| 
								 | 
							
								                opts.port = opts.secureEndpoint ? 443 : 80;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            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.
							 | 
						||
| 
								 | 
							
								                delete opts.path;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            delete opts.agent;
							 | 
						||
| 
								 | 
							
								            delete opts.hostname;
							 | 
						||
| 
								 | 
							
								            delete opts._defaultAgent;
							 | 
						||
| 
								 | 
							
								            delete opts.defaultPort;
							 | 
						||
| 
								 | 
							
								            delete opts.createConnection;
							 | 
						||
| 
								 | 
							
								            // Hint to use "Connection: close"
							 | 
						||
| 
								 | 
							
								            // XXX: non-documented `http` module API :(
							 | 
						||
| 
								 | 
							
								            req._last = true;
							 | 
						||
| 
								 | 
							
								            req.shouldKeepAlive = false;
							 | 
						||
| 
								 | 
							
								            let timedOut = false;
							 | 
						||
| 
								 | 
							
								            let timeoutId = null;
							 | 
						||
| 
								 | 
							
								            const timeoutMs = opts.timeout || this.timeout;
							 | 
						||
| 
								 | 
							
								            const onerror = (err) => {
							 | 
						||
| 
								 | 
							
								                if (req._hadError)
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                req.emit('error', err);
							 | 
						||
| 
								 | 
							
								                // For Safety. Some additional errors might fire later on
							 | 
						||
| 
								 | 
							
								                // and we need to make sure we don't double-fire the error event.
							 | 
						||
| 
								 | 
							
								                req._hadError = true;
							 | 
						||
| 
								 | 
							
								            };
							 | 
						||
| 
								 | 
							
								            const ontimeout = () => {
							 | 
						||
| 
								 | 
							
								                timeoutId = null;
							 | 
						||
| 
								 | 
							
								                timedOut = true;
							 | 
						||
| 
								 | 
							
								                const err = new Error(`A "socket" was not created for HTTP request before ${timeoutMs}ms`);
							 | 
						||
| 
								 | 
							
								                err.code = 'ETIMEOUT';
							 | 
						||
| 
								 | 
							
								                onerror(err);
							 | 
						||
| 
								 | 
							
								            };
							 | 
						||
| 
								 | 
							
								            const callbackError = (err) => {
							 | 
						||
| 
								 | 
							
								                if (timedOut)
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                if (timeoutId !== null) {
							 | 
						||
| 
								 | 
							
								                    clearTimeout(timeoutId);
							 | 
						||
| 
								 | 
							
								                    timeoutId = null;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                onerror(err);
							 | 
						||
| 
								 | 
							
								            };
							 | 
						||
| 
								 | 
							
								            const onsocket = (socket) => {
							 | 
						||
| 
								 | 
							
								                if (timedOut)
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                if (timeoutId != null) {
							 | 
						||
| 
								 | 
							
								                    clearTimeout(timeoutId);
							 | 
						||
| 
								 | 
							
								                    timeoutId = null;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                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);
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                if (socket) {
							 | 
						||
| 
								 | 
							
								                    socket.once('free', () => {
							 | 
						||
| 
								 | 
							
								                        this.freeSocket(socket, opts);
							 | 
						||
| 
								 | 
							
								                    });
							 | 
						||
| 
								 | 
							
								                    req.onSocket(socket);
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                const err = new Error(`no Duplex stream was returned to agent-base for \`${req.method} ${req.path}\``);
							 | 
						||
| 
								 | 
							
								                onerror(err);
							 | 
						||
| 
								 | 
							
								            };
							 | 
						||
| 
								 | 
							
								            if (typeof this.callback !== 'function') {
							 | 
						||
| 
								 | 
							
								                onerror(new Error('`callback` is not defined'));
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (!this.promisifiedCallback) {
							 | 
						||
| 
								 | 
							
								                if (this.callback.length >= 3) {
							 | 
						||
| 
								 | 
							
								                    debug('Converting legacy callback function to promise');
							 | 
						||
| 
								 | 
							
								                    this.promisifiedCallback = promisify_1.default(this.callback);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else {
							 | 
						||
| 
								 | 
							
								                    this.promisifiedCallback = this.callback;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (typeof timeoutMs === 'number' && timeoutMs > 0) {
							 | 
						||
| 
								 | 
							
								                timeoutId = setTimeout(ontimeout, timeoutMs);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if ('port' in opts && typeof opts.port !== 'number') {
							 | 
						||
| 
								 | 
							
								                opts.port = Number(opts.port);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            try {
							 | 
						||
| 
								 | 
							
								                debug('Resolving socket for %o request: %o', opts.protocol, `${req.method} ${req.path}`);
							 | 
						||
| 
								 | 
							
								                Promise.resolve(this.promisifiedCallback(req, opts)).then(onsocket, callbackError);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            catch (err) {
							 | 
						||
| 
								 | 
							
								                Promise.reject(err).catch(callbackError);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        freeSocket(socket, opts) {
							 | 
						||
| 
								 | 
							
								            debug('Freeing socket %o %o', socket.constructor.name, opts);
							 | 
						||
| 
								 | 
							
								            socket.destroy();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        destroy() {
							 | 
						||
| 
								 | 
							
								            debug('Destroying agent %o', this.constructor.name);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    createAgent.Agent = Agent;
							 | 
						||
| 
								 | 
							
								    // So that `instanceof` works correctly
							 | 
						||
| 
								 | 
							
								    createAgent.prototype = createAgent.Agent.prototype;
							 | 
						||
| 
								 | 
							
								})(createAgent || (createAgent = {}));
							 | 
						||
| 
								 | 
							
								module.exports = createAgent;
							 | 
						||
| 
								 | 
							
								//# sourceMappingURL=index.js.map
							 |