From accf7a59489a4cd6107708d41900142d06544be9 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Wed, 22 Jun 2016 10:09:42 -0400 Subject: Add case-insensitive accessors for headers --- Cargo.toml | 2 +- src/lib.rs | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ba7c4b7..c031570 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mailparse" -version = "0.1.1" +version = "0.2.0" authors = ["Kartikaya Gupta "] description = "A simple parser for MIME e-mail messages" documentation = "https://staktrace.github.io/mailparse/target/doc/mailparse/" diff --git a/src/lib.rs b/src/lib.rs index 091f34d..00e6176 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -375,6 +375,11 @@ pub trait MailHeaderMap { /// ``` fn get_first_value(&self, key: &str) -> Result, 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, 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, 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, MailParseError>; } impl<'a> MailHeaderMap for Vec> { @@ -403,6 +413,16 @@ impl<'a> MailHeaderMap for Vec> { Ok(None) } + fn get_first_value_ci(&self, key: &str) -> Result, 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, MailParseError> { let mut values: Vec = Vec::new(); for x in self { @@ -412,6 +432,17 @@ impl<'a> MailHeaderMap for Vec> { } Ok(values) } + + fn get_all_values_ci(&self, key: &str) -> Result, MailParseError> { + let lower_key = key.to_lowercase(); + let mut values: Vec = 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 { - 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 { 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"); } } -- cgit v1.2.3