changeset 19586:f9d75e6e1618

lib-mail: istream-binary-converter lost last few chars from root-level binary content.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Mon, 18 Jan 2016 14:57:45 +0200
parents 796996d66955
children 999368a35f8f
files src/lib-mail/istream-binary-converter.c src/lib-mail/test-istream-binary-converter.c
diffstat 2 files changed, 85 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-mail/istream-binary-converter.c	Mon Jan 18 14:56:47 2016 +0200
+++ b/src/lib-mail/istream-binary-converter.c	Mon Jan 18 14:57:45 2016 +0200
@@ -182,10 +182,19 @@
 
 	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 @@
 		break;
 	}
 
-	old_size = stream->pos - stream->skip;
-
 	if (block.part != bstream->convert_part &&
 	    bstream->convert_part != NULL) {
 		/* end of base64 encoded part */
--- a/src/lib-mail/test-istream-binary-converter.c	Mon Jan 18 14:56:47 2016 +0200
+++ b/src/lib-mail/test-istream-binary-converter.c	Mon Jan 18 14:57:45 2016 +0200
@@ -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 @@
 "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 @@
 "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 @@
 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)