Skip to content

Commit d628bfc

Browse files
test: add connect tests for proxy package (#58)
* test: add connect tests for proxy package * test: add http connect tests for proxy package * fix: linter
1 parent 07deeeb commit d628bfc

File tree

1 file changed

+130
-0
lines changed

1 file changed

+130
-0
lines changed

proxy/proxy_test.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"log"
77
"log/slog"
88
"net/http"
9+
"net/url"
910
"os"
1011
"os/user"
1112
"strconv"
@@ -200,3 +201,132 @@ func TestProxyServerBasicHTTPS(t *testing.T) {
200201
err = server.Stop()
201202
require.NoError(t, err)
202203
}
204+
205+
// TestProxyServerCONNECT tests HTTP CONNECT method for HTTPS tunneling
206+
func TestProxyServerCONNECT(t *testing.T) {
207+
// Create test logger
208+
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
209+
Level: slog.LevelError,
210+
}))
211+
212+
// Create test rules (allow all for testing)
213+
testRules, err := rules.ParseAllowSpecs([]string{"*"})
214+
if err != nil {
215+
t.Fatalf("Failed to parse test rules: %v", err)
216+
}
217+
218+
// Create rule engine
219+
ruleEngine := rules.NewRuleEngine(testRules, logger)
220+
221+
// Create mock auditor
222+
auditor := &mockAuditor{}
223+
224+
// Get current user for TLS setup
225+
currentUser, err := user.Current()
226+
if err != nil {
227+
log.Fatal(err)
228+
}
229+
230+
uid, _ := strconv.Atoi(currentUser.Uid)
231+
gid, _ := strconv.Atoi(currentUser.Gid)
232+
233+
// Create TLS certificate manager
234+
certManager, err := boundary_tls.NewCertificateManager(boundary_tls.Config{
235+
Logger: logger,
236+
ConfigDir: "/tmp/boundary_connect_test",
237+
Uid: uid,
238+
Gid: gid,
239+
})
240+
require.NoError(t, err)
241+
242+
// Setup TLS to get cert path for proxy
243+
tlsConfig, caCertPath, configDir, err := certManager.SetupTLSAndWriteCACert()
244+
require.NoError(t, err)
245+
_, _ = caCertPath, configDir
246+
247+
// Create proxy server
248+
server := NewProxyServer(Config{
249+
HTTPPort: 8080,
250+
251+
RuleEngine: ruleEngine,
252+
Auditor: auditor,
253+
Logger: logger,
254+
TLSConfig: tlsConfig,
255+
})
256+
257+
// Start server
258+
err = server.Start()
259+
require.NoError(t, err)
260+
261+
// Give server time to start
262+
time.Sleep(100 * time.Millisecond)
263+
264+
// Test HTTPS request through proxy transport (automatic CONNECT)
265+
t.Run("HTTPSRequestThroughProxyTransport", func(t *testing.T) {
266+
// Create proxy URL
267+
proxyURL, err := url.Parse("http://localhost:8080")
268+
require.NoError(t, err)
269+
270+
// Create HTTP client with proxy transport
271+
client := &http.Client{
272+
Transport: &http.Transport{
273+
Proxy: http.ProxyURL(proxyURL),
274+
TLSClientConfig: &tls.Config{
275+
InsecureSkipVerify: true, // Skip cert verification for testing
276+
},
277+
},
278+
Timeout: 10 * time.Second,
279+
}
280+
281+
// Because this is HTTPS, Go will issue CONNECT localhost:8080 → dev.coder.com:443
282+
resp, err := client.Get("https://dev.coder.com/api/v2")
283+
require.NoError(t, err)
284+
285+
// Read response
286+
body, err := io.ReadAll(resp.Body)
287+
require.NoError(t, err)
288+
require.NoError(t, resp.Body.Close())
289+
290+
// Verify response contains expected content
291+
expectedResponse := `{"message":"👋"}
292+
`
293+
require.Equal(t, expectedResponse, string(body))
294+
})
295+
296+
// Test HTTP request through proxy transport
297+
t.Run("HTTPRequestThroughProxyTransport", func(t *testing.T) {
298+
// Create proxy URL
299+
proxyURL, err := url.Parse("http://localhost:8080")
300+
require.NoError(t, err)
301+
302+
// Create HTTP client with proxy transport
303+
client := &http.Client{
304+
Transport: &http.Transport{
305+
Proxy: http.ProxyURL(proxyURL),
306+
},
307+
Timeout: 10 * time.Second,
308+
}
309+
310+
// For HTTP requests, Go will send the request directly to the proxy
311+
// The proxy will forward it to the target server
312+
resp, err := client.Get("http://jsonplaceholder.typicode.com/todos/1")
313+
require.NoError(t, err)
314+
315+
// Read response
316+
body, err := io.ReadAll(resp.Body)
317+
require.NoError(t, err)
318+
require.NoError(t, resp.Body.Close())
319+
320+
// Verify response contains expected content
321+
expectedResponse := `{
322+
"userId": 1,
323+
"id": 1,
324+
"title": "delectus aut autem",
325+
"completed": false
326+
}`
327+
require.Equal(t, expectedResponse, string(body))
328+
})
329+
330+
err = server.Stop()
331+
require.NoError(t, err)
332+
}

0 commit comments

Comments
 (0)