Mercurial > thymian
comparison 3rdparty/vmime/tests/parser/bodyPartTest.cpp @ 0:a4671277546c tip
created the repository for the thymian project
| author | ferencd |
|---|---|
| date | Tue, 17 Aug 2021 11:19:54 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:a4671277546c |
|---|---|
| 1 // | |
| 2 // VMime library (http://www.vmime.org) | |
| 3 // Copyright (C) 2002-2013 Vincent Richard <vincent@vmime.org> | |
| 4 // | |
| 5 // This program is free software; you can redistribute it and/or | |
| 6 // modify it under the terms of the GNU General Public License as | |
| 7 // published by the Free Software Foundation; either version 3 of | |
| 8 // the License, or (at your option) any later version. | |
| 9 // | |
| 10 // This program is distributed in the hope that it will be useful, | |
| 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 13 // General Public License for more details. | |
| 14 // | |
| 15 // You should have received a copy of the GNU General Public License along | |
| 16 // with this program; if not, write to the Free Software Foundation, Inc., | |
| 17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 18 // | |
| 19 // Linking this library statically or dynamically with other modules is making | |
| 20 // a combined work based on this library. Thus, the terms and conditions of | |
| 21 // the GNU General Public License cover the whole combination. | |
| 22 // | |
| 23 | |
| 24 #include "tests/testUtils.hpp" | |
| 25 | |
| 26 | |
| 27 VMIME_TEST_SUITE_BEGIN(bodyPartTest) | |
| 28 | |
| 29 VMIME_TEST_LIST_BEGIN | |
| 30 VMIME_TEST(testParse) | |
| 31 VMIME_TEST(testGenerate) | |
| 32 VMIME_TEST(testParseGuessBoundary) | |
| 33 VMIME_TEST(testParseGuessBoundaryWithTransportPadding) | |
| 34 VMIME_TEST(testParseMissingLastBoundary) | |
| 35 VMIME_TEST(testPrologEpilog) | |
| 36 VMIME_TEST(testPrologEncoding) | |
| 37 VMIME_TEST(testSuccessiveBoundaries) | |
| 38 VMIME_TEST(testTransportPaddingInBoundary) | |
| 39 VMIME_TEST(testGenerate7bit) | |
| 40 VMIME_TEST(testTextUsageForQPEncoding) | |
| 41 VMIME_TEST(testParseVeryBigMessage) | |
| 42 VMIME_TEST_LIST_END | |
| 43 | |
| 44 | |
| 45 static const vmime::string extractComponentString | |
| 46 (const vmime::string& buffer, const vmime::component& c) | |
| 47 { | |
| 48 return vmime::string(buffer.begin() + c.getParsedOffset(), | |
| 49 buffer.begin() + c.getParsedOffset() + c.getParsedLength()); | |
| 50 } | |
| 51 | |
| 52 static const vmime::string extractContents(const vmime::shared_ptr <const vmime::contentHandler> cts) | |
| 53 { | |
| 54 std::ostringstream oss; | |
| 55 vmime::utility::outputStreamAdapter os(oss); | |
| 56 | |
| 57 cts->extract(os); | |
| 58 | |
| 59 return oss.str(); | |
| 60 } | |
| 61 | |
| 62 | |
| 63 void testParse() | |
| 64 { | |
| 65 vmime::string str1 = "HEADER\r\n\r\nBODY"; | |
| 66 vmime::bodyPart p1; | |
| 67 p1.parse(str1); | |
| 68 | |
| 69 VASSERT_EQ("1", "HEADER\r\n\r\n", extractComponentString(str1, *p1.getHeader())); | |
| 70 VASSERT_EQ("2", "BODY", extractComponentString(str1, *p1.getBody())); | |
| 71 | |
| 72 vmime::string str2 = "HEADER\n\nBODY"; | |
| 73 vmime::bodyPart p2; | |
| 74 p2.parse(str2); | |
| 75 | |
| 76 VASSERT_EQ("3", "HEADER\n\n", extractComponentString(str2, *p2.getHeader())); | |
| 77 VASSERT_EQ("4", "BODY", extractComponentString(str2, *p2.getBody())); | |
| 78 | |
| 79 vmime::string str3 = "HEADER\r\n\nBODY"; | |
| 80 vmime::bodyPart p3; | |
| 81 p3.parse(str3); | |
| 82 | |
| 83 VASSERT_EQ("5", "HEADER\r\n\n", extractComponentString(str3, *p3.getHeader())); | |
| 84 VASSERT_EQ("6", "BODY", extractComponentString(str3, *p3.getBody())); | |
| 85 } | |
| 86 | |
| 87 void testParseMissingLastBoundary() | |
| 88 { | |
| 89 vmime::string str = | |
| 90 "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\"" | |
| 91 "\r\n\r\n" | |
| 92 "--MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n" | |
| 93 "--MY-BOUNDARY\r\nHEADER2\r\n\r\nBODY2"; | |
| 94 | |
| 95 vmime::bodyPart p; | |
| 96 p.parse(str); | |
| 97 | |
| 98 VASSERT_EQ("count", 2, p.getBody()->getPartCount()); | |
| 99 | |
| 100 VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents())); | |
| 101 VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents())); | |
| 102 } | |
| 103 | |
| 104 void testGenerate() | |
| 105 { | |
| 106 vmime::bodyPart p1; | |
| 107 p1.getHeader()->getField("Foo")->setValue(vmime::string("bar")); | |
| 108 p1.getBody()->setContents(vmime::make_shared <vmime::stringContentHandler>("Baz")); | |
| 109 | |
| 110 VASSERT_EQ("1", "Foo: bar\r\n\r\nBaz", p1.generate()); | |
| 111 } | |
| 112 | |
| 113 void testPrologEpilog() | |
| 114 { | |
| 115 const char testMail[] = | |
| 116 "To: test@vmime.org\r\n" | |
| 117 "From: test@vmime.org\r\n" | |
| 118 "Subject: Prolog and epilog test\r\n" | |
| 119 "Content-Type: multipart/mixed; \r\n" | |
| 120 " boundary=\"=_boundary\"\r\n" | |
| 121 "\r\n" | |
| 122 "Prolog text\r\n" | |
| 123 "--=_boundary\r\n" | |
| 124 "Content-Type: text/plain\r\n" | |
| 125 "\r\n" | |
| 126 "Part1\r\n" | |
| 127 "--=_boundary--\r\n" | |
| 128 "Epilog text"; | |
| 129 | |
| 130 vmime::bodyPart part; | |
| 131 part.parse(testMail); | |
| 132 | |
| 133 VASSERT_EQ("prolog", "Prolog text", part.getBody()->getPrologText()); | |
| 134 VASSERT_EQ("epilog", "Epilog text", part.getBody()->getEpilogText()); | |
| 135 } | |
| 136 | |
| 137 // Test for bug fix: prolog should not be encoded | |
| 138 // http://sourceforge.net/tracker/?func=detail&atid=525568&aid=3174903&group_id=69724 | |
| 139 void testPrologEncoding() | |
| 140 { | |
| 141 const char testmail[] = | |
| 142 "To: test@vmime.org\r\n" | |
| 143 "From: test@vmime.org\r\n" | |
| 144 "Subject: Prolog encoding test\r\n" | |
| 145 "Content-Type: multipart/mixed; \r\n" | |
| 146 " boundary=\"=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\"\r\n" | |
| 147 "\r\n" | |
| 148 "This is a multi-part message in MIME format. Your mail reader does not\r\n" | |
| 149 "understand MIME message format.\r\n" | |
| 150 "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\r\n" | |
| 151 "Content-Type: text/html; charset=windows-1251\r\n" | |
| 152 "Content-Transfer-Encoding: quoted-printable\r\n" | |
| 153 "\r\n" | |
| 154 "=DD=F2=EE =F2=E5=EA=F1=F2=EE=E2=E0=FF =F7=E0=F1=F2=FC =F1=EB=EE=E6=ED=EE=E3=\r\n" | |
| 155 "=EE =F1=EE=EE=E1=F9=E5=ED=E8=FF\r\n" | |
| 156 "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\r\n" | |
| 157 "Content-Type: application/octet-stream; charset=windows-1251\r\n" | |
| 158 "Content-Disposition: attachment; filename=FNS.zip\r\n" | |
| 159 "Content-Transfer-Encoding: base64\r\n" | |
| 160 "\r\n" | |
| 161 "UEsDBB...snap...EEAAAAAA==\r\n" | |
| 162 "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q--\r\n" | |
| 163 "Epilog text"; | |
| 164 | |
| 165 vmime::shared_ptr<vmime::message> msg = vmime::make_shared<vmime::message>(); | |
| 166 | |
| 167 std::string istr(testmail); | |
| 168 | |
| 169 std::string ostr; | |
| 170 vmime::utility::outputStreamStringAdapter out(ostr); | |
| 171 | |
| 172 for (int i = 0 ; i < 10 ; ++i) | |
| 173 { | |
| 174 ostr.clear(); | |
| 175 | |
| 176 msg->parse(istr); | |
| 177 msg->generate(out); | |
| 178 | |
| 179 istr = ostr; | |
| 180 } | |
| 181 | |
| 182 VASSERT_EQ("prolog", "This is a multi-part message in MIME format. Your mail reader" | |
| 183 " does not understand MIME message format.", msg->getBody()->getPrologText()); | |
| 184 VASSERT_EQ("epilog", "Epilog text", msg->getBody()->getEpilogText()); | |
| 185 } | |
| 186 | |
| 187 void testSuccessiveBoundaries() | |
| 188 { | |
| 189 vmime::string str = | |
| 190 "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\"" | |
| 191 "\r\n\r\n" | |
| 192 "--MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n" | |
| 193 "--MY-BOUNDARY\r\n" | |
| 194 "--MY-BOUNDARY--\r\n"; | |
| 195 | |
| 196 vmime::bodyPart p; | |
| 197 p.parse(str); | |
| 198 | |
| 199 VASSERT_EQ("count", 2, p.getBody()->getPartCount()); | |
| 200 | |
| 201 VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents())); | |
| 202 VASSERT_EQ("part2-body", "", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents())); | |
| 203 } | |
| 204 | |
| 205 void testTransportPaddingInBoundary() | |
| 206 { | |
| 207 vmime::string str = | |
| 208 "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\"" | |
| 209 "\r\n\r\n" | |
| 210 "-- \t MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n" | |
| 211 "--MY-BOUNDARY\r\n" | |
| 212 "-- MY-BOUNDARY--\r\n"; | |
| 213 | |
| 214 vmime::bodyPart p; | |
| 215 p.parse(str); | |
| 216 | |
| 217 VASSERT_EQ("count", 2, p.getBody()->getPartCount()); | |
| 218 | |
| 219 VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents())); | |
| 220 VASSERT_EQ("part2-body", "", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents())); | |
| 221 } | |
| 222 | |
| 223 /** Ensure '7bit' encoding is used when body is 7-bit only. */ | |
| 224 void testGenerate7bit() | |
| 225 { | |
| 226 vmime::shared_ptr <vmime::plainTextPart> p1 = vmime::make_shared <vmime::plainTextPart>(); | |
| 227 p1->setText(vmime::make_shared <vmime::stringContentHandler>("Part1 is US-ASCII only.")); | |
| 228 | |
| 229 vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>(); | |
| 230 p1->generateIn(msg, msg); | |
| 231 | |
| 232 vmime::shared_ptr <vmime::header> header1 = msg->getBody()->getPartAt(0)->getHeader(); | |
| 233 VASSERT_EQ("1", "7bit", header1->ContentTransferEncoding()->getValue()->generate()); | |
| 234 } | |
| 235 | |
| 236 void testTextUsageForQPEncoding() | |
| 237 { | |
| 238 vmime::shared_ptr <vmime::plainTextPart> part = vmime::make_shared <vmime::plainTextPart>(); | |
| 239 part->setText(vmime::make_shared <vmime::stringContentHandler>("Part1-line1\r\nPart1-line2\r\n\x89")); | |
| 240 | |
| 241 vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>(); | |
| 242 part->generateIn(msg, msg); | |
| 243 | |
| 244 vmime::shared_ptr <vmime::body> body = msg->getBody()->getPartAt(0)->getBody(); | |
| 245 vmime::shared_ptr <vmime::header> header = msg->getBody()->getPartAt(0)->getHeader(); | |
| 246 | |
| 247 std::ostringstream oss; | |
| 248 vmime::utility::outputStreamAdapter os(oss); | |
| 249 body->generate(os, 80); | |
| 250 | |
| 251 VASSERT_EQ("1", "quoted-printable", header->ContentTransferEncoding()->getValue()->generate()); | |
| 252 | |
| 253 // This should *NOT* be: | |
| 254 // Part1-line1=0D=0APart1-line2=0D=0A=89 | |
| 255 VASSERT_EQ("2", "Part1-line1\r\nPart1-line2\r\n=89", oss.str()); | |
| 256 } | |
| 257 | |
| 258 void testParseGuessBoundary() | |
| 259 { | |
| 260 // Boundary is not specified in "Content-Type" field | |
| 261 // Parser will try to guess it from message contents. | |
| 262 | |
| 263 vmime::string str = | |
| 264 "Content-Type: multipart/mixed" | |
| 265 "\r\n\r\n" | |
| 266 "--UNKNOWN-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n" | |
| 267 "--UNKNOWN-BOUNDARY\r\nHEADER2\r\n\r\nBODY2\r\n" | |
| 268 "--UNKNOWN-BOUNDARY--"; | |
| 269 | |
| 270 vmime::bodyPart p; | |
| 271 p.parse(str); | |
| 272 | |
| 273 VASSERT_EQ("count", 2, p.getBody()->getPartCount()); | |
| 274 | |
| 275 VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents())); | |
| 276 VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents())); | |
| 277 } | |
| 278 | |
| 279 void testParseGuessBoundaryWithTransportPadding() | |
| 280 { | |
| 281 // Boundary is not specified in "Content-Type" field | |
| 282 // Parser will try to guess it from message contents. | |
| 283 // Transport padding white spaces should be ignored. | |
| 284 | |
| 285 vmime::string str = | |
| 286 "Content-Type: multipart/mixed" | |
| 287 "\r\n\r\n" | |
| 288 "-- \t UNKNOWN-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n" | |
| 289 "--UNKNOWN-BOUNDARY\r\nHEADER2\r\n\r\nBODY2\r\n" | |
| 290 "--UNKNOWN-BOUNDARY--"; | |
| 291 | |
| 292 vmime::bodyPart p; | |
| 293 p.parse(str); | |
| 294 | |
| 295 VASSERT_EQ("count", 2, p.getBody()->getPartCount()); | |
| 296 | |
| 297 VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents())); | |
| 298 VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents())); | |
| 299 } | |
| 300 | |
| 301 void testParseVeryBigMessage() | |
| 302 { | |
| 303 // When parsing from a seekable input stream, body contents should not | |
| 304 // be kept in memory in a "stringContentHandler" object. Instead, content | |
| 305 // should be accessible via a "streamContentHandler" object. | |
| 306 | |
| 307 static const std::string BODY1_BEGIN = "BEGIN1BEGIN1BEGIN1"; | |
| 308 static const std::string BODY1_LINE = "BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1"; | |
| 309 static const std::string BODY1_END = "END1END1"; | |
| 310 static const unsigned int BODY1_REPEAT = 35000; | |
| 311 static const unsigned int BODY1_LENGTH = | |
| 312 BODY1_BEGIN.length() + BODY1_LINE.length() * BODY1_REPEAT + BODY1_END.length(); | |
| 313 | |
| 314 static const std::string BODY2_LINE = "BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2"; | |
| 315 static const unsigned int BODY2_REPEAT = 20000; | |
| 316 | |
| 317 std::ostringstream oss; | |
| 318 oss << "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\"" | |
| 319 << "\r\n\r\n" | |
| 320 << "--MY-BOUNDARY\r\n" | |
| 321 << "HEADER1\r\n" | |
| 322 << "\r\n"; | |
| 323 | |
| 324 oss << BODY1_BEGIN; | |
| 325 | |
| 326 for (unsigned int i = 0 ; i < BODY1_REPEAT ; ++i) | |
| 327 oss << BODY1_LINE; | |
| 328 | |
| 329 oss << BODY1_END; | |
| 330 | |
| 331 oss << "\r\n" | |
| 332 << "--MY-BOUNDARY\r\n" | |
| 333 << "HEADER2\r\n" | |
| 334 << "\r\n"; | |
| 335 | |
| 336 for (unsigned int i = 0 ; i < BODY2_REPEAT ; ++i) | |
| 337 oss << BODY2_LINE; | |
| 338 | |
| 339 oss << "\r\n" | |
| 340 << "--MY-BOUNDARY--\r\n"; | |
| 341 | |
| 342 vmime::shared_ptr <vmime::utility::inputStreamStringAdapter> is = | |
| 343 vmime::make_shared <vmime::utility::inputStreamStringAdapter>(oss.str()); | |
| 344 | |
| 345 vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>(); | |
| 346 msg->parse(is, oss.str().length()); | |
| 347 | |
| 348 vmime::shared_ptr <vmime::body> body1 = msg->getBody()->getPartAt(0)->getBody(); | |
| 349 vmime::shared_ptr <const vmime::contentHandler> body1Cts = body1->getContents(); | |
| 350 | |
| 351 vmime::shared_ptr <vmime::body> body2 = msg->getBody()->getPartAt(1)->getBody(); | |
| 352 vmime::shared_ptr <const vmime::contentHandler> body2Cts = body2->getContents(); | |
| 353 | |
| 354 vmime::string body1CtsExtracted; | |
| 355 vmime::utility::outputStreamStringAdapter body1CtsExtractStream(body1CtsExtracted); | |
| 356 body1Cts->extract(body1CtsExtractStream); | |
| 357 | |
| 358 VASSERT_EQ("1.1", BODY1_LENGTH, body1Cts->getLength()); | |
| 359 VASSERT("1.2", vmime::dynamicCast <const vmime::streamContentHandler>(body1Cts) != NULL); | |
| 360 VASSERT_EQ("1.3", BODY1_LENGTH, body1CtsExtracted.length()); | |
| 361 VASSERT_EQ("1.4", BODY1_BEGIN, body1CtsExtracted.substr(0, BODY1_BEGIN.length())); | |
| 362 VASSERT_EQ("1.5", BODY1_END, body1CtsExtracted.substr(BODY1_LENGTH - BODY1_END.length(), BODY1_END.length())); | |
| 363 | |
| 364 VASSERT_EQ("2.1", BODY2_LINE.length() * BODY2_REPEAT, body2Cts->getLength()); | |
| 365 VASSERT("2.2", vmime::dynamicCast <const vmime::streamContentHandler>(body2Cts) != NULL); | |
| 366 } | |
| 367 | |
| 368 VMIME_TEST_SUITE_END | |
| 369 |
