11use std:: ops:: { ControlFlow , Deref } ;
2+ use std:: str:: FromStr ;
23use std:: sync:: Arc ;
3- use std:: time:: Duration ;
4+ use std:: time:: { Duration , SystemTime } ;
45use std:: { fmt, slice} ;
56
67use base64:: prelude:: { BASE64_URL_SAFE_NO_PAD , Engine } ;
8+ use http:: header:: RETRY_AFTER ;
9+ use httpdate:: HttpDate ;
710#[ cfg( feature = "rcgen" ) ]
811use rcgen:: { CertificateParams , DistinguishedName , KeyPair } ;
912use serde:: Serialize ;
@@ -14,7 +17,7 @@ use crate::types::{
1417 Authorization , AuthorizationState , AuthorizationStatus , AuthorizedIdentifier , Challenge ,
1518 ChallengeType , Empty , FinalizeRequest , OrderState , OrderStatus , Problem ,
1619} ;
17- use crate :: { Error , Key , crypto, nonce_from_response} ;
20+ use crate :: { BytesResponse , Error , Key , crypto, nonce_from_response} ;
1821
1922/// An ACME order as described in RFC 8555 (section 7.1.3)
2023///
@@ -27,6 +30,7 @@ use crate::{Error, Key, crypto, nonce_from_response};
2730pub struct Order {
2831 pub ( crate ) account : Arc < AccountInner > ,
2932 pub ( crate ) nonce : Option < String > ,
33+ pub ( crate ) retry_after : Option < SystemTime > ,
3034 pub ( crate ) url : String ,
3135 pub ( crate ) state : OrderState ,
3236}
@@ -163,8 +167,9 @@ impl Order {
163167 /// Yields the [`OrderStatus`] immediately if `Ready` or `Invalid`, or after `tries` attempts.
164168 pub async fn poll ( & mut self , retries : & RetryPolicy ) -> Result < OrderStatus , Error > {
165169 let mut retrying = retries. state ( ) ;
170+ self . retry_after = None ;
166171 loop {
167- if let ControlFlow :: Break ( ( ) ) = retrying. wait ( ) . await {
172+ if let ControlFlow :: Break ( ( ) ) = retrying. wait ( self . retry_after . take ( ) ) . await {
168173 return Ok ( self . state . status ) ;
169174 }
170175
@@ -185,6 +190,7 @@ impl Order {
185190 . await ?;
186191
187192 self . nonce = nonce_from_response ( & rsp) ;
193+ self . retry_after = retry_after ( & rsp) ;
188194 self . state = Problem :: check :: < OrderState > ( rsp) . await ?;
189195 Ok ( & self . state )
190196 }
@@ -544,14 +550,44 @@ struct RetryState {
544550}
545551
546552impl RetryState {
547- async fn wait ( & mut self ) -> ControlFlow < ( ) , ( ) > {
553+ async fn wait ( & mut self , after : Option < SystemTime > ) -> ControlFlow < ( ) , ( ) > {
548554 if self . tries == 0 {
549555 return ControlFlow :: Break ( ( ) ) ;
550556 }
551557
558+ if let Some ( after) = after {
559+ if let Ok ( delay) = after. duration_since ( SystemTime :: now ( ) ) {
560+ sleep ( delay) . await ;
561+ self . tries -= 1 ;
562+ return ControlFlow :: Continue ( ( ) ) ;
563+ }
564+ }
565+
552566 sleep ( self . delay ) . await ;
553567 self . delay *= 2 ;
554568 self . tries -= 1 ;
555569 ControlFlow :: Continue ( ( ) )
556570 }
557571}
572+
573+ /// Parse the `Retry-After` header from the response
574+ ///
575+ /// <https://httpwg.org/specs/rfc9110.html#field.retry-after>
576+ ///
577+ /// # Syntax
578+ ///
579+ /// Retry-After = HTTP-date / delay-seconds
580+ /// delay-seconds = 1*DIGIT
581+ fn retry_after ( rsp : & BytesResponse ) -> Option < SystemTime > {
582+ let value = rsp. parts . headers . get ( RETRY_AFTER ) ?. to_str ( ) . ok ( ) ?. trim ( ) ;
583+ if value. is_empty ( ) {
584+ return None ;
585+ }
586+
587+ Some ( match u64:: from_str ( value) {
588+ // `delay-seconds` is a number of seconds to wait
589+ Ok ( secs) => SystemTime :: now ( ) + Duration :: from_secs ( secs) ,
590+ // `HTTP-date` looks like `Fri, 31 Dec 1999 23:59:59 GMT`
591+ Err ( _) => SystemTime :: from ( HttpDate :: from_str ( value) . ok ( ) ?) ,
592+ } )
593+ }
0 commit comments