diff options
Diffstat (limited to 'node_modules/global-agent/src/factories')
3 files changed, 247 insertions, 0 deletions
| diff --git a/node_modules/global-agent/src/factories/createGlobalProxyAgent.js b/node_modules/global-agent/src/factories/createGlobalProxyAgent.js new file mode 100644 index 0000000..d515a9d --- /dev/null +++ b/node_modules/global-agent/src/factories/createGlobalProxyAgent.js @@ -0,0 +1,197 @@ +// @flow + +import http from 'http'; +import https from 'https'; +import { +  boolean as parseBoolean, +} from 'boolean'; +import semver from 'semver'; +import Logger from '../Logger'; +import { +  HttpProxyAgent, +  HttpsProxyAgent, +} from '../classes'; +import { +  UnexpectedStateError, +} from '../errors'; +import { +  bindHttpMethod, +  isUrlMatchingNoProxy, +  parseProxyUrl, +} from '../utilities'; +import type { +  ProxyAgentConfigurationInputType, +  ProxyAgentConfigurationType, +} from '../types'; +import createProxyController from './createProxyController'; + +const httpGet = http.get; +const httpRequest = http.request; +const httpsGet = https.get; +const httpsRequest = https.request; + +const log = Logger.child({ +  namespace: 'createGlobalProxyAgent', +}); + +const defaultConfigurationInput = { +  environmentVariableNamespace: undefined, +  forceGlobalAgent: undefined, +  socketConnectionTimeout: 60000, +}; + +const omitUndefined = (subject) => { +  const keys = Object.keys(subject); + +  const result = {}; + +  for (const key of keys) { +    const value = subject[key]; + +    if (value !== undefined) { +      result[key] = value; +    } +  } + +  return result; +}; + +const createConfiguration = (configurationInput: ProxyAgentConfigurationInputType): ProxyAgentConfigurationType => { +  // eslint-disable-next-line 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' ? 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, +  }; + +  // $FlowFixMe +  return { +    ...defaultConfiguration, +    ...omitUndefined(configurationInput), +  }; +}; + +export default (configurationInput: ProxyAgentConfigurationInputType = defaultConfigurationInput) => { +  const configuration = createConfiguration(configurationInput); + +  const proxyController = createProxyController(); + +  // eslint-disable-next-line no-process-env +  proxyController.HTTP_PROXY = process.env[configuration.environmentVariableNamespace + 'HTTP_PROXY'] || null; + +  // eslint-disable-next-line no-process-env +  proxyController.HTTPS_PROXY = process.env[configuration.environmentVariableNamespace + 'HTTPS_PROXY'] || null; + +  // eslint-disable-next-line no-process-env +  proxyController.NO_PROXY = process.env[configuration.environmentVariableNamespace + 'NO_PROXY'] || 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 !isUrlMatchingNoProxy(url, proxyController.NO_PROXY); +    }; +  }; + +  const getUrlProxy = (getProxy) => { +    return () => { +      const proxy = getProxy(); + +      if (!proxy) { +        throw new UnexpectedStateError('HTTP(S) proxy must be configured.'); +      } + +      return parseProxyUrl(proxy); +    }; +  }; + +  const getHttpProxy = () => { +    return proxyController.HTTP_PROXY; +  }; + +  const BoundHttpProxyAgent = class extends HttpProxyAgent { +    constructor () { +      super( +        () => { +          return getHttpProxy(); +        }, +        mustUrlUseProxy(getHttpProxy), +        getUrlProxy(getHttpProxy), +        http.globalAgent, +        configuration.socketConnectionTimeout, +      ); +    } +  }; + +  const httpAgent = new BoundHttpProxyAgent(); + +  const getHttpsProxy = () => { +    return proxyController.HTTPS_PROXY || proxyController.HTTP_PROXY; +  }; + +  const BoundHttpsProxyAgent = class extends HttpsProxyAgent { +    constructor () { +      super( +        () => { +          return getHttpsProxy(); +        }, +        mustUrlUseProxy(getHttpsProxy), +        getUrlProxy(getHttpsProxy), +        https.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.gte(process.version, 'v11.7.0')) { +    // @see https://github.com/facebook/flow/issues/7670 +    // $FlowFixMe +    http.globalAgent = httpAgent; + +    // $FlowFixMe +    https.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.gte(process.version, 'v10.0.0')) { +    // $FlowFixMe +    http.get = bindHttpMethod(httpGet, httpAgent, configuration.forceGlobalAgent); + +    // $FlowFixMe +    http.request = bindHttpMethod(httpRequest, httpAgent, configuration.forceGlobalAgent); + +    // $FlowFixMe +    https.get = bindHttpMethod(httpsGet, httpsAgent, configuration.forceGlobalAgent); + +    // $FlowFixMe +    https.request = bindHttpMethod(httpsRequest, httpsAgent, configuration.forceGlobalAgent); +  } else { +    log.warn('attempt to initialize global-agent in unsupported Node.js version was ignored'); +  } + +  return proxyController; +}; diff --git a/node_modules/global-agent/src/factories/createProxyController.js b/node_modules/global-agent/src/factories/createProxyController.js new file mode 100644 index 0000000..5805ec8 --- /dev/null +++ b/node_modules/global-agent/src/factories/createProxyController.js @@ -0,0 +1,46 @@ +// @flow + +import Logger from '../Logger'; + +type ProxyControllerType = {| +  HTTP_PROXY: string | null, +  HTTPS_PROXY: string | null, +  NO_PROXY: string | null, +|}; + +const log = Logger.child({ +  namespace: 'createProxyController', +}); + +const KNOWN_PROPERTY_NAMES = [ +  'HTTP_PROXY', +  'HTTPS_PROXY', +  'NO_PROXY', +]; + +export default (): ProxyControllerType => { +  // eslint-disable-next-line fp/no-proxy +  return new Proxy({ +    HTTP_PROXY: null, +    HTTPS_PROXY: null, +    NO_PROXY: null, +  }, { +    set: (subject, name, value) => { +      if (!KNOWN_PROPERTY_NAMES.includes(name)) { +        throw new Error('Cannot set an unmapped property "' + name + '".'); +      } + +      subject[name] = value; + +      log.info({ +        change: { +          name, +          value, +        }, +        newConfiguration: subject, +      }, 'configuration changed'); + +      return true; +    }, +  }); +}; diff --git a/node_modules/global-agent/src/factories/index.js b/node_modules/global-agent/src/factories/index.js new file mode 100644 index 0000000..c16eca6 --- /dev/null +++ b/node_modules/global-agent/src/factories/index.js @@ -0,0 +1,4 @@ +// @flow + +export {default as createGlobalProxyAgent} from './createGlobalProxyAgent'; +export {default as createProxyController} from './createProxyController'; | 
