test-message-header-parser.c (dovecot-2.3.16) | : | test-message-header-parser.c (dovecot-2.3.17) | ||
---|---|---|---|---|
/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */ | /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */ | |||
#include "lib.h" | #include "lib.h" | |||
#include "str.h" | #include "str.h" | |||
#include "strfuncs.h" | ||||
#include "unichar.h" | #include "unichar.h" | |||
#include "istream.h" | #include "istream.h" | |||
#include "message-size.h" | #include "message-size.h" | |||
#include "message-header-parser.h" | #include "message-header-parser.h" | |||
#include "test-common.h" | #include "test-common.h" | |||
#define TEST1_MSG_BODY_LEN 5 | #define TEST1_MSG_BODY_LEN 5 | |||
static const char *test1_msg = | static const char *test1_msg = | |||
"h1: v1\n" | "h1: v1\n" | |||
"h2:\n" | "h2:\n" | |||
" v2\r\n" | " v2\r\n" | |||
"h3: \r\n" | "h3: \r\n" | |||
"\tv3\n" | "\tv3\n" | |||
"\tw3\r\n" | "\tw3\r\n" | |||
"h4: \r\n" | ||||
"\n" | "\n" | |||
" body"; | " body"; | |||
static void | static void | |||
test_message_header_parser_one(struct message_header_parser_ctx *parser, | test_message_header_parser_one(struct message_header_parser_ctx *parser, | |||
enum message_header_parser_flags hdr_flags) | enum message_header_parser_flags hdr_flags) | |||
{ | { | |||
struct message_header_line *hdr; | struct message_header_line *hdr; | |||
bool use_full_value; | bool use_full_value; | |||
skipping to change at line 119 | skipping to change at line 121 | |||
memcmp(hdr->full_value, " v3 w3", 6) == 0); | memcmp(hdr->full_value, " v3 w3", 6) == 0); | |||
} else if ((hdr_flags & MESSAGE_HEADER_PARSER_FLAG_DROP_CR) != 0) { | } else if ((hdr_flags & MESSAGE_HEADER_PARSER_FLAG_DROP_CR) != 0) { | |||
test_assert(hdr->full_value_len == 8 && | test_assert(hdr->full_value_len == 8 && | |||
memcmp(hdr->full_value, "\n\tv3\n\tw3", 8) == 0); | memcmp(hdr->full_value, "\n\tv3\n\tw3", 8) == 0); | |||
} else if (use_full_value) { | } else if (use_full_value) { | |||
test_assert(hdr->full_value_len == 9 && | test_assert(hdr->full_value_len == 9 && | |||
memcmp(hdr->full_value, "\r\n\tv3\n\tw3", 9) == 0); | memcmp(hdr->full_value, "\r\n\tv3\n\tw3", 9) == 0); | |||
} | } | |||
test_assert(message_parse_header_next(parser, &hdr) > 0); | test_assert(message_parse_header_next(parser, &hdr) > 0); | |||
test_assert(hdr->name_offset == 32 && hdr->full_value_offset == 32); | test_assert(hdr->name_offset == 32 && hdr->full_value_offset == 36); | |||
test_assert(hdr->name_len == 2 && strcmp(hdr->name, "h4") == 0); | ||||
test_assert(hdr->middle_len == 2 && memcmp(hdr->middle, ": ", 2) == 0); | ||||
test_assert(hdr->value_len == 0 && memcmp(hdr->value, "", 0) == 0); | ||||
test_assert(!hdr->continues && !hdr->continued && !hdr->eoh && | ||||
!hdr->no_newline && hdr->crlf_newline); | ||||
test_assert(hdr->full_value_len == 0 && hdr->full_value != NULL); | ||||
test_assert(message_parse_header_next(parser, &hdr) > 0); | ||||
test_assert(hdr->name_offset == 38 && hdr->full_value_offset == 38); | ||||
test_assert(hdr->name_len == 0 && hdr->middle_len == 0 && hdr->value_len == 0); | test_assert(hdr->name_len == 0 && hdr->middle_len == 0 && hdr->value_len == 0); | |||
test_assert(!hdr->continues && !hdr->continued && hdr->eoh && | test_assert(!hdr->continues && !hdr->continued && hdr->eoh && | |||
!hdr->no_newline && !hdr->crlf_newline); | !hdr->no_newline && !hdr->crlf_newline); | |||
test_assert(message_parse_header_next(parser, &hdr) < 0); | test_assert(message_parse_header_next(parser, &hdr) < 0); | |||
} | } | |||
static void test_message_header_parser(void) | static void test_message_header_parser(void) | |||
{ | { | |||
static enum message_header_parser_flags max_hdr_flags = | static enum message_header_parser_flags max_hdr_flags = | |||
skipping to change at line 238 | skipping to change at line 249 | |||
message_parse_header_deinit(&parser); | message_parse_header_deinit(&parser); | |||
i_stream_seek(input, 0); | i_stream_seek(input, 0); | |||
/* Buffer must be +1 for message_get_header_size as it's using | /* Buffer must be +1 for message_get_header_size as it's using | |||
i_stream_read_bytes which does not work with lower buffersize | i_stream_read_bytes which does not work with lower buffersize | |||
because it returns -2 (input buffer full) if 2 bytes are wanted. */ | because it returns -2 (input buffer full) if 2 bytes are wanted. */ | |||
test_istream_set_max_buffer_size(input, buffer_size+1); | test_istream_set_max_buffer_size(input, buffer_size+1); | |||
message_get_header_size(input, size_2_r, &has_nuls); | message_get_header_size(input, size_2_r, &has_nuls); | |||
i_stream_unref(&input); | i_stream_unref(&input); | |||
} | } | |||
#define NAME10 "1234567890" | ||||
#define NAME100 NAME10 NAME10 NAME10 NAME10 NAME10 \ | ||||
NAME10 NAME10 NAME10 NAME10 NAME10 | ||||
#define NAME1000 NAME100 NAME100 NAME100 NAME100 NAME100 \ | ||||
NAME100 NAME100 NAME100 NAME100 NAME100 | ||||
static void test_message_header_parser_long_lines(void) | static void test_message_header_parser_long_lines(void) | |||
{ | { | |||
static const char *lf_str = "1234567890: 345\n\n"; | static const char *lf_str = NAME10": 345\n\n"; | |||
static const char *crlf_str = "1234567890: 345\r\n\r\n"; | static const char *crlf_str = NAME10": 345\r\n\r\n"; | |||
static const char *lf_str_vl = NAME1000": Is a long header name\n\n"; | ||||
static const char *crlf_str_vl = NAME1000": Is a long header name\r\n\r\n | ||||
"; | ||||
static const char *lf_str_ol = NAME1000 \ | ||||
NAME100 ": Is a overlong header name\n\n"; | ||||
static const char *crlf_str_ol = NAME1000 \ | ||||
NAME100 ": Is a overlong header name\r\n\r\n"; | ||||
struct message_size hdr_size, hdr_size2; | struct message_size hdr_size, hdr_size2; | |||
size_t i, len; | size_t i, len; | |||
test_begin("message header parser long lines"); | test_begin("message header parser long lines"); | |||
len = strlen(lf_str); | len = strlen(lf_str); | |||
for (i = 2; i < len; i++) { | for (i = 2; i < len; i++) { | |||
test_message_header_parser_long_lines_str(lf_str, i, &hdr_size, & hdr_size2); | test_message_header_parser_long_lines_str(lf_str, i, &hdr_size, & hdr_size2); | |||
test_assert(hdr_size.physical_size == len); | test_assert(hdr_size.physical_size == len); | |||
test_assert(hdr_size.virtual_size == len + 2); | test_assert(hdr_size.virtual_size == len + 2); | |||
test_assert(hdr_size.virtual_size == hdr_size2.virtual_size); | test_assert(hdr_size.virtual_size == hdr_size2.virtual_size); | |||
test_assert(hdr_size.physical_size == hdr_size2.physical_size); | test_assert(hdr_size.physical_size == hdr_size2.physical_size); | |||
} | } | |||
len = strlen(crlf_str); | len = strlen(crlf_str); | |||
for (i = 3; i < len; i++) { | for (i = 3; i < len; i++) { | |||
test_message_header_parser_long_lines_str(crlf_str, i, &hdr_size, &hdr_size2); | test_message_header_parser_long_lines_str(crlf_str, i, &hdr_size, &hdr_size2); | |||
test_assert(hdr_size.physical_size == len); | test_assert(hdr_size.physical_size == len); | |||
test_assert(hdr_size.virtual_size == len); | test_assert(hdr_size.virtual_size == len); | |||
test_assert(hdr_size.virtual_size == hdr_size2.virtual_size); | test_assert(hdr_size.virtual_size == hdr_size2.virtual_size); | |||
test_assert(hdr_size.physical_size == hdr_size2.physical_size); | test_assert(hdr_size.physical_size == hdr_size2.physical_size); | |||
} | } | |||
/* increment these faster, otherwise the test is very slow */ | ||||
len = strlen(lf_str_vl); | ||||
for (i = 3; i < len; i *= 2) { | ||||
test_message_header_parser_long_lines_str(lf_str_vl, i, &hdr_siz | ||||
e, &hdr_size2); | ||||
test_assert(hdr_size.physical_size == len); | ||||
test_assert(hdr_size.virtual_size == len + 2); | ||||
test_assert(hdr_size.virtual_size == hdr_size2.virtual_size); | ||||
test_assert(hdr_size.physical_size == hdr_size2.physical_size); | ||||
} | ||||
len = strlen(crlf_str_vl); | ||||
for (i = 3; i < len; i *= 2) { | ||||
test_message_header_parser_long_lines_str(crlf_str_vl, i, &hdr_si | ||||
ze, &hdr_size2); | ||||
test_assert(hdr_size.physical_size == len); | ||||
test_assert(hdr_size.virtual_size == len); | ||||
test_assert(hdr_size.virtual_size == hdr_size2.virtual_size); | ||||
test_assert(hdr_size.physical_size == hdr_size2.physical_size); | ||||
} | ||||
/* test that parsing overlength lines work so that name & middle are | ||||
empty. */ | ||||
struct message_header_line *hdr; | ||||
struct message_header_parser_ctx *ctx; | ||||
struct istream *input; | ||||
input = test_istream_create(lf_str_ol); | ||||
ctx = message_parse_header_init(input, NULL, 0); | ||||
test_assert(message_parse_header_next(ctx, &hdr) > 0 && | ||||
*hdr->name == '\0' && hdr->middle == uchar_empty_ptr && | ||||
hdr->name_len == 0 && hdr->middle_len == 0 && | ||||
hdr->value != NULL && hdr->value_len > 0); | ||||
test_assert(message_parse_header_next(ctx, &hdr) > 0 && | ||||
hdr->eoh); | ||||
message_parse_header_deinit(&ctx); | ||||
i_stream_unref(&input); | ||||
input = test_istream_create(crlf_str_ol); | ||||
ctx = message_parse_header_init(input, NULL, 0); | ||||
test_assert(message_parse_header_next(ctx, &hdr) > 0 && | ||||
*hdr->name == '\0' && hdr->middle == uchar_empty_ptr && | ||||
hdr->name_len == 0 && hdr->middle_len == 0 && | ||||
hdr->value != NULL && hdr->value_len > 0); | ||||
test_assert(message_parse_header_next(ctx, &hdr) > 0 && | ||||
hdr->eoh); | ||||
message_parse_header_deinit(&ctx); | ||||
i_stream_unref(&input); | ||||
/* test offset parsing */ | ||||
static const char *data = "h1" NAME1000 NAME100 \ | ||||
": value1\r\n" \ | ||||
"h2" NAME1000 NAME100 \ | ||||
": value2\r\n" \ | ||||
"h3" NAME1000 NAME100 \ | ||||
": value3\r\n\r\n"; | ||||
input = test_istream_create(data); | ||||
ctx = message_parse_header_init(input, NULL, 0); | ||||
test_assert(message_parse_header_next(ctx, &hdr) > 0 && | ||||
hdr->full_value[0] == 'h' && | ||||
hdr->full_value[1] == '1' && | ||||
hdr->full_value_offset == 0); | ||||
test_assert(message_parse_header_next(ctx, &hdr) > 0 && | ||||
hdr->full_value[0] == 'h' && | ||||
hdr->full_value[1] == '2' && | ||||
hdr->full_value_offset == 1112); | ||||
test_assert(message_parse_header_next(ctx, &hdr) > 0 && | ||||
hdr->full_value[0] == 'h' && | ||||
hdr->full_value[1] == '3' && | ||||
hdr->full_value_offset == 2224); | ||||
test_assert(message_parse_header_next(ctx, &hdr) > 0 && | ||||
hdr->eoh); | ||||
message_parse_header_deinit(&ctx); | ||||
i_stream_unref(&input); | ||||
test_end(); | test_end(); | |||
} | } | |||
static void test_message_header_parser_extra_cr_in_eoh(void) | static void test_message_header_parser_extra_cr_in_eoh(void) | |||
{ | { | |||
static const char *str = "a:b\n\r\r\n"; | static const char *str = "a:b\n\r\r\n"; | |||
struct message_header_parser_ctx *parser; | struct message_header_parser_ctx *parser; | |||
struct message_header_line *hdr; | struct message_header_line *hdr; | |||
struct istream *input; | struct istream *input; | |||
test_begin("message header parser extra CR in EOH"); | test_begin("message header parser extra CR in EOH"); | |||
input = test_istream_create(str); | input = test_istream_create(str); | |||
parser = message_parse_header_init(input, NULL, 0); | parser = message_parse_header_init(input, NULL, 0); | |||
test_assert(message_parse_header_next(parser, &hdr) > 0 && | test_assert(message_parse_header_next(parser, &hdr) > 0 && | |||
strcmp(hdr->name, "a") == 0); | strcmp(hdr->name, "a") == 0); | |||
test_assert(message_parse_header_next(parser, &hdr) > 0 && | test_assert(message_parse_header_next(parser, &hdr) > 0 && | |||
strcmp(hdr->name, "\r") == 0 && hdr->middle_len == 0 && | *hdr->value == '\r' && hdr->value_len == 1 && | |||
hdr->value_len == 0 && !hdr->eoh); | hdr->full_value_offset == 4 && | |||
hdr->middle_len == 0 && | ||||
hdr->name_len == 0 && !hdr->eoh); | ||||
test_assert(message_parse_header_next(parser, &hdr) < 0); | test_assert(message_parse_header_next(parser, &hdr) < 0); | |||
message_parse_header_deinit(&parser); | message_parse_header_deinit(&parser); | |||
test_assert(input->stream_errno == 0); | test_assert(input->stream_errno == 0); | |||
i_stream_unref(&input); | i_stream_unref(&input); | |||
test_end(); | test_end(); | |||
} | } | |||
static void test_message_header_parser_no_eoh(void) | static void test_message_header_parser_no_eoh(void) | |||
{ | { | |||
static const char *str = "a:b\n"; | static const char *str = "a:b\n"; | |||
skipping to change at line 335 | skipping to change at line 437 | |||
test_assert_strcmp(message_header_strdup(pool_datastack_create(), | test_assert_strcmp(message_header_strdup(pool_datastack_create(), | |||
hdr->value, hdr->value_len), | hdr->value, hdr->value_len), | |||
UNICODE_REPLACEMENT_CHAR_UTF8 UNICODE_REPLACEMENT_CHAR _UTF8"b"); | UNICODE_REPLACEMENT_CHAR_UTF8 UNICODE_REPLACEMENT_CHAR _UTF8"b"); | |||
test_assert(message_parse_header_next(parser, &hdr) < 0); | test_assert(message_parse_header_next(parser, &hdr) < 0); | |||
message_parse_header_deinit(&parser); | message_parse_header_deinit(&parser); | |||
test_assert(input->stream_errno == 0); | test_assert(input->stream_errno == 0); | |||
i_stream_unref(&input); | i_stream_unref(&input); | |||
test_end(); | test_end(); | |||
} | } | |||
static void test_message_header_parser_extra_crlf_in_name(void) | ||||
{ | ||||
static const unsigned char str[] = "X-Header\r\n Name: Header Value\n\n" | ||||
; | ||||
struct message_header_parser_ctx *parser; | ||||
struct message_header_line *hdr; | ||||
struct istream *input; | ||||
test_begin("message header parser CRLF in header name"); | ||||
input = test_istream_create_data(str, sizeof(str)-1); | ||||
parser = message_parse_header_init(input, NULL, 0); | ||||
hdr = NULL; | ||||
test_assert(message_parse_header_next(parser, &hdr) > 0 && | ||||
*hdr->name == '\0' && hdr->middle == uchar_empty_ptr && | ||||
hdr->name_len == 0 && hdr->middle_len == 0 && | ||||
hdr->value != NULL && hdr->value_len > 0); | ||||
test_assert(message_parse_header_next(parser, &hdr) > 0 && | ||||
*hdr->name == '\0' && hdr->middle == uchar_empty_ptr && | ||||
hdr->name_len == 0 && hdr->middle_len == 0 && | ||||
hdr->value != NULL && hdr->value_len > 0 && | ||||
hdr->continued); | ||||
test_assert(message_parse_header_next(parser, &hdr) > 0 && | ||||
hdr->eoh); | ||||
message_parse_header_deinit(&parser); | ||||
i_stream_unref(&input); | ||||
test_end(); | ||||
} | ||||
int main(void) | int main(void) | |||
{ | { | |||
static void (*const test_functions[])(void) = { | static void (*const test_functions[])(void) = { | |||
test_message_header_parser, | test_message_header_parser, | |||
test_message_header_parser_partial, | test_message_header_parser_partial, | |||
test_message_header_parser_long_lines, | test_message_header_parser_long_lines, | |||
test_message_header_parser_extra_cr_in_eoh, | test_message_header_parser_extra_cr_in_eoh, | |||
test_message_header_parser_no_eoh, | test_message_header_parser_no_eoh, | |||
test_message_header_parser_nul, | test_message_header_parser_nul, | |||
test_message_header_parser_extra_crlf_in_name, | ||||
NULL | NULL | |||
}; | }; | |||
return test_run(test_functions); | return test_run(test_functions); | |||
} | } | |||
End of changes. 9 change blocks. | ||||
5 lines changed or deleted | 141 lines changed or added |