Skip to content

Commit

Permalink
Retry bad nonce errors after generating a new nonce
Browse files Browse the repository at this point in the history
Retry `urn:ietf:params:acme:error:badNonce` errors as they are defined
as retryable[^1]. Requests failing with a bad nonce error will be
retried three time retried three times before the failure is returned
to the caller.

This implenments the `BytesBody` trait for `bytes::Bytes` as we need
to consume the response body to be able check if the failure was due
to a bad nonce which required parsing the body. The body is only
consumed if the response status is bad request, in all other cases the
body is still lazily consumable.

[^1]: https://datatracker.ietf.org/doc/html/rfc8555/#section-6.5
  • Loading branch information
Nick Spain committed Sep 16, 2024
1 parent 643c585 commit 7708c8e
Showing 1 changed file with 40 additions and 0 deletions.
40 changes: 40 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,39 @@ impl Client {
}

async fn post(
&self,
payload: Option<&impl Serialize>,
mut nonce: Option<String>,
signer: &impl Signer,
url: &str,
) -> Result<BytesResponse, Error> {
let mut retries = 3;
loop {
let mut response = self
.post_attempt(payload, nonce.clone(), signer, url)
.await?;
if response.parts.status != StatusCode::BAD_REQUEST {
return Ok(response);
}
let body = response.body.into_bytes().await.map_err(Error::Other)?;
let problem = serde_json::from_slice::<Problem>(&body)?;
if let Some("urn:ietf:params:acme:error:badNonce") = problem.r#type.as_deref() {
retries -= 1;
if retries != 0 {
// Set to `None` so on the next run it'll get regenerated.
nonce = None;
continue;
}
}

return Ok(BytesResponse {
parts: response.parts,
body: Box::new(body),
});
}
}

async fn post_attempt(
&self,
payload: Option<&impl Serialize>,
nonce: Option<String>,
Expand Down Expand Up @@ -789,6 +822,13 @@ where
}
}

#[async_trait]
impl BytesBody for Bytes {
async fn into_bytes(&mut self) -> Result<Bytes, Box<dyn StdError + Send + Sync + 'static>> {
Ok(self.to_owned())
}
}

/// Object safe body trait
#[async_trait]
pub trait BytesBody: Send {
Expand Down

0 comments on commit 7708c8e

Please sign in to comment.