Skip to content

fix(apiv2): honor NO_PROXY when an HTTPS_PROXY is configured - #11328

Open
wahajahmed010 wants to merge 1 commit into
firebase:mainfrom
wahajahmed010:fix/11249-no-proxy-support
Open

wahajahmed010 wants to merge 1 commit into
firebase:mainfrom
wahajahmed010:fix/11249-no-proxy-support

Conversation

@wahajahmed010

@wahajahmed010 wahajahmed010 commented Oct 21, 2026 •

Copy link
Copy Markdown

Description

When HTTPS_PROXY (or HTTP_PROXY) is set, every request the CLI makes goes through new undici.ProxyAgent({ uri: proxyURI }). That agent does not honor NO_PROXY/no_proxy, so requests between emulators on 127.0.0.1 are also proxied. Behind a corporate or sandbox proxy, the Functions emulator then fails to register its Firestore trigger and emulators:start/emulators:exec errors out with ECONNREFUSED.

This PR swaps undici.ProxyAgent for undici.EnvHttpProxyAgent, which is built on top of ProxyAgent and applies the same NO_PROXY/no_proxy rules as Node.js and other CLIs. The proxy URI is passed as both httpProxy and httpsProxy; noProxy is read from the same environment variables that other Node tools consult.

Fixes #11249

Scenarios Tested

  • With HTTPS_PROXY=http://127.0.0.1:52672 and NO_PROXY=127.0.0.1, a request to http://127.0.0.1:52673 succeeds and reaches the target server.
  • Without NO_PROXY, requests are still proxied (existing behavior preserved).
  • All existing tests in src/apiv2.spec.ts continue to pass (41/41 passing). One new test was added that asserts the NO_PROXY bypass branch.
  • tsc --project tsconfig.compile.json is clean (0 errors).

Sample Commands

# Triggers the bug before the patch
export HTTPS_PROXY=http://127.0.0.1:9
export NO_PROXY=localhost,127.0.0.1
firebase emulators:exec --project demo-repro --only firestore,functions "echo hi"
# Before: ECONNREFUSED 127.0.0.1:9
# After:  Functions emulator registers the trigger and the script runs.

Replace undici.ProxyAgent with undici.EnvHttpProxyAgent when a proxy
URI is detected, and read NO_PROXY/no_proxy from the environment.
Previously every request was sent through the proxy, including
localhost calls between emulators; in this case the proxy URI may
not resolve to a host that can reach 127.0.0.1, and the request would
fail with ECONNREFUSED (or worse, hit an unrelated external server).

Closes firebase#11249
@google-cla

google-cla Bot commented Oct 21, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces ProxyAgent with EnvHttpProxyAgent from undici in src/apiv2.ts to ensure that NO_PROXY/no_proxy environment variables are properly honored, and adds a corresponding unit test in src/apiv2.spec.ts. The reviewer suggests extracting a shared helper getEnvVar to handle environment variable retrieval and filter out literal 'undefined' or 'null' strings, which prevents potential issues when checking fallback variables. Additionally, the reviewer recommends using this helper to separately configure httpProxy and httpsProxy rather than forcing both to use the same proxy URI.

Comment thread src/apiv2.ts
Comment on lines +165 to +168
function noProxyFromEnv(): string {
const env = process.env.NO_PROXY || process.env.no_proxy || "";
return env === "undefined" || env === "null" ? "" : env;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If process.env.NO_PROXY is set to the literal string "undefined", the expression process.env.NO_PROXY || process.env.no_proxy will evaluate to "undefined", which prevents a potentially valid process.env.no_proxy from being used.\n\nAdditionally, to adhere to the repository style guide's rule on Survey prior art & harmonize utilities (lines 28-30), we should extract a shared helper to retrieve environment variables while filtering out "undefined" and "null" strings. This helper can then be reused by both proxyURIFromEnv and noProxyFromEnv.

function getEnvVar(keys: string[]): string | undefined {\n  for (const key of keys) {\n    const val = process.env[key];\n    if (val && val !== \"undefined\" && val !== \"null\") {\n      return val;\n    }\n  }\n  return undefined;\n}\n\nfunction noProxyFromEnv(): string {\n  return getEnvVar([\"NO_PROXY\", \"no_proxy\"]) || \"\";\n}
References
  1. Survey prior art & harmonize utilities: Extract and unify shared helpers when logic is duplicated or warrants a new common utility. (link)

Comment thread src/apiv2.ts
Comment on lines +437 to +441
fetchOptions.dispatcher = new EnvHttpProxyAgent({
httpProxy: proxyURI,
httpsProxy: proxyURI,
noProxy: noProxyFromEnv(),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Currently, both httpProxy and httpsProxy are set to the same proxyURI (which prefers HTTPS_PROXY over HTTP_PROXY). In environments where separate proxies are configured for HTTP and HTTPS, this forces HTTP requests to go through the HTTPS proxy.\n\nSince we are using EnvHttpProxyAgent, we can leverage the getEnvVar helper to pass the correct proxy for each protocol individually.

      fetchOptions.dispatcher = new EnvHttpProxyAgent({\n        httpProxy: getEnvVar([\"HTTP_PROXY\", \"http_proxy\"]),\n        httpsProxy: getEnvVar([\"HTTPS_PROXY\", \"https_proxy\"]),\n        noProxy: noProxyFromEnv(),\n      });

This branch has not been deployed

No deployments
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

Successfully merging this pull request may close these issues.

CLI HTTP client ignores NO_PROXY, so emulators can’t reach each other behind a proxy

1 participant