fix: Bypass proxy for loopback addresses to prevent localhost connection failures (#194)

When users have HTTP_PROXY/HTTPS_PROXY set in their shell (e.g. corporate
proxy), PMG's upstream transport routes all traffic through that external
proxy — including requests to localhost/127.0.0.1. The external proxy
cannot reach the user's loopback, causing EFAULT/ConnectionRefused errors.

This adds loopback bypass in two places:
- Proxy upstream transport skips external proxy for localhost/127.0.0.1/::1
- Child process env gets NO_PROXY so proxy-aware libs (axios) skip PMG's
  proxy for loopback addresses

Fixes #193

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sahil Bansal
2026-04-01 19:28:25 +05:30
committed by GitHub
co-authored by Claude Opus 4.6
parent 5fdc3a03ae
commit 635e40cc1f
3 changed files with 46 additions and 2 deletions
+29
View File
@@ -126,6 +126,35 @@ func TestNormalizeRequestURLNilSafety(t *testing.T) {
normalizeRequestURL(&http.Request{URL: &url.URL{}})
}
func TestProxyWithLoopbackBypass(t *testing.T) {
tests := []struct {
name string
url string
shouldBypass bool
}{
{"localhost bypassed", "http://localhost:9876/", true},
{"127.0.0.1 bypassed", "http://127.0.0.1:9876/", true},
{"ipv6 loopback bypassed", "http://[::1]:9876/", true},
{"registry not bypassed", "https://registry.npmjs.org/lodash", false},
{"external host not bypassed", "http://example.com/", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
parsed, err := url.Parse(tt.url)
require.NoError(t, err)
req := &http.Request{URL: parsed}
proxyURL, err := proxyWithLoopbackBypass(req)
assert.NoError(t, err)
if tt.shouldBypass {
assert.Nil(t, proxyURL, "loopback address should bypass proxy")
}
})
}
}
func TestNewProxyServerRejectsUntrustedUpstreamCertByDefault(t *testing.T) {
target := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)