From cc72a267f0b14f05802aa40614c27767bb300582 Mon Sep 17 00:00:00 2001 From: Nick Spain Date: Mon, 16 Sep 2024 09:03:17 +1000 Subject: [PATCH] First pass at retrying bad nonce errors I'm not sure I'm super happy with this solution but it does minimise the amount of interface I have to change. I think the copying is okay because it only happens when we get a bad nonce error which should be pretty uncommon (unless you're running against pebble but that'll only be for testing). --- src/lib.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index f7fffee..33375b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -495,6 +495,44 @@ impl Client { nonce: Option, signer: &impl Signer, url: &str, + ) -> Result { + let mut retries = 3; + + let mut nonce = nonce; + loop { + let response = self.inner_post(payload, nonce.clone(), signer, url).await?; + if response.parts.status == StatusCode::BAD_REQUEST { + let parts = response.parts.clone(); + let body = response.body().await.map_err(Error::Other)?; + let problem: Problem = serde_json::from_slice(&body)?; + if problem + .r#type + .map(|t| t == "urn:ietf:params:acme:error:badNonce") + .unwrap_or_default() + { + retries -= 1; + if retries != 0 { + nonce = Some(self.nonce(None).await?); + continue; + } + } + + let response = BytesResponse { + parts, + body: Box::new(StaticBody { bytes: body }), + }; + return Ok(response); + } + return Ok(response); + } + } + + async fn inner_post( + &self, + payload: Option<&impl Serialize>, + nonce: Option, + signer: &impl Signer, + url: &str, ) -> Result { let nonce = self.nonce(nonce).await?; let body = JoseJson::new(payload, signer.header(Some(&nonce), url), signer)?; @@ -789,6 +827,17 @@ where } } +struct StaticBody { + bytes: Bytes, +} + +#[async_trait] +impl BytesBody for StaticBody { + async fn into_bytes(&mut self) -> Result> { + Ok(self.bytes.to_owned()) + } +} + /// Object safe body trait #[async_trait] pub trait BytesBody: Send {