@codacy/codacy-mcp
Version:
Codacy MCP server
75 lines (74 loc) • 3.58 kB
JavaScript
import { Agent, ProxyAgent, setGlobalDispatcher } from 'undici';
// Matches a request hostname against the NO_PROXY / no_proxy list.
// Handles exact matches and suffix matches (e.g. "example.com" also covers "sub.example.com").
function matchesNoProxy(hostname) {
const noProxy = process.env.NO_PROXY ?? process.env.no_proxy;
if (!noProxy)
return false;
const lower = hostname.toLowerCase();
return noProxy
.split(',')
.map(h => h.trim().toLowerCase().replace(/^\./, ''))
.filter(Boolean)
.some(entry => entry === '*' || lower === entry || lower.endsWith('.' + entry));
}
// Ensures a proxy URL has a protocol prefix. A bare host:port (e.g. "localhost:8080")
// is treated as HTTP, matching the convention used by curl and most proxy tools.
function normalizeProxyUrl(url) {
return /^https?:\/\//i.test(url) ? url : `http://${url}`;
}
// Routes each fetch() call through HTTPS_PROXY or HTTP_PROXY based on the request
// protocol, bypassing the proxy for any host that matches NO_PROXY.
// Extends Agent so all Dispatcher methods are already implemented.
class ProxyRoutingDispatcher extends Agent {
_httpsProxy;
_httpProxy;
constructor(httpProxy, httpsProxy, disableSSL) {
super();
// requestTls — TLS to the target server through the CONNECT tunnel.
// proxyTls — TLS to the proxy itself (relevant when proxy URL is HTTPS).
const tlsOpts = disableSSL ? { rejectUnauthorized: false } : undefined;
const proxyOpts = tlsOpts ? { requestTls: tlsOpts, proxyTls: tlsOpts } : {};
this._httpsProxy = httpsProxy
? new ProxyAgent({ uri: normalizeProxyUrl(httpsProxy), ...proxyOpts })
: undefined;
this._httpProxy = httpProxy
? new ProxyAgent({ uri: normalizeProxyUrl(httpProxy), ...proxyOpts })
: undefined;
}
dispatch(options, handler) {
const origin = options.origin instanceof URL ? options.origin : new URL(String(options.origin));
if (!matchesNoProxy(origin.hostname)) {
const proxy = origin.protocol === 'https:'
? (this._httpsProxy ?? this._httpProxy)
: (this._httpProxy ?? this._httpsProxy);
if (proxy)
return proxy.dispatch(options, handler);
}
return super.dispatch(options, handler);
}
}
/**
* Reads proxy configuration from environment variables and patches the global
* fetch dispatcher used by Node.js native fetch.
*
* Supported env vars:
* HTTPS_PROXY / https_proxy — proxy for HTTPS requests
* HTTP_PROXY / http_proxy — proxy for HTTP requests
* NO_PROXY / no_proxy — comma-separated list of hosts to bypass
* NODE_TLS_REJECT_UNAUTHORIZED=0 — disable TLS certificate verification
*
* For corporate environments that use SSL inspection (MITM proxies), prefer adding the
* corporate CA certificate to Node's trust store rather than disabling verification:
* NODE_EXTRA_CA_CERTS=/path/to/corporate-ca.pem
* Node reads this at startup and it applies to all TLS connections, including
* the inner tunnel established through a CONNECT proxy.
*/
export function applyProxyConfig() {
const httpsProxy = process.env.HTTPS_PROXY ?? process.env.https_proxy;
const httpProxy = process.env.HTTP_PROXY ?? process.env.http_proxy;
if (!httpsProxy && !httpProxy)
return;
const disableSSL = process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0';
setGlobalDispatcher(new ProxyRoutingDispatcher(httpProxy, httpsProxy, disableSSL));
}