From 560f9e539973028c43198b84e7d05e7105c21a1f Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Sun, 9 Aug 2020 09:50:20 +0300 Subject: [PATCH] melib/email: parse empty attachments correctly --- melib/src/email/parser.rs | 57 ++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/melib/src/email/parser.rs b/melib/src/email/parser.rs index 27ab853d..b9edb174 100644 --- a/melib/src/email/parser.rs +++ b/melib/src/email/parser.rs @@ -28,7 +28,7 @@ use nom::{ error::ErrorKind, multi::{many0, many1, separated_list, separated_nonempty_list}, number::complete::le_u8, - sequence::{delimited, preceded, separated_pair, terminated}, + sequence::{delimited, pair, preceded, separated_pair, terminated}, }; use std::borrow::Cow; @@ -222,11 +222,14 @@ impl<'a, P: for<'r> FnMut(&'r u8) -> bool> BytesIterExt for std::slice::Split<'a //fn parser(input: I) -> IResult; pub fn mail(input: &[u8]) -> Result<(Vec<(&[u8], &[u8])>, &[u8])> { - let (rest, result) = separated_pair( - headers::headers, - alt((tag(b"\n"), tag(b"\r\n"))), - take_while(|_| true), - )(input) + let (rest, result) = alt(( + separated_pair( + headers::headers, + alt((tag(b"\n"), tag(b"\r\n"))), + take_while(|_| true), + ), + pair(headers::headers, generic::eof), + ))(input) .chain_err_summary(|| "Could not parse mail")?; if !rest.is_empty() { @@ -378,6 +381,14 @@ pub mod generic { } } } + + pub fn eof(input: &[u8]) -> IResult<&[u8], &[u8]> { + if input.is_empty() { + Ok((input, input)) + } else { + Err(nom::Err::Error((input, "expected EOF").into())) + } + } } pub mod headers { @@ -645,11 +656,14 @@ pub mod attachments { use crate::email::address::*; use crate::email::attachment_types::{ContentDisposition, ContentDispositionKind}; pub fn attachment(input: &[u8]) -> IResult<&[u8], (std::vec::Vec<(&[u8], &[u8])>, &[u8])> { - separated_pair( - many0(headers::header), - alt((tag(b"\n"), tag(b"\r\n"))), - take_while(|_| true), - )(input) + alt(( + separated_pair( + many0(headers::header), + alt((tag(b"\n"), tag(b"\r\n"))), + take_while(|_| true), + ), + pair(headers::headers, generic::eof), + ))(input) } pub fn multipart_parts<'a>( @@ -703,10 +717,17 @@ pub mod attachments { (input, "multipart_parts(): malformed boundary").into(), )); } - ret.push(StrBuilder { - offset, - length: end - 2, - }); + if input[..end - 2].ends_with(b"\r\n") { + ret.push(StrBuilder { + offset, + length: end - 4, + }); + } else { + ret.push(StrBuilder { + offset, + length: end - 3, + }); + } offset += end + boundary.len(); input = &input[end + boundary.len()..]; if input.len() < 2 || input[0] != b'\n' || &input[0..2] == b"--" { @@ -769,7 +790,11 @@ pub mod attachments { if &input[end - 2..end] != b"--" { return Err(nom::Err::Error((input, "parts_f(): found EOF").into())); } - ret.push(&input[0..end - 2]); + if input[..end - 2].ends_with(b"\r\n") { + ret.push(&input[..end - 4]); + } else { + ret.push(&input[..end - 3]); + } input = &input[end + boundary.len()..]; if input.len() < 2 || (input[0] != b'\n' && &input[0..2] != b"\r\n")