Skip to content

Commit 67b192b

Browse files
authored
Merge pull request #28 from vast-data/proxy_config
feat: add proxy environment variable support
2 parents 04c77b0 + c0b0503 commit 67b192b

File tree

5 files changed

+163
-1
lines changed

5 files changed

+163
-1
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## 0.112.0
6+
7+
ENHANCEMENTS:
8+
9+
* **Proxy Environment Variable Support**: The HTTP client now respects standard proxy environment variables (`HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`) for routing requests through proxy servers.
10+
511
## 0.109.0
612

713
BREAKING CHANGES:

core/auth.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ func (auth *JWTAuthenticator) authorize() error {
156156
)
157157
tr := &http.Transport{
158158
TLSClientConfig: &tls.Config{InsecureSkipVerify: !auth.SslVerify},
159+
// Ensure proxy environment variables are respected during authentication
160+
Proxy: http.ProxyFromEnvironment,
159161
}
160162
client := &http.Client{
161163
Transport: tr,

core/session.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ func NewVMSSession(config *VMSConfig) (*VMSSession, error) {
104104
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: !config.SslVerify}
105105
transport.MaxConnsPerHost = config.MaxConnections
106106
transport.IdleConnTimeout = *config.Timeout
107+
// Ensure proxy environment variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY) are respected
108+
transport.Proxy = http.ProxyFromEnvironment
107109
client := &http.Client{Transport: transport}
108110
authenticator, err := createAuthenticator(config)
109111
if err != nil {

core/session_proxy_test.go

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package core
2+
3+
import (
4+
"net/http"
5+
"net/url"
6+
"os"
7+
"testing"
8+
"time"
9+
)
10+
11+
// clearProxyEnv clears all proxy environment variables and registers cleanup to restore them
12+
func clearProxyEnv(t *testing.T) {
13+
t.Helper()
14+
proxyVars := []string{"HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY", "http_proxy", "https_proxy", "no_proxy"}
15+
16+
// Save original values
17+
saved := make(map[string]string)
18+
for _, key := range proxyVars {
19+
if val := os.Getenv(key); val != "" {
20+
saved[key] = val
21+
}
22+
os.Unsetenv(key)
23+
}
24+
25+
// Register cleanup to restore original values
26+
t.Cleanup(func() {
27+
// First clear everything again (in case test set something)
28+
for _, key := range proxyVars {
29+
os.Unsetenv(key)
30+
}
31+
// Then restore originals
32+
for key, val := range saved {
33+
os.Setenv(key, val)
34+
}
35+
})
36+
}
37+
38+
// TestProxyEnvironmentVariable verifies that HTTPS_PROXY environment variable is respected
39+
func TestProxyEnvironmentVariable(t *testing.T) {
40+
// Set up test proxy URL
41+
testProxyURL := "http://10.100.11.154:3128"
42+
43+
// Clear all proxy environment variables first (handles cleanup automatically)
44+
clearProxyEnv(t)
45+
46+
// Set the proxy environment variable we want to test
47+
os.Setenv("HTTPS_PROXY", testProxyURL)
48+
49+
// Create a test config using API token to avoid authentication
50+
timeout := time.Minute
51+
config := &VMSConfig{
52+
Host: "test.example.com",
53+
Port: 443,
54+
ApiToken: "test-token",
55+
SslVerify: false,
56+
Timeout: &timeout,
57+
MaxConnections: 10,
58+
}
59+
60+
// Create a session
61+
session, err := NewVMSSession(config)
62+
if err != nil {
63+
t.Fatalf("Failed to create session: %v", err)
64+
}
65+
66+
// Verify that the transport has the proxy set
67+
transport, ok := session.client.Transport.(*http.Transport)
68+
if !ok {
69+
t.Fatal("Expected http.Transport, got different type")
70+
}
71+
72+
if transport.Proxy == nil {
73+
t.Fatal("Proxy function is nil - environment variables will not be respected")
74+
}
75+
76+
// Test that the proxy function returns the expected proxy URL
77+
testURL, _ := url.Parse("https://test.example.com")
78+
req := &http.Request{URL: testURL}
79+
proxyURL, err := transport.Proxy(req)
80+
if err != nil {
81+
t.Fatalf("Proxy function returned error: %v", err)
82+
}
83+
84+
if proxyURL == nil {
85+
t.Fatal("Proxy function returned nil - HTTPS_PROXY not being respected")
86+
}
87+
88+
if proxyURL.String() != testProxyURL {
89+
t.Errorf("Expected proxy URL %s, got %s", testProxyURL, proxyURL.String())
90+
}
91+
}
92+
93+
// TestNO_PROXY verifies that NO_PROXY environment variable is respected
94+
// Note: Due to Go's internal proxy caching in http.ProxyFromEnvironment, this test only
95+
// passes when run in isolation. To run it, use:
96+
//
97+
// go test ./core -run ^TestNO_PROXY$ -v
98+
func TestNO_PROXY(t *testing.T) {
99+
// Skip by default to avoid test suite failures due to Go's proxy caching
100+
// Only run when explicitly requested
101+
if os.Getenv("RUN_ISOLATION_TESTS") == "" {
102+
t.Skip("Skipping TestNO_PROXY (requires isolation). To run: go test ./core -run ^TestNO_PROXY$ -v")
103+
}
104+
105+
// Set up test proxy and NO_PROXY
106+
testProxyURL := "http://proxy.example.com:8080"
107+
108+
// Clear all proxy environment variables first (handles cleanup automatically)
109+
clearProxyEnv(t)
110+
111+
// Set the proxy and NO_PROXY environment variables we want to test
112+
os.Setenv("HTTPS_PROXY", testProxyURL)
113+
os.Setenv("NO_PROXY", "localhost,127.0.0.1,internal.example.com")
114+
115+
// Create a test config using API token to avoid authentication
116+
timeout := time.Minute
117+
config := &VMSConfig{
118+
Host: "test.example.com",
119+
Port: 443,
120+
ApiToken: "test-token",
121+
SslVerify: false,
122+
Timeout: &timeout,
123+
MaxConnections: 10,
124+
}
125+
126+
// Create a session
127+
session, err := NewVMSSession(config)
128+
if err != nil {
129+
t.Fatalf("Failed to create session: %v", err)
130+
}
131+
132+
transport, ok := session.client.Transport.(*http.Transport)
133+
if !ok {
134+
t.Fatal("Expected http.Transport, got different type")
135+
}
136+
137+
// Test that proxy is used for non-excluded hosts
138+
testURL1, _ := url.Parse("https://external.example.com")
139+
req1 := &http.Request{URL: testURL1}
140+
proxyURL1, _ := transport.Proxy(req1)
141+
if proxyURL1 == nil || proxyURL1.String() != testProxyURL {
142+
t.Errorf("Expected proxy for external host, got %v", proxyURL1)
143+
}
144+
145+
// Test that proxy is NOT used for excluded hosts
146+
testURL2, _ := url.Parse("https://internal.example.com")
147+
req2 := &http.Request{URL: testURL2}
148+
proxyURL2, _ := transport.Proxy(req2)
149+
if proxyURL2 != nil {
150+
t.Errorf("Expected no proxy for NO_PROXY host, got %v", proxyURL2)
151+
}
152+
}

core/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.111.0
1+
0.112.0

0 commit comments

Comments
 (0)