From: Timo Sirainen Date: Mon, 25 Apr 2016 13:58:30 +0000 (+0300) Subject: lib-mail: More fixes to istream-header-filter with large input. X-Git-Tag: 2.2.24~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ad09af2c9157fbb20c5d2e588f1fac61d87b1b44;p=thirdparty%2Fdovecot%2Fcore.git lib-mail: More fixes to istream-header-filter with large input. Don't assume that when reading the header the second time we'll get exactly the same header blocks as the first time. This commit also prevents the filter callback from switching the matching-decision on non-first header line. This shouldn't be needed and it could just cause confusion. (It also made it a bit easier to implement this fix.) --- diff --git a/src/lib-mail/istream-header-filter.c b/src/lib-mail/istream-header-filter.c index e99a757fa0..1afb02641b 100644 --- a/src/lib-mail/istream-header-filter.c +++ b/src/lib-mail/istream-header-filter.c @@ -39,6 +39,7 @@ struct header_filter_istream { unsigned int end_body_with_lf:1; unsigned int last_lf_added:1; unsigned int eoh_not_matched:1; + unsigned int prev_matched:1; }; header_filter_callback *null_header_filter_callback = NULL; @@ -155,7 +156,6 @@ static ssize_t read_header(struct header_filter_istream *mstream) struct message_header_line *hdr; uoff_t highwater_offset; ssize_t ret, ret2; - bool matched; int hdr_ret; if (mstream->hdr_ctx == NULL) { @@ -189,8 +189,10 @@ static ssize_t read_header(struct header_filter_istream *mstream) while ((hdr_ret = message_parse_header_next(mstream->hdr_ctx, &hdr)) > 0) { - mstream->cur_line++; + bool matched; + if (!hdr->continued) + mstream->cur_line++; if (hdr->eoh) { mstream->seen_eoh = TRUE; matched = TRUE; @@ -212,15 +214,25 @@ static ssize_t read_header(struct header_filter_istream *mstream) continue; } - matched = mstream->headers_count == 0 ? FALSE : - i_bsearch(hdr->name, mstream->headers, - mstream->headers_count, - sizeof(*mstream->headers), - bsearch_strcasecmp) != NULL; + if (hdr->continued) { + /* Header line continued - use only the first line's + matched-result. Otherwise multiline headers might + end up being only partially picked, which wouldn't + be very good. However, allow callbacks to modify + the headers in any way they want. */ + matched = mstream->prev_matched; + } else if (mstream->headers_count == 0) { + /* no include/exclude headers - default matching */ + matched = FALSE; + } else { + matched = i_bsearch(hdr->name, mstream->headers, + mstream->headers_count, + sizeof(*mstream->headers), + bsearch_strcasecmp) != NULL; + } if (mstream->callback == NULL) { /* nothing gets excluded */ - } else if (mstream->cur_line > mstream->parsed_lines || - mstream->headers_edited) { + } else if (!mstream->header_parsed || mstream->headers_edited) { /* first time in this line or we have actually modified the header so we always want to call the callbacks */ bool orig_matched = matched; @@ -229,18 +241,19 @@ static ssize_t read_header(struct header_filter_istream *mstream) mstream->callback(mstream, hdr, &matched, mstream->context); if (matched != orig_matched && - !mstream->headers_edited) { + !hdr->continued && !mstream->headers_edited) { if (!array_is_created(&mstream->match_change_lines)) i_array_init(&mstream->match_change_lines, 8); array_append(&mstream->match_change_lines, &mstream->cur_line, 1); } - } else { + } else if (!hdr->continued) { /* second time in this line. was it excluded by the callback the first time? */ if (match_line_changed(mstream)) matched = !matched; } + mstream->prev_matched = matched; if (matched == mstream->exclude) { /* ignore */ @@ -303,6 +316,7 @@ static ssize_t read_header(struct header_filter_istream *mstream) mstream->hdr_ctx = NULL; if (!mstream->header_parsed && mstream->callback != NULL) { + bool matched = FALSE; mstream->callback(mstream, NULL, &matched, mstream->context); /* check if the callback added more headers. @@ -427,6 +441,7 @@ i_stream_header_filter_seek_to_header(struct header_filter_istream *mstream, message_parse_header_deinit(&mstream->hdr_ctx); mstream->skip_count = v_offset; mstream->cur_line = 0; + mstream->prev_matched = FALSE; mstream->header_read = FALSE; mstream->seen_eoh = FALSE; } diff --git a/src/lib-mail/test-istream-header-filter.c b/src/lib-mail/test-istream-header-filter.c index 048e3a3a38..cfa544ccb5 100644 --- a/src/lib-mail/test-istream-header-filter.c +++ b/src/lib-mail/test-istream-header-filter.c @@ -172,9 +172,11 @@ static void test_istream_filter_large_buffer(void) i_assert(p != NULL); test_assert(strcmp(p+1, str_c(output) + prefix_len) == 0); - /* seek back and retry once with caching */ + /* seek back and retry once with caching and different + buffer size */ i_stream_seek(filter, 0); str_truncate(output, 0); + test_istream_set_max_buffer_size(istream, 4096); } str_free(&input);