test-message-parser.c revision f148466c7b648669b99bf20c651ae7fc81d28659
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2007-2015 Dovecot authors, see the included COPYING file */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "lib.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "istream.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "message-parser.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "test-common.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic const char test_msg[] =
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"Return-Path: <test@example.org>\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"Subject: Hello world\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"From: Test User <test@example.org>\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"To: Another User <test2@example.org>\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"Message-Id: <1.2.3.4@example>\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"Mime-Version: 1.0\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"Date: Sun, 23 May 2007 04:58:08 +0300\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"Content-Type: multipart/signed; micalg=pgp-sha1;\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch" protocol=\"application/pgp-signature\";\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch" boundary=\"=-GNQXLhuj24Pl1aCkk4/d\"\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"--=-GNQXLhuj24Pl1aCkk4/d\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"Content-Type: text/plain\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"Content-Transfer-Encoding: quoted-printable\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"There was a day=20\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"a happy=20day\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"--=-GNQXLhuj24Pl1aCkk4/d\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"Content-Type: application/pgp-signature; name=signature.asc\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"-----BEGIN PGP SIGNATURE-----\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"Version: GnuPG v1.2.4 (GNU/Linux)\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"invalid\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"-----END PGP SIGNATURE-----\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"--=-GNQXLhuj24Pl1aCkk4/d--\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"\n";
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#define TEST_MSG_LEN (sizeof(test_msg)-1)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic bool msg_parts_cmp(struct message_part *p1, struct message_part *p2)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch while (p1 != NULL || p2 != NULL) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if ((p1 != NULL) != (p2 != NULL))
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return FALSE;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if ((p1->children != NULL) != (p2->children != NULL))
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return FALSE;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (p1->children) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (!msg_parts_cmp(p1->children, p2->children))
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return FALSE;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (p1->physical_pos != p2->physical_pos ||
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch p1->header_size.physical_size != p2->header_size.physical_size ||
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch p1->header_size.virtual_size != p2->header_size.virtual_size ||
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch p1->header_size.lines != p2->header_size.lines ||
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch p1->body_size.physical_size != p2->body_size.physical_size ||
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch p1->body_size.virtual_size != p2->body_size.virtual_size ||
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch p1->body_size.lines != p2->body_size.lines ||
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch p1->flags != p2->flags)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return FALSE;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch p1 = p1->next;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch p2 = p2->next;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return TRUE;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic void test_message_parser_small_blocks(void)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct message_parser_ctx *parser;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct istream *input;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct message_part *parts, *parts2;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct message_block block;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch unsigned int i, end_of_headers_idx;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pool_t pool;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch int ret;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch test_begin("message parser in small blocks");
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch pool = pool_alloconly_create("message parser", 10240);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch input = test_istream_create(test_msg);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* full parsing */
56d1345c43bbd28c36b7faa85e4163bd9e874290Timo Sirainen parser = message_parser_init(pool, input, 0, 0);
30d917bcd48d70af0371baf27571cc198d621a62Timo Sirainen while ((ret = message_parser_parse_next_block(parser, &block)) > 0) ;
9d0aee99a8c80d71137aa9b8c216cc203bec7a9aTimo Sirainen test_assert(ret < 0);
9d0aee99a8c80d71137aa9b8c216cc203bec7a9aTimo Sirainen test_assert(message_parser_deinit(&parser, &parts) == 0);
35e962a9186b4e9b2001628c1d7b55c24b33ce84Timo Sirainen
35e962a9186b4e9b2001628c1d7b55c24b33ce84Timo Sirainen /* parsing in small blocks */
35e962a9186b4e9b2001628c1d7b55c24b33ce84Timo Sirainen i_stream_seek(input, 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_istream_set_allow_eof(input, FALSE);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch parser = message_parser_init(pool, input, 0, 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch for (i = 1; i <= TEST_MSG_LEN*2+1; i++) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_istream_set_size(input, i/2);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (i > TEST_MSG_LEN*2)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_istream_set_allow_eof(input, TRUE);
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Bosch while ((ret = message_parser_parse_next_block(parser,
a8c4e79ff50fac21b05a7368b052583d410ca15cTimo Sirainen &block)) > 0) ;
a8c4e79ff50fac21b05a7368b052583d410ca15cTimo Sirainen test_assert((ret == 0 && i <= TEST_MSG_LEN*2) ||
70505f4839520ac67895992621c97d2480c22e7fTimo Sirainen (ret < 0 && i > TEST_MSG_LEN*2));
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(message_parser_deinit(&parser, &parts2) == 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(msg_parts_cmp(parts, parts2));
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* parsing in small blocks from preparsed parts */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_stream_seek(input, 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_istream_set_allow_eof(input, FALSE);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch end_of_headers_idx = (strstr(test_msg, "\n-----") - test_msg);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch parser = message_parser_init_from_parts(parts, input, 0,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch for (i = 1; i <= TEST_MSG_LEN*2+1; i++) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_istream_set_size(input, i/2);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (i > TEST_MSG_LEN*2)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_istream_set_allow_eof(input, TRUE);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch while ((ret = message_parser_parse_next_block(parser,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch &block)) > 0) ;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert((ret == 0 && i/2 <= end_of_headers_idx) ||
9dc01e0d10a61cab14867b26bf0d2d1dcf8ad978Timo Sirainen (ret < 0 && i/2 > end_of_headers_idx));
9dc01e0d10a61cab14867b26bf0d2d1dcf8ad978Timo Sirainen }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(message_parser_deinit(&parser, &parts2) == 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(msg_parts_cmp(parts, parts2));
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_stream_unref(&input);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pool_unref(&pool);
aacf2a69acc59e9382578d6f4e030788abc79706Timo Sirainen test_end();
aacf2a69acc59e9382578d6f4e030788abc79706Timo Sirainen}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic void test_message_parser_truncated_mime_headers(void)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic const char input_msg[] =
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"Content-Type: multipart/mixed; boundary=\":foo\"\n"
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen"\n"
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen"--:foo\n"
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen"--:foo\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"Content-Type: text/plain\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"--:foo\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"Content-Type: text/plain\r\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"--:foo\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"Content-Type: text/html\n"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch"--:foo--\n";
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct message_parser_ctx *parser;
636d0f43138468f8efe685a681326b123f660e49Timo Sirainen struct istream *input;
fc94140acba51adafedafbc8491a3223a51db7a8Stephan Bosch struct message_part *parts, *part;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct message_block block;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pool_t pool;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch int ret;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_begin("message parser truncated mime headers");
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pool = pool_alloconly_create("message parser", 10240);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch input = test_istream_create(input_msg);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch parser = message_parser_init(pool, input, 0, 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch while ((ret = message_parser_parse_next_block(parser, &block)) > 0) ;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(ret < 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(message_parser_deinit(&parser, &parts) == 0);
fc94140acba51adafedafbc8491a3223a51db7a8Stephan Bosch
fc94140acba51adafedafbc8491a3223a51db7a8Stephan Bosch test_assert((parts->flags & MESSAGE_PART_FLAG_MULTIPART) != 0);
fc94140acba51adafedafbc8491a3223a51db7a8Stephan Bosch test_assert(parts->body_size.lines == 8);
fc94140acba51adafedafbc8491a3223a51db7a8Stephan Bosch test_assert(parts->body_size.physical_size == 112);
636d0f43138468f8efe685a681326b123f660e49Timo Sirainen test_assert(parts->body_size.virtual_size == 112+7);
636d0f43138468f8efe685a681326b123f660e49Timo Sirainen test_assert(parts->children->header_size.physical_size == 0);
636d0f43138468f8efe685a681326b123f660e49Timo Sirainen test_assert(parts->children->body_size.physical_size == 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(parts->children->body_size.lines == 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(parts->children->next->header_size.physical_size == 24);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(parts->children->next->header_size.virtual_size == 24);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(parts->children->next->header_size.lines == 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(parts->children->next->next->header_size.physical_size == 24);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(parts->children->next->next->header_size.virtual_size == 24);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(parts->children->next->next->header_size.lines == 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(parts->children->next->next->next->header_size.physical_size == 23);
fb1be3de0159d6a10e916ad992e2bc53be64c6d5Timo Sirainen test_assert(parts->children->next->next->next->header_size.virtual_size == 23);
fb1be3de0159d6a10e916ad992e2bc53be64c6d5Timo Sirainen test_assert(parts->children->next->next->next->header_size.lines == 0);
fb1be3de0159d6a10e916ad992e2bc53be64c6d5Timo Sirainen for (part = parts->children; part != NULL; part = part->next) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(part->body_size.physical_size == 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_assert(part->body_size.virtual_size == 0);
1a9a35a6b307f8d5b25345af55e40a99162b4072Timo Sirainen }
1a9a35a6b307f8d5b25345af55e40a99162b4072Timo Sirainen test_assert(parts->children->next->next->next->next == NULL);
1a9a35a6b307f8d5b25345af55e40a99162b4072Timo Sirainen
1a9a35a6b307f8d5b25345af55e40a99162b4072Timo Sirainen i_stream_unref(&input);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pool_unref(&pool);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_end();
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic void test_message_parser_no_eoh(void)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch static const char input_msg[] = "a:b\n";
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct message_parser_ctx *parser;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct istream *input;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct message_part *parts;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct message_block block;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pool_t pool;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch test_begin("message parser no EOH");
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pool = pool_alloconly_create("message parser", 10240);
17cd0e0963f2fb0e66d49703e8cd0bda1b842468Timo Sirainen input = test_istream_create(input_msg);
17cd0e0963f2fb0e66d49703e8cd0bda1b842468Timo Sirainen
17cd0e0963f2fb0e66d49703e8cd0bda1b842468Timo Sirainen parser = message_parser_init(pool, input, 0, 0);
17cd0e0963f2fb0e66d49703e8cd0bda1b842468Timo Sirainen test_assert(message_parser_parse_next_block(parser, &block) > 0 &&
17cd0e0963f2fb0e66d49703e8cd0bda1b842468Timo Sirainen block.hdr != NULL && strcmp(block.hdr->name, "a") == 0 &&
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen block.hdr->value_len == 1 && block.hdr->value[0] == 'b');
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen test_assert(message_parser_parse_next_block(parser, &block) > 0 &&
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen block.hdr == NULL && block.size == 0);
ba1c847d0af4afe4787ed470d0c818e948e184e2Timo Sirainen test_assert(message_parser_parse_next_block(parser, &block) < 0);
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen test_assert(message_parser_deinit(&parser, &parts) == 0);
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen i_stream_unref(&input);
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen pool_unref(&pool);
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen test_end();
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen}
56d1345c43bbd28c36b7faa85e4163bd9e874290Timo Sirainen
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainenint main(void)
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen{
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen static void (*test_functions[])(void) = {
35e962a9186b4e9b2001628c1d7b55c24b33ce84Timo Sirainen test_message_parser_small_blocks,
35e962a9186b4e9b2001628c1d7b55c24b33ce84Timo Sirainen test_message_parser_truncated_mime_headers,
35e962a9186b4e9b2001628c1d7b55c24b33ce84Timo Sirainen test_message_parser_no_eoh,
d47b9f1bd7274c7b2d9049c2e1718d1cf89cc572Timo Sirainen NULL
d47b9f1bd7274c7b2d9049c2e1718d1cf89cc572Timo Sirainen };
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen return test_run(test_functions);
ba1c847d0af4afe4787ed470d0c818e948e184e2Timo Sirainen}
ba1c847d0af4afe4787ed470d0c818e948e184e2Timo Sirainen