static void test_message_header_parser_partial(void) { struct message_header_parser_ctx *parser; struct message_header_line *hdr; struct istream *input; unsigned int i, max = (strlen(test1_msg)-TEST1_MSG_BODY_LEN)*2; string_t *str; int ret; test_begin("message header parser partial"); input = test_istream_create(test1_msg); test_istream_set_allow_eof(input, FALSE); str = t_str_new(max); parser = message_parse_header_init(input, NULL, 0); for (i = 0; i <= max; i++) { test_istream_set_size(input, i/2); while ((ret = message_parse_header_next(parser, &hdr)) > 0) hdr_write(str, hdr); test_assert((ret == 0 && i < max) || (ret < 0 && i == max)); } message_parse_header_deinit(&parser); str_append(str, " body"); test_assert(strcmp(str_c(str), test1_msg) == 0); i_stream_unref(&input); test_end(); }
static void test_message_parser_small_blocks(void) { struct message_parser_ctx *parser; struct istream *input; struct message_part *parts, *parts2; struct message_block block; unsigned int i, end_of_headers_idx; pool_t pool; int ret; test_begin("message parser in small blocks"); pool = pool_alloconly_create("message parser", 10240); input = test_istream_create(test_msg); /* full parsing */ 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); /* parsing in small blocks */ i_stream_seek(input, 0); test_istream_set_allow_eof(input, FALSE); parser = message_parser_init(pool, input, 0, 0); for (i = 1; i <= TEST_MSG_LEN*2+1; i++) { test_istream_set_size(input, i/2); if (i > TEST_MSG_LEN*2) test_istream_set_allow_eof(input, TRUE); while ((ret = message_parser_parse_next_block(parser, &block)) > 0) ; test_assert((ret == 0 && i <= TEST_MSG_LEN*2) || (ret < 0 && i > TEST_MSG_LEN*2)); } test_assert(message_parser_deinit(&parser, &parts2) == 0); test_assert(msg_parts_cmp(parts, parts2)); /* parsing in small blocks from preparsed parts */ i_stream_seek(input, 0); test_istream_set_allow_eof(input, FALSE); end_of_headers_idx = (strstr(test_msg, "\n-----") - test_msg); parser = message_parser_init_from_parts(parts, input, 0, MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK); for (i = 1; i <= TEST_MSG_LEN*2+1; i++) { test_istream_set_size(input, i/2); if (i > TEST_MSG_LEN*2) test_istream_set_allow_eof(input, TRUE); while ((ret = message_parser_parse_next_block(parser, &block)) > 0) ; test_assert((ret == 0 && i/2 <= end_of_headers_idx) || (ret < 0 && i/2 > end_of_headers_idx)); } test_assert(message_parser_deinit(&parser, &parts2) == 0); test_assert(msg_parts_cmp(parts, parts2)); i_stream_unref(&input); pool_unref(&pool); test_end(); }
static void test_ostream_dot_one(const struct dot_test *test) { struct istream *test_input; struct ostream *output, *test_output; buffer_t *output_data; const unsigned char *data; size_t size; ssize_t ret; test_input = test_istream_create(test->input); output_data = buffer_create_dynamic(pool_datastack_create(), 1024); test_output = o_stream_create_buffer(output_data); output = o_stream_create_dot(test_output, FALSE); while ((ret = i_stream_read(test_input)) > 0 || ret == -2) { data = i_stream_get_data(test_input, &size); ret = o_stream_send(output, data, size); test_assert(ret >= 0); if (ret <= 0) break; i_stream_skip(test_input, ret); } test_assert(test_input->eof); test_assert(o_stream_flush(output) > 0); o_stream_unref(&output); o_stream_unref(&test_output); test_assert(strcmp(str_c(output_data), test->output) == 0); i_stream_unref(&test_input); }
static void test_message_header_parser(void) { static enum message_header_parser_flags max_hdr_flags = MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP | MESSAGE_HEADER_PARSER_FLAG_DROP_CR | MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE; enum message_header_parser_flags hdr_flags; struct message_header_parser_ctx *parser; struct message_size hdr_size; struct istream *input; test_begin("message header parser"); input = test_istream_create(test1_msg); for (hdr_flags = 0; hdr_flags <= max_hdr_flags; hdr_flags++) { i_stream_seek(input, 0); parser = message_parse_header_init(input, &hdr_size, hdr_flags); test_message_header_parser_one(parser, hdr_flags); message_parse_header_deinit(&parser); } test_assert(hdr_size.physical_size == strlen(test1_msg)-TEST1_MSG_BODY_LEN); test_assert(hdr_size.virtual_size == strlen(test1_msg) - TEST1_MSG_BODY_LEN + 4); i_stream_unref(&input); test_end(); }
static void test_istream_tee_blocks(const char *str) { struct istream *test_input, *child_input[CHILD_COUNT]; struct tee_istream *tee; unsigned int i, j; test_input = test_istream_create(str); test_istream_set_max_buffer_size(test_input, TEST_BUF_SIZE); test_begin("istream tee blocks"); tee = tee_i_stream_create(test_input); for (i = 0; i < CHILD_COUNT; i++) child_input[i] = tee_i_stream_create_child(tee); test_istream_set_allow_eof(test_input, FALSE); for (j = 1; j <= 3; j++) { test_istream_set_size(test_input, TEST_BUF_SIZE*j); for (i = 0; i < CHILD_COUNT; i++) { test_assert(i_stream_read(child_input[i]) == TEST_BUF_SIZE); i_stream_skip(child_input[i], TEST_BUF_SIZE); } } test_istream_set_allow_eof(test_input, TRUE); for (i = 0; i < CHILD_COUNT; i++) { test_assert(i_stream_read(child_input[i]) == -1); i_stream_unref(&child_input[i]); } i_stream_unref(&test_input); test_end(); }
static void test_istream_dot_error(const char *input_str, bool test_bufsize) { struct istream *test_input, *input; unsigned int i; size_t outsize, input_len; uoff_t offset; int ret; test_input = test_istream_create(input_str); input = i_stream_create_dot(test_input, FALSE); input_len = strlen(input_str); if (!test_bufsize) { outsize = 1; i = 0; i_stream_set_max_buffer_size(input, outsize); test_istream_set_size(test_input, 1); while ((ret = i_stream_read(input)) != -1) { switch (ret) { case -2: i_stream_set_max_buffer_size(input, ++outsize); offset = test_input->v_offset; /* seek one byte backwards so stream gets reset */ i_stream_seek(test_input, offset - 1); /* go back to original position */ test_istream_set_size(test_input, offset); i_stream_skip(test_input, 1); /* and finally allow reading one more byte */ test_istream_set_size(test_input, offset + 1); break; case 0: test_istream_set_size(test_input, ++i); break; default: test_assert(ret > 0); } } test_istream_set_size(test_input, input_len); (void)i_stream_read(test_input); } else { test_istream_set_size(test_input, input_len); for (i = 1; i <= input_len; i++) { i_stream_set_max_buffer_size(input, i); (void)i_stream_read(input); (void)i_stream_read(input); } i_stream_set_max_buffer_size(input, i+1); (void)i_stream_read(input); } test_assert(input->stream_errno == EPIPE); i_stream_unref(&test_input); i_stream_unref(&input); }
static void test_imap_parser_crlf(void) { static const char *test_input = "foo\r\nx\ry\n"; struct istream *input; struct imap_parser *parser; const struct imap_arg *args; unsigned int i; bool fatal; test_begin("imap parser crlf handling"); input = test_istream_create(test_input); parser = imap_parser_create(input, NULL, 1024); /* must return -2 until LF is read */ for (i = 0; test_input[i] != '\n'; i++) { test_istream_set_size(input, i+1); (void)i_stream_read(input); test_assert(imap_parser_read_args(parser, 0, 0, &args) == -2); } test_istream_set_size(input, i+1); (void)i_stream_read(input); test_assert(imap_parser_read_args(parser, 0, 0, &args) == 1); test_assert(args[0].type == IMAP_ARG_ATOM); test_assert(args[1].type == IMAP_ARG_EOL); /* CR without LF should fail with error */ imap_parser_reset(parser); i_stream_seek(input, ++i); test_istream_set_size(input, ++i); (void)i_stream_read(input); test_assert(imap_parser_read_args(parser, 0, 0, &args) == -2); test_istream_set_size(input, ++i); (void)i_stream_read(input); test_assert(imap_parser_read_args(parser, 0, 0, &args) == -2); test_istream_set_size(input, ++i); (void)i_stream_read(input); test_assert(imap_parser_read_args(parser, 0, 0, &args) == -1); test_assert(strcmp(imap_parser_get_error(parser, &fatal), "CR sent without LF") == 0 && !fatal); imap_parser_destroy(&parser); i_stream_destroy(&input); test_end(); }
static void test_message_header_parser_no_eoh(void) { static const char *str = "a:b\n"; struct message_header_parser_ctx *parser; struct message_header_line *hdr; struct istream *input; test_begin("message header parser no EOH"); input = test_istream_create(str); parser = message_parse_header_init(input, NULL, 0); test_assert(message_parse_header_next(parser, &hdr) > 0 && strcmp(hdr->name, "a") == 0); test_assert(message_parse_header_next(parser, &hdr) < 0); message_parse_header_deinit(&parser); test_assert(input->stream_errno == 0); i_stream_unref(&input); test_end(); }
static void test_message_header_parser_long_lines_str(const char *str, unsigned int buffer_size, struct message_size *size_r) { struct message_header_parser_ctx *parser; struct message_header_line *hdr; struct istream *input; unsigned int i, len = strlen(str); input = test_istream_create(str); test_istream_set_max_buffer_size(input, buffer_size); parser = message_parse_header_init(input, size_r, 0); for (i = 1; i <= len; i++) { test_istream_set_size(input, i); while (message_parse_header_next(parser, &hdr) > 0) ; } message_parse_header_deinit(&parser); i_stream_unref(&input); }
static void test_istream_dot_one(const struct dot_test *test, bool send_last_lf, bool test_bufsize) { struct istream *test_input, *input; const unsigned char *data; size_t size; unsigned int i, outsize, input_len, output_len; string_t *str; uoff_t offset; int ret; test_input = test_istream_create(test->input); input = i_stream_create_dot(test_input, send_last_lf); input_len = strlen(test->input); output_len = strlen(test->output); if (!send_last_lf && (test->input[input_len-1] == '\n' || strstr(test->input, "\n.\n") != NULL || strstr(test->input, "\n.\r\n") != NULL)) { if (test->output[output_len-1] == '\n') { output_len--; if (output_len > 0 && test->output[output_len-1] == '\r') output_len--; } } str = t_str_new(256); if (!test_bufsize) { outsize = 1; i = 0; i_stream_set_max_buffer_size(input, outsize); test_istream_set_size(test_input, 1); while ((ret = i_stream_read(input)) != -1) { switch (ret) { case -2: i_stream_set_max_buffer_size(input, ++outsize); offset = test_input->v_offset; /* seek one byte backwards so stream gets reset */ i_stream_seek(test_input, offset - 1); /* go back to original position */ test_istream_set_size(test_input, offset); i_stream_skip(test_input, 1); /* and finally allow reading one more byte */ test_istream_set_size(test_input, offset + 1); break; case 0: test_istream_set_size(test_input, ++i); break; default: test_assert(ret > 0); data = i_stream_get_data(input, &size); str_append_n(str, data, size); i_stream_skip(input, size); } } test_istream_set_size(test_input, input_len); (void)i_stream_read(test_input); } else { test_istream_set_size(test_input, input_len); size = 0; for (i = 1; i < output_len; i++) { i_stream_set_max_buffer_size(input, i); test_assert(i_stream_read(input) == 1); test_assert(i_stream_read(input) == -2); data = i_stream_get_data(input, &size); test_assert(memcmp(data, test->output, size) == 0); } i_stream_set_max_buffer_size(input, i+2); if (size < output_len) test_assert(i_stream_read(input) == 1); test_assert(i_stream_read(input) == -1); data = i_stream_get_data(input, &size); str_append_n(str, data, size); } test_assert(str_len(str) == output_len); test_assert(memcmp(str_data(str), test->output, output_len) == 0); data = i_stream_get_data(test_input, &size); test_assert(size == strlen(test->parent_input)); test_assert(memcmp(data, test->parent_input, size) == 0); i_stream_unref(&test_input); i_stream_unref(&input); }
static void test_istream_tee_tailing(const char *str) { struct istream *test_input, *child_input[CHILD_COUNT]; struct tee_istream *tee; unsigned int i, len; test_input = test_istream_create(str); test_istream_set_max_buffer_size(test_input, TEST_BUF_SIZE); test_begin("istream tee tailing"); tee = tee_i_stream_create(test_input); for (i = 0; i < CHILD_COUNT; i++) child_input[i] = tee_i_stream_create_child(tee); test_istream_set_allow_eof(test_input, FALSE); for (len = 1; len < TEST_BUF_SIZE; len++) { test_istream_set_size(test_input, len); for (i = 0; i < CHILD_COUNT; i++) { test_assert(i_stream_read(child_input[i]) == 1); test_assert(!tee_i_stream_child_is_waiting(child_input[i])); test_assert(i_stream_read(child_input[i]) == 0); test_assert(!tee_i_stream_child_is_waiting(child_input[i])); } } test_istream_set_size(test_input, len); for (i = 0; i < CHILD_COUNT; i++) { test_assert(i_stream_read(child_input[i]) == 1); test_assert(i_stream_read(child_input[i]) == -2); test_assert(!tee_i_stream_child_is_waiting(child_input[i])); } for (len++; len <= TEST_STR_LEN; len++) { test_istream_set_size(test_input, len); for (i = 0; i < CHILD_COUNT; i++) { test_assert(i_stream_read(child_input[i]) == -2); test_assert(!tee_i_stream_child_is_waiting(child_input[i])); } for (i = 0; i < CHILD_COUNT-1; i++) { i_stream_skip(child_input[i], 1); test_assert(i_stream_read(child_input[i]) == 0); test_assert(tee_i_stream_child_is_waiting(child_input[i])); } i_stream_skip(child_input[i], 1); for (i = 0; i < CHILD_COUNT; i++) { test_assert(i_stream_read(child_input[i]) == 1); test_assert(i_stream_read(child_input[i]) == -2); test_assert(!tee_i_stream_child_is_waiting(child_input[i])); } } for (i = 0; i < CHILD_COUNT-1; i++) { i_stream_skip(child_input[i], 1); test_assert(i_stream_read(child_input[i]) == 0); test_assert(tee_i_stream_child_is_waiting(child_input[i])); } i_stream_skip(child_input[i], 1); test_assert(i_stream_read(child_input[i]) == 0); test_assert(!tee_i_stream_child_is_waiting(child_input[i])); test_istream_set_allow_eof(test_input, TRUE); for (i = 0; i < CHILD_COUNT; i++) { test_assert(i_stream_read(child_input[i]) == -1); i_stream_unref(&child_input[i]); } i_stream_unref(&test_input); test_end(); }