@@ -50,12 +50,27 @@ type Config struct {
5050 // If no API key is set, either a TLS.Certificates
5151 // or TLS.GetClientCertificate must be present.
5252 TLS * tls.Config
53+
54+ // Optional custom Transport specifying the mechanism
55+ // by which individual HTTP requests are made. If empty,
56+ // a default transport is used.
57+ //
58+ // A custom Transport cannot be used in combination with
59+ // an APIKey or TLS config. It's the users responsibility
60+ // to set a TLS configuration on the custom Transport.
61+ Transport http.RoundTripper
5362}
5463
5564// NewClient returns a new Client with the given configuration.
5665func NewClient (conf * Config ) (* Client , error ) {
57- if conf .APIKey == nil && (conf .TLS == nil || (len (conf .TLS .Certificates ) == 0 && conf .TLS .GetClientCertificate == nil )) {
58- return nil , errors .New ("kms: invalid config: no API key or TLS client certificate provided" )
66+ if conf .Transport != nil && (conf .APIKey != nil || conf .TLS != nil ) {
67+ // We must not modify the TLSClientConfig of a custom Transport (even if we type-assert that it's *http.Transport).
68+ // Hence, we cannot allow a custom Transport in combination with a APIKey or custom TLS config. Users that want
69+ // to use a custom Transport have to create a proper TLS config themselves.
70+ return nil , errors .New ("kms: invalid config: cannot use custom Transport with APIKey or TLS config" )
71+ }
72+ if conf .APIKey == nil && (conf .TLS == nil || (len (conf .TLS .Certificates ) == 0 && conf .TLS .GetClientCertificate == nil )) && conf .Transport == nil {
73+ return nil , errors .New ("kms: invalid config: no API key, TLS client certificate or custom Transport provided" )
5974 }
6075 if conf .APIKey != nil && conf .TLS != nil && len (conf .TLS .Certificates ) > 0 {
6176 return nil , errors .New ("kms: invalid config: 'APIKey' and 'TLS.Certificates' are present" )
@@ -64,24 +79,41 @@ func NewClient(conf *Config) (*Client, error) {
6479 return nil , errors .New ("kms: invalid config: 'APIKey' and 'TLS.GetClientCertificate' are present" )
6580 }
6681
67- tlsConf := conf .TLS
68- if conf .APIKey != nil {
69- cert , err := GenerateCertificate (conf .APIKey , nil )
70- if err != nil {
71- return nil , err
72- }
73-
74- // ensure that the TLS configuration is not nil and
75- // the TLS configuration is cloned to avoid
76- // modifying the original TLS configuration.
77- if tlsConf == nil {
78- tlsConf = & tls.Config {}
79- } else {
80- tlsConf = tlsConf .Clone ()
82+ transport := conf .Transport
83+ if transport == nil {
84+ tlsConf := conf .TLS
85+ if conf .APIKey != nil {
86+ cert , err := GenerateCertificate (conf .APIKey , nil )
87+ if err != nil {
88+ return nil , err
89+ }
90+
91+ // ensure that the TLS configuration is not nil and
92+ // the TLS configuration is cloned to avoid
93+ // modifying the original TLS configuration.
94+ if tlsConf == nil {
95+ tlsConf = & tls.Config {}
96+ } else {
97+ tlsConf = tlsConf .Clone ()
98+ }
99+
100+ tlsConf .GetClientCertificate = func (* tls.CertificateRequestInfo ) (* tls.Certificate , error ) {
101+ return & cert , nil
102+ }
81103 }
82-
83- tlsConf .GetClientCertificate = func (* tls.CertificateRequestInfo ) (* tls.Certificate , error ) {
84- return & cert , nil
104+ transport = & http.Transport {
105+ Proxy : http .ProxyFromEnvironment ,
106+ DialContext : (& net.Dialer {
107+ Timeout : 30 * time .Second ,
108+ KeepAlive : 30 * time .Second ,
109+ DualStack : true ,
110+ }).DialContext ,
111+ ForceAttemptHTTP2 : true ,
112+ MaxIdleConnsPerHost : 50 ,
113+ IdleConnTimeout : 90 * time .Second ,
114+ TLSHandshakeTimeout : 10 * time .Second ,
115+ ExpectContinueTimeout : 1 * time .Second ,
116+ TLSClientConfig : tlsConf ,
85117 }
86118 }
87119
@@ -97,21 +129,8 @@ func NewClient(conf *Config) (*Client, error) {
97129 }
98130
99131 lb := & https.LoadBalancer {
100- Hosts : hosts ,
101- RoundTripper : & http.Transport {
102- Proxy : http .ProxyFromEnvironment ,
103- DialContext : (& net.Dialer {
104- Timeout : 30 * time .Second ,
105- KeepAlive : 30 * time .Second ,
106- DualStack : true ,
107- }).DialContext ,
108- ForceAttemptHTTP2 : true ,
109- MaxIdleConnsPerHost : 50 ,
110- IdleConnTimeout : 90 * time .Second ,
111- TLSHandshakeTimeout : 10 * time .Second ,
112- ExpectContinueTimeout : 1 * time .Second ,
113- TLSClientConfig : tlsConf ,
114- },
132+ Hosts : hosts ,
133+ RoundTripper : transport ,
115134 }
116135 return & Client {
117136 direct : http.Client {Transport : lb .RoundTripper },
0 commit comments