From e4f54f9af1685095a42d00a66f7a09db2f9eef37 Mon Sep 17 00:00:00 2001 From: Bruce Guenter Date: Fri, 11 Nov 2016 08:12:42 -0600 Subject: Make MailHeaderMap perform case-insensitive searches The trait MailHeaderMap has two methods for searching headers, normal and case-insensitive. This documentation says: > According to the spec the mail headers are supposed to be > case-sensitive, but in real-world scenarios that's not always the > case. Actually, the spec says nothing that headers supposed to case-sensitive, and historical precedent is to be case-insensitive. Certainly, all the mail processing software I am familiar with (Thunderbird, qmail, ezmlm, and mutt) treat headers as case insensitive. RFC 822 section 3.4.7 says: > When matching any other syntactic unit, case is to be ignored. For > example, the field-names "From", "FROM", "from", and even "FroM" are > semantically equal and should all be treated identically. While RFC 2822 did drop that section (and RFC 5322 didn't restore it), others interpret other parts to indicate case insensitivity. https://stackoverflow.com/a/6143644 > RFC 5322 does actually specify this, but it is very indirect. https://www.gnu.org/software/emacs/manual/html_node/emacs/Mail-Headers.html > Upper and lower case are equivalent in field names. https://nifi.apache.org/docs/nifi-docs/components/org.apache.nifi.processors.email.ExtractEmailHeaders/index.html > NOTE the header key is case insensitive This change makes all header searches case insensitive. --- src/lib.rs | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ee2a038..691d5dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -144,7 +144,7 @@ fn test_find_from_u8() { } impl<'a> MailHeader<'a> { - /// Get the name of the header. Note that header names are case-sensitive. + /// Get the name of the header. Note that header names are case-insensitive. pub fn get_key(&self) -> Result { Ok(try!(encoding::all::ISO_8859_1.decode(self.key, encoding::DecoderTrap::Strict)) .trim() @@ -364,7 +364,7 @@ pub fn parse_header(raw_data: &[u8]) -> Result<(MailHeader, usize), MailParseErr pub trait MailHeaderMap { /// Look through the list of headers and return the value of the first one /// that matches the provided key. It returns Ok(None) if the no matching - /// header was found. + /// header was found. Header names are matched case-insensitively. /// /// # Examples /// ``` @@ -378,15 +378,14 @@ 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. + /// Same as get_first_value. 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 - /// of the matching headers in the message. + /// of the matching headers in the message. Header names are matched + /// case-insensitively. /// /// # Examples /// ``` @@ -400,20 +399,13 @@ pub trait MailHeaderMap { /// ``` 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. + /// Same as get_all_values. fn get_all_values_ci(&self, key: &str) -> Result, MailParseError>; } impl<'a> MailHeaderMap for Vec> { fn get_first_value(&self, key: &str) -> Result, MailParseError> { - for x in self { - if try!(x.get_key()) == key { - return x.get_value().map(|v| Some(v)); - } - } - Ok(None) + self.get_first_value_ci(key) } fn get_first_value_ci(&self, key: &str) -> Result, MailParseError> { @@ -427,13 +419,7 @@ impl<'a> MailHeaderMap for Vec> { } fn get_all_values(&self, key: &str) -> Result, MailParseError> { - let mut values: Vec = Vec::new(); - for x in self { - if try!(x.get_key()) == key { - values.push(try!(x.get_value())); - } - } - Ok(values) + self.get_all_values_ci(key) } fn get_all_values_ci(&self, key: &str) -> Result, MailParseError> { -- cgit v1.2.3