"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAgent = void 0;
const url = require("url");
const http = require("http");
const https = require("https");
const LRU = require("lru-cache");
const getHttpsProxyAgent = require("https-proxy-agent");
const getPacProxyAgent = require("pac-proxy-agent");
const socks_proxy_agent_1 = require("socks-proxy-agent");
const getSocksProxyAgent = (opts) => new socks_proxy_agent_1.SocksProxyAgent(opts);
const util_1 = require("../util/util");
const proxy_config_1 = require("./proxy-config");
const KeepAliveAgents = util_1.isNode
    ? {
        'http:': new http.Agent({
            keepAlive: true
        }),
        'https:': new https.Agent({
            keepAlive: true
        })
    } : {};
const ProxyAgentFactoryMap = {
    'http:': getHttpsProxyAgent,
    'https:': getHttpsProxyAgent,
    'pac+http:': getPacProxyAgent,
    'pac+https:': getPacProxyAgent,
    'socks:': getSocksProxyAgent,
    'socks4:': getSocksProxyAgent,
    'socks4a:': getSocksProxyAgent,
    'socks5:': getSocksProxyAgent,
    'socks5h:': getSocksProxyAgent
};
const proxyAgentCache = new LRU({
    max: 20,
    ttl: 1000 * 60 * 5,
    ttlResolution: 1000 * 60,
    ttlAutopurge: true,
    updateAgeOnGet: true // Don't drop agents while they're in use
});
const getCacheKey = (options) => JSON.stringify(options);
async function getAgent({ protocol, hostname, port, tryHttp2, keepAlive, proxySettingSource }) {
    const proxySetting = await (0, proxy_config_1.getProxySetting)(proxySettingSource, { hostname });
    if (proxySetting?.proxyUrl) {
        // If there's a (non-empty) proxy configured, use it. We require non-empty because empty strings
        // will fall back to detecting from the environment, which is likely to behave unexpectedly.
        if (!(0, proxy_config_1.matchesNoProxy)(hostname, port, proxySetting.noProxy)) {
            // We notably ignore HTTP/2 upstream in this case: it's complicated to mix that up with proxying
            // so for now we ignore it entirely.
            const cacheKey = getCacheKey({
                url: proxySetting.proxyUrl,
                ca: proxySetting.trustedCAs
            });
            if (!proxyAgentCache.has(cacheKey)) {
                const { protocol, auth, hostname, port } = url.parse(proxySetting.proxyUrl);
                const buildProxyAgent = ProxyAgentFactoryMap[protocol];
                proxyAgentCache.set(cacheKey, buildProxyAgent({
                    protocol,
                    auth,
                    hostname,
                    port,
                    // If you specify trusted CAs, we override the CAs used for this connection, i.e. the trusted
                    // CA for the certificate of an HTTPS proxy. This is *not* the CAs trusted for upstream servers
                    // on the otherside of the proxy - see the `trustAdditionalCAs` passthrough option for that.
                    ...(proxySetting.trustedCAs
                        ? { ca: proxySetting.trustedCAs }
                        : {})
                }));
            }
            return proxyAgentCache.get(cacheKey);
        }
    }
    if (tryHttp2 && (protocol === 'https:' || protocol === 'wss:')) {
        // H2 wrapper takes multiple agents, uses the appropriate one for the detected protocol.
        // We notably never use H2 upstream for plaintext, it's rare and we can't use ALPN to detect it.
        return { https: KeepAliveAgents['https:'], http2: undefined };
    }
    else if (keepAlive && protocol !== 'wss:' && protocol !== 'ws:') {
        // HTTP/1.1 or HTTP/1 with explicit keep-alive
        return KeepAliveAgents[protocol || 'http:'];
    }
    else {
        // HTTP/1 without KA - just send the request with no agent
        return undefined;
    }
}
exports.getAgent = getAgent;
//# sourceMappingURL=http-agents.js.map