@@ -2,7 +2,6 @@ use core::cell::RefCell;
2
2
use core:: ptr:: NonNull ;
3
3
use core:: time:: Duration ;
4
4
use std:: collections:: VecDeque ;
5
- use std:: io;
6
5
use std:: string:: { String , ToString } ;
7
6
8
7
use anyhow:: { anyhow, Result } ;
@@ -30,7 +29,6 @@ pub mod types;
30
29
const DEFAULT_RETRY_INTERVAL : Duration = Duration :: from_secs ( 1 ) ;
31
30
static REPLAY_NONCE : http:: HeaderName = http:: HeaderName :: from_static ( "replay-nonce" ) ;
32
31
33
- #[ derive( Debug ) ]
34
32
pub struct NewCertificateOutput {
35
33
pub chain : Bytes ,
36
34
pub x509 : Vec < X509 > ,
@@ -64,12 +62,12 @@ impl NoncePool {
64
62
}
65
63
66
64
pub fn add ( & self , nonce : String ) {
67
- self . 0 . borrow_mut ( ) . push_back ( nonce. to_string ( ) ) ;
65
+ self . 0 . borrow_mut ( ) . push_back ( nonce) ;
68
66
}
69
67
70
68
pub fn add_from_response < T > ( & self , res : & http:: Response < T > ) {
71
69
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 ( ) ) ;
73
71
}
74
72
}
75
73
}
@@ -130,51 +128,6 @@ where
130
128
. map ( String :: from)
131
129
}
132
130
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
-
178
131
pub async fn get ( & self , url : & Uri ) -> Result < http:: Response < Bytes > > {
179
132
let req = http:: Request :: builder ( )
180
133
. uri ( url)
@@ -238,12 +191,6 @@ where
238
191
. ok_or ( anyhow ! ( "no nonce in response" ) ) ?
239
192
. to_string ( ) ;
240
193
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
-
247
194
let err: types:: Problem = serde_json:: from_slice ( res. body ( ) ) ?;
248
195
249
196
let retriable = matches ! (
@@ -257,7 +204,8 @@ where
257
204
}
258
205
259
206
fails += 1 ;
260
- sleep ( retry_after) . await ;
207
+
208
+ wait_for_retry ( & res) . await ;
261
209
ngx_log_debug ! ( self . log. as_ptr( ) , "retrying: {} of 3" , fails + 1 ) ;
262
210
} ;
263
211
@@ -339,7 +287,8 @@ where
339
287
340
288
let mut authorizations: Vec < ( http:: Uri , types:: Authorization ) > = Vec :: new ( ) ;
341
289
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 ( ) ) ?;
343
292
344
293
authorization
345
294
. challenges
@@ -379,8 +328,8 @@ where
379
328
self . do_authorization ( & order, url, authorization) . await ?;
380
329
}
381
330
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 ( ) ) ?;
384
333
385
334
if order. status != OrderStatus :: Ready {
386
335
anyhow:: bail!( "not ready" ) ;
@@ -390,10 +339,10 @@ where
390
339
let payload = std:: format!( r#"{{"csr":"{}"}}"# , crate :: jws:: base64url( csr) ) ;
391
340
392
341
match self . post ( & order. finalize , payload) . await {
393
- Ok ( res ) => {
342
+ Ok ( x ) => {
394
343
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 ( ) ) ?;
397
346
}
398
347
Err ( err) => {
399
348
if !err. to_string ( ) . contains ( "orderNotReady" ) {
@@ -403,25 +352,20 @@ where
403
352
}
404
353
} ;
405
354
406
- let mut retry_after = DEFAULT_RETRY_INTERVAL ;
355
+ let mut tries = 10 ;
407
356
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 ;
410
360
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 ) ;
417
361
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 ( ) ) ?;
420
364
}
421
365
422
- let certificate = order. certificate . ok_or ( anyhow ! ( "certifcate not ready" ) ) ?;
366
+ let certificate = order. certificate . ok_or ( anyhow ! ( "certificate not ready" ) ) ?;
423
367
424
- let chain = self . post ( & certificate, & [ ] ) . await ?. into_body ( ) ;
368
+ let chain = self . post ( & certificate, b"" ) . await ?. into_body ( ) ;
425
369
426
370
// FIXME: avoid reallocation from std::vec::Vec.
427
371
let x509 = Vec :: from_iter ( X509 :: stack_from_pem ( & chain) ?) ;
@@ -453,8 +397,19 @@ where
453
397
454
398
result?;
455
399
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
+ } ;
458
413
459
414
ngx_log_debug ! (
460
415
self . log. as_ptr( ) ,
@@ -476,14 +431,9 @@ where
476
431
identifier : & Identifier < & str > ,
477
432
challenge : & types:: Challenge ,
478
433
) -> 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 ( ) ) ?;
485
436
486
- let result: types:: Challenge = self . post_json ( & challenge. url , b"" ) . await ?;
487
437
// Previous challenge result is still valid.
488
438
// Should not happen as we already skip valid authorizations.
489
439
if result. status == ChallengeStatus :: Valid {
@@ -494,11 +444,25 @@ where
494
444
. ok_or ( anyhow ! ( "no solver for {:?}" , challenge. kind) ) ?
495
445
. register ( ctx, identifier, challenge) ?;
496
446
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 ;
502
466
} ;
503
467
504
468
if result. status != ChallengeStatus :: Valid {
@@ -547,7 +511,17 @@ pub fn make_certificate_request(
547
511
Ok ( req. build ( ) )
548
512
}
549
513
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 > {
551
525
let val = val. to_str ( ) . ok ( ) ?;
552
526
553
527
// Retry-After: <http-date>
0 commit comments