diff options
-rw-r--r-- | src/vmime/body.cpp | 18 | ||||
-rw-r--r-- | tests/parser/bodyPartTest.cpp | 38 |
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 |