diff options
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/lib.rs | 40 |
2 files changed, 39 insertions, 3 deletions
@@ -1,6 +1,6 @@ [package] name = "mailparse" -version = "0.1.1" +version = "0.2.0" authors = ["Kartikaya Gupta <kats@seldon.staktrace.com>"] description = "A simple parser for MIME e-mail messages" documentation = "https://staktrace.github.io/mailparse/target/doc/mailparse/" @@ -375,6 +375,11 @@ pub trait MailHeaderMap { /// ``` fn get_first_value(&self, key: &str) -> Result<Option<String>, MailParseError>; + /// Same as get_first_value, but does a case-insensitive search for the header. + /// According to the spec the mail headers are supposed to be case-sensitive, + /// but in real-world scenarios that's not always the case. + fn get_first_value_ci(&self, key: &str) -> Result<Option<String>, MailParseError>; + /// Look through the list of headers and return the values of all headers /// matching the provided key. Returns an empty vector if no matching headers /// were found. The order of the returned values is the same as the order @@ -391,6 +396,11 @@ pub trait MailHeaderMap { /// vec!["Value1".to_string(), "Value2".to_string()]); /// ``` fn get_all_values(&self, key: &str) -> Result<Vec<String>, MailParseError>; + + /// Same as get_all_values, but does a case-insensitive search for the header. + /// According to the spec the mail headers are supposed to be case-sensitive, + /// but in real-world scenarios that's not always the case. + fn get_all_values_ci(&self, key: &str) -> Result<Vec<String>, MailParseError>; } impl<'a> MailHeaderMap for Vec<MailHeader<'a>> { @@ -403,6 +413,16 @@ impl<'a> MailHeaderMap for Vec<MailHeader<'a>> { Ok(None) } + fn get_first_value_ci(&self, key: &str) -> Result<Option<String>, MailParseError> { + let lower_key = key.to_lowercase(); + for x in self { + if try!(x.get_key()).to_lowercase() == lower_key { + return x.get_value().map(|v| Some(v)); + } + } + Ok(None) + } + fn get_all_values(&self, key: &str) -> Result<Vec<String>, MailParseError> { let mut values: Vec<String> = Vec::new(); for x in self { @@ -412,6 +432,17 @@ impl<'a> MailHeaderMap for Vec<MailHeader<'a>> { } Ok(values) } + + fn get_all_values_ci(&self, key: &str) -> Result<Vec<String>, MailParseError> { + let lower_key = key.to_lowercase(); + let mut values: Vec<String> = Vec::new(); + for x in self { + if try!(x.get_key()).to_lowercase() == lower_key { + values.push(try!(x.get_value())); + } + } + Ok(values) + } } /// Parses all the headers from the raw data given. @@ -563,7 +594,7 @@ impl<'a> ParsedMail<'a> { /// assert_eq!(p.get_body().unwrap(), "This is the body"); /// ``` pub fn get_body(&self) -> Result<String, MailParseError> { - let transfer_coding = try!(self.headers.get_first_value("Content-Transfer-Encoding")) + let transfer_coding = try!(self.headers.get_first_value_ci("Content-Transfer-Encoding")) .map(|s| s.to_lowercase()); let decoded = match transfer_coding.unwrap_or(String::new()).as_ref() { "base64" => { @@ -625,7 +656,7 @@ impl<'a> ParsedMail<'a> { /// ``` pub fn parse_mail(raw_data: &[u8]) -> Result<ParsedMail, MailParseError> { let (headers, ix_body) = try!(parse_headers(raw_data)); - let ctype = match try!(headers.get_first_value("Content-Type")) { + let ctype = match try!(headers.get_first_value_ci("Content-Type")) { Some(s) => try!(parse_content_type(&s)), None => { ParsedContentType { @@ -928,5 +959,10 @@ mod tests { let mail = parse_mail(b"Content-Type: text/plain; charset=x-unknown\r\n\r\nhello world") .unwrap(); assert_eq!(mail.get_body().unwrap(), "hello world"); + + let mail = parse_mail(b"ConTENT-tyPE: text/html\r\n\r\nhello world") + .unwrap(); + assert_eq!(mail.ctype.mimetype, "text/html"); + assert_eq!(mail.get_body().unwrap(), "hello world"); } } |