From f0525108bd35b222cfe1a018db24efa369ceab31 Mon Sep 17 00:00:00 2001 From: M-YasirGhaffar Date: Thu, 5 Feb 2026 05:43:30 +0500 Subject: [PATCH] fix: handle schema-less HTTP_PROXY env vars Signed-off-by: M-YasirGhaffar --- lib/dispatcher/env-http-proxy-agent.js | 12 ++++++++++-- test/env-http-proxy-agent.js | 27 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/lib/dispatcher/env-http-proxy-agent.js b/lib/dispatcher/env-http-proxy-agent.js index 018bc6ce28d..696e719fd2f 100644 --- a/lib/dispatcher/env-http-proxy-agent.js +++ b/lib/dispatcher/env-http-proxy-agent.js @@ -10,6 +10,14 @@ const DEFAULT_PORTS = { 'https:': 443 } +// Prepend http:// to proxy URLs without a scheme (matches Go's httpproxy behavior) +function normalizeProxyUrl (proxyUrl) { + if (proxyUrl && !proxyUrl.startsWith('http://') && !proxyUrl.startsWith('https://')) { + return 'http://' + proxyUrl + } + return proxyUrl +} + class EnvHttpProxyAgent extends DispatcherBase { #noProxyValue = null #noProxyEntries = null @@ -23,14 +31,14 @@ class EnvHttpProxyAgent extends DispatcherBase { this[kNoProxyAgent] = new Agent(agentOpts) - const HTTP_PROXY = httpProxy ?? process.env.http_proxy ?? process.env.HTTP_PROXY + const HTTP_PROXY = normalizeProxyUrl(httpProxy ?? process.env.http_proxy ?? process.env.HTTP_PROXY) if (HTTP_PROXY) { this[kHttpProxyAgent] = new ProxyAgent({ ...agentOpts, uri: HTTP_PROXY }) } else { this[kHttpProxyAgent] = this[kNoProxyAgent] } - const HTTPS_PROXY = httpsProxy ?? process.env.https_proxy ?? process.env.HTTPS_PROXY + const HTTPS_PROXY = normalizeProxyUrl(httpsProxy ?? process.env.https_proxy ?? process.env.HTTPS_PROXY) if (HTTPS_PROXY) { this[kHttpsProxyAgent] = new ProxyAgent({ ...agentOpts, uri: HTTPS_PROXY }) } else { diff --git a/test/env-http-proxy-agent.js b/test/env-http-proxy-agent.js index 1a707fad538..6d695bbd8ec 100644 --- a/test/env-http-proxy-agent.js +++ b/test/env-http-proxy-agent.js @@ -67,6 +67,33 @@ test('handles uppercase HTTP_PROXY and HTTPS_PROXY', async (t) => { return dispatcher.close() }) +test('handles schema-less HTTP_PROXY by assuming http://', async (t) => { + t = tspl(t, { plan: 2 }) + process.env.HTTP_PROXY = 'localhost:8080' + const dispatcher = new EnvHttpProxyAgent() + t.ok(dispatcher[kHttpProxyAgent] instanceof ProxyAgent) + t.equal(dispatcher[kHttpProxyAgent][kProxy].uri, 'http://localhost:8080/') + return dispatcher.close() +}) + +test('handles schema-less HTTPS_PROXY by assuming http://', async (t) => { + t = tspl(t, { plan: 2 }) + process.env.HTTPS_PROXY = 'localhost:8443' + const dispatcher = new EnvHttpProxyAgent() + t.ok(dispatcher[kHttpsProxyAgent] instanceof ProxyAgent) + t.equal(dispatcher[kHttpsProxyAgent][kProxy].uri, 'http://localhost:8443/') + return dispatcher.close() +}) + +test('preserves explicit https:// schema in proxy URL', async (t) => { + t = tspl(t, { plan: 2 }) + process.env.HTTP_PROXY = 'https://secure-proxy.example.com:8080' + const dispatcher = new EnvHttpProxyAgent() + t.ok(dispatcher[kHttpProxyAgent] instanceof ProxyAgent) + t.equal(dispatcher[kHttpProxyAgent][kProxy].uri, 'https://secure-proxy.example.com:8080/') + return dispatcher.close() +}) + test('accepts httpProxy and httpsProxy options', async (t) => { t = tspl(t, { plan: 6 }) const opts = {