boundary_find(struct message_boundary *boundaries,
const unsigned char *data, size_t len)
{
+ struct message_boundary *best = NULL;
+
/* As MIME spec says: search from latest one to oldest one so that we
don't break if the same boundary is used in nested parts. Also the
full message line doesn't have to match the boundary, only the
- beginning. */
+ beginning. However, if there are multiple prefixes whose beginning
+ matches, use the longest matching one. */
while (boundaries != NULL) {
if (boundaries->len <= len &&
- memcmp(boundaries->boundary, data, boundaries->len) == 0)
- return boundaries;
+ memcmp(boundaries->boundary, data, boundaries->len) == 0 &&
+ (best == NULL || best->len < boundaries->len))
+ best = boundaries;
boundaries = boundaries->next;
}
- return NULL;
+ return best;
}
static void parse_body_add_block(struct message_parser_ctx *ctx,
test_end();
}
+static void test_message_parser_truncated_mime_headers2(void)
+{
+static const char input_msg[] =
+"Content-Type: multipart/mixed; boundary=\"ab\"\n"
+"\n"
+"--ab\n"
+"Content-Type: multipart/mixed; boundary=\"a\"\n"
+"\n"
+"--ab\n"
+"Content-Type: text/plain\n"
+"\n"
+"--a\n\n";
+ struct message_parser_ctx *parser;
+ struct istream *input;
+ struct message_part *parts;
+ struct message_block block;
+ pool_t pool;
+ int ret;
+
+ test_begin("message parser truncated mime headers 2");
+ pool = pool_alloconly_create("message parser", 10240);
+ input = test_istream_create(input_msg);
+
+ parser = message_parser_init(pool, input, 0, 0);
+ while ((ret = message_parser_parse_next_block(parser, &block)) > 0) ;
+ test_assert(ret < 0);
+ test_assert(message_parser_deinit(&parser, &parts) == 0);
+
+ test_assert(parts->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
+ test_assert(parts->header_size.lines == 2);
+ test_assert(parts->header_size.physical_size == 46);
+ test_assert(parts->header_size.virtual_size == 46+2);
+ test_assert(parts->body_size.lines == 8);
+ test_assert(parts->body_size.physical_size == 86);
+ test_assert(parts->body_size.virtual_size == 86+8);
+
+ test_assert(parts->children->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
+ test_assert(parts->children->physical_pos == 51);
+ test_assert(parts->children->header_size.lines == 1);
+ test_assert(parts->children->header_size.physical_size == 44);
+ test_assert(parts->children->header_size.virtual_size == 44+1);
+ test_assert(parts->children->body_size.lines == 0);
+ test_assert(parts->children->body_size.physical_size == 0);
+ test_assert(parts->children->children == NULL);
+
+ test_assert(parts->children->next->flags == (MESSAGE_PART_FLAG_TEXT | MESSAGE_PART_FLAG_IS_MIME));
+ test_assert(parts->children->next->physical_pos == 101);
+ test_assert(parts->children->next->header_size.lines == 2);
+ test_assert(parts->children->next->header_size.physical_size == 26);
+ test_assert(parts->children->next->header_size.virtual_size == 26+2);
+ test_assert(parts->children->next->body_size.lines == 2);
+ test_assert(parts->children->next->body_size.physical_size == 5);
+ test_assert(parts->children->next->body_size.virtual_size == 5+2);
+ test_assert(parts->children->next->children == NULL);
+
+ i_stream_unref(&input);
+ pool_unref(&pool);
+ test_end();
+}
+
+static void test_message_parser_truncated_mime_headers3(void)
+{
+static const char input_msg[] =
+"Content-Type: multipart/mixed; boundary=\"ab\"\n";
+ struct message_parser_ctx *parser;
+ struct istream *input;
+ struct message_part *parts;
+ struct message_block block;
+ pool_t pool;
+ int ret;
+
+ test_begin("message parser truncated mime headers 3");
+ pool = pool_alloconly_create("message parser", 10240);
+ input = test_istream_create(input_msg);
+
+ parser = message_parser_init(pool, input, 0, 0);
+ while ((ret = message_parser_parse_next_block(parser, &block)) > 0) ;
+ test_assert(ret < 0);
+ test_assert(message_parser_deinit(&parser, &parts) == 0);
+
+ test_assert(parts->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
+ test_assert(parts->header_size.lines == 1);
+ test_assert(parts->header_size.physical_size == 45);
+ test_assert(parts->header_size.virtual_size == 45+1);
+ test_assert(parts->body_size.lines == 0);
+ test_assert(parts->body_size.physical_size == 0);
+
+ test_assert(parts->children == NULL);
+
+ i_stream_unref(&input);
+ pool_unref(&pool);
+ test_end();
+}
+
static void test_message_parser_duplicate_mime_boundary(void)
{
static const char input_msg[] =
static void (*test_functions[])(void) = {
test_message_parser_small_blocks,
test_message_parser_truncated_mime_headers,
+ test_message_parser_truncated_mime_headers2,
+ test_message_parser_truncated_mime_headers3,
test_message_parser_duplicate_mime_boundary,
test_message_parser_continuing_mime_boundary,
test_message_parser_no_eoh,