media_type.rs (2368B)
1 //! Canonical Blossom media-type values. 2 //! 3 //! [`MediaType`] rejects wildcards and duplicate parameters, then emits a 4 //! deterministic parameter order. Parsing describes declared media type only; 5 //! callers remain responsible for sniffing or applying content policy where 6 //! untrusted bytes require it. 7 8 #[cfg(feature = "serde")] 9 use alloc::string::String; 10 use alloc::{collections::BTreeMap, vec::Vec}; 11 use core::{fmt, str::FromStr}; 12 use mediatype::{MediaTypeBuf, ReadParams}; 13 14 use crate::Error; 15 16 #[derive(Clone, Debug, PartialEq, Eq, Hash)] 17 pub struct MediaType(MediaTypeBuf); 18 19 impl MediaType { 20 pub fn parse(value: &str) -> Result<Self, Error> { 21 let parsed = MediaTypeBuf::from_str(value).map_err(|_| Error::InvalidMediaType)?; 22 if parsed.as_str() != value || parsed.ty().as_str() == "*" || parsed.subty().as_str() == "*" 23 { 24 return Err(Error::InvalidMediaType); 25 } 26 let canonical = parsed.canonicalize(); 27 let mut unique_params = BTreeMap::new(); 28 for (name, value) in canonical.params() { 29 if unique_params.insert(name, value).is_some() { 30 return Err(Error::InvalidMediaType); 31 } 32 } 33 let ordered_params = unique_params.into_iter().collect::<Vec<_>>(); 34 Ok(Self(MediaTypeBuf::from_parts( 35 canonical.ty(), 36 canonical.subty(), 37 canonical.suffix(), 38 &ordered_params, 39 ))) 40 } 41 42 pub fn as_str(&self) -> &str { 43 self.0.as_str() 44 } 45 } 46 47 impl fmt::Display for MediaType { 48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 49 f.write_str(self.as_str()) 50 } 51 } 52 53 impl FromStr for MediaType { 54 type Err = Error; 55 56 fn from_str(value: &str) -> Result<Self, Self::Err> { 57 Self::parse(value) 58 } 59 } 60 61 #[cfg(feature = "serde")] 62 impl serde::Serialize for MediaType { 63 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 64 where 65 S: serde::Serializer, 66 { 67 serializer.serialize_str(self.as_str()) 68 } 69 } 70 71 #[cfg(feature = "serde")] 72 impl<'de> serde::Deserialize<'de> for MediaType { 73 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 74 where 75 D: serde::Deserializer<'de>, 76 { 77 let value = String::deserialize(deserializer)?; 78 Self::parse(&value).map_err(serde::de::Error::custom) 79 } 80 }