Skip to content

Commit 5a01a1b

Browse files
committed
Guard DefaultTransport assertion in transportForAuth
Fall back to a transport with stdlib-matching defaults if DefaultTransport is not a *http.Transport, to avoid a panic when another component has replaced the global default. The fallback sets Proxy: http.ProxyFromEnvironment, 30s dial/keep-alive, and the standard idle/TLS/expect-continue timeouts so runtime behaviour stays close to the baseline.
1 parent e7908cc commit 5a01a1b

2 files changed

Lines changed: 75 additions & 1 deletion

File tree

internal/bundlereader/charturl.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"errors"
1111
"fmt"
1212
"io"
13+
"net"
1314
"net/http"
1415
"net/url"
1516
"strings"
@@ -290,7 +291,25 @@ func transportForAuth(insecureSkipVerify bool, caBundle []byte) http.RoundTrippe
290291
}
291292

292293
// Create new transport
293-
transport := http.DefaultTransport.(*http.Transport).Clone()
294+
baseTransport, ok := http.DefaultTransport.(*http.Transport)
295+
if !ok {
296+
// Another component has replaced the global default transport.
297+
// Construct a transport that preserves the standard proxy and timeout
298+
// defaults so runtime behaviour stays close to the stdlib baseline.
299+
baseTransport = &http.Transport{
300+
Proxy: http.ProxyFromEnvironment,
301+
DialContext: (&net.Dialer{
302+
Timeout: 30 * time.Second,
303+
KeepAlive: 30 * time.Second,
304+
}).DialContext,
305+
ForceAttemptHTTP2: true,
306+
MaxIdleConns: 100,
307+
IdleConnTimeout: 90 * time.Second,
308+
TLSHandshakeTimeout: 10 * time.Second,
309+
ExpectContinueTimeout: 1 * time.Second,
310+
}
311+
}
312+
transport := baseTransport.Clone()
294313
transport.TLSClientConfig = &tls.Config{
295314
InsecureSkipVerify: insecureSkipVerify, //nolint:gosec
296315
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package bundlereader
2+
3+
import (
4+
"net/http"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
// fakeRoundTripper is a RoundTripper that is not *http.Transport, so substituting
12+
// it for http.DefaultTransport triggers the type-assertion path in transportForAuth.
13+
type fakeRoundTripper struct{}
14+
15+
func (fakeRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { return nil, nil }
16+
17+
// TestTransportForAuthNonDefaultTransport verifies that transportForAuth does not
18+
// panic when http.DefaultTransport has been replaced by a value that is not
19+
// *http.Transport, and that the resulting transport has proxy and timeout defaults.
20+
//
21+
// Not parallel: the test mutates the process-global http.DefaultTransport.
22+
func TestTransportForAuthNonDefaultTransport(t *testing.T) {
23+
orig := http.DefaultTransport
24+
t.Cleanup(func() { http.DefaultTransport = orig })
25+
26+
http.DefaultTransport = fakeRoundTripper{}
27+
28+
// The transport cache is package-level; clear it so a fresh entry is built.
29+
transportsCacheMutex.Lock()
30+
transportsCache = map[string]http.RoundTripper{}
31+
transportsCacheMutex.Unlock()
32+
33+
var result http.RoundTripper
34+
require.NotPanics(t, func() {
35+
result = transportForAuth(false, nil)
36+
}, "transportForAuth must not panic when http.DefaultTransport is not *http.Transport")
37+
require.NotNil(t, result)
38+
39+
// The fallback transport must carry proxy and timeout settings, not bare &http.Transport{}.
40+
tr, ok := result.(*http.Transport)
41+
require.True(t, ok, "result must be *http.Transport")
42+
assert.NotNil(t, tr.Proxy, "fallback transport must have Proxy set")
43+
assert.NotNil(t, tr.DialContext, "fallback transport must have DialContext set")
44+
assert.Greater(t, tr.TLSHandshakeTimeout, tr.IdleConnTimeout*0, "TLSHandshakeTimeout must be positive")
45+
46+
// Also verify the custom-CA path does not panic.
47+
transportsCacheMutex.Lock()
48+
transportsCache = map[string]http.RoundTripper{}
49+
transportsCacheMutex.Unlock()
50+
51+
require.NotPanics(t, func() {
52+
result = transportForAuth(false, []byte("not-a-real-cert"))
53+
assert.NotNil(t, result)
54+
}, "transportForAuth must not panic with a CA bundle when DefaultTransport is not *http.Transport")
55+
}

0 commit comments

Comments
 (0)