]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-mail: istream-binary-converter lost last few chars from root-level binary content.
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 18 Jan 2016 12:57:45 +0000 (14:57 +0200)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 18 Jan 2016 13:00:40 +0000 (15:00 +0200)
src/lib-mail/istream-binary-converter.c
src/lib-mail/test-istream-binary-converter.c

index d0d059ec50012666f5570f8fb64bcb1dcbcb087e..ccc2990e2ec9abd10e15a711fc8f2105c05251fc 100644 (file)
@@ -182,10 +182,19 @@ static ssize_t i_stream_binary_converter_read(struct istream_private *stream)
 
        if (stream->pos - stream->skip >= stream->max_buffer_size)
                return -2;
+       old_size = stream->pos - stream->skip;
 
        switch (message_parser_parse_next_block(bstream->parser, &block)) {
        case -1:
                /* done / error */
+               if (bstream->convert_part != NULL &&
+                   bstream->base64_delayed_len > 0) {
+                       /* flush any pending base64 output */
+                       stream_encode_base64(bstream, "", 0);
+                       new_size = stream->pos - stream->skip;
+                       i_assert(old_size != new_size);
+                       return new_size - old_size;
+               }
                stream->istream.eof = TRUE;
                stream->istream.stream_errno = stream->parent->stream_errno;
                return -1;
@@ -196,8 +205,6 @@ static ssize_t i_stream_binary_converter_read(struct istream_private *stream)
                break;
        }
 
