diff --git a/lambda/api_client_proxy_test.go b/lambda/api_client_proxy_test.go index ec4230f8..c16de107 100644 --- a/lambda/api_client_proxy_test.go +++ b/lambda/api_client_proxy_test.go @@ -61,3 +61,42 @@ func TestExtensionAPIClientBypassesProxy(t *testing.T) { proxy := proxyForClient(t, client, nonLoopbackAPIRequest(t)) require.Nil(t, proxy, "Extensions API client must not route through the configured proxy, got %v", proxy) } + +// wrappedRoundTripper is a RoundTripper that is not an *http.Transport, mirroring +// how instrumentation libraries (for example otelhttp) replace http.DefaultTransport. +type wrappedRoundTripper struct { + base http.RoundTripper +} + +func (w *wrappedRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + return w.base.RoundTrip(req) +} + +// When http.DefaultTransport is a non-*http.Transport wrapper, constructing the +// clients must not panic on a type assertion, and the transport must still bypass +// the proxy. +func TestAPIClientsWithWrappedDefaultTransport(t *testing.T) { + t.Setenv("HTTP_PROXY", "http://192.0.2.100:3128") + t.Setenv("HTTPS_PROXY", "http://192.0.2.100:3128") + t.Setenv("http_proxy", "http://192.0.2.100:3128") + t.Setenv("https_proxy", "http://192.0.2.100:3128") + + original := http.DefaultTransport + t.Cleanup(func() { http.DefaultTransport = original }) + http.DefaultTransport = &wrappedRoundTripper{base: original} + + for _, tc := range []struct { + name string + client func() *http.Client + }{ + {"runtime", func() *http.Client { return newRuntimeAPIClient("192.0.2.1:9001").httpClient }}, + {"extension", func() *http.Client { return newExtensionAPIClient("192.0.2.1:9001").httpClient }}, + } { + t.Run(tc.name, func(t *testing.T) { + var client *http.Client + require.NotPanics(t, func() { client = tc.client() }) + proxy := proxyForClient(t, client, nonLoopbackAPIRequest(t)) + require.Nil(t, proxy, "%s API client must not route through the configured proxy, got %v", tc.name, proxy) + }) + } +} diff --git a/lambda/runtime_api_client.go b/lambda/runtime_api_client.go index 42fe5232..7893c176 100644 --- a/lambda/runtime_api_client.go +++ b/lambda/runtime_api_client.go @@ -43,7 +43,12 @@ type runtimeAPIClient struct { // newAPITransport returns an HTTP transport that never proxies, so calls to the // link-local Runtime/Extensions API bypass any customer-configured proxy. func newAPITransport() *http.Transport { - transport := http.DefaultTransport.(*http.Transport).Clone() + transport, ok := http.DefaultTransport.(*http.Transport) + if ok { + transport = transport.Clone() + } else { + transport = &http.Transport{} + } transport.Proxy = nil return transport }