Skip to main content

http_msgsign_draft/digest/
header.rs

1use crate::errors::InvalidDigestDataFormat;
2use base64::Engine;
3use http::HeaderMap;
4use http_content_digest::DigestHash;
5use http_content_digest::errors::ExtractHeaderError;
6
7pub const DIGEST: &str = "digest";
8
9#[derive(Debug, Clone)]
10pub(crate) struct Digest {
11    pub alg: String,
12    pub digest: DigestHash,
13}
14
15impl Digest {
16    //noinspection DuplicatedCode
17    pub fn from_header(map: &HeaderMap) -> Result<Digest, ExtractHeaderError> {
18        let header = match map.get(DIGEST).map(|header| header.to_str()) {
19            Some(Ok(header)) => header,
20            Some(Err(e)) => return Err(ExtractHeaderError::FailedToStr(e)),
21            None => {
22                return Err(ExtractHeaderError::NoExist {
23                    header_name: DIGEST,
24                });
25            }
26        };
27
28        // `Digest` can specify multiple algorithms, but this is not permitted in `draft-cavage-http-signatures-12`.
29        // This is because, unlike Content-Digest,
30        // there is no way to distinguish the `=` that appears when the digest value is Base64-encoded from `<alg_name>=<digest_value>`.
31        let Some((alg, digest)) = header.split_once("=") else {
32            return Err(InvalidDigestDataFormat {
33                reason: "no `=` found"
34            })?;
35        };
36
37        let digest = base64::engine::general_purpose::STANDARD.decode(digest)?;
38
39        Ok(Self {
40            alg: alg.to_string(),
41            digest: DigestHash::new(digest),
42        })
43    }
44}