@@ -83,22 +83,20 @@ func (r rewriteTransport) RoundTrip(req *http.Request) (*http.Response, error) {
8383// Connect - connect to GCS
8484func (gcs * GCS ) Connect (ctx context.Context ) error {
8585 var err error
86- clientOptions := make ([]option.ClientOption , 0 )
87- clientOptions = append (clientOptions , option .WithTelemetryDisabled ())
8886 endpoint := "https://storage.googleapis.com/storage/v1/"
89-
9087 if gcs .Config .Endpoint != "" {
9188 endpoint = gcs .Config .Endpoint
92- clientOptions = append (clientOptions , option .WithEndpoint (endpoint ))
9389 }
9490
91+ // 1. Build the credential option
92+ var credOption option.ClientOption
9593 if gcs .Config .CredentialsJSON != "" {
96- clientOptions = append ( clientOptions , option .WithCredentialsJSON ([]byte (gcs .Config .CredentialsJSON ) ))
94+ credOption = option .WithCredentialsJSON ([]byte (gcs .Config .CredentialsJSON ))
9795 } else if gcs .Config .CredentialsJSONEncoded != "" {
9896 d , _ := base64 .StdEncoding .DecodeString (gcs .Config .CredentialsJSONEncoded )
99- clientOptions = append ( clientOptions , option .WithCredentialsJSON (d ) )
97+ credOption = option .WithCredentialsJSON (d )
10098 } else if gcs .Config .CredentialsFile != "" {
101- clientOptions = append ( clientOptions , option .WithCredentialsFile (gcs .Config .CredentialsFile ) )
99+ credOption = option .WithCredentialsFile (gcs .Config .CredentialsFile )
102100 } else if gcs .Config .SAEmail != "" {
103101 ts , err := impersonate .CredentialsTokenSource (ctx , impersonate.CredentialsConfig {
104102 TargetPrincipal : gcs .Config .SAEmail ,
@@ -110,66 +108,75 @@ func (gcs *GCS) Connect(ctx context.Context) error {
110108 if err != nil {
111109 return errors .Wrap (err , "failed to create impersonation token source" )
112110 }
113- clientOptions = append ( clientOptions , option .WithTokenSource (ts ) )
111+ credOption = option .WithTokenSource (ts )
114112 } else if gcs .Config .SkipCredentials {
115- clientOptions = append ( clientOptions , option .WithoutAuthentication () )
113+ credOption = option .WithoutAuthentication ()
116114 }
117115
118- storageClientOptions := clientOptions
119-
120- if gcs .Config .ForceHttp || gcs .Config .Debug {
121- dialOptions := make ([]option.ClientOption , len (clientOptions ))
122- copy (dialOptions , clientOptions )
123- if gcs .Config .Endpoint == "" && ! gcs .Config .SkipCredentials {
124- dialOptions = append (dialOptions , option .WithScopes (storage .ScopeFullControl ))
125- }
116+ // 2. Build dial options for the HTTP client
117+ dialOptions := []option.ClientOption {option .WithTelemetryDisabled ()}
118+ if gcs .Config .Endpoint != "" {
119+ dialOptions = append (dialOptions , option .WithEndpoint (endpoint ))
120+ }
121+ if credOption != nil {
122+ dialOptions = append (dialOptions , credOption )
123+ }
124+ // Scopes are required when dialing manually, but conflict with NoAuth in newer library versions
125+ if ! gcs .Config .SkipCredentials {
126+ dialOptions = append (dialOptions , option .WithScopes (storage .ScopeFullControl ))
127+ }
126128
127- var httpClient * http.Client
128- if gcs .Config .ForceHttp {
129- customTransport := & http.Transport {
130- WriteBufferSize : 128 * 1024 ,
131- Proxy : http .ProxyFromEnvironment ,
132- DialContext : (& net.Dialer {
133- Timeout : 30 * time .Second ,
134- KeepAlive : 30 * time .Second ,
135- }).DialContext ,
136- MaxIdleConns : 1 ,
137- MaxIdleConnsPerHost : 1 ,
138- IdleConnTimeout : 90 * time .Second ,
139- TLSHandshakeTimeout : 10 * time .Second ,
140- ExpectContinueTimeout : 1 * time .Second ,
141- }
142- // must set ForceAttemptHTTP2 to false so that when a custom TLSClientConfig
143- // is provided Golang does not setup HTTP/2 transport
144- customTransport .ForceAttemptHTTP2 = false
145- customTransport .TLSClientConfig = & tls.Config {
146- NextProtos : []string {"http/1.1" },
147- }
148- customRoundTripper := & rewriteTransport {base : customTransport }
149- transport , err := googleHTTPTransport .NewTransport (ctx , customRoundTripper , dialOptions ... )
150- if err != nil {
151- return errors .Wrap (err , "failed to create GCP transport" )
152- }
153- httpClient = & http.Client {Transport : transport }
154- } else {
155- httpClient , _ , err = googleHTTPTransport .NewClient (ctx , dialOptions ... )
156- if err != nil {
157- return errors .Wrap (err , "googleHTTPTransport.NewClient error" )
158- }
129+ // 3. Create the HTTP client
130+ var httpClient * http.Client
131+ if gcs .Config .ForceHttp {
132+ customTransport := & http.Transport {
133+ WriteBufferSize : 128 * 1024 ,
134+ Proxy : http .ProxyFromEnvironment ,
135+ DialContext : (& net.Dialer {
136+ Timeout : 30 * time .Second ,
137+ KeepAlive : 30 * time .Second ,
138+ }).DialContext ,
139+ MaxIdleConns : 1 ,
140+ MaxIdleConnsPerHost : 1 ,
141+ IdleConnTimeout : 90 * time .Second ,
142+ TLSHandshakeTimeout : 10 * time .Second ,
143+ ExpectContinueTimeout : 1 * time .Second ,
159144 }
160-
161- if gcs .Config .Debug {
162- httpClient .Transport = debugGCSTransport {base : httpClient .Transport }
145+ // must set ForceAttemptHTTP2 to false so that when a custom TLSClientConfig
146+ // is provided Golang does not setup HTTP/2 transport
147+ customTransport .ForceAttemptHTTP2 = false
148+ customTransport .TLSClientConfig = & tls.Config {
149+ NextProtos : []string {"http/1.1" },
163150 }
164- storageClientOptions = []option.ClientOption {
165- option .WithTelemetryDisabled (),
166- option .WithHTTPClient (httpClient ),
151+ customRoundTripper := & rewriteTransport {base : customTransport }
152+ // Use NewTransport to get an authenticated transport using dialOptions
153+ transport , err := googleHTTPTransport .NewTransport (ctx , customRoundTripper , dialOptions ... )
154+ if err != nil {
155+ return errors .Wrap (err , "failed to create GCP transport" )
167156 }
168- if gcs .Config .Endpoint != "" {
169- storageClientOptions = append (storageClientOptions , option .WithEndpoint (endpoint ))
157+ httpClient = & http.Client {Transport : transport }
158+ } else {
159+ // Use NewClient to get an authenticated client using dialOptions
160+ httpClient , _ , err = googleHTTPTransport .NewClient (ctx , dialOptions ... )
161+ if err != nil {
162+ return errors .Wrap (err , "googleHTTPTransport.NewClient error" )
170163 }
171164 }
172165
166+ if gcs .Config .Debug {
167+ httpClient .Transport = debugGCSTransport {base : httpClient .Transport }
168+ }
169+
170+ // 4. Build storage client options using our custom httpClient
171+ // Credentials and scopes are already handled by the httpClient.
172+ storageClientOptions := []option.ClientOption {
173+ option .WithHTTPClient (httpClient ),
174+ option .WithTelemetryDisabled (),
175+ }
176+ if gcs .Config .Endpoint != "" {
177+ storageClientOptions = append (storageClientOptions , option .WithEndpoint (endpoint ))
178+ }
179+
173180 factory := pool .NewPooledObjectFactorySimple (
174181 func (context.Context ) (interface {}, error ) {
175182 sClient , err := storage .NewClient (ctx , storageClientOptions ... )
0 commit comments