xcraft-global-agent
Version:
Global HTTP/HTTPS proxy configurable using environment variables.
129 lines (128 loc) • 6.55 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const http_1 = __importDefault(require("http"));
const https_1 = __importDefault(require("https"));
const omit_undefined_1 = require("omit-undefined");
const semver_1 = __importDefault(require("semver"));
const Logger_1 = __importDefault(require("../Logger"));
const classes_1 = require("../classes");
const errors_1 = require("../errors");
const utilities_1 = require("../utilities");
const createProxyController_1 = __importDefault(require("./createProxyController"));
const httpGet = http_1.default.get;
const httpRequest = http_1.default.request;
const httpsGet = https_1.default.get;
const httpsRequest = https_1.default.request;
const log = Logger_1.default.child({
namespace: 'createGlobalProxyAgent',
});
const defaultConfigurationInput = {
environmentVariableNamespace: undefined,
forceGlobalAgent: undefined,
socketConnectionTimeout: 60000,
};
const createConfiguration = (configurationInput) => {
// eslint-disable-next-line node/no-process-env
const environment = process.env;
const defaultConfiguration = {
environmentVariableNamespace: typeof environment.GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE === 'string' ? environment.GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE : 'GLOBAL_AGENT_',
forceGlobalAgent: typeof environment.GLOBAL_AGENT_FORCE_GLOBAL_AGENT === 'string' ? (0, utilities_1.parseBoolean)(environment.GLOBAL_AGENT_FORCE_GLOBAL_AGENT) : true,
socketConnectionTimeout: typeof environment.GLOBAL_AGENT_SOCKET_CONNECTION_TIMEOUT === 'string' ? Number.parseInt(environment.GLOBAL_AGENT_SOCKET_CONNECTION_TIMEOUT, 10) : defaultConfigurationInput.socketConnectionTimeout,
};
return {
...defaultConfiguration,
...(0, omit_undefined_1.omitUndefined)(configurationInput),
};
};
exports.default = (configurationInput = defaultConfigurationInput) => {
var _a, _b, _c;
const configuration = createConfiguration(configurationInput);
const proxyController = (0, createProxyController_1.default)();
// eslint-disable-next-line node/no-process-env
proxyController.HTTP_PROXY = (_a = process.env[configuration.environmentVariableNamespace + 'HTTP_PROXY']) !== null && _a !== void 0 ? _a : null;
// eslint-disable-next-line node/no-process-env
proxyController.HTTPS_PROXY = (_b = process.env[configuration.environmentVariableNamespace + 'HTTPS_PROXY']) !== null && _b !== void 0 ? _b : null;
// eslint-disable-next-line node/no-process-env
proxyController.NO_PROXY = (_c = process.env[configuration.environmentVariableNamespace + 'NO_PROXY']) !== null && _c !== void 0 ? _c : null;
log.info({
configuration,
state: proxyController,
}, 'global agent has been initialized');
const mustUrlUseProxy = (getProxy) => {
return (url) => {
if (!getProxy()) {
return false;
}
if (!proxyController.NO_PROXY) {
return true;
}
return !(0, utilities_1.isUrlMatchingNoProxy)(url, proxyController.NO_PROXY);
};
};
const getUrlProxy = (getProxy) => {
return () => {
const proxy = getProxy();
if (!proxy) {
throw new errors_1.UnexpectedStateError('HTTP(S) proxy must be configured.');
}
return (0, utilities_1.parseProxyUrl)(proxy);
};
};
const getHttpProxy = () => {
return proxyController.HTTP_PROXY;
};
const BoundHttpProxyAgent = class extends classes_1.HttpProxyAgent {
constructor() {
super(() => {
return Boolean(getHttpProxy());
}, mustUrlUseProxy(getHttpProxy), getUrlProxy(getHttpProxy), http_1.default.globalAgent, configuration.socketConnectionTimeout);
}
};
const httpAgent = new BoundHttpProxyAgent();
const getHttpsProxy = () => {
var _a;
return (_a = proxyController.HTTPS_PROXY) !== null && _a !== void 0 ? _a : proxyController.HTTP_PROXY;
};
const BoundHttpsProxyAgent = class extends classes_1.HttpsProxyAgent {
constructor() {
super(() => {
return Boolean(getHttpsProxy());
}, mustUrlUseProxy(getHttpsProxy), getUrlProxy(getHttpsProxy), https_1.default.globalAgent, configuration.socketConnectionTimeout);
}
};
const httpsAgent = new BoundHttpsProxyAgent();
// Overriding globalAgent was added in v11.7.
// @see https://nodejs.org/uk/blog/release/v11.7.0/
if (semver_1.default.gte(process.version, 'v11.7.0')) {
// @see https://github.com/facebook/flow/issues/7670
// @ts-expect-error Node.js version compatibility
http_1.default.globalAgent = httpAgent;
// @ts-expect-error Node.js version compatibility
https_1.default.globalAgent = httpsAgent;
}
// The reason this logic is used in addition to overriding http(s).globalAgent
// is because there is no guarantee that we set http(s).globalAgent variable
// before an instance of http(s).Agent has been already constructed by someone,
// e.g. Stripe SDK creates instances of http(s).Agent at the top-level.
// @see https://github.com/gajus/global-agent/pull/13
//
// We still want to override http(s).globalAgent when possible to enable logic
// in `bindHttpMethod`.
if (semver_1.default.gte(process.version, 'v10.0.0')) {
// @ts-expect-error seems like we are using wrong type for httpAgent
http_1.default.get = (0, utilities_1.bindHttpMethod)(httpGet, httpAgent, configuration.forceGlobalAgent);
// @ts-expect-error seems like we are using wrong type for httpAgent
http_1.default.request = (0, utilities_1.bindHttpMethod)(httpRequest, httpAgent, configuration.forceGlobalAgent);
// @ts-expect-error seems like we are using wrong type for httpAgent
https_1.default.get = (0, utilities_1.bindHttpMethod)(httpsGet, httpsAgent, configuration.forceGlobalAgent);
// @ts-expect-error seems like we are using wrong type for httpAgent
https_1.default.request = (0, utilities_1.bindHttpMethod)(httpsRequest, httpsAgent, configuration.forceGlobalAgent);
}
else {
log.warn('attempt to initialize global-agent in unsupported Node.js version was ignored');
}
return proxyController;
};
;