http_content_digest/digest/
response.rs

1use 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}