bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainenstatic void run_callback(struct header_filter_istream *input,
75891a354ed229a4e56bbb0eceab75a0d1278687Josef 'Jeff' Sipekstatic inline void
75891a354ed229a4e56bbb0eceab75a0d1278687Josef 'Jeff' Sipektest_istream_run_prep(struct run_ctx *run_ctx,
75891a354ed229a4e56bbb0eceab75a0d1278687Josef 'Jeff' Sipektest_istream_run_check(struct run_ctx *run_ctx,
75891a354ed229a4e56bbb0eceab75a0d1278687Josef 'Jeff' Sipek test_assert(run_ctx->null_hdr_seen == run_ctx->callback_called);
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek if (first && ((flags & HEADER_FILTER_ADD_MISSING_EOH) != 0))
75891a354ed229a4e56bbb0eceab75a0d1278687Josef 'Jeff' Sipek data = i_stream_get_data(filter, size_r);
75891a354ed229a4e56bbb0eceab75a0d1278687Josef 'Jeff' Sipek test_assert(i_stream_stat(filter, TRUE, &st) == 0 &&
75891a354ed229a4e56bbb0eceab75a0d1278687Josef 'Jeff' Sipek test_istream_run_prep(&run_ctx, callback);
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen filter = i_stream_create_header_filter(test_istream, flags, NULL, 0,
adb90447f6bf7b11b5fca7e87a3f256622fdef9fTimo Sirainen test_istream_set_size(test_istream, input_len);
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek test_istream_run_check(&run_ctx, filter, output, flags, TRUE, &size);
201ce62e1dc315e5dd5e59c24660ed0946343bbbTimo Sirainen orig_callback_call_count = run_ctx.callback_call_count;
adb90447f6bf7b11b5fca7e87a3f256622fdef9fTimo Sirainen /* run again to make sure it's still correct the second time */
75891a354ed229a4e56bbb0eceab75a0d1278687Josef 'Jeff' Sipek test_istream_run_prep(&run_ctx, callback);
69eb1a17f443454e0b3025f86f428671ace06e89Josef 'Jeff' Sipek test_istream_run_check(&run_ctx, filter, output, flags, FALSE, &size);
201ce62e1dc315e5dd5e59c24660ed0946343bbbTimo Sirainen test_assert(run_ctx.callback_call_count == 0 ||
201ce62e1dc315e5dd5e59c24660ed0946343bbbTimo Sirainen run_ctx.callback_call_count == orig_callback_call_count);
f7ec15aefabeb0a17d1f262bc5e9a15e43dfc5adTimo Sirainenfilter_callback(struct header_filter_istream *input ATTR_UNUSED,
0989e8ba44ec35dc9322e424b5213b96596319e7Timo Sirainen /* drop 1) first header, 2) X-Drop header */
2719970c2c246f976178da179deeb64eecaec5baTimo Sirainen static const char *exclude_headers[] = { "Subject", "To" };
0989e8ba44ec35dc9322e424b5213b96596319e7Timo Sirainen const char *input = "From: foo\nFrom: abc\nTo: bar\nSubject: plop\nX-Drop: 1\n\nhello world\n";
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen const char *output = "From: abc\n\nhello world\n";
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen unsigned int i;
6e81d67a4e8985d35034eab791e270ffc01800b8Timo Sirainen test_begin("i_stream_create_header_filter: exclude");
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen filter = i_stream_create_header_filter(istream,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen filter2 = i_stream_create_header_filter(filter,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen test_assert(size == output_len && memcmp(data, output, size) == 0);
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen test_assert(i_stream_stat(filter, TRUE, &st) == 0 &&
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen test_assert(size == output_len && memcmp(data, output, size) == 0);
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen test_assert(i_stream_stat(filter, TRUE, &st) == 0 &&
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainenstatic void add_random_text(string_t *dest, unsigned int count)
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainen unsigned int i;
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainen for (i = 0; i < count; i++)
191153d1a5b0eb0c129139570e3aa5212f28d2acJosef 'Jeff' Sipek str_append_c(dest, i_rand_minmax('a', 'z'));
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainenfilter2_callback(struct header_filter_istream *input ATTR_UNUSED,
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainenstatic void test_istream_filter_large_buffer(void)
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainen const char *p;
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainen unsigned int i;
6e81d67a4e8985d35034eab791e270ffc01800b8Timo Sirainen test_begin("i_stream_create_header_filter: large buffer");
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainen istream = test_istream_create_data(str_data(input), str_len(input));
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainen test_istream_set_max_buffer_size(istream, 8192);
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainen filter = i_stream_create_header_filter(istream,
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainen for (i = 0; i < 2; i++) {
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen /* callbacks are called only once */
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainen test_assert(strncmp(str_c(input), str_c(output), prefix_len) == 0);
76a71915c6452a4bee9a8ae89ddbdf58fa941deeTimo Sirainen test_assert(strcmp(p+1, str_c(output) + prefix_len) == 0);
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen test_assert(i_stream_stat(filter, TRUE, &st) == 0 &&
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen (uoff_t)st->st_size == filter->v_offset + size);
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen /* seek back and retry once with caching and different
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen buffer size */
270c7cd669b1ad4b69edb366dc5f22262948bfedTimo Sirainen test_istream_set_max_buffer_size(istream, 4096);
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainenstatic void test_istream_filter_large_buffer2(void)
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen static const char *wanted_headers[] = { "References" };
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen unsigned int i;
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen test_begin("i_stream_create_header_filter: large buffer2");
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen istream = test_istream_create_data(str_data(input), str_len(input));
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen test_istream_set_max_buffer_size(istream, 8192);
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen filter = i_stream_create_header_filter(istream,
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen HEADER_FILTER_INCLUDE | HEADER_FILTER_HIDE_BODY,
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen for (i = 0; i < 2; i++) {
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen while ((ret = i_stream_read_more(filter, &data, &size)) > 0) {
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen test_assert(strcmp(str_c(input), str_c(output)) == 0);
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen test_assert(i_stream_stat(filter, TRUE, &st) == 0 &&
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen (uoff_t)st->st_size == filter->v_offset + size);
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen /* seek back and retry once with caching and different
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen buffer size */
07bba7cf547c26c6f46f23bb84b6cab919b4ae0cTimo Sirainen test_istream_set_max_buffer_size(istream, 4096);
88d100753bd4b26f038093d3794c2dc50875443dTimo Sirainenfilter3_callback(struct header_filter_istream *input ATTR_UNUSED,
88d100753bd4b26f038093d3794c2dc50875443dTimo Sirainen unsigned int i;
6e81d67a4e8985d35034eab791e270ffc01800b8Timo Sirainen test_begin("i_stream_create_header_filter: callbacks");
88d100753bd4b26f038093d3794c2dc50875443dTimo Sirainen str_append(input, "\nTo: first line\n\tsecond line\n\t");
88d100753bd4b26f038093d3794c2dc50875443dTimo Sirainen istream = test_istream_create_data(str_data(input), str_len(input));
88d100753bd4b26f038093d3794c2dc50875443dTimo Sirainen test_istream_set_max_buffer_size(istream, 8192);
88d100753bd4b26f038093d3794c2dc50875443dTimo Sirainen filter = i_stream_create_header_filter(istream,
88d100753bd4b26f038093d3794c2dc50875443dTimo Sirainen /* callback should be called exactly once for all the header input */
88d100753bd4b26f038093d3794c2dc50875443dTimo Sirainen for (i = 0; i < 2; i++) {
88d100753bd4b26f038093d3794c2dc50875443dTimo Sirainen i_stream_skip(filter, i_stream_get_data_size(filter));
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen test_assert(i_stream_stat(filter, TRUE, &st) == 0 &&
88d100753bd4b26f038093d3794c2dc50875443dTimo Sirainen test_assert(strcmp(str_c(output), str_c(input)) == 0);
82705acc82d625a60146b72b9296146dd8312261Timo Sirainenedit_callback(struct header_filter_istream *input,
bf5682ed5399fce13b2053e20098e2de19751c59Timo Sirainen /* add a new header */
bf5682ed5399fce13b2053e20098e2de19751c59Timo Sirainen i_stream_header_filter_add(input, new_hdr, strlen(new_hdr));
bf5682ed5399fce13b2053e20098e2de19751c59Timo Sirainen } else if (strcasecmp(hdr->name, "To") == 0) {
82705acc82d625a60146b72b9296146dd8312261Timo Sirainen /* modify To header */
82705acc82d625a60146b72b9296146dd8312261Timo Sirainen i_stream_header_filter_add(input, new_to, strlen(new_to));
82705acc82d625a60146b72b9296146dd8312261Timo Sirainen const char *input = "From: foo\nTo: bar\n\nhello world\n";
bf5682ed5399fce13b2053e20098e2de19751c59Timo Sirainen const char *output = "From: foo\nTo: 123\nAdded: header\n\nhello world\n";
6e81d67a4e8985d35034eab791e270ffc01800b8Timo Sirainen test_begin("i_stream_create_header_filter: edit headers");
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen test_istream_run(istream, strlen(input), output,
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainenstatic void test_istream_end_body_with_lf(void)
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen const char *input = "From: foo\n\nhello world";
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen const char *output = "From: foo\n\nhello world\n";
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen unsigned int i;
6e81d67a4e8985d35034eab791e270ffc01800b8Timo Sirainen test_begin("i_stream_create_header_filter: end_body_with_lf");
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen filter = i_stream_create_header_filter(istream,
ef3ebb56989cb9b1b80edd133a091338e4206836Timo Sirainen test_assert(size == output_len && memcmp(data, output, size) == 0);
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen test_assert(i_stream_stat(filter, TRUE, &st) == 0 &&
c8e34785671d3b13f4500144a2ec7af968ce3307Timo Sirainen (uoff_t)st->st_size == filter->v_offset + size);
b7324e421e2132cbbf753e6fdbe675bbaecdf929Timo Sirainen static const struct {
10d2dbb8343d9f7a294519224e5e08e1c13e7453Timo Sirainen { "From: foo\n\nbar", "From: foo\n\nbar", 0 },
10d2dbb8343d9f7a294519224e5e08e1c13e7453Timo Sirainen { "From: foo\r\n\r\n", "From: foo\r\n\r\n", 0 },
10d2dbb8343d9f7a294519224e5e08e1c13e7453Timo Sirainen { "From: foo\r\n\r\nbar", "From: foo\r\n\r\nbar", 0 }
10d2dbb8343d9f7a294519224e5e08e1c13e7453Timo Sirainen unsigned int i;
6e81d67a4e8985d35034eab791e270ffc01800b8Timo Sirainen test_begin("i_stream_create_header_filter: add missing EOH");
10d2dbb8343d9f7a294519224e5e08e1c13e7453Timo Sirainen istream = test_istream_create(tests[i].input);
201ce62e1dc315e5dd5e59c24660ed0946343bbbTimo Sirainenstatic void test_istream_add_missing_eoh_and_edit(void)
201ce62e1dc315e5dd5e59c24660ed0946343bbbTimo Sirainen const char *output = "From: foo\nTo: 123\nAdded: header\n\n";
201ce62e1dc315e5dd5e59c24660ed0946343bbbTimo Sirainen test_begin("i_stream_create_header_filter: add missing EOH and edit headers");
201ce62e1dc315e5dd5e59c24660ed0946343bbbTimo Sirainen test_istream_run(istream, strlen(input), output,
b7324e421e2132cbbf753e6fdbe675bbaecdf929Timo Sirainen static const struct {
32e3da4a505b3b258d44abdf4366fbfc95680027Timo Sirainen { "From: foo\r\n\r\n", "From: foo\r\n\r\n", 0 },
32e3da4a505b3b258d44abdf4366fbfc95680027Timo Sirainen { "From: foo\r\n\r\nbar", "From: foo\r\n\r\n", -3 }
32e3da4a505b3b258d44abdf4366fbfc95680027Timo Sirainen unsigned int i;
6e81d67a4e8985d35034eab791e270ffc01800b8Timo Sirainen test_begin("i_stream_create_header_filter: hide body");
32e3da4a505b3b258d44abdf4366fbfc95680027Timo Sirainen istream = test_istream_create(tests[i].input);
adb90447f6bf7b11b5fca7e87a3f256622fdef9fTimo Sirainenstrip_eoh_callback(struct header_filter_istream *input ATTR_UNUSED,
adb90447f6bf7b11b5fca7e87a3f256622fdef9fTimo Sirainen const char *input = "From: foo\nTo: bar\n\nhello world\n";
adb90447f6bf7b11b5fca7e87a3f256622fdef9fTimo Sirainen const char *output = "From: foo\nTo: bar\nhello world\n";
6e81d67a4e8985d35034eab791e270ffc01800b8Timo Sirainen test_begin("i_stream_create_header_filter: strip_eoh");
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen test_istream_run(istream, strlen(input), output,
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainenmissing_eoh_callback(struct header_filter_istream *input ATTR_UNUSED,
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen bool *matched ATTR_UNUSED, void *context ATTR_UNUSED)
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen i_stream_header_filter_add(input, new_hdr, strlen(new_hdr));
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainenstatic void test_istream_missing_eoh_callback(void)
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen const char *output = "From: foo\nTo: bar\nSubject: added\n\n";
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen test_begin("i_stream_create_header_filter: add headers when EOH is missing");
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen test_istream_run(istream, strlen(input) + 1, output,
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainenstatic void test_istream_empty_missing_eoh_callback(void)
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen test_begin("i_stream_create_header_filter: add headers when mail is empty");
71ecc97593a25c2444316b74e5882e6ce0a82c0cTimo Sirainen test_istream_run(istream, strlen(input)+1, output,
baf3e87e186453fda13bd21f7cbcb2efc8492e8bTimo Sirainen static void (*const test_functions[])(void) = {