-       old_size = stream->pos - stream->skip;
-
        if (block.part != bstream->convert_part &&
            bstream->convert_part != NULL) {
                /* end of base64 encoded part */
index 5d2ebd9b1e034822a9f6632831edf5006ee29ea0..0da002f3e6301956aaa20316bae4fa9167fa50f7 100644 (file)
@@ -1,6 +1,8 @@
 /* Copyright (c) 2007-2016 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "base64.h"
+#include "buffer.h"
 #include "str.h"
 #include "sha1.h"
 #include "istream.h"
@@ -21,7 +23,7 @@
 #define BINARY_TEXT_SHORT "eh"
 #define BINARY_TEXT_SHORT_BASE64 "ZWg="
 
-static const char mail_input[] =
+static const char mail_input_mime[] =
 "MIME-Version: 1.0\r\n"
 "Content-Type: multipart/alternative;\r\n boundary=\"bound\"\r\n"
 "\r\n"
@@ -36,13 +38,13 @@ BINARY_TEXT_LONG
 "Content-Transfer-Encoding: binary\r\n"
 "\r\n"
 BINARY_TEXT_SHORT
-"\r\n--bound\r\n"
+"\n--bound\r\n"
 "Content-Type: text/plain\r\n"
 "\r\n"
 "hello world\r\n"
 "\r\n--bound--\r\n";
 
-static const char mail_output[] =
+static const char mail_output_mime[] =
 "MIME-Version: 1.0\r\n"
 "Content-Type: multipart/alternative;\r\n boundary=\"bound\"\r\n"
 "\r\n"
@@ -57,38 +59,97 @@ BINARY_TEXT_LONG_BASE64
 "Content-Transfer-Encoding: base64\r\n"
 "\r\n"
 BINARY_TEXT_SHORT_BASE64
-"\r\n--bound\r\n"
+"\n--bound\r\n"
 "Content-Type: text/plain\r\n"
 "\r\n"
 "hello world\r\n"
 "\r\n--bound--\r\n";
 
-static void test_istream_binary_converter(void)
+static const char mail_input_root_hdr[] =
+"MIME-Version: 1.0\r\n"
+"Content-Transfer-Encoding: binary\r\n"
+"Content-Type: text/plain\r\n"
+"\r\n";
+
+static const char mail_output_root_hdr[] =
+"MIME-Version: 1.0\r\n"
+"Content-Transfer-Encoding: base64\r\n"
+"Content-Type: text/plain\r\n"
+"\r\n";
+
+static const char mail_root_nonbinary[] =
+"MIME-Version: 1.0\r\n"
+"Content-Type: text/plain\r\n"
+"\r\n"
+"hello\n\n";
+
+static void
+test_istream_binary_converter_test(const char *mail_input, unsigned int mail_input_len,
+                                  const char *mail_output, unsigned int mail_output_len,
+                                  unsigned int idx)
 {
        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));
+       datainput = test_istream_create_data(mail_input, mail_input_len);
        test_istream_set_allow_eof(datainput, FALSE);
        input = i_stream_create_binary_converter(datainput);
 
-       for (i = 1; i <= sizeof(mail_input); i++) {
+       for (i = 1; i <= mail_input_len; i++) {
                test_istream_set_size(datainput, i);
                while ((ret = i_stream_read(input)) > 0) ;
-               test_assert(ret == 0);
+               test_assert_idx(ret == 0, idx);
        }
        test_istream_set_allow_eof(datainput, TRUE);
        while ((ret = i_stream_read(input)) > 0) ;
-       test_assert(ret == -1);
+       test_assert_idx(ret == -1, idx);
 
        data = i_stream_get_data(input, &size);
-       test_assert(size == sizeof(mail_output) &&
-                   memcmp(data, mail_output, size) == 0);
+       test_assert_idx(size == mail_output_len &&
+                       memcmp(data, mail_output, size) == 0, idx);
        i_stream_unref(&input);
        i_stream_unref(&datainput);
+}
+
+static void test_istream_binary_converter_mime(void)
+{
+       test_begin("istream binary converter in mime parts");
+       test_istream_binary_converter_test(mail_input_mime, sizeof(mail_input_mime)-1,
+                                          mail_output_mime, sizeof(mail_output_mime)-1, 0);
+       test_end();
+}
+
+static void test_istream_binary_converter_root(void)
+{
+       buffer_t *inbuf = buffer_create_dynamic(pool_datastack_create(), 512);
+       buffer_t *outbuf = buffer_create_dynamic(pool_datastack_create(), 512);
+       const char *const suffixes[] = { "\n", "\r\n", "\n\r\n\n\n" };
+       unsigned int i;
+       unsigned int input_hdr_len = sizeof(mail_input_root_hdr)-1;
+
+       test_begin("istream binary converter in root");
+       buffer_append(inbuf, mail_input_root_hdr, input_hdr_len);
+       buffer_append(outbuf, mail_output_root_hdr, sizeof(mail_output_root_hdr)-1);
+       for (i = 0; i < N_ELEMENTS(suffixes); i++) {
+               buffer_set_used_size(inbuf, input_hdr_len);
+               buffer_set_used_size(outbuf, sizeof(mail_output_root_hdr)-1);
+               buffer_append(inbuf, BINARY_TEXT_SHORT, sizeof(BINARY_TEXT_SHORT)-1);
+               buffer_append(inbuf, suffixes[i], strlen(suffixes[i]));
+               base64_encode(CONST_PTR_OFFSET(inbuf->data, input_hdr_len),
+                             inbuf->used - input_hdr_len, outbuf);
+               test_istream_binary_converter_test(inbuf->data, inbuf->used,
+                                                  outbuf->data, outbuf->used, i);
+       }
+       test_end();
+}
+
+static void test_istream_binary_converter_root_nonbinary(void)
+{
+       test_begin("istream binary converter in root having non-binary");
+       test_istream_binary_converter_test(mail_root_nonbinary, sizeof(mail_root_nonbinary)-1,
+                                          mail_root_nonbinary, sizeof(mail_root_nonbinary)-1, 0);
        test_end();
 }
 
@@ -142,7 +203,9 @@ static int test_input_file(const char *path)
 int main(int argc, char *argv[])
 {
        static void (*test_functions[])(void) = {
-               test_istream_binary_converter,
+               test_istream_binary_converter_mime,
+               test_istream_binary_converter_root,
+               test_istream_binary_converter_root_nonbinary,
                NULL
        };
        if (argc > 1)