summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBruce Guenter <bruce@untroubled.org>2016-11-11 08:12:42 -0600
committerstaktrace <accounts.github@staktrace.com>2016-11-11 11:32:53 -0500
commite4f54f9af1685095a42d00a66f7a09db2f9eef37 (patch)
tree17e56cead98909ef003686ee05103535d40e6e31
parentef6816e494c581ff670d30ab1dba2163c26ebf0b (diff)
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.
-rw-r--r--src/lib.rs30
1 files 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<String, MailParseError> {
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<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.
+ /// Same as get_first_value.
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
- /// 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<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.
+ /// Same as get_all_values.
fn get_all_values_ci(&self, key: &str) -> Result<Vec<String>, MailParseError>;
}
impl<'a> MailHeaderMap for Vec<MailHeader<'a>> {
fn get_first_value(&self, key: &str) -> Result<Option<String>, 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<Option<String>, MailParseError> {
@@ -427,13 +419,7 @@ impl<'a> MailHeaderMap for Vec<MailHeader<'a>> {
}
fn get_all_values(&self, key: &str) -> Result<Vec<String>, MailParseError> {
- let mut values: Vec<String> = 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<Vec<String>, MailParseError> {