From 29a7935b10de51c9ecec06afb7fc9d8bf442df17 Mon Sep 17 00:00:00 2001 From: Jayce Fayne Date: Thu, 29 Jan 2026 12:59:01 +0100 Subject: [PATCH 1/2] simplify --- src/lib.rs | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d914823..3d4dba7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -949,28 +949,24 @@ fn parse_mail_recursive( let (headers, ix_body) = parse_headers(raw_data)?; let ctype = headers .get_first_value("Content-Type") - .map(|s| parse_content_type(&s)) + .as_deref() + .map(parse_content_type) .unwrap_or_else(|| ParsedContentType::default_conditional(in_multipart_digest)); - let mut result = ParsedMail { - raw_bytes: raw_data, - header_bytes: &raw_data[0..ix_body], - headers, - ctype, - body_bytes: &raw_data[ix_body..], - subparts: Vec::::new(), - }; - if result.ctype.mimetype.starts_with("multipart/") - && result.ctype.params.contains_key("boundary") + let mut subparts = Vec::new(); + let mut body_bytes = &raw_data[ix_body..]; + + if ctype.mimetype.starts_with("multipart/") + && let Some(boundary) = ctype.params.get("boundary") && raw_data.len() > ix_body { - let in_multipart_digest = result.ctype.mimetype == "multipart/digest"; - let boundary = String::from("--") + &result.ctype.params["boundary"]; + let boundary = String::from("--") + boundary; + let in_multipart_digest = ctype.mimetype == "multipart/digest"; if let Some(ix_boundary_start) = find_from_u8_line_prefix(raw_data, ix_body, boundary.as_bytes()) { let ix_body_end = strip_trailing_crlf(raw_data, ix_body, ix_boundary_start); - result.body_bytes = &raw_data[ix_body..ix_body_end]; + body_bytes = &raw_data[ix_body..ix_body_end]; let mut ix_boundary_end = ix_boundary_start + boundary.len(); while let Some(ix_part_start) = find_from_u8(raw_data, ix_boundary_end, b"\n").map(|v| v + 1) @@ -982,7 +978,7 @@ fn parse_mail_recursive( // if there is no terminating boundary, assume the part end is the end of the email .unwrap_or(raw_data.len()); - result.subparts.push(parse_mail_recursive( + subparts.push(parse_mail_recursive( &raw_data[ix_part_start..ix_part_end], in_multipart_digest, )?); @@ -997,7 +993,15 @@ fn parse_mail_recursive( } } } - Ok(result) + + Ok(ParsedMail { + raw_bytes: raw_data, + header_bytes: &raw_data[..ix_body], + headers, + ctype, + body_bytes, + subparts, + }) } /// Used to store params for content-type and content-disposition From 0782c72d25ca7518550985c25763f627189fbd1f Mon Sep 17 00:00:00 2001 From: Jayce Fayne Date: Thu, 29 Jan 2026 15:30:02 +0100 Subject: [PATCH 2/2] refactor --- src/lib.rs | 100 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 40 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3d4dba7..09c20f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -942,6 +942,65 @@ fn strip_trailing_crlf(raw_data: &[u8], ix_start: usize, mut ix: usize) -> usize ix } +fn parse_multipart( + raw_data: &[u8], + ix_body: usize, + boundary: String, + in_multipart_digest: bool, +) -> Result<(Vec>, usize), MailParseError> { + let mut subparts = Vec::new(); + let mut ix_body_end = ix_body; + + if let Some(ix_boundary_start) = + find_from_u8_line_prefix(raw_data, ix_body, boundary.as_bytes()) + { + ix_body_end = strip_trailing_crlf(raw_data, ix_body, ix_boundary_start); + let mut ix_boundary_end = ix_boundary_start + boundary.len(); + while let Some(ix_part_start) = + find_from_u8(raw_data, ix_boundary_end, b"\n").map(|v| v + 1) + { + let ix_part_boundary_start = + find_from_u8_line_prefix(raw_data, ix_part_start, boundary.as_bytes()); + let ix_part_end = ix_part_boundary_start + .map(|x| strip_trailing_crlf(raw_data, ix_part_start, x)) + // if there is no terminating boundary, assume the part end is the end of the email + .unwrap_or(raw_data.len()); + + subparts.push(parse_mail_recursive( + &raw_data[ix_part_start..ix_part_end], + in_multipart_digest, + )?); + ix_boundary_end = ix_part_boundary_start + .map(|x| x + boundary.len()) + .unwrap_or(raw_data.len()); + if ix_boundary_end + 2 > raw_data.len() + || (raw_data[ix_boundary_end] == b'-' && raw_data[ix_boundary_end + 1] == b'-') + { + break; + } + } + } + Ok((subparts, ix_body_end)) +} + +fn parse_subparts<'a>( + raw_data: &'a [u8], + ix_body: usize, + ctype: &'_ ParsedContentType, +) -> Result<(Vec>, &'a [u8]), MailParseError> { + if raw_data.len() > ix_body + && ctype.mimetype.starts_with("multipart") + && let Some(boundary) = ctype.params.get("boundary") + { + let boundary = String::from("--") + boundary; + let in_multipart_digest = ctype.mimetype == "multipart/digest"; + let (subparts, ix_body_end) = + parse_multipart(raw_data, ix_body, boundary, in_multipart_digest)?; + return Ok((subparts, &raw_data[ix_body..ix_body_end])); + } + Ok((Vec::new(), &raw_data[ix_body..])) +} + fn parse_mail_recursive( raw_data: &[u8], in_multipart_digest: bool, @@ -953,46 +1012,7 @@ fn parse_mail_recursive( .map(parse_content_type) .unwrap_or_else(|| ParsedContentType::default_conditional(in_multipart_digest)); - let mut subparts = Vec::new(); - let mut body_bytes = &raw_data[ix_body..]; - - if ctype.mimetype.starts_with("multipart/") - && let Some(boundary) = ctype.params.get("boundary") - && raw_data.len() > ix_body - { - let boundary = String::from("--") + boundary; - let in_multipart_digest = ctype.mimetype == "multipart/digest"; - if let Some(ix_boundary_start) = - find_from_u8_line_prefix(raw_data, ix_body, boundary.as_bytes()) - { - let ix_body_end = strip_trailing_crlf(raw_data, ix_body, ix_boundary_start); - body_bytes = &raw_data[ix_body..ix_body_end]; - let mut ix_boundary_end = ix_boundary_start + boundary.len(); - while let Some(ix_part_start) = - find_from_u8(raw_data, ix_boundary_end, b"\n").map(|v| v + 1) - { - let ix_part_boundary_start = - find_from_u8_line_prefix(raw_data, ix_part_start, boundary.as_bytes()); - let ix_part_end = ix_part_boundary_start - .map(|x| strip_trailing_crlf(raw_data, ix_part_start, x)) - // if there is no terminating boundary, assume the part end is the end of the email - .unwrap_or(raw_data.len()); - - subparts.push(parse_mail_recursive( - &raw_data[ix_part_start..ix_part_end], - in_multipart_digest, - )?); - ix_boundary_end = ix_part_boundary_start - .map(|x| x + boundary.len()) - .unwrap_or(raw_data.len()); - if ix_boundary_end + 2 > raw_data.len() - || (raw_data[ix_boundary_end] == b'-' && raw_data[ix_boundary_end + 1] == b'-') - { - break; - } - } - } - } + let (subparts, body_bytes) = parse_subparts(raw_data, ix_body, &ctype)?; Ok(ParsedMail { raw_bytes: raw_data,