From 386bc3a48ca2d2c417d4be5974713e5e60a2d827 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Sat, 24 Jun 2023 21:16:53 +0200 Subject: [PATCH] Add Content-MD5 header --- src/common/content_md5.rs | 62 +++++++++++++++++++++++++++++++++++++++ src/common/mod.rs | 2 ++ 2 files changed, 64 insertions(+) create mode 100644 src/common/content_md5.rs diff --git a/src/common/content_md5.rs b/src/common/content_md5.rs new file mode 100644 index 00000000..a805953d --- /dev/null +++ b/src/common/content_md5.rs @@ -0,0 +1,62 @@ +use std::convert::TryInto; +use {Header, HeaderValue}; + +/// `Content-MD5` header, defined in +/// [RFC1864](https://datatracker.ietf.org/doc/html/rfc1864) +/// +/// ## ABNF +/// +/// ```text +/// Content-Length = 1*DIGIT +/// ``` +/// +/// ## Example values +/// +/// * `Q2hlY2sgSW50ZWdyaXR5IQ==` +/// +/// # Example +/// +/// ``` +/// # extern crate headers; +/// # extern crate http; +/// # extern crate headers_core; +/// use http::HeaderValue; +/// use headers::ContentMd5; +/// use headers_core::Header; +/// +/// let value = HeaderValue::from_static("Q2hlY2sgSW50ZWdyaXR5IQ=="); +/// +/// let md5 = ContentMd5::decode(&mut [value].into_iter()).unwrap(); +/// assert_eq!(md5.0, "Check Integrity!".as_bytes()) +/// ``` +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct ContentMd5(pub [u8; 16]); + +static CONTENT_MD5: ::http::header::HeaderName = + ::http::header::HeaderName::from_static("content-md5"); + +impl Header for ContentMd5 { + fn name() -> &'static ::http::header::HeaderName { + &CONTENT_MD5 + } + + fn decode<'i, I: Iterator>(values: &mut I) -> Result { + let value = values.next().ok_or_else(::Error::invalid)?; + + // Ensure base64 encoded length fits the expected MD5 digest length. + if value.len() < 22 || value.len() > 24 { + return Err(::Error::invalid()); + } + + let value = value.to_str().map_err(|_| ::Error::invalid())?; + let vec = base64::decode(value).map_err(|_| ::Error::invalid())?; + Ok(Self(vec[..16].try_into().map_err(|_| ::Error::invalid())?)) + } + + fn encode>(&self, values: &mut E) { + let encoded = base64::encode(self.0); + if let Ok(value) = HeaderValue::from_str(&encoded) { + values.extend(std::iter::once(value)); + } + } +} diff --git a/src/common/mod.rs b/src/common/mod.rs index 2237ae8e..a0720701 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -29,6 +29,7 @@ pub use self::content_encoding::ContentEncoding; //pub use self::content_language::ContentLanguage; pub use self::content_length::ContentLength; pub use self::content_location::ContentLocation; +pub use self::content_md5::ContentMd5; pub use self::content_range::ContentRange; pub use self::content_type::ContentType; pub use self::cookie::Cookie; @@ -149,6 +150,7 @@ mod content_encoding; //mod content_language; mod content_length; mod content_location; +mod content_md5; mod content_range; mod content_type; mod cookie;