@@ -2,7 +2,6 @@ use core::cell::RefCell;
22use core:: ptr:: NonNull ;
33use core:: time:: Duration ;
44use std:: collections:: VecDeque ;
5- use std:: io;
65use std:: string:: { String , ToString } ;
76
87use anyhow:: { anyhow, Result } ;
@@ -30,7 +29,6 @@ pub mod types;
3029const DEFAULT_RETRY_INTERVAL : Duration = Duration :: from_secs ( 1 ) ;
3130static REPLAY_NONCE : http:: HeaderName = http:: HeaderName :: from_static ( "replay-nonce" ) ;
3231
33- #[ derive( Debug ) ]
3432pub struct NewCertificateOutput {
3533 pub chain : Bytes ,
3634 pub x509 : Vec < X509 > ,
@@ -64,12 +62,12 @@ impl NoncePool {
6462 }
6563
6664 pub fn add ( & self , nonce : String ) {
67- self . 0 . borrow_mut ( ) . push_back ( nonce. to_string ( ) ) ;
65+ self . 0 . borrow_mut ( ) . push_back ( nonce) ;
6866 }
6967
7068 pub fn add_from_response < T > ( & self , res : & http:: Response < T > ) {
7169 if let Some ( nonce) = try_get_header ( res. headers ( ) , & REPLAY_NONCE ) {
72- self . 0 . borrow_mut ( ) . push_back ( nonce. to_string ( ) ) ;
70+ self . add ( nonce. to_string ( ) ) ;
7371 }
7472 }
7573}
@@ -130,51 +128,6 @@ where
130128 . map ( String :: from)
131129 }
132130
133- pub async fn poll < T , P , F > (
134- & self ,
135- url : & Uri ,
136- payload : P ,
137- mut tries : usize ,
138- predicate : F ,
139- ) -> Result < T >
140- where
141- T : serde:: de:: DeserializeOwned ,
142- P : AsRef < [ u8 ] > ,
143- F : Fn ( & T ) -> bool ,
144- {
145- loop {
146- let res = self . post ( url, & payload) . await ?;
147-
148- let retry_after = res
149- . headers ( )
150- . get ( http:: header:: RETRY_AFTER )
151- . and_then ( parse_retry_after)
152- . unwrap_or ( DEFAULT_RETRY_INTERVAL ) ;
153-
154- let result = serde_json:: from_slice ( res. body ( ) ) ?;
155-
156- if predicate ( & result) {
157- return Ok ( result) ;
158- }
159-
160- tries -= 1 ;
161- if tries == 0 {
162- return Err ( io:: Error :: from ( io:: ErrorKind :: TimedOut ) . into ( ) ) ;
163- }
164-
165- sleep ( retry_after) . await ;
166- }
167- }
168-
169- pub async fn post_json < T : serde:: de:: DeserializeOwned , P : AsRef < [ u8 ] > > (
170- & self ,
171- url : & Uri ,
172- payload : P ,
173- ) -> Result < T > {
174- let res = self . post ( url, payload) . await ?;
175- Ok ( serde_json:: from_slice ( res. body ( ) ) ?)
176- }
177-
178131 pub async fn get ( & self , url : & Uri ) -> Result < http:: Response < Bytes > > {
179132 let req = http:: Request :: builder ( )
180133 . uri ( url)
@@ -238,12 +191,6 @@ where
238191 . ok_or ( anyhow ! ( "no nonce in response" ) ) ?
239192 . to_string ( ) ;
240193
241- let retry_after = res
242- . headers ( )
243- . get ( http:: header:: RETRY_AFTER )
244- . and_then ( parse_retry_after)
245- . unwrap_or ( DEFAULT_RETRY_INTERVAL ) ;
246-
247194 let err: types:: Problem = serde_json:: from_slice ( res. body ( ) ) ?;
248195
249196 let retriable = matches ! (
@@ -257,7 +204,8 @@ where
257204 }
258205
259206 fails += 1 ;
260- sleep ( retry_after) . await ;
207+
208+ wait_for_retry ( & res) . await ;
261209 ngx_log_debug ! ( self . log. as_ptr( ) , "retrying: {} of 3" , fails + 1 ) ;
262210 } ;
263211
@@ -339,7 +287,8 @@ where
339287
340288 let mut authorizations: Vec < ( http:: Uri , types:: Authorization ) > = Vec :: new ( ) ;
341289 for auth_url in order. authorizations {
342- let mut authorization: types:: Authorization = self . post_json ( & auth_url, & [ ] ) . await ?;
290+ let res = self . post ( & auth_url, b"" ) . await ?;
291+ let mut authorization: types:: Authorization = serde_json:: from_slice ( res. body ( ) ) ?;
343292
344293 authorization
345294 . challenges
@@ -379,8 +328,8 @@ where
379328 self . do_authorization ( & order, url, authorization) . await ?;
380329 }
381330
382- let mut bytes = self . post ( & order_url, & [ ] ) . await ?. into_body ( ) ;
383- let mut order: types:: Order = serde_json:: from_slice ( & bytes ) ?;
331+ let mut res = self . post ( & order_url, b"" ) . await ?;
332+ let mut order: types:: Order = serde_json:: from_slice ( res . body ( ) ) ?;
384333
385334 if order. status != OrderStatus :: Ready {
386335 anyhow:: bail!( "not ready" ) ;
@@ -390,10 +339,10 @@ where
390339 let payload = std:: format!( r#"{{"csr":"{}"}}"# , crate :: jws:: base64url( csr) ) ;
391340
392341 match self . post ( & order. finalize , payload) . await {
393- Ok ( res ) => {
342+ Ok ( x ) => {
394343 drop ( order) ;
395- bytes = res . into_body ( ) ;
396- order = serde_json:: from_slice ( & bytes ) ?;
344+ res = x ;
345+ order = serde_json:: from_slice ( res . body ( ) ) ?;
397346 }
398347 Err ( err) => {
399348 if !err. to_string ( ) . contains ( "orderNotReady" ) {
@@ -403,25 +352,20 @@ where
403352 }
404353 } ;
405354
406- let mut retry_after = DEFAULT_RETRY_INTERVAL ;
355+ let mut tries = 10 ;
407356
408- while order. status == OrderStatus :: Processing {
409- sleep ( retry_after) . await ;
357+ while order. status == OrderStatus :: Processing && tries > 0 {
358+ tries -= 1 ;
359+ wait_for_retry ( & res) . await ;
410360
411- let res = self . post ( & order_url, & [ ] ) . await ?;
412- retry_after = res
413- . headers ( )
414- . get ( http:: header:: RETRY_AFTER )
415- . and_then ( parse_retry_after)
416- . unwrap_or ( DEFAULT_RETRY_INTERVAL ) ;
417361 drop ( order) ;
418- bytes = res . into_body ( ) ;
419- order = serde_json:: from_slice ( & bytes ) ?;
362+ res = self . post ( & order_url , b"" ) . await ? ;
363+ order = serde_json:: from_slice ( res . body ( ) ) ?;
420364 }
421365
422- let certificate = order. certificate . ok_or ( anyhow ! ( "certifcate not ready" ) ) ?;
366+ let certificate = order. certificate . ok_or ( anyhow ! ( "certificate not ready" ) ) ?;
423367
424- let chain = self . post ( & certificate, & [ ] ) . await ?. into_body ( ) ;
368+ let chain = self . post ( & certificate, b"" ) . await ?. into_body ( ) ;
425369
426370 // FIXME: avoid reallocation from std::vec::Vec.
427371 let x509 = Vec :: from_iter ( X509 :: stack_from_pem ( & chain) ?) ;
@@ -453,8 +397,19 @@ where
453397
454398 result?;
455399
456- let is_ready = |x : & types:: Authorization | x. status != AuthorizationStatus :: Pending ;
457- let result = self . poll ( & url, b"" , 5 , is_ready) . await ?;
400+ let mut tries = 10 ;
401+
402+ let result = loop {
403+ let res = self . post ( & url, b"" ) . await ?;
404+ let result: types:: Authorization = serde_json:: from_slice ( res. body ( ) ) ?;
405+
406+ if result. status != AuthorizationStatus :: Pending || tries == 0 {
407+ break result;
408+ }
409+
410+ tries -= 1 ;
411+ wait_for_retry ( & res) . await ;
412+ } ;
458413
459414 ngx_log_debug ! (
460415 self . log. as_ptr( ) ,
@@ -476,14 +431,9 @@ where
476431 identifier : & Identifier < & str > ,
477432 challenge : & types:: Challenge ,
478433 ) -> Result < ( ) > {
479- fn is_ready ( x : & types:: Challenge ) -> bool {
480- !matches ! (
481- x. status,
482- ChallengeStatus :: Pending | ChallengeStatus :: Processing ,
483- )
484- }
434+ let res = self . post ( & challenge. url , b"" ) . await ?;
435+ let result: types:: Challenge = serde_json:: from_slice ( res. body ( ) ) ?;
485436
486- let result: types:: Challenge = self . post_json ( & challenge. url , b"" ) . await ?;
487437 // Previous challenge result is still valid.
488438 // Should not happen as we already skip valid authorizations.
489439 if result. status == ChallengeStatus :: Valid {
@@ -494,11 +444,25 @@ where
494444 . ok_or ( anyhow ! ( "no solver for {:?}" , challenge. kind) ) ?
495445 . register ( ctx, identifier, challenge) ?;
496446
497- let result: types:: Challenge = self . post_json ( & challenge. url , b"{}" ) . await ?;
498- let result = if is_ready ( & result) {
499- result
500- } else {
501- self . poll ( & challenge. url , b"" , 10 , is_ready) . await ?
447+ // "{}" in request payload initiates the challenge, "" checks the status.
448+ let mut payload: & [ u8 ] = b"{}" ;
449+ let mut tries = 10 ;
450+
451+ let result = loop {
452+ let res = self . post ( & challenge. url , payload) . await ?;
453+ let result: types:: Challenge = serde_json:: from_slice ( res. body ( ) ) ?;
454+
455+ if !matches ! (
456+ result. status,
457+ ChallengeStatus :: Pending | ChallengeStatus :: Processing ,
458+ ) || tries == 0
459+ {
460+ break result;
461+ }
462+
463+ tries -= 1 ;
464+ payload = b"" ;
465+ wait_for_retry ( & res) . await ;
502466 } ;
503467
504468 if result. status != ChallengeStatus :: Valid {
@@ -547,7 +511,17 @@ pub fn make_certificate_request(
547511 Ok ( req. build ( ) )
548512}
549513
550- pub fn parse_retry_after ( val : & http:: HeaderValue ) -> Option < Duration > {
514+ /// Waits until the next retry attempt is allowed.
515+ async fn wait_for_retry < B > ( res : & http:: Response < B > ) {
516+ let retry_after = res
517+ . headers ( )
518+ . get ( http:: header:: RETRY_AFTER )
519+ . and_then ( parse_retry_after)
520+ . unwrap_or ( DEFAULT_RETRY_INTERVAL ) ;
521+ sleep ( retry_after) . await
522+ }
523+
524+ fn parse_retry_after ( val : & http:: HeaderValue ) -> Option < Duration > {
551525 let val = val. to_str ( ) . ok ( ) ?;
552526
553527 // Retry-After: <http-date>
0 commit comments