Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support global registration like global-agent #314

Open
segevfiner opened this issue May 19, 2024 · 1 comment
Open

Support global registration like global-agent #314

segevfiner opened this issue May 19, 2024 · 1 comment

Comments

@segevfiner
Copy link

The package global-agent supports registering a proxy agent globally, by registering under the globalAgent property and an additional hack for packages that don't use it. It would be nice to have this functionality available in this package as it has a more robust proxy agent.

@segevfiner
Copy link
Author

So it goes something like this based on the code in global-agent:

import http from 'http';
import https from 'https';
import semver from 'semver';

export default function bindHttpMethod(
  originalMethod: (...args: unknown[]) => unknown,
  agent: AgentType,
  forceGlobalAgent: boolean
) {
  return (...args: unknown[]) => {
    let url;
    let options: Record<string, unknown>;
    let callback;

    if (typeof args[0] === 'string' || args[0] instanceof URL) {
      url = args[0];

      if (typeof args[1] === 'function') {
        options = {};
        callback = args[1];
      } else {
        options = {
          ...(args[1] as object),
        };
        callback = args[2];
      }
    } else {
      options = {
        ...(args[0] as object),
      };
      callback = args[1];
    }

    if (forceGlobalAgent) {
      options.agent = agent;
    } else {
      if (!options.agent) {
        options.agent = agent;
      }

      if (options.agent === http.globalAgent || options.agent === https.globalAgent) {
        options.agent = agent;
      }
    }

    if (url) {
      return originalMethod(url, options, callback);
    } else {
      return originalMethod(options, callback);
    }
  };
}

const httpGet = http.get;
const httpRequest = http.request;
const httpsGet = https.get;
const httpsRequest = https.request;

export function enableGlobalProxyAgent(proxyAgent: ProxyAgent, configuration?: { forceGlobalAgent?: boolean }): void {
  // 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
    // @ts-ignore Node.js version compatibility
    http.globalAgent = proxyAgent;

    // @ts-ignore Node.js version compatibility
    https.globalAgent = proxyAgent;
  }

  // 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')) {
    // @ts-expect-error seems like we are using wrong type for httpAgent
    http.get = bindHttpMethod(httpGet, proxyAgent, configuration?.forceGlobalAgent ?? true);

    // @ts-expect-error seems like we are using wrong type for httpAgent
    http.request = bindHttpMethod(httpRequest, proxyAgent, configuration?.forceGlobalAgent ?? true);

    // @ts-expect-error seems like we are using wrong type for httpAgent
    https.get = bindHttpMethod(httpsGet, proxyAgent, configuration?.forceGlobalAgent ?? true);

    // @ts-expect-error seems like we are using wrong type for httpAgent
    https.request = bindHttpMethod(httpsRequest, proxyAgent, configuration?.forceGlobalAgent ?? true);
  } else {
    // eslint-disable-next-line no-console
    console.warn('attempt to initialize global proxy-agent in unsupported Node.js version was ignored');
  }
}

@TooTallNate What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant