http_content_digest/digest/
request.rs1use bytes::Bytes;
2use http::Request;
3use http_body_util::combinators::BoxBody;
4use http_body_util::{BodyExt, Full};
5
6use super::ContentDigest;
7use crate::digest::header::{self, CONTENT_DIGEST};
8use crate::digest::{BodyDigest, ContentHasher};
9use crate::errors::DigestError;
10
11impl<B> ContentDigest for Request<B>
12where
13 B: http_body::Body + Send,
14 B::Data: Send,
15{
16 type Error = DigestError;
17 type Content = Request<BoxBody<Bytes, DigestError>>;
18
19 async fn digest<H: ContentHasher>(self) -> Result<Self::Content, Self::Error> {
20 let (mut parts, body) = self.into_parts();
21 let actual = body.digest::<H>().await.map_err(|_e| DigestError::Body)?;
22
23 let body = Full::new(actual.body)
24 .map_err(|infallible| match infallible {})
25 .boxed();
26
27 parts.headers.insert(
28 CONTENT_DIGEST,
29 format!("{}={}", H::DIGEST_ALG, actual.digest.to_base64().to_sfv())
30 .parse()
31 .unwrap(),
32 );
33
34 Ok(Request::from_parts(parts, body))
35 }
36
37 async fn verify_digest<H: ContentHasher>(self) -> Result<Self::Content, Self::Error> {
38 let (parts, body) = self.into_parts();
39 let Some(expect) = header::ContentDigest::from_header(&parts.headers)?.find(H::DIGEST_ALG)
40 else {
41 return Err(DigestError::AlgorithmNotSupported);
42 };
43
44 let actual = body.digest::<H>().await.map_err(|_e| DigestError::Body)?;
45
46 if actual.digest != expect {
47 return Err(DigestError::Mismatch);
48 }
49
50 let body = Full::new(actual.body)
51 .map_err(|infallible| match infallible {})
52 .boxed();
53
54 Ok(Request::from_parts(parts, body))
55 }
56}