Skip to content

Commit 65533d3

Browse files
committed
v0.9.2
1 parent 28a9b67 commit 65533d3

File tree

9 files changed

+82
-12
lines changed

9 files changed

+82
-12
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
mail-parser 0.9.2
2+
================================
3+
- Fixed `quoted_printable_decode` external function (not used by mail-parser directly).
4+
- Fix `Received` header serialization for bincode compatibility.
5+
16
mail-parser 0.9.1
27
================================
38
- Fixed panic when Content-Disposition is empty (#63)

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "mail-parser"
33
description = "Fast and robust e-mail parsing library for Rust"
4-
version = "0.9.1"
4+
version = "0.9.2"
55
edition = "2021"
66
authors = [ "Stalwart Labs <hello@stalw.art>"]
77
license = "Apache-2.0 OR MIT"

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ Performance and memory safety were two important factors while designing _mail-p
2727
- **High performance Base64 decoding** based on Chromium's decoder ([the fastest non-SIMD decoder](https://github.com/lemire/fastbase64)).
2828
- **Fast parsing** of message header fields, character set names and HTML entities using [perfect hashing](https://en.wikipedia.org/wiki/Perfect_hash_function).
2929
- Written in **100% safe** Rust with no external dependencies.
30-
- Every function in the library has been [fuzzed](#testing-fuzzing--benchmarking) and
31-
thoroughly [tested with MIRI](#testing-fuzzing--benchmarking).
32-
- **Battle-tested** with millions of real-world e-mail messages dating from 1995 until today.
30+
- Every function in the library has been [fuzzed](#testing-fuzzing--benchmarking) and thoroughly [tested with MIRI](#testing-fuzzing--benchmarking).
31+
- **Battle-tested** with millions of real-world e-mail messages dating from 1995 until today.
32+
- Used in production environments worldwide by [Stalwart Mail Server](https://github.com/stalwartlabs/mail-server).
3333

3434
## Usage Example
3535

resources/eml/rfc/002.crlf.json

+14
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,19 @@
192192
"Name": "mailhost.whitehouse.gov"
193193
},
194194
"from_ip": "192.168.51.200",
195+
"from_iprev": null,
195196
"by": {
196197
"Name": "heartbeat.whitehouse.gov"
197198
},
198199
"for_": "vice-president@heartbeat.whitehouse.gov",
199200
"with": "ESMTP",
201+
"tls_version": null,
202+
"tls_cipher": null,
200203
"id": "SAA22453",
204+
"ident": null,
205+
"helo": null,
206+
"helo_cmd": null,
207+
"via": null,
201208
"date": {
202209
"year": 1998,
203210
"month": 8,
@@ -223,12 +230,19 @@
223230
"Name": "the_big_box.whitehouse.gov"
224231
},
225232
"from_ip": "192.168.51.50",
233+
"from_iprev": null,
226234
"by": {
227235
"Name": "mailhost.whitehouse.gov"
228236
},
229237
"for_": "vice-president@whitehouse.gov",
230238
"with": "ESMTP",
239+
"tls_version": null,
240+
"tls_cipher": null,
231241
"id": "RAA20366",
242+
"ident": null,
243+
"helo": null,
244+
"helo_cmd": null,
245+
"via": null,
232246
"date": {
233247
"year": 1998,
234248
"month": 8,

resources/eml/rfc/002.json

+14
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,19 @@
192192
"Name": "mailhost.whitehouse.gov"
193193
},
194194
"from_ip": "192.168.51.200",
195+
"from_iprev": null,
195196
"by": {
196197
"Name": "heartbeat.whitehouse.gov"
197198
},
198199
"for_": "vice-president@heartbeat.whitehouse.gov",
199200
"with": "ESMTP",
201+
"tls_version": null,
202+
"tls_cipher": null,
200203
"id": "SAA22453\n",
204+
"ident": null,
205+
"helo": null,
206+
"helo_cmd": null,
207+
"via": null,
201208
"date": {
202209
"year": 1998,
203210
"month": 8,
@@ -223,12 +230,19 @@
223230
"Name": "the_big_box.whitehouse.gov"
224231
},
225232
"from_ip": "192.168.51.50",
233+
"from_iprev": null,
226234
"by": {
227235
"Name": "mailhost.whitehouse.gov"
228236
},
229237
"for_": "vice-president@whitehouse.gov",
230238
"with": "ESMTP",
239+
"tls_version": null,
240+
"tls_cipher": null,
231241
"id": "RAA20366\n",
242+
"ident": null,
243+
"helo": null,
244+
"helo_cmd": null,
245+
"via": null,
232246
"date": {
233247
"year": 1998,
234248
"month": 8,

resources/eml/thirdparty/011.crlf.json

+8
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,18 @@
3939
"IpAddr": "10.1.1.1"
4040
},
4141
"from_ip": "10.1.1.1",
42+
"from_iprev": null,
4243
"by": {
4344
"Name": "xyz-webserver.abcd-gestion.com"
4445
},
46+
"for_": null,
4547
"with": "ESMTPA",
48+
"tls_version": null,
49+
"tls_cipher": null,
50+
"ident": null,
51+
"helo": null,
52+
"helo_cmd": null,
53+
"via": null,
4654
"date": {
4755
"year": 2022,
4856
"month": 7,

resources/eml/thirdparty/011.json

+8
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,18 @@
3939
"IpAddr": "10.1.1.1"
4040
},
4141
"from_ip": "10.1.1.1",
42+
"from_iprev": null,
4243
"by": {
4344
"Name": "xyz-webserver.abcd-gestion.com"
4445
},
46+
"for_": null,
4547
"with": "ESMTPA",
48+
"tls_version": null,
49+
"tls_cipher": null,
50+
"ident": null,
51+
"helo": null,
52+
"helo_cmd": null,
53+
"via": null,
4654
"date": {
4755
"year": 2022,
4856
"month": 7,

src/decoders/quoted_printable.rs

+27-6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ pub fn quoted_printable_decode(bytes: &[u8]) -> Option<Vec<u8>> {
2525

2626
let mut state = QuotedPrintableState::None;
2727
let mut hex1 = 0;
28+
let mut ws_count = 0;
29+
let mut crlf = b"\n".as_ref();
2830

2931
for &ch in bytes {
3032
match ch {
@@ -39,12 +41,23 @@ pub fn quoted_printable_decode(bytes: &[u8]) -> Option<Vec<u8>> {
3941
if QuotedPrintableState::Eq == state {
4042
state = QuotedPrintableState::None;
4143
} else {
42-
buf.push(b'\n');
44+
if ws_count > 0 {
45+
buf.truncate(buf.len() - ws_count);
46+
}
47+
buf.extend_from_slice(crlf);
4348
}
49+
ws_count = 0;
50+
}
51+
b'\r' => {
52+
crlf = b"\r\n".as_ref();
4453
}
45-
b'\r' => (),
4654
_ => match state {
4755
QuotedPrintableState::None => {
56+
if ch.is_ascii_whitespace() {
57+
ws_count += 1;
58+
} else {
59+
ws_count = 0;
60+
}
4861
buf.push(ch);
4962
}
5063
QuotedPrintableState::Eq => {
@@ -59,7 +72,7 @@ pub fn quoted_printable_decode(bytes: &[u8]) -> Option<Vec<u8>> {
5972

6073
if hex1 != -1 {
6174
state = QuotedPrintableState::Hex1;
62-
} else {
75+
} else if !ch.is_ascii_whitespace() {
6376
return None;
6477
}
6578
}
@@ -72,6 +85,7 @@ pub fn quoted_printable_decode(bytes: &[u8]) -> Option<Vec<u8>> {
7285
state = QuotedPrintableState::None;
7386
if hex2 != -1 {
7487
buf.push(((hex1 as u8) << 4) | hex2 as u8);
88+
ws_count = 0;
7589
} else {
7690
return None;
7791
}
@@ -337,14 +351,21 @@ mod tests {
337351
concat!(
338352
"Die Hasen klagten einst uber ihre Lage; \"wir leben\", ",
339353
"sprach ein Redner, \"in steter Furcht vor Menschen und ",
340-
"Tieren, eine Beute der Hunde, der\n"
354+
"Tieren, eine Beute der Hunde, der\r\n"
355+
),
356+
),
357+
(
358+
concat!(
359+
"hello \r\nbar=\r\n\r\nfoo\t=\r\nbar\r\nfoo\t \t= \r\n=62\r\nfoo = ",
360+
"\t\r\nbar\r\nfoo =\r\n=62\r\nfoo \r\nbar=\r\n\r\nfoo_bar\r\n"
341361
),
362+
"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",
342363
),
343364
("\n\n", "\n\n"),
344365
] {
345366
assert_eq!(
346-
super::quoted_printable_decode(encoded_str.as_bytes()).unwrap_or_default(),
347-
expected_result.as_bytes(),
367+
String::from_utf8(super::quoted_printable_decode(encoded_str.as_bytes()).unwrap_or_default()).unwrap(),
368+
expected_result,
348369
"Failed for {encoded_str:?}",
349370
);
350371
}

src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@
3333
//! - **High performance Base64 decoding** based on Chromium's decoder ([the fastest non-SIMD decoder](https://github.com/lemire/fastbase64)).
3434
//! - **Fast parsing** of message header fields, character set names and HTML entities using [perfect hashing](https://en.wikipedia.org/wiki/Perfect_hash_function).
3535
//! - Written in **100% safe** Rust with no external dependencies.
36-
//! - Every function in the library has been [fuzzed](#testing-fuzzing--benchmarking) and
37-
//! thoroughly [tested with MIRI](#testing-fuzzing--benchmarking).
36+
//! - Every function in the library has been [fuzzed](#testing-fuzzing--benchmarking) and thoroughly [tested with MIRI](#testing-fuzzing--benchmarking).
3837
//! - **Battle-tested** with millions of real-world e-mail messages dating from 1995 until today.
38+
//! - Used in production environments worldwide by [Stalwart Mail Server](https://github.com/stalwartlabs/mail-server).
3939
//!
4040
//! Jump to the [example](#usage-example).
4141
//!

0 commit comments

Comments
 (0)