@@ -129,6 +129,15 @@ enum TokenState {
129129 Initialized ( Option < AccessToken > ) ,
130130}
131131
132+ #[ derive( Clone ) ]
133+ enum S3CredentialState {
134+ /// The S3 credential state has not yet been initialized.
135+ Uninitialized ,
136+ /// The S3 credential state has been initialized, with either a signer or `None` if
137+ /// no S3 endpoint is configured.
138+ Initialized ( Option < Arc < Authentication > > ) ,
139+ }
140+
132141/// A middleware that adds basic authentication to requests.
133142///
134143/// Uses a cache to propagate credentials from previously seen requests and
@@ -150,6 +159,8 @@ pub struct AuthMiddleware {
150159 pyx_token_store : Option < PyxTokenStore > ,
151160 /// Tokens to use for persistent credentials.
152161 pyx_token_state : Mutex < TokenState > ,
162+ /// Cached S3 credentials to avoid running the credential helper multiple times.
163+ s3_credential_state : Mutex < S3CredentialState > ,
153164 preview : Preview ,
154165}
155166
@@ -172,6 +183,7 @@ impl AuthMiddleware {
172183 base_client : None ,
173184 pyx_token_store : None ,
174185 pyx_token_state : Mutex :: new ( TokenState :: Uninitialized ) ,
186+ s3_credential_state : Mutex :: new ( S3CredentialState :: Uninitialized ) ,
175187 preview : Preview :: default ( ) ,
176188 }
177189 }
@@ -678,13 +690,26 @@ impl AuthMiddleware {
678690 return Some ( credentials) ;
679691 }
680692
681- if let Some ( credentials) = S3EndpointProvider :: credentials_for ( url, self . preview )
682- . map ( Authentication :: from)
683- . map ( Arc :: new)
684- {
685- debug ! ( "Found S3 credentials for {url}" ) ;
686- self . cache ( ) . fetches . done ( key, Some ( credentials. clone ( ) ) ) ;
687- return Some ( credentials) ;
693+ if S3EndpointProvider :: is_s3_endpoint ( url, self . preview ) {
694+ let mut s3_state = self . s3_credential_state . lock ( ) . await ;
695+
696+ // If the S3 credential state is uninitialized, initialize it.
697+ let credentials = match & * s3_state {
698+ S3CredentialState :: Uninitialized => {
699+ trace ! ( "Initializing S3 credentials for {url}" ) ;
700+ let signer = S3EndpointProvider :: create_signer ( ) ;
701+ let credentials = Arc :: new ( Authentication :: from ( signer) ) ;
702+ * s3_state = S3CredentialState :: Initialized ( Some ( credentials. clone ( ) ) ) ;
703+ Some ( credentials)
704+ }
705+ S3CredentialState :: Initialized ( credentials) => credentials. clone ( ) ,
706+ } ;
707+
708+ if let Some ( credentials) = credentials {
709+ debug ! ( "Found S3 credentials for {url}" ) ;
710+ self . cache ( ) . fetches . done ( key, Some ( credentials. clone ( ) ) ) ;
711+ return Some ( credentials) ;
712+ }
688713 }
689714
690715 // If this is a known URL, authenticate it via the token store.
0 commit comments