melib/email/headers: fix &[u8] index in HeaderMap

pull/223/head
Manos Pitsidianakis 2023-06-03 19:31:09 +03:00
parent f537c24909
commit 6388bea9a0
2 changed files with 61 additions and 57 deletions

View File

@ -93,10 +93,7 @@ impl std::ops::Index<usize> for HeaderMap {
impl std::ops::Index<&[u8]> for HeaderMap {
type Output = str;
fn index(&self, k: &[u8]) -> &Self::Output {
(self.0)[HeaderName::try_from(k)
.expect("Invalid bytes in header name.")
.borrow() as &dyn HeaderKey]
.as_str()
(self.0)[&HeaderName::try_from(k).expect("Invalid bytes in header name.")].as_str()
}
}
@ -133,7 +130,7 @@ impl HeaderMap {
where
<T as TryInto<HeaderName>>::Error: std::fmt::Debug,
{
let k = key.try_into().expect("Invalid bytes in header name.");
let k = key.try_into().ok()?;
(self.0).get_mut(&k)
}
@ -141,7 +138,7 @@ impl HeaderMap {
where
<T as TryInto<HeaderName>>::Error: std::fmt::Debug,
{
let k = key.try_into().expect("Invalid bytes in header name.");
let k = key.try_into().ok()?;
(self.0).get(&k).map(|x| x.as_str())
}
@ -149,16 +146,17 @@ impl HeaderMap {
where
<T as TryInto<HeaderName>>::Error: std::fmt::Debug,
{
let k = key.try_into().expect("Invalid bytes in header name.");
(self.0).contains_key(&k)
key.try_into()
.ok()
.map(|k| (self.0).contains_key(&k))
.unwrap_or(false)
}
pub fn remove<T: TryInto<HeaderName> + std::fmt::Debug>(&mut self, key: T) -> Option<String>
where
<T as TryInto<HeaderName>>::Error: std::fmt::Debug,
{
let k = key.try_into().expect("Invalid bytes in header name.");
(self.0).remove(&k)
key.try_into().ok().and_then(|k| (self.0).remove(&k))
}
pub fn into_inner(self) -> indexmap::IndexMap<HeaderName, String> {
@ -180,16 +178,36 @@ impl DerefMut for HeaderMap {
}
}
#[test]
fn test_headers_case_sensitivity() {
use std::convert::TryInto;
let mut headers = HeaderMap::default();
headers.insert("from".try_into().unwrap(), "Myself <a@b.c>".into());
assert_eq!(&headers["From"], "Myself <a@b.c>");
assert_eq!(&headers["From"], &headers["from"]);
assert_eq!(&headers["fROm"], &headers["from"]);
headers.get_mut("from").unwrap().pop();
assert_eq!(&headers["From"], "Myself <a@b.c");
headers.insert("frOM".try_into().unwrap(), "nada".into());
assert_eq!(&headers["fROm"], "nada");
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_headers_case_sensitivity() {
let mut headers = HeaderMap::default();
headers.insert("from".try_into().unwrap(), "Myself <a@b.c>".into());
dbg!(&headers);
assert_eq!(&headers["From"], "Myself <a@b.c>");
assert_eq!(&headers["From"], &headers["from"]);
assert_eq!(&headers["fROm"], &headers["from"]);
headers.get_mut("from").unwrap().pop();
assert_eq!(&headers["From"], "Myself <a@b.c");
headers.insert("frOM".try_into().unwrap(), "nada".into());
assert_eq!(&headers["fROm"], "nada");
}
#[test]
fn test_headers_map_index() {
let mut headers = HeaderMap::default();
headers.insert(HeaderName::SUBJECT, "foobar".into());
headers.insert(HeaderName::MESSAGE_ID, "foobar@examplecom".into());
dbg!(&headers);
assert_eq!(&headers[0], "foobar");
assert_eq!(&headers[HeaderName::SUBJECT], "foobar");
assert_eq!(&headers[&HeaderName::SUBJECT], "foobar");
assert_eq!(&headers["subject"], "foobar");
assert_eq!(&headers["Subject"], "foobar");
assert_eq!(&headers[b"Subject".as_slice()], "foobar");
assert!(&headers[HeaderName::MESSAGE_ID] != "foobar");
}
}

View File

@ -175,40 +175,6 @@ macro_rules! standard_headers {
(StandardHeader::$konst, $name),
)+
];
#[test]
fn test_parse_standard_headers() {
for &(std, name) in TEST_HEADERS {
// Test lower case
assert_eq!(HeaderName::from_bytes(name.as_bytes()).unwrap(), HeaderName::from(std));
// Test upper case
let upper = std::str::from_utf8(name.as_bytes()).expect("byte string constants are all utf-8").to_uppercase();
assert_eq!(HeaderName::from_bytes(upper.as_bytes()).unwrap(), HeaderName::from(std));
}
}
#[test]
fn test_standard_headers_into_bytes() {
//for &(std, name) in TEST_HEADERS {
//let name = std::str::from_utf8(name.as_bytes()).unwrap();
//let std = HeaderName::from(std);
// Test lower case
//let bytes: Bytes =
// HeaderName::from_bytes(name.as_bytes()).unwrap().inner.into();
//assert_eq!(bytes, name);
//assert_eq!(HeaderName::from_bytes(name.as_bytes()).unwrap(), std);
// Test upper case
// let upper = name.to_uppercase();
//let bytes: Bytes =
// HeaderName::from_bytes(upper.as_bytes()).unwrap().inner.into();
//assert_eq!(bytes, name.as_bytes());
//assert_eq!(HeaderName::from_bytes(upper.as_bytes()).unwrap(),
// std);
//}
}
}
}
@ -912,7 +878,7 @@ mod tests {
use super::*;
#[test]
fn test_headername_display() {
fn test_email_headers_headername_display() {
assert_eq!(&HeaderName::SUBJECT.to_string(), "Subject");
assert_eq!(&HeaderName::CC.to_string(), "Cc");
assert_eq!(&HeaderName::IN_REPLY_TO.to_string(), "In-Reply-To");
@ -947,4 +913,24 @@ mod tests {
"Something-DKIM"
);
}
#[test]
fn test_email_headers_parse_standard_headers() {
for &(std, name) in TEST_HEADERS {
// Test lower case
assert_eq!(
HeaderName::from_bytes(name.to_ascii_lowercase().as_bytes()).unwrap(),
HeaderName::from(std)
);
// Test upper case
let upper = std::str::from_utf8(name.as_bytes())
.expect("byte string constants are all utf-8")
.to_uppercase();
assert_eq!(
HeaderName::from_bytes(upper.as_bytes()).unwrap(),
HeaderName::from(std)
);
}
}
}