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