@@ -174,6 +174,7 @@ pub struct RetryableRequest {
174174 retry_timeout : Duration ,
175175 backoff : Backoff ,
176176
177+ sensitive : bool ,
177178 idempotent : Option < bool > ,
178179 payload : Option < PutPayload > ,
179180}
@@ -190,6 +191,14 @@ impl RetryableRequest {
190191 }
191192 }
192193
194+ /// Set whether this request contains sensitive data
195+ ///
196+ /// This will avoid printing out the URL in error messages
197+ #[ allow( unused) ]
198+ pub fn sensitive ( self , sensitive : bool ) -> Self {
199+ Self { sensitive, ..self }
200+ }
201+
193202 /// Provide a [`PutPayload`]
194203 pub fn payload ( self , payload : Option < PutPayload > ) -> Self {
195204 Self { payload, ..self }
@@ -206,6 +215,11 @@ impl RetryableRequest {
206215 . idempotent
207216 . unwrap_or_else ( || self . request . method ( ) . is_safe ( ) ) ;
208217
218+ let sanitize_err = move |e : reqwest:: Error | match self . sensitive {
219+ true => e. without_url ( ) ,
220+ false => e,
221+ } ;
222+
209223 loop {
210224 let mut request = self
211225 . request
@@ -238,6 +252,7 @@ impl RetryableRequest {
238252 } ;
239253 }
240254 Err ( e) => {
255+ let e = sanitize_err ( e) ;
241256 let status = r. status ( ) ;
242257 if retries == max_retries
243258 || now. elapsed ( ) > retry_timeout
@@ -280,6 +295,8 @@ impl RetryableRequest {
280295 }
281296 } ,
282297 Err ( e) => {
298+ let e = sanitize_err ( e) ;
299+
283300 let mut do_retry = false ;
284301 if e. is_connect ( )
285302 || e. is_body ( )
@@ -365,6 +382,7 @@ impl RetryExt for reqwest::RequestBuilder {
365382 backoff : Backoff :: new ( & config. backoff ) ,
366383 idempotent : None ,
367384 payload : None ,
385+ sensitive : false ,
368386 }
369387 }
370388
@@ -565,6 +583,48 @@ mod tests {
565583 "{e}"
566584 ) ;
567585
586+ let url = format ! ( "{}/SENSITIVE" , mock. url( ) ) ;
587+ for _ in 0 ..=retry. max_retries {
588+ mock. push (
589+ Response :: builder ( )
590+ . status ( StatusCode :: BAD_GATEWAY )
591+ . body ( "ignored" . to_string ( ) )
592+ . unwrap ( ) ,
593+ ) ;
594+ }
595+ let res = client. request ( Method :: GET , url) . send_retry ( & retry) . await ;
596+ let err = res. unwrap_err ( ) . to_string ( ) ;
597+ assert ! ( err. contains( "SENSITIVE" ) , "{err}" ) ;
598+
599+ let url = format ! ( "{}/SENSITIVE" , mock. url( ) ) ;
600+ for _ in 0 ..=retry. max_retries {
601+ mock. push (
602+ Response :: builder ( )
603+ . status ( StatusCode :: BAD_GATEWAY )
604+ . body ( "ignored" . to_string ( ) )
605+ . unwrap ( ) ,
606+ ) ;
607+ }
608+
609+ // Sensitive requests should strip URL from error
610+ let req = client
611+ . request ( Method :: GET , & url)
612+ . retryable ( & retry)
613+ . sensitive ( true ) ;
614+ let err = req. send ( ) . await . unwrap_err ( ) . to_string ( ) ;
615+ assert ! ( !err. contains( "SENSITIVE" ) , "{err}" ) ;
616+
617+ for _ in 0 ..=retry. max_retries {
618+ mock. push_fn ( |_| panic ! ( ) ) ;
619+ }
620+
621+ let req = client
622+ . request ( Method :: GET , & url)
623+ . retryable ( & retry)
624+ . sensitive ( true ) ;
625+ let err = req. send ( ) . await . unwrap_err ( ) . to_string ( ) ;
626+ assert ! ( !err. contains( "SENSITIVE" ) , "{err}" ) ;
627+
568628 // Shutdown
569629 mock. shutdown ( ) . await
570630 }
0 commit comments