diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fdc66b1e9cb..312cd6e2610 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -270,10 +270,11 @@ jobs: fail-fast: false max-parallel: 0 matrix: - # Node.js 22 is intentionally excluded here: --shared-builtin-undici/undici-path - # embedding is only validated for supported/current majors. - # Start validating shared builtin embedding from Node.js 26 onward. - node-version: ['26'] + # Node.js 20 and 22 are intentionally excluded here because + # --shared-builtin-undici/undici-path still hits upstream Node.js issues there. + # Keep validating supported/current majors, and start exercising 26 + # automatically once a release is available. + node-version: ['24', '25', '26'] runs-on: ['ubuntu-latest'] with: node-version: ${{ matrix.node-version }} diff --git a/lib/dispatcher/env-http-proxy-agent.js b/lib/dispatcher/env-http-proxy-agent.js index df2e9fec9f4..f88437f1936 100644 --- a/lib/dispatcher/env-http-proxy-agent.js +++ b/lib/dispatcher/env-http-proxy-agent.js @@ -10,22 +10,6 @@ const DEFAULT_PORTS = { 'https:': 443 } -/** - * Normalizes a proxy URL by prepending a scheme if one is missing. - * This matches the behavior of curl and Go's httpproxy package, which - * assume http:// for scheme-less proxy values. - * - * @param {string} proxyUrl - The proxy URL to normalize - * @param {string} defaultScheme - The scheme to prepend if missing ('http' or 'https') - * @returns {string} The normalized proxy URL - */ -function normalizeProxyUrl (proxyUrl, defaultScheme) { - if (!proxyUrl) return proxyUrl - // If the value already contains a scheme (e.g. http://, https://, socks5://), return as-is - if (/^[a-z][a-z0-9+\-.]*:\/\//i.test(proxyUrl)) return proxyUrl - return `${defaultScheme}://${proxyUrl}` -} - class EnvHttpProxyAgent extends DispatcherBase { #noProxyValue = null #noProxyEntries = null @@ -39,20 +23,14 @@ class EnvHttpProxyAgent extends DispatcherBase { this[kNoProxyAgent] = new Agent(agentOpts) - const HTTP_PROXY = normalizeProxyUrl( - httpProxy ?? process.env.http_proxy ?? process.env.HTTP_PROXY, - 'http' - ) + const HTTP_PROXY = 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 = normalizeProxyUrl( - httpsProxy ?? process.env.https_proxy ?? process.env.HTTPS_PROXY, - 'https' - ) + const HTTPS_PROXY = 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 bf061704906..97969cfaf20 100644 --- a/test/env-http-proxy-agent.js +++ b/test/env-http-proxy-agent.js @@ -124,61 +124,6 @@ test('prefers lowercase over uppercase env vars even when empty', async (t) => { return dispatcher.close() }) -test('handles scheme-less HTTP_PROXY by assuming http://', async (t) => { - t = tspl(t, { plan: 2 }) - process.env.HTTP_PROXY = 'example.com:8080' - const dispatcher = new EnvHttpProxyAgent() - t.ok(dispatcher[kHttpProxyAgent] instanceof ProxyAgent) - t.equal(dispatcher[kHttpProxyAgent][kProxy].uri, 'http://example.com:8080/') - return dispatcher.close() -}) - -test('handles scheme-less HTTPS_PROXY by assuming https://', async (t) => { - t = tspl(t, { plan: 2 }) - process.env.HTTPS_PROXY = 'example.com:8443' - const dispatcher = new EnvHttpProxyAgent() - t.ok(dispatcher[kHttpsProxyAgent] instanceof ProxyAgent) - t.equal(dispatcher[kHttpsProxyAgent][kProxy].uri, 'https://example.com:8443/') - return dispatcher.close() -}) - -test('handles scheme-less httpProxy option by assuming http://', async (t) => { - t = tspl(t, { plan: 2 }) - const dispatcher = new EnvHttpProxyAgent({ httpProxy: 'myproxy:9000' }) - t.ok(dispatcher[kHttpProxyAgent] instanceof ProxyAgent) - t.equal(dispatcher[kHttpProxyAgent][kProxy].uri, 'http://myproxy:9000/') - return dispatcher.close() -}) - -test('handles scheme-less httpsProxy option by assuming https://', async (t) => { - t = tspl(t, { plan: 2 }) - const dispatcher = new EnvHttpProxyAgent({ httpsProxy: 'myproxy:9443' }) - t.ok(dispatcher[kHttpsProxyAgent] instanceof ProxyAgent) - t.equal(dispatcher[kHttpsProxyAgent][kProxy].uri, 'https://myproxy:9443/') - return dispatcher.close() -}) - -test('does not modify proxy URLs that already have a scheme', async (t) => { - t = tspl(t, { plan: 4 }) - process.env.HTTP_PROXY = 'http://example.com:8080' - process.env.HTTPS_PROXY = 'http://example.com:8443' - const dispatcher = new EnvHttpProxyAgent() - t.ok(dispatcher[kHttpProxyAgent] instanceof ProxyAgent) - t.equal(dispatcher[kHttpProxyAgent][kProxy].uri, 'http://example.com:8080/') - t.ok(dispatcher[kHttpsProxyAgent] instanceof ProxyAgent) - t.equal(dispatcher[kHttpsProxyAgent][kProxy].uri, 'http://example.com:8443/') - return dispatcher.close() -}) - -test('handles scheme-less hostname-only proxy values', async (t) => { - t = tspl(t, { plan: 2 }) - process.env.HTTP_PROXY = 'myproxy' - const dispatcher = new EnvHttpProxyAgent() - t.ok(dispatcher[kHttpProxyAgent] instanceof ProxyAgent) - t.equal(dispatcher[kHttpProxyAgent][kProxy].uri, 'http://myproxy/') - return dispatcher.close() -}) - test('creates a proxy agent only for https when only https_proxy is set', async (t) => { t = tspl(t, { plan: 5 }) process.env.https_proxy = 'http://example.com:8443'