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