From 65533d3faf6f147fa288fa30eae0bb4df80b2948 Mon Sep 17 00:00:00 2001 From: mdecimus Date: Mon, 27 Nov 2023 09:34:59 +0100 Subject: [PATCH] v0.9.2 --- CHANGELOG.md | 5 ++++ Cargo.toml | 2 +- README.md | 6 ++--- resources/eml/rfc/002.crlf.json | 14 +++++++++++ resources/eml/rfc/002.json | 14 +++++++++++ resources/eml/thirdparty/011.crlf.json | 8 +++++++ resources/eml/thirdparty/011.json | 8 +++++++ src/decoders/quoted_printable.rs | 33 +++++++++++++++++++++----- src/lib.rs | 4 ++-- 9 files changed, 82 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f55e3d..ddaaff3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +mail-parser 0.9.2 +================================ +- Fixed `quoted_printable_decode` external function (not used by mail-parser directly). +- Fix `Received` header serialization for bincode compatibility. + mail-parser 0.9.1 ================================ - Fixed panic when Content-Disposition is empty (#63) diff --git a/Cargo.toml b/Cargo.toml index ce8d52b..4a45a18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "mail-parser" description = "Fast and robust e-mail parsing library for Rust" -version = "0.9.1" +version = "0.9.2" edition = "2021" authors = [ "Stalwart Labs "] license = "Apache-2.0 OR MIT" diff --git a/README.md b/README.md index 53d430e..e49a94e 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,9 @@ Performance and memory safety were two important factors while designing _mail-p - **High performance Base64 decoding** based on Chromium's decoder ([the fastest non-SIMD decoder](https://github.com/lemire/fastbase64)). - **Fast parsing** of message header fields, character set names and HTML entities using [perfect hashing](https://en.wikipedia.org/wiki/Perfect_hash_function). - Written in **100% safe** Rust with no external dependencies. -- Every function in the library has been [fuzzed](#testing-fuzzing--benchmarking) and - thoroughly [tested with MIRI](#testing-fuzzing--benchmarking). -- **Battle-tested** with millions of real-world e-mail messages dating from 1995 until today. +- Every function in the library has been [fuzzed](#testing-fuzzing--benchmarking) and thoroughly [tested with MIRI](#testing-fuzzing--benchmarking). +- **Battle-tested** with millions of real-world e-mail messages dating from 1995 until today. +- Used in production environments worldwide by [Stalwart Mail Server](https://github.com/stalwartlabs/mail-server). ## Usage Example diff --git a/resources/eml/rfc/002.crlf.json b/resources/eml/rfc/002.crlf.json index 91bafbf..14934d2 100644 --- a/resources/eml/rfc/002.crlf.json +++ b/resources/eml/rfc/002.crlf.json @@ -192,12 +192,19 @@ "Name": "mailhost.whitehouse.gov" }, "from_ip": "192.168.51.200", + "from_iprev": null, "by": { "Name": "heartbeat.whitehouse.gov" }, "for_": "vice-president@heartbeat.whitehouse.gov", "with": "ESMTP", + "tls_version": null, + "tls_cipher": null, "id": "SAA22453", + "ident": null, + "helo": null, + "helo_cmd": null, + "via": null, "date": { "year": 1998, "month": 8, @@ -223,12 +230,19 @@ "Name": "the_big_box.whitehouse.gov" }, "from_ip": "192.168.51.50", + "from_iprev": null, "by": { "Name": "mailhost.whitehouse.gov" }, "for_": "vice-president@whitehouse.gov", "with": "ESMTP", + "tls_version": null, + "tls_cipher": null, "id": "RAA20366", + "ident": null, + "helo": null, + "helo_cmd": null, + "via": null, "date": { "year": 1998, "month": 8, diff --git a/resources/eml/rfc/002.json b/resources/eml/rfc/002.json index b3e95f1..7911439 100644 --- a/resources/eml/rfc/002.json +++ b/resources/eml/rfc/002.json @@ -192,12 +192,19 @@ "Name": "mailhost.whitehouse.gov" }, "from_ip": "192.168.51.200", + "from_iprev": null, "by": { "Name": "heartbeat.whitehouse.gov" }, "for_": "vice-president@heartbeat.whitehouse.gov", "with": "ESMTP", + "tls_version": null, + "tls_cipher": null, "id": "SAA22453\n", + "ident": null, + "helo": null, + "helo_cmd": null, + "via": null, "date": { "year": 1998, "month": 8, @@ -223,12 +230,19 @@ "Name": "the_big_box.whitehouse.gov" }, "from_ip": "192.168.51.50", + "from_iprev": null, "by": { "Name": "mailhost.whitehouse.gov" }, "for_": "vice-president@whitehouse.gov", "with": "ESMTP", + "tls_version": null, + "tls_cipher": null, "id": "RAA20366\n", + "ident": null, + "helo": null, + "helo_cmd": null, + "via": null, "date": { "year": 1998, "month": 8, diff --git a/resources/eml/thirdparty/011.crlf.json b/resources/eml/thirdparty/011.crlf.json index eb7da13..bfb1da9 100644 --- a/resources/eml/thirdparty/011.crlf.json +++ b/resources/eml/thirdparty/011.crlf.json @@ -39,10 +39,18 @@ "IpAddr": "10.1.1.1" }, "from_ip": "10.1.1.1", + "from_iprev": null, "by": { "Name": "xyz-webserver.abcd-gestion.com" }, + "for_": null, "with": "ESMTPA", + "tls_version": null, + "tls_cipher": null, + "ident": null, + "helo": null, + "helo_cmd": null, + "via": null, "date": { "year": 2022, "month": 7, diff --git a/resources/eml/thirdparty/011.json b/resources/eml/thirdparty/011.json index 2f616cf..b81bd6c 100644 --- a/resources/eml/thirdparty/011.json +++ b/resources/eml/thirdparty/011.json @@ -39,10 +39,18 @@ "IpAddr": "10.1.1.1" }, "from_ip": "10.1.1.1", + "from_iprev": null, "by": { "Name": "xyz-webserver.abcd-gestion.com" }, + "for_": null, "with": "ESMTPA", + "tls_version": null, + "tls_cipher": null, + "ident": null, + "helo": null, + "helo_cmd": null, + "via": null, "date": { "year": 2022, "month": 7, diff --git a/src/decoders/quoted_printable.rs b/src/decoders/quoted_printable.rs index 64c9071..4493d9a 100644 --- a/src/decoders/quoted_printable.rs +++ b/src/decoders/quoted_printable.rs @@ -25,6 +25,8 @@ pub fn quoted_printable_decode(bytes: &[u8]) -> Option> { let mut state = QuotedPrintableState::None; let mut hex1 = 0; + let mut ws_count = 0; + let mut crlf = b"\n".as_ref(); for &ch in bytes { match ch { @@ -39,12 +41,23 @@ pub fn quoted_printable_decode(bytes: &[u8]) -> Option> { if QuotedPrintableState::Eq == state { state = QuotedPrintableState::None; } else { - buf.push(b'\n'); + if ws_count > 0 { + buf.truncate(buf.len() - ws_count); + } + buf.extend_from_slice(crlf); } + ws_count = 0; + } + b'\r' => { + crlf = b"\r\n".as_ref(); } - b'\r' => (), _ => match state { QuotedPrintableState::None => { + if ch.is_ascii_whitespace() { + ws_count += 1; + } else { + ws_count = 0; + } buf.push(ch); } QuotedPrintableState::Eq => { @@ -59,7 +72,7 @@ pub fn quoted_printable_decode(bytes: &[u8]) -> Option> { if hex1 != -1 { state = QuotedPrintableState::Hex1; - } else { + } else if !ch.is_ascii_whitespace() { return None; } } @@ -72,6 +85,7 @@ pub fn quoted_printable_decode(bytes: &[u8]) -> Option> { state = QuotedPrintableState::None; if hex2 != -1 { buf.push(((hex1 as u8) << 4) | hex2 as u8); + ws_count = 0; } else { return None; } @@ -337,14 +351,21 @@ mod tests { concat!( "Die Hasen klagten einst uber ihre Lage; \"wir leben\", ", "sprach ein Redner, \"in steter Furcht vor Menschen und ", - "Tieren, eine Beute der Hunde, der\n" + "Tieren, eine Beute der Hunde, der\r\n" + ), + ), + ( + concat!( + "hello \r\nbar=\r\n\r\nfoo\t=\r\nbar\r\nfoo\t \t= \r\n=62\r\nfoo = ", + "\t\r\nbar\r\nfoo =\r\n=62\r\nfoo \r\nbar=\r\n\r\nfoo_bar\r\n" ), + "hello\r\nbar\r\nfoo\tbar\r\nfoo\t \tb\r\nfoo bar\r\nfoo b\r\nfoo\r\nbar\r\nfoo_bar\r\n", ), ("\n\n", "\n\n"), ] { assert_eq!( - super::quoted_printable_decode(encoded_str.as_bytes()).unwrap_or_default(), - expected_result.as_bytes(), + String::from_utf8(super::quoted_printable_decode(encoded_str.as_bytes()).unwrap_or_default()).unwrap(), + expected_result, "Failed for {encoded_str:?}", ); } diff --git a/src/lib.rs b/src/lib.rs index 3faed91..220936f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,9 +33,9 @@ //! - **High performance Base64 decoding** based on Chromium's decoder ([the fastest non-SIMD decoder](https://github.com/lemire/fastbase64)). //! - **Fast parsing** of message header fields, character set names and HTML entities using [perfect hashing](https://en.wikipedia.org/wiki/Perfect_hash_function). //! - Written in **100% safe** Rust with no external dependencies. -//! - Every function in the library has been [fuzzed](#testing-fuzzing--benchmarking) and -//! thoroughly [tested with MIRI](#testing-fuzzing--benchmarking). +//! - Every function in the library has been [fuzzed](#testing-fuzzing--benchmarking) and thoroughly [tested with MIRI](#testing-fuzzing--benchmarking). //! - **Battle-tested** with millions of real-world e-mail messages dating from 1995 until today. +//! - Used in production environments worldwide by [Stalwart Mail Server](https://github.com/stalwartlabs/mail-server). //! //! Jump to the [example](#usage-example). //!