diff --git a/resources/eml/malformed/019.crlf.json b/resources/eml/malformed/019.crlf.json new file mode 100644 index 0000000..698dd43 --- /dev/null +++ b/resources/eml/malformed/019.crlf.json @@ -0,0 +1,135 @@ +{ + "html_body": [ + 1 + ], + "text_body": [ + 1 + ], + "attachments": [ + 2 + ], + "parts": [ + { + "headers": [ + { + "name": "content_type", + "value": { + "ContentType": { + "c_type": "multipart", + "c_subtype": "mixed", + "attributes": [ + { + "name": "boundary", + "value": "89" + } + ] + } + }, + "offset_field": 0, + "offset_start": 13, + "offset_end": 46 + } + ], + "is_encoding_problem": false, + "body": { + "Multipart": [ + 1, + 2 + ] + }, + "offset_header": 0, + "offset_body": 48, + "offset_end": 135 + }, + { + "headers": [ + { + "name": "content_type", + "value": { + "ContentType": { + "c_type": "text", + "c_subtype": "plain", + "attributes": null + } + }, + "offset_field": 54, + "offset_start": 67, + "offset_end": 80 + } + ], + "is_encoding_problem": false, + "body": { + "Text": "" + }, + "offset_header": 54, + "offset_body": 82, + "offset_end": 82 + }, + { + "headers": [ + { + "name": "content_type", + "value": { + "ContentType": { + "c_type": "message", + "c_subtype": "rfc822", + "attributes": null + } + }, + "offset_field": 88, + "offset_start": 101, + "offset_end": 118 + } + ], + "is_encoding_problem": false, + "body": { + "Message": { + "html_body": [], + "text_body": [], + "attachments": [], + "parts": [ + { + "headers": [ + { + "name": { + "other": "--89--" + }, + "value": "Empty", + "offset_field": 129, + "offset_start": 135, + "offset_end": 135 + } + ], + "is_encoding_problem": true, + "body": { + "Binary": [ + 105, + 110, + 118, + 97, + 108, + 105, + 100, + 13, + 10, + 45, + 45, + 56, + 57, + 45, + 45 + ] + }, + "offset_header": 120, + "offset_body": 0, + "offset_end": 0 + } + ] + } + }, + "offset_header": 88, + "offset_body": 120, + "offset_end": 135 + } + ] +} \ No newline at end of file diff --git a/resources/eml/malformed/019.eml b/resources/eml/malformed/019.eml new file mode 100644 index 0000000..7c95c7c --- /dev/null +++ b/resources/eml/malformed/019.eml @@ -0,0 +1,10 @@ +Content-Type: multipart/mixed; boundary="89" + +--89 +Content-Type: text/plain + +--89 +Content-Type: message/rfc822 + +invalid +--89-- \ No newline at end of file diff --git a/resources/eml/malformed/019.json b/resources/eml/malformed/019.json new file mode 100644 index 0000000..1dfd2a4 --- /dev/null +++ b/resources/eml/malformed/019.json @@ -0,0 +1,134 @@ +{ + "html_body": [ + 1 + ], + "text_body": [ + 1 + ], + "attachments": [ + 2 + ], + "parts": [ + { + "headers": [ + { + "name": "content_type", + "value": { + "ContentType": { + "c_type": "multipart", + "c_subtype": "mixed", + "attributes": [ + { + "name": "boundary", + "value": "89" + } + ] + } + }, + "offset_field": 0, + "offset_start": 13, + "offset_end": 45 + } + ], + "is_encoding_problem": false, + "body": { + "Multipart": [ + 1, + 2 + ] + }, + "offset_header": 0, + "offset_body": 46, + "offset_end": 126 + }, + { + "headers": [ + { + "name": "content_type", + "value": { + "ContentType": { + "c_type": "text", + "c_subtype": "plain", + "attributes": null + } + }, + "offset_field": 51, + "offset_start": 64, + "offset_end": 76 + } + ], + "is_encoding_problem": false, + "body": { + "Text": "" + }, + "offset_header": 51, + "offset_body": 77, + "offset_end": 77 + }, + { + "headers": [ + { + "name": "content_type", + "value": { + "ContentType": { + "c_type": "message", + "c_subtype": "rfc822", + "attributes": null + } + }, + "offset_field": 82, + "offset_start": 95, + "offset_end": 111 + } + ], + "is_encoding_problem": false, + "body": { + "Message": { + "html_body": [], + "text_body": [], + "attachments": [], + "parts": [ + { + "headers": [ + { + "name": { + "other": "--89--" + }, + "value": "Empty", + "offset_field": 120, + "offset_start": 126, + "offset_end": 126 + } + ], + "is_encoding_problem": true, + "body": { + "Binary": [ + 105, + 110, + 118, + 97, + 108, + 105, + 100, + 10, + 45, + 45, + 56, + 57, + 45, + 45 + ] + }, + "offset_header": 112, + "offset_body": 0, + "offset_end": 0 + } + ] + } + }, + "offset_header": 82, + "offset_body": 112, + "offset_end": 126 + } + ] +} \ No newline at end of file diff --git a/src/decoders/encoded_word.rs b/src/decoders/encoded_word.rs index 61138dc..fc3adfe 100644 --- a/src/decoders/encoded_word.rs +++ b/src/decoders/encoded_word.rs @@ -167,7 +167,7 @@ mod tests { //println!("Decoded '{}'", string); assert_eq!(result, expected_result); } - _ => panic!("Failed to decode '{}'", input), + _ => panic!("Failed to decode '{input}'"), } } } diff --git a/src/parsers/fields/raw.rs b/src/parsers/fields/raw.rs index e81dcb4..ec6d77f 100644 --- a/src/parsers/fields/raw.rs +++ b/src/parsers/fields/raw.rs @@ -79,8 +79,7 @@ mod tests { .parse_raw() .unwrap_text(), expected, - "Failed for '{:?}'", - input + "Failed for '{input:?}'", ); } } diff --git a/src/parsers/message.rs b/src/parsers/message.rs index 4ff25f9..f2b78bf 100644 --- a/src/parsers/message.rs +++ b/src/parsers/message.rs @@ -490,11 +490,29 @@ impl MessageParser { } // Corrupted MIME message, try to recover whatever is possible. + let mut last_message = true; while let Some((prev_state, prev_message)) = state_stack.pop() { if let Some(mut prev_message) = prev_message { message.raw_message = raw_message.into(); //raw_message[state.offset_header..stream.offset()].as_ref().into(); if let Some(part) = prev_message.parts.get_mut(state.part_id as usize) { + // complete message as best we can if no parts yet assigned + if message.parts.is_empty() { + let bytes = &message.raw_message[state.offset_header..]; + message.parts.push(MessagePart { + headers: std::mem::take(&mut part_headers), + encoding: Encoding::None, + is_encoding_problem: true, + body: if last_message { + PartType::Binary(bytes.to_owned().into()) + } else { + PartType::Text("".into()) + }, + offset_header: state.offset_header as u32, + offset_body: state.offset_body as u32, + offset_end: state.offset_end as u32, + }); + } part.body = PartType::Message(message); part.offset_end = stream.offset() as u32; } else { @@ -509,12 +527,13 @@ impl MessageParser { debug_assert!(false, "This should not have happened."); } state = prev_state; + last_message = false; } message.raw_message = raw_message.into(); - if !message.is_empty() { - message.parts[0].offset_end = message.raw_message.len() as u32; + if let Some(part) = message.parts.first_mut() { + part.offset_end = message.raw_message.len() as u32; Some(message) } else if !part_headers.is_empty() { // Message without a body