diff --git a/crates/integration-tests/src/test/spf_basic.rs b/crates/integration-tests/src/test/spf_basic.rs index 172028fc..8b4e2972 100644 --- a/crates/integration-tests/src/test/spf_basic.rs +++ b/crates/integration-tests/src/test/spf_basic.rs @@ -71,8 +71,8 @@ async fn spf_basic() -> anyhow::Result<()> { let from = headers.from().unwrap().unwrap().0; let results = headers.authentication_results().unwrap().unwrap().results; eprintln!("{results:#?}"); - match from[0].address.domain.as_str() { - "example.com" => { + match from[0].address.domain.as_slice() { + b"example.com" => { assert_eq!(results.len(), 1); assert_eq!(results[0].result, "none"); assert_eq!(results[0].method, "spf"); @@ -85,7 +85,7 @@ async fn spf_basic() -> anyhow::Result<()> { "sender@example.com" ); } - "allowed.localhost" => { + b"allowed.localhost" => { assert_eq!(results.len(), 1); assert_eq!(results[0].result, "pass"); assert_eq!(results[0].method, "spf"); diff --git a/crates/mailparsing/src/rfc5322_parser.rs b/crates/mailparsing/src/rfc5322_parser.rs index 3b2c8ce9..ffa0bc1b 100644 --- a/crates/mailparsing/src/rfc5322_parser.rs +++ b/crates/mailparsing/src/rfc5322_parser.rs @@ -1,7 +1,7 @@ use crate::headermap::EncodeHeaderValue; use crate::nom_utils::{explain_nom, make_context_error, make_span, IResult, ParseError, Span}; use crate::{MailParsingError, Result, SharedString}; -use bstr::ByteVec; +use bstr::{BString, ByteVec}; use charset_normalizer_rs::Encoding; use nom::branch::alt; use nom::bytes::complete::{tag, take_while, take_while1}; @@ -406,7 +406,13 @@ fn obs_route(input: Span) -> IResult { fn addr_spec(input: Span) -> IResult { let (loc, (local_part, domain)) = context("addr_spec", separated_pair(local_part, char('@'), domain)).parse(input)?; - Ok((loc, AddrSpec { local_part, domain })) + Ok(( + loc, + AddrSpec { + local_part: local_part.into(), + domain: domain.into(), + }, + )) } fn parse_with<'a, R, F>(text: &'a str, parser: F) -> Result @@ -1614,15 +1620,15 @@ pub struct AuthenticationResult { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct AddrSpec { - pub local_part: String, - pub domain: String, + pub local_part: BString, + pub domain: BString, } impl AddrSpec { pub fn new(local_part: &str, domain: &str) -> Self { Self { - local_part: local_part.to_string(), - domain: domain.to_string(), + local_part: local_part.into(), + domain: domain.into(), } } @@ -1633,26 +1639,29 @@ impl AddrSpec { impl EncodeHeaderValue for AddrSpec { fn encode_value(&self) -> SharedString<'static> { - let mut result = String::new(); + let mut result: Vec = vec![]; - let needs_quoting = !self.local_part.chars().all(|c| is_atext(c) || c == '.'); + let needs_quoting = !self + .local_part + .iter() + .all(|&c| is_atext(c as char) || c == b'.'); if needs_quoting { - result.push('"'); + result.push(b'"'); // RFC5321 4.1.2 qtextSMTP: // within a quoted string, any ASCII graphic or space is permitted without // blackslash-quoting except double-quote and the backslash itself. - for c in self.local_part.chars() { - if c == '"' || c == '\\' { - result.push('\\'); + for &c in self.local_part.iter() { + if c == b'"' || c == b'\\' { + result.push(b'\\'); } result.push(c); } - result.push('"'); + result.push(b'"'); } else { result.push_str(&self.local_part); } - result.push('@'); + result.push(b'@'); result.push_str(&self.domain); result.into() @@ -2283,8 +2292,8 @@ mod test { let mbox = Mailbox { name: Some("foo@bar.com".to_string()), address: AddrSpec { - local_part: "foo".to_string(), - domain: "bar.com".to_string(), + local_part: "foo".into(), + domain: "bar.com".into(), }, }; assert_eq!(mbox.encode_value(), "\"foo@bar.com\" ");