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_write_read_v2(void) { test_begin("test_write_read_v2"); unsigned char payload[IO_BLOCK_SIZE*10]; const unsigned char *ptr; size_t pos = 0, siz; random_fill_weak(payload, IO_BLOCK_SIZE*10); buffer_t *buf = buffer_create_dynamic(default_pool, sizeof(payload)); struct ostream *os = o_stream_create_buffer(buf); struct ostream *os_2 = o_stream_create_encrypt(os, "aes-256-gcm-sha256", test_v1_kp.pub, IO_STREAM_ENC_INTEGRITY_AEAD); o_stream_nsend(os_2, payload, sizeof(payload)); test_assert(o_stream_nfinish(os_2) == 0); if (os_2->stream_errno != 0) i_debug("error: %s", o_stream_get_error(os_2)); o_stream_unref(&os); o_stream_unref(&os_2); struct istream *is = test_istream_create_data(buf->data, buf->used); /* test regression where read fails due to incorrect behaviour when buffer is full before going to decrypt code */ i_stream_set_max_buffer_size(is, 8192); i_stream_read(is); struct istream *is_2 = i_stream_create_decrypt(is, test_v1_kp.priv); size_t offset = 0; test_istream_set_size(is, 0); test_istream_set_allow_eof(is, FALSE); while(i_stream_read_data(is_2, &ptr, &siz, 0)>=0) { if (offset == buf->used) test_istream_set_allow_eof(is, TRUE); else test_istream_set_size(is, ++offset); test_assert_idx(pos + siz <= sizeof(payload), pos); if (pos + siz > sizeof(payload)) break; test_assert_idx(siz == 0 || memcmp(ptr, payload + pos, siz) == 0, pos); i_stream_skip(is_2, siz); pos += siz; } test_assert(is_2->stream_errno == 0); if (is_2->stream_errno != 0) i_debug("error: %s", i_stream_get_error(is_2)); i_stream_unref(&is); i_stream_unref(&is_2); buffer_free(&buf); test_end(); }
static void test_write_read_v1_short(void) { test_begin("test_write_read_v1_short"); unsigned char payload[1]; const unsigned char *ptr; size_t pos = 0, siz; random_fill_weak(payload, 1); buffer_t *buf = buffer_create_dynamic(default_pool, 64); struct ostream *os = o_stream_create_buffer(buf); struct ostream *os_2 = o_stream_create_encrypt(os, "<unused>", test_v2_kp.pub, IO_STREAM_ENC_VERSION_1); o_stream_nsend(os_2, payload, sizeof(payload)); if (os_2->stream_errno != 0) i_debug("error: %s", o_stream_get_error(os_2)); test_assert(os_2->stream_errno == 0); test_assert(o_stream_nfinish(os_2) == 0); test_assert(os_2->stream_errno == 0); o_stream_unref(&os); o_stream_unref(&os_2); struct istream *is = test_istream_create_data(buf->data, buf->used); struct istream *is_2 = i_stream_create_decrypt(is, test_v2_kp.priv); size_t offset = 0; test_istream_set_allow_eof(is, FALSE); test_istream_set_size(is, 0); while(i_stream_read_data(is_2, &ptr, &siz, 0)>=0) { if (offset == buf->used) test_istream_set_allow_eof(is, TRUE); else test_istream_set_size(is, ++offset); test_assert_idx(pos + siz <= sizeof(payload), pos); if (pos + siz > sizeof(payload)) break; test_assert_idx(siz == 0 || memcmp(ptr, payload + pos, siz) == 0, pos); i_stream_skip(is_2, siz); pos += siz; } test_assert(is_2->stream_errno == 0); i_stream_unref(&is); i_stream_unref(&is_2); buffer_free(&buf); test_end(); }
static void decode_test(const char *base64_input, const char *output, bool broken_input) { unsigned int base64_input_len = strlen(base64_input); struct istream *input_data, *input; const unsigned char *data; size_t i, size; int ret = 0; input_data = test_istream_create_data(base64_input, base64_input_len); test_istream_set_allow_eof(input_data, FALSE); input = i_stream_create_base64_decoder(input_data); for (i = 1; i <= base64_input_len; i++) { test_istream_set_size(input_data, i); while ((ret = i_stream_read(input)) > 0) ; if (ret == -1 && broken_input) break; test_assert(ret == 0); } if (ret == 0) { test_istream_set_allow_eof(input_data, TRUE); while ((ret = i_stream_read(input)) > 0) ; } test_assert(ret == -1); test_assert((input->stream_errno == 0 && !broken_input) || (input->stream_errno == EINVAL && broken_input)); data = i_stream_get_data(input, &size); test_assert(size == strlen(output)); if (size > 0) test_assert(memcmp(data, output, size) == 0); i_stream_unref(&input); i_stream_unref(&input_data); }
static void test_istream_binary_converter(void) { struct istream *datainput, *input; const unsigned char *data; size_t i, size; int ret; test_begin("istream binary converter"); datainput = test_istream_create_data(mail_input, sizeof(mail_input)); test_istream_set_allow_eof(datainput, FALSE); input = i_stream_create_binary_converter(datainput); for (i = 1; i <= sizeof(mail_input); i++) { test_istream_set_size(datainput, i); while ((ret = i_stream_read(input)) > 0) ; test_assert(ret == 0); } test_istream_set_allow_eof(datainput, TRUE); while ((ret = i_stream_read(input)) > 0) ; test_assert(ret == -1); data = i_stream_get_data(input, &size); test_assert(size == sizeof(mail_output) && memcmp(data, mail_output, size) == 0); i_stream_unref(&input); i_stream_unref(&datainput); test_end(); }
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 encode_test(const char *text, unsigned int chars_per_line, bool crlf, const char *output) { unsigned int i, text_len = strlen(text); struct istream *input, *input_data; const unsigned char *data; size_t size; ssize_t ret; input_data = test_istream_create_data(text, text_len); test_istream_set_allow_eof(input_data, FALSE); input = i_stream_create_base64_encoder(input_data, chars_per_line, crlf); for (i = 1; i <= text_len; i++) { test_istream_set_size(input_data, i); while ((ret = i_stream_read(input)) > 0) ; test_assert(ret == 0); } test_istream_set_allow_eof(input_data, TRUE); while ((ret = i_stream_read(input)) > 0) ; test_assert(ret == -1); data = i_stream_get_data(input, &size); test_assert(size == strlen(output) && memcmp(data, output, size) == 0); i_stream_unref(&input); i_stream_unref(&input_data); }
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_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_write_read_v1_empty(void) { const unsigned char *ptr; size_t siz; test_begin("test_write_read_v1_empty"); buffer_t *buf = buffer_create_dynamic(default_pool, 64); struct ostream *os = o_stream_create_buffer(buf); struct ostream *os_2 = o_stream_create_encrypt(os, "<unused>", test_v1_kp.pub, IO_STREAM_ENC_VERSION_1); test_assert(o_stream_nfinish(os_2) == 0); if (os_2->stream_errno != 0) i_debug("error: %s", o_stream_get_error(os_2)); o_stream_unref(&os); o_stream_unref(&os_2); /* this should've been enough */ struct istream *is = test_istream_create_data(buf->data, buf->used); struct istream *is_2 = i_stream_create_decrypt(is, test_v1_kp.priv); /* read should not fail */ test_istream_set_allow_eof(is, FALSE); test_istream_set_size(is, 0); size_t offset = 0; ssize_t ret; while ((ret = i_stream_read_data(is_2, &ptr, &siz, 0)) >= 0) { test_assert(ret == 0); if (offset == buf->used) test_istream_set_allow_eof(is, TRUE); else test_istream_set_size(is, ++offset); }; test_assert(is_2->stream_errno == 0); if (is_2->stream_errno != 0) i_debug("error: %s", i_stream_get_error(is_2)); i_stream_unref(&is); i_stream_unref(&is_2); buffer_free(&buf); test_end(); }
static void test_json_parser_success(bool full_size) { struct json_parser *parser; struct istream *input, *jsoninput = NULL; enum json_type type; const char *value, *error; unsigned int i, pos, json_input_len = strlen(json_input); int ret = 0; test_begin(full_size ? "json parser" : "json parser (nonblocking)"); input = test_istream_create_data(json_input, json_input_len); test_istream_set_allow_eof(input, FALSE); parser = json_parser_init(input); i = full_size ? json_input_len : 0; for (pos = 0; i <= json_input_len; i++) { test_istream_set_size(input, i); for (;;) { value = NULL; if (pos < N_ELEMENTS(json_output) && json_output[pos].type == (enum json_type)TYPE_SKIP) { json_parse_skip_next(parser); pos++; continue; } else if (pos == N_ELEMENTS(json_output) || json_output[pos].type != (enum json_type)TYPE_STREAM) { ret = json_parse_next(parser, &type, &value); } else { ret = jsoninput != NULL ? 1 : json_parse_next_stream(parser, &jsoninput); if (jsoninput != NULL) ret = stream_read_value(&jsoninput, &value); type = TYPE_STREAM; } if (ret <= 0) break; i_assert(pos < N_ELEMENTS(json_output)); test_assert(json_output[pos].type == type); test_assert(null_strcmp(json_output[pos].value, value) == 0); pos++; } test_assert(ret == 0); } test_assert(pos == N_ELEMENTS(json_output)); test_istream_set_allow_eof(input, TRUE); test_assert(json_parse_next(parser, &type, &value) == -1); i_stream_unref(&input); test_assert(json_parser_deinit(&parser, &error) == 0); 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 decode_test(const char *qp_input, const char *output, bool broken_input, unsigned int buffer_size) { unsigned int qp_input_len = strlen(qp_input); struct istream *input_data, *input; const unsigned char *data; size_t i, size; string_t *str = t_str_new(32); int ret = 0; input_data = test_istream_create_data(qp_input, qp_input_len); test_istream_set_max_buffer_size(input_data, buffer_size); test_istream_set_allow_eof(input_data, FALSE); input = i_stream_create_qp_decoder(input_data); for (i = 1; i <= qp_input_len; i++) { test_istream_set_size(input_data, i); while ((ret = i_stream_read_more(input, &data, &size)) > 0) { str_append_n(str, data, size); i_stream_skip(input, size); } if (ret == -1 && broken_input) break; test_assert(ret == 0); } if (ret == 0) { test_istream_set_allow_eof(input_data, TRUE); while ((ret = i_stream_read_more(input, &data, &size)) > 0) { str_append_n(str, data, size); i_stream_skip(input, size); } } test_assert(ret == -1); test_assert((input->stream_errno == 0 && !broken_input) || (input->stream_errno == EINVAL && broken_input)); test_assert(strcmp(str_c(str), output) == 0); i_stream_unref(&input); i_stream_unref(&input_data); }
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(); }