diff --git a/src/lib.rs b/src/lib.rs index f7fffee..ed63fdc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -490,6 +490,43 @@ impl Client { } async fn post( + &self, + payload: Option<&impl Serialize>, + mut nonce: Option, + signer: &impl Signer, + url: &str, + ) -> Result { + 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::(&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, @@ -789,6 +826,13 @@ where } } +#[async_trait] +impl BytesBody for Bytes { + async fn into_bytes(&mut self) -> Result> { + Ok(self.to_owned()) + } +} + /// Object safe body trait #[async_trait] pub trait BytesBody: Send {