aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/vmime/body.cpp18
-rw-r--r--tests/parser/bodyPartTest.cpp38
2 files changed, 56 insertions, 0 deletions
diff --git a/src/vmime/body.cpp b/src/vmime/body.cpp
index 4103f328..a3875b9d 100644
--- a/src/vmime/body.cpp
+++ b/src/vmime/body.cpp
@@ -53,6 +53,11 @@ body::~body() {
}
+/*
+ * boundaryStart: will become the index for "\r\n--marker"
+ * boundaryEnd: will become the index after "marker", i.e. index for potential trailing "--", "\r\n", etc.
+ * return value: index for "marker"
+ */
// static
size_t body::findNextBoundaryPosition(
const shared_ptr <utility::parserInputStreamAdapter>& parser,
@@ -271,6 +276,19 @@ void body::parseImpl(
boundaryEnd += 2;
} else if (boundaryEnd < end && parser->peekByte() == '\n') {
++boundaryEnd;
+ } else if (boundaryEnd == end) {
+ } else {
+ /*
+ * RFC 2046 §5.1.1 page 19: """[...] optional
+ * linear whitespace, and a terminating
+ * CRLF.""" — junk handling is left
+ * unspecified, so we might as well skip it to
+ * facilitate broken mails.
+ */
+ boundaryEnd += parser->skipIf([](char_t c) { return c != '\n'; }, end);
+ pos = findNextBoundaryPosition(parser, boundary, boundaryEnd, end, &boundaryStart, &boundaryEnd);
+ --index;
+ continue;
}
if (index == 0) {
diff --git a/tests/parser/bodyPartTest.cpp b/tests/parser/bodyPartTest.cpp
index 062007d9..3aaadd03 100644
--- a/tests/parser/bodyPartTest.cpp
+++ b/tests/parser/bodyPartTest.cpp
@@ -39,6 +39,7 @@ VMIME_TEST_SUITE_BEGIN(bodyPartTest)
VMIME_TEST(testGenerate7bit)
VMIME_TEST(testTextUsageForQPEncoding)
VMIME_TEST(testParseVeryBigMessage)
+ VMIME_TEST(testParseBoundaryPrefix)
VMIME_TEST_LIST_END
@@ -373,4 +374,41 @@ VMIME_TEST_SUITE_BEGIN(bodyPartTest)
VASSERT("2.2", vmime::dynamicCast <const vmime::streamContentHandler>(body2Cts) != NULL);
}
+ void testParseBoundaryPrefix() {
+ /*
+ * Clients are not supposed to create boundary identifiers that
+ * contain a prefix of another (RFC 2046 section 5.1), but alas
+ * CANCOM FortiMail produces this garbage.
+ */
+ vmime::string str =
+ "Content-Type: multipart/related; boundary=\"--b12\"\r\n"
+ "\r\n"
+ "----b12\r\n"
+ "Content-Type: multipart/alternative; boundary=\"--b12-1\"\r\n"
+ "\r\n"
+ "----b12-1\r\n"
+ "Content-Type: text/plain; charset=utf-8\r\n"
+ "\r\n"
+ "P11\r\n"
+ "----b12-1\r\n"
+ "Content-Type: text/html; charset=utf-8\r\n"
+ "\r\n"
+ "P12\r\n"
+ "----b12-1--\r\n"
+ "----b12\r\n"
+ "\r\n"
+ "P2\r\n"
+ "----b12--\r\n";
+
+ vmime::bodyPart relco;
+ relco.parse(str);
+ auto relbd = relco.getBody();
+ VASSERT_EQ("global-partcount", 2, relbd->getPartCount());
+ auto altbd = relbd->getPartAt(0)->getBody();
+ VASSERT_EQ("part1-partcount", 2, altbd->getPartCount());
+ VASSERT_EQ("part1.1-body", "P11", extractContents(altbd->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part1.2-body", "P12", extractContents(altbd->getPartAt(1)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "P2", extractContents(relbd->getPartAt(1)->getBody()->getContents()));
+ }
+
VMIME_TEST_SUITE_END