http_types_rs/mime/
mod.rs1mod constants;
6mod parse;
7
8pub use constants::*;
9
10use std::borrow::Cow;
11use std::fmt::{self, Debug, Display};
12use std::option;
13use std::str::FromStr;
14
15use crate::headers::{HeaderValue, ToHeaderValues};
16
17use infer::Infer;
18
19#[derive(Clone, PartialEq, Eq, Debug)]
32pub struct Mime {
33 pub(crate) essence: Cow<'static, str>,
34 pub(crate) basetype: Cow<'static, str>,
35 pub(crate) subtype: Cow<'static, str>,
36 pub(crate) is_utf8: bool,
39 pub(crate) params: Vec<(ParamName, ParamValue)>,
40}
41
42impl Mime {
43 pub fn sniff(bytes: &[u8]) -> crate::Result<Self> {
45 let info = Infer::new();
46 let mime = match info.get(bytes) {
47 Some(info) => info.mime_type(),
48 None => crate::bail!("Could not sniff the mime type"),
49 };
50 Mime::from_str(mime)
51 }
52
53 pub fn from_extension(extension: impl AsRef<str>) -> Option<Self> {
55 match extension.as_ref() {
56 "7z" => Some(SEVENZIP),
57 "atom" => Some(ATOM),
58 "avi" => Some(AVI),
59 "bin" | "exe" | "dll" | "iso" | "img" => Some(BYTE_STREAM),
60 "bmp" => Some(BMP),
61 "css" => Some(CSS),
62 "html" => Some(HTML),
63 "ico" => Some(ICO),
64 "js" | "mjs" | "jsonp" => Some(JAVASCRIPT),
65 "json" => Some(JSON),
66 "m4a" => Some(M4A),
67 "mid" | "midi" | "kar" => Some(MIDI),
68 "mp3" => Some(MP3),
69 "mp4" => Some(MP4),
70 "mpeg" | "mpg" => Some(MPEG),
71 "ogg" => Some(OGG),
72 "otf" => Some(OTF),
73 "rss" => Some(RSS),
74 "svg" | "svgz" => Some(SVG),
75 "ttf" => Some(TTF),
76 "txt" => Some(PLAIN),
77 "wasm" => Some(WASM),
78 "webm" => Some(WEBM),
79 "webp" => Some(WEBP),
80 "woff" => Some(WOFF),
81 "woff2" => Some(WOFF2),
82 "xml" => Some(XML),
83 "zip" => Some(ZIP),
84 _ => None,
85 }
86 }
87
88 pub fn basetype(&self) -> &str {
93 &self.basetype
94 }
95
96 pub fn subtype(&self) -> &str {
98 &self.subtype
99 }
100
101 pub fn essence(&self) -> &str {
103 &self.essence
104 }
105
106 pub fn param(&self, name: impl Into<ParamName>) -> Option<&ParamValue> {
108 let name: ParamName = name.into();
109 if name.as_str() == "charset" && self.is_utf8 {
110 return Some(&ParamValue(Cow::Borrowed("utf-8")));
111 }
112
113 self.params.iter().find(|(k, _)| k == &name).map(|(_, v)| v)
114 }
115
116 pub fn remove_param(&mut self, name: impl Into<ParamName>) -> Option<ParamValue> {
118 let name: ParamName = name.into();
119 if name.as_str() == "charset" && self.is_utf8 {
120 self.is_utf8 = false;
121 return Some(ParamValue(Cow::Borrowed("utf-8")));
122 }
123 self.params.iter().position(|(k, _)| k == &name).map(|pos| self.params.remove(pos).1)
124 }
125
126 pub fn subset_eq(&self, other: &Mime) -> bool {
147 if other.basetype() != "*" && self.basetype() != other.basetype() {
148 return false;
149 }
150 if other.subtype() != "*" && self.subtype() != other.subtype() {
151 return false;
152 }
153 for (name, value) in other.params.iter() {
154 if !self.param(name.clone()).map(|v| v == value).unwrap_or(false) {
155 return false;
156 }
157 }
158 true
159 }
160}
161
162impl Display for Mime {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 parse::format(self, f)
165 }
166}
167
168impl FromStr for Mime {
175 type Err = crate::Error;
176
177 fn from_str(s: &str) -> Result<Self, Self::Err> {
181 parse::parse(s)
182 }
183}
184
185impl<'a> From<&'a str> for Mime {
186 fn from(value: &'a str) -> Self {
187 Self::from_str(value).unwrap()
188 }
189}
190
191impl ToHeaderValues for Mime {
192 type Iter = option::IntoIter<HeaderValue>;
193
194 fn to_header_values(&self) -> crate::Result<Self::Iter> {
195 let mime = self.clone();
196 let header: HeaderValue = mime.into();
197
198 Ok(header.to_header_values().unwrap())
200 }
201}
202
203#[derive(Debug, Clone, PartialEq, Eq, Hash)]
205pub struct ParamName(Cow<'static, str>);
206
207impl ParamName {
208 pub fn as_str(&self) -> &str {
210 &self.0
211 }
212}
213
214impl Display for ParamName {
215 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
216 Display::fmt(&self.0, f)
217 }
218}
219
220impl FromStr for ParamName {
221 type Err = crate::Error;
222
223 fn from_str(s: &str) -> Result<Self, Self::Err> {
227 crate::ensure!(s.is_ascii(), "String slice should be valid ASCII");
228 Ok(ParamName(Cow::Owned(s.to_ascii_lowercase())))
229 }
230}
231
232impl<'a> From<&'a str> for ParamName {
233 fn from(value: &'a str) -> Self {
234 Self::from_str(value).unwrap()
235 }
236}
237
238#[derive(Debug, Clone, PartialEq, Eq, Hash)]
240pub struct ParamValue(Cow<'static, str>);
241
242impl ParamValue {
243 pub fn as_str(&self) -> &str {
245 &self.0
246 }
247}
248
249impl Display for ParamValue {
250 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
251 Display::fmt(&self.0, f)
252 }
253}
254
255impl<'a> PartialEq<&'a str> for ParamValue {
256 fn eq(&self, other: &&'a str) -> bool {
257 &self.0 == other
258 }
259}
260
261impl PartialEq<str> for ParamValue {
262 fn eq(&self, other: &str) -> bool {
263 self.0 == other
264 }
265}