Skip to content

Commit 2bb0235

Browse files
committed
Adds a MIME parser and serializer following WHATWAG algorithm
Follows https://mimesniff.spec.whatwg.org/ Runs the MIME parsing web platform tests Uses a Vec instead of a HashMap to store the MIME parameters to keep their order
1 parent b9129e4 commit 2bb0235

File tree

2 files changed

+482
-190
lines changed

2 files changed

+482
-190
lines changed

src/mime/mod.rs

Lines changed: 19 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ mod parse;
88
pub use constants::*;
99

1010
use std::borrow::Cow;
11-
use std::collections::HashMap;
1211
use std::fmt::{self, Debug, Display};
1312
use std::option;
1413
use std::str::FromStr;
@@ -18,6 +17,15 @@ use crate::headers::{HeaderValue, ToHeaderValues};
1817
use infer::Infer;
1918

2019
/// An IANA media type.
20+
///
21+
/// ```
22+
/// use http_types::Mime;
23+
/// use std::str::FromStr;
24+
///
25+
/// let mime = Mime::from_str("text/html;charset=utf-8").unwrap();
26+
/// assert_eq!(mime.essence(), "text/html");
27+
/// assert_eq!(mime.param("charset").unwrap(), "utf-8");
28+
/// ```
2129
// NOTE: we cannot statically initialize Strings with values yet, so we keep dedicated static
2230
// fields for the static strings.
2331
#[derive(Clone)]
@@ -39,16 +47,7 @@ impl Mime {
3947
Some(info) => info.mime,
4048
None => crate::bail!("Could not sniff the mime type"),
4149
};
42-
43-
Ok(Self {
44-
essence: mime,
45-
static_essence: None,
46-
basetype: String::new(), // TODO: fill in.
47-
subtype: String::new(), // TODO: fill in.
48-
static_basetype: None, // TODO: fill in
49-
static_subtype: None,
50-
params: None, // TODO: fill in.
51-
})
50+
Mime::from_str(&mime)
5251
}
5352

5453
/// Access the Mime's `type` value.
@@ -87,7 +86,9 @@ impl Mime {
8786
self.params
8887
.as_ref()
8988
.map(|inner| match inner {
90-
ParamKind::Map(hm) => hm.get(&name),
89+
ParamKind::Vec(v) => v
90+
.iter()
91+
.find_map(|(k, v)| if k == &name { Some(v) } else { None }),
9192
ParamKind::Utf8 => match name {
9293
ParamName(Cow::Borrowed("charset")) => Some(&ParamValue(Cow::Borrowed("utf8"))),
9394
_ => None,
@@ -99,27 +100,7 @@ impl Mime {
99100

100101
impl Display for Mime {
101102
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102-
if let Some(essence) = self.static_essence {
103-
write!(f, "{}", essence)?
104-
} else {
105-
write!(f, "{}", &self.essence)?
106-
}
107-
if let Some(params) = &self.params {
108-
match params {
109-
ParamKind::Utf8 => write!(f, "; charset=utf-8")?,
110-
ParamKind::Map(params) => {
111-
assert!(!params.is_empty());
112-
write!(f, "; ")?;
113-
for (i, (key, value)) in params.iter().enumerate() {
114-
write!(f, "{}={}", key, value)?;
115-
if i != params.len() - 1 {
116-
write!(f, ",")?;
117-
}
118-
}
119-
}
120-
}
121-
}
122-
Ok(())
103+
parse::format(self, f)
123104
}
124105
}
125106

@@ -136,20 +117,11 @@ impl Debug for Mime {
136117
impl FromStr for Mime {
137118
type Err = crate::Error;
138119

139-
/// Create a new `HeaderName`.
120+
/// Create a new `Mime`.
140121
///
141-
/// This checks it's valid ASCII, and lowercases it.
122+
/// Follows the [WHATWG MIME parsing algorithm](https://mimesniff.spec.whatwg.org/#parsing-a-mime-type).
142123
fn from_str(s: &str) -> Result<Self, Self::Err> {
143-
crate::ensure!(s.is_ascii(), "String slice should be valid ASCII");
144-
Ok(Self {
145-
essence: s.to_ascii_lowercase(),
146-
static_essence: None,
147-
basetype: String::new(), // TODO: fill in.
148-
subtype: String::new(), // TODO: fill in.
149-
static_basetype: None, // TODO: fill in
150-
static_subtype: None, // TODO: fill in
151-
params: None, // TODO: fill in.
152-
})
124+
parse::parse(s)
153125
}
154126
}
155127

@@ -210,7 +182,7 @@ impl<'a> PartialEq<&'a str> for ParamValue {
210182

211183
impl PartialEq<str> for ParamValue {
212184
fn eq(&self, other: &str) -> bool {
213-
&self.0 == other
185+
self.0 == other
214186
}
215187
}
216188

@@ -219,14 +191,5 @@ impl PartialEq<str> for ParamValue {
219191
#[derive(Debug, Clone)]
220192
pub(crate) enum ParamKind {
221193
Utf8,
222-
Map(HashMap<ParamName, ParamValue>),
223-
}
224-
225-
impl ParamKind {
226-
pub(crate) fn unwrap(&mut self) -> &mut HashMap<ParamName, ParamValue> {
227-
match self {
228-
Self::Map(t) => t,
229-
_ => panic!("Unwrapped a ParamKind::utf8"),
230-
}
231-
}
194+
Vec(Vec<(ParamName, ParamValue)>),
232195
}

0 commit comments

Comments
 (0)