Retry bad nonce errors after generating a new nonce
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
This commit is contained in:
parent
643c5859a6
commit
e83836b719
44
src/lib.rs
44
src/lib.rs
|
@ -490,6 +490,43 @@ 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 {
|
||||
// Retrieve the new nonce. If it isn't there (it
|
||||
// should be, the spec requires it) then we will
|
||||
// manually refresh a new one in `post_attempt`
|
||||
// due to `nonce` being `None` but getting it from
|
||||
// the response saves us making that request.
|
||||
nonce = nonce_from_response(&response);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(BytesResponse {
|
||||
parts: response.parts,
|
||||
body: Box::new(body),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async fn post_attempt(
|
||||
&self,
|
||||
payload: Option<&impl Serialize>,
|
||||
nonce: Option<String>,
|
||||
|
@ -789,6 +826,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 {
|
||||
|
|
Loading…
Reference in New Issue