]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-mail: istream-header-filter HEADER_FILTER_ADD_MISSING_EOH fixes
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 3 May 2016 14:25:07 +0000 (17:25 +0300)
committerGitLab <gitlab@git.dovecot.net>
Tue, 3 May 2016 16:44:37 +0000 (19:44 +0300)
When using HEADER_FILTER_CRLF_PRESERVE, add CR to the EOH if the previous
header line ended with CRLF.

When header ends to a header without newline, add two newlines so we can get
the actual EOH added.

src/lib-mail/istream-header-filter.c
src/lib-mail/test-istream-header-filter.c

index 0a6c9a2fe196fc446c3a751d2ed0006e1d037768..400180d20f045688993bdf68620e88afb91d2983 100644 (file)
@@ -38,6 +38,8 @@ struct header_filter_istream {
        unsigned int add_missing_eoh:1;
        unsigned int end_body_with_lf:1;
        unsigned int last_lf_added:1;
+       unsigned int last_orig_crlf:1;
+       unsigned int last_added_newline:1;
        unsigned int eoh_not_matched:1;
        unsigned int prev_matched:1;
 };
@@ -133,6 +135,8 @@ static void add_eol(struct header_filter_istream *mstream, bool orig_crlf)
                buffer_append(mstream->hdr_buf, "\r\n", 2);
        else
                buffer_append_c(mstream->hdr_buf, '\n');
+       mstream->last_orig_crlf = orig_crlf;
+       mstream->last_added_newline = TRUE;
 }
 
 static ssize_t hdr_stream_update_pos(struct header_filter_istream *mstream)
@@ -284,6 +288,11 @@ static ssize_t read_header(struct header_filter_istream *mstream)
                if (mstream->hdr_buf->used >= mstream->istream.max_buffer_size)
                        break;
        }
+       if (mstream->hdr_buf->used > 0) {
+               const unsigned char *data = mstream->hdr_buf->data;
+               mstream->last_added_newline =
+                       data[mstream->hdr_buf->used-1] == '\n';
+       }
 
        if (hdr_ret < 0) {
                if (mstream->istream.parent->stream_errno != 0) {
@@ -295,7 +304,9 @@ static ssize_t read_header(struct header_filter_istream *mstream)
                }
                if (!mstream->seen_eoh && mstream->add_missing_eoh) {
                        mstream->seen_eoh = TRUE;
-                       add_eol(mstream, FALSE);
+                       if (!mstream->last_added_newline)
+                               add_eol(mstream, mstream->last_orig_crlf);
+                       add_eol(mstream, mstream->last_orig_crlf);
                }
        }
 
index 6c1357c52470701c9731ab48b939111e044551d8..0f92ecbfd1bfe8785e02122b33279cc01b0e4a70 100644 (file)
@@ -349,6 +349,42 @@ static void test_istream_end_body_with_lf(void)
        test_end();
 }
 
+static void test_istream_add_missing_eoh(void)
+{
+       struct {
+               const char *input;
+               const char *output;
+               unsigned int extra;
+       } tests[] = {
+               { "From: foo", "From: foo\n\n", 1 },
+               { "From: foo\n", "From: foo\n\n", 1 },
+               { "From: foo\n\n", "From: foo\n\n", 1 },
+               { "From: foo\n\nbar", "From: foo\n\nbar", 0 },
+               { "From: foo\r\n", "From: foo\r\n\r\n", 1 },
+               { "From: foo\r\n\r\n", "From: foo\r\n\r\n", 0 },
+               { "From: foo\r\n\r\nbar", "From: foo\r\n\r\nbar", 0 }
+       };
+       struct istream *istream, *filter;
+       unsigned int i;
+
+       test_begin("i_stream_create_header_filter(add_missing_eoh)");
+       for (i = 0; i < N_ELEMENTS(tests); i++) {
+               istream = test_istream_create(tests[i].input);
+               filter = i_stream_create_header_filter(istream,
+                                              HEADER_FILTER_EXCLUDE |
+                                              HEADER_FILTER_CRLF_PRESERVE |
+                                              HEADER_FILTER_ADD_MISSING_EOH,
+                                              NULL, 0,
+                                              *null_header_filter_callback, (void *)NULL);
+               test_istream_run(istream, filter,
+                                strlen(tests[i].input) + tests[i].extra,
+                                tests[i].output);
+               i_stream_unref(&filter);
+               i_stream_unref(&istream);
+       }
+       test_end();
+}
+
 static void ATTR_NULL(3)
 strip_eoh_callback(struct header_filter_istream *input ATTR_UNUSED,
                   struct message_header_line *hdr,
@@ -383,6 +419,7 @@ int main(void)
                test_istream_filter_large_buffer,
                test_istream_callbacks,
                test_istream_edit,
+               test_istream_add_missing_eoh,
                test_istream_end_body_with_lf,
                test_istream_strip_eoh,
                NULL