Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions internal/runtime/executor/helps/proxy_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,22 @@ import (
log "github.com/sirupsen/logrus"
)

func init() {
if transport, ok := http.DefaultTransport.(*http.Transport); ok && transport != nil {
applyTransportTuning(transport)
}
}

func applyTransportTuning(t *http.Transport) {
if t == nil {
return
}
t.MaxIdleConns = 200
t.MaxIdleConnsPerHost = 20
t.IdleConnTimeout = 90 * time.Second
t.ForceAttemptHTTP2 = true
}

// NewProxyAwareHTTPClient creates an HTTP client with proper proxy configuration priority:
// 1. Use auth.ProxyURL if configured (highest priority)
// 2. Use cfg.ProxyURL if auth proxy is not configured
Expand Down Expand Up @@ -46,6 +62,7 @@ func NewProxyAwareHTTPClient(ctx context.Context, cfg *config.Config, auth *clip
if proxyURL != "" {
transport := buildProxyTransport(proxyURL)
if transport != nil {
applyTransportTuning(transport)
httpClient.Transport = transport
return httpClient
}
Expand Down
56 changes: 56 additions & 0 deletions internal/runtime/executor/helps/proxy_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"net/http"
"testing"
"time"

"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
cliproxyauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
Expand All @@ -28,3 +29,58 @@ func TestNewProxyAwareHTTPClientDirectBypassesGlobalProxy(t *testing.T) {
t.Fatal("expected direct transport to disable proxy function")
}
}

func assertTransportTuned(t *testing.T, transport *http.Transport, label string) {
t.Helper()
if transport.MaxIdleConns != 200 {
t.Errorf("%s: MaxIdleConns = %d, want 200", label, transport.MaxIdleConns)
}
if transport.MaxIdleConnsPerHost != 20 {
t.Errorf("%s: MaxIdleConnsPerHost = %d, want 20", label, transport.MaxIdleConnsPerHost)
}
if transport.IdleConnTimeout != 90*time.Second {
t.Errorf("%s: IdleConnTimeout = %v, want 90s", label, transport.IdleConnTimeout)
}
if !transport.ForceAttemptHTTP2 {
t.Errorf("%s: ForceAttemptHTTP2 = false, want true", label)
}
}

func TestNewProxyAwareHTTPClient_DefaultTransportTuned(t *testing.T) {
t.Parallel()

transport, ok := http.DefaultTransport.(*http.Transport)
if !ok {
t.Skip("http.DefaultTransport is not *http.Transport")
}

assertTransportTuned(t, transport, "global tuned transport")

client := NewProxyAwareHTTPClient(context.Background(), nil, nil, 0)
if client.Transport != nil {
t.Error("expected NewProxyAwareHTTPClient to return nil transport when no proxy is configured to use http.DefaultTransport")
}
}

func TestNewProxyAwareHTTPClient_ContextRoundTripperReused(t *testing.T) {
t.Parallel()

original := &http.Transport{
MaxIdleConns: 1,
MaxIdleConnsPerHost: 1,
IdleConnTimeout: time.Second,
ForceAttemptHTTP2: false,
}

ctx := context.WithValue(context.Background(), "cliproxy.roundtripper", original)
client := NewProxyAwareHTTPClient(ctx, nil, nil, 0)

if client.Transport != original {
t.Error("expected original context RoundTripper to be reused without cloning")
}

// Verify the original transport was NOT mutated by NewProxyAwareHTTPClient
if original.MaxIdleConns != 1 || original.MaxIdleConnsPerHost != 1 {
t.Error("original transport was mutated, but it should be preserved as-is when provided via context")
}
}
Loading