dovecot-2.2: lib-http: Fixed hangs/crashes with chunked ostream.

dovecot at dovecot.org dovecot at dovecot.org
Thu Feb 21 10:23:01 EET 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/3b905464ea09
changeset: 15867:3b905464ea09
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Feb 21 10:21:31 2013 +0200
description:
lib-http: Fixed hangs/crashes with chunked ostream.
Based on patch by Stephan Bosch.

diffstat:

 src/lib-http/http-client-request.c   |   7 ++++++-
 src/lib-http/http-transfer-chunked.c |  13 ++++++++++---
 2 files changed, 16 insertions(+), 4 deletions(-)

diffs (81 lines):

diff -r c945d06207b8 -r 3b905464ea09 src/lib-http/http-client-request.c
--- a/src/lib-http/http-client-request.c	Thu Feb 21 06:22:40 2013 +0200
+++ b/src/lib-http/http-client-request.c	Thu Feb 21 10:21:31 2013 +0200
@@ -230,6 +230,9 @@
 
 	while (req->state < HTTP_REQUEST_STATE_FINISHED) {
 		http_client_request_debug(req, "Waiting for request to finish");
+		
+		if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT)
+			o_stream_set_flush_pending(req->payload_output, TRUE);
 		io_loop_run(client->ioloop);
 
 		if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT &&
@@ -280,7 +283,8 @@
 
 	i_assert(req->payload_input != NULL);
 
-	o_stream_set_max_buffer_size(output, 0);
+	/* chunked ostream needs to write to the parent stream's buffer */
+	o_stream_set_max_buffer_size(output, IO_BLOCK_SIZE);
 	if (o_stream_send_istream(output, req->payload_input) < 0)
 		ret = -1;
 	o_stream_set_max_buffer_size(output, (size_t)-1);
@@ -293,6 +297,7 @@
 		}
 
 		if (req->payload_wait) {
+			conn->output_locked = TRUE;
 			if (req->client->ioloop != NULL)
 				io_loop_stop(req->client->ioloop);
 		} else {
diff -r c945d06207b8 -r 3b905464ea09 src/lib-http/http-transfer-chunked.c
--- a/src/lib-http/http-transfer-chunked.c	Thu Feb 21 06:22:40 2013 +0200
+++ b/src/lib-http/http-transfer-chunked.c	Thu Feb 21 10:21:31 2013 +0200
@@ -8,6 +8,8 @@
 
 #include "http-transfer.h"
 
+#define MIN_CHUNK_SIZE_WITH_EXTRA 6
+
 /*
  * Chunked input stream
  */
@@ -540,14 +542,17 @@
 
 static size_t _max_chunk_size(size_t avail)
 {
+	size_t chunk_extra = 2*2;
+
 	/* Make sure we have room for both chunk data and overhead
 
 	   chunk          = chunk-size CRLF
 	                    chunk-data CRLF
 	   chunk-size     = 1*HEXDIG
 	 */
-	avail -= (2*2);
-	return avail - (_log16(avail));
+	chunk_extra += _log16(avail);
+	return avail < chunk_extra ? 0 :
+		avail - chunk_extra;
 }
 
 static void
@@ -572,6 +577,8 @@
 	ssize_t ret;
 	const char *prefix;
 
+	i_assert(stream->parent->real_stream->max_buffer_size >= MIN_CHUNK_SIZE_WITH_EXTRA);
+
 	if ((ret=o_stream_flush(stream->parent)) <= 0) {
 		/* error / we still couldn't flush existing data to
 		   parent stream. */
@@ -588,7 +595,7 @@
 	/* check if we have room to send at least one byte */
 	max_bytes = o_stream_get_buffer_avail_size(stream->parent);
 	max_bytes = _max_chunk_size(max_bytes);
-	if (max_bytes < 6)
+	if (max_bytes < MIN_CHUNK_SIZE_WITH_EXTRA)
 		return 0;
 
 	tcstream->chunk_size = bytes > max_bytes ? max_bytes : bytes;


More information about the dovecot-cvs mailing list