]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: http-transfer-chunked - Make sending of the trailer chunk in ostream more...
authorStephan Bosch <stephan.bosch@dovecot.fi>
Tue, 20 Mar 2018 17:23:43 +0000 (18:23 +0100)
committermartti.rannanjarvi <martti.rannanjarvi@open-xchange.com>
Sat, 18 Apr 2020 14:55:11 +0000 (14:55 +0000)
Use the new o_stream_finish() functionality.

src/lib-http/http-transfer-chunked.c
src/lib-http/test-http-transfer.c

index 618455324d2884ae26993aec99294b2edc8a17cf..5a2445878b9076840ae18acfdfb264e12899b64b 100644 (file)
@@ -570,6 +570,7 @@ struct http_transfer_chunked_ostream {
        size_t chunk_size, chunk_pos;
 
        bool chunk_active:1;
+       bool sent_trailer:1;
 };
 
 static size_t _log16(size_t in)
@@ -597,6 +598,34 @@ static size_t _max_chunk_size(size_t avail)
        return (avail < chunk_extra ? 0 : avail - chunk_extra);
 }
 
+static int
+http_transfer_chunked_ostream_send_trailer(
+       struct http_transfer_chunked_ostream *tcstream)
+{
+       struct ostream_private *stream = &tcstream->ostream;
+       ssize_t sent;
+
+       if (tcstream->sent_trailer)
+               return 1;
+
+       if (o_stream_get_buffer_avail_size(stream->parent) < 5) {
+               if (o_stream_flush_parent(stream) < 0)
+                       return -1;
+               if (o_stream_get_buffer_avail_size(stream->parent) < 5)
+                       return 0;
+       }
+
+       sent = o_stream_send(tcstream->ostream.parent, "0\r\n\r\n", 5);
+       if (sent < 0) {
+               o_stream_copy_error_from_parent(stream);
+               return -1;
+       }
+       i_assert(sent == 5);
+
+       tcstream->sent_trailer = TRUE;
+       return 1;
+}
+
 static void
 http_transfer_chunked_ostream_close(struct iostream_private *stream,
                                    bool close_parent)
@@ -604,12 +633,29 @@ http_transfer_chunked_ostream_close(struct iostream_private *stream,
        struct http_transfer_chunked_ostream *tcstream =
                (struct http_transfer_chunked_ostream *)stream;
 
-       o_stream_nsend(tcstream->ostream.parent, "0\r\n\r\n", 5);
-       (void)o_stream_flush(&tcstream->ostream.ostream);
+       i_assert(tcstream->ostream.finished ||
+                tcstream->ostream.ostream.stream_errno != 0 ||
+                tcstream->ostream.error_handling_disabled);
+       if (!tcstream->ostream.finished)
+               (void)o_stream_finish(&tcstream->ostream.ostream);
        if (close_parent)
                o_stream_close(tcstream->ostream.parent);
 }
 
+static int
+http_transfer_chunked_ostream_flush(struct ostream_private *stream)
+{
+       struct http_transfer_chunked_ostream *tcstream =
+               (struct http_transfer_chunked_ostream *)stream;
+       int ret;
+
+       if (stream->finished &&
+           (ret = http_transfer_chunked_ostream_send_trailer(tcstream)) <= 0)
+               return ret;
+
+       return o_stream_flush_parent(stream);
+}
+
 static ssize_t
 http_transfer_chunked_ostream_sendv(struct ostream_private *stream,
                                    const struct const_iovec *iov,
@@ -691,6 +737,7 @@ http_transfer_chunked_ostream_create(struct ostream *output)
 
        tcstream = i_new(struct http_transfer_chunked_ostream, 1);
        tcstream->ostream.sendv = http_transfer_chunked_ostream_sendv;
+       tcstream->ostream.flush = http_transfer_chunked_ostream_flush;
        tcstream->ostream.iostream.close = http_transfer_chunked_ostream_close;
        if (output->real_stream->max_buffer_size > 0)
                max_size = output->real_stream->max_buffer_size;
index 88c428bda50a980791b7ff7c6e747fb2ad430b41..39b08a6368e57fbfb968bdd76ed6b2190b20f16a 100644 (file)
@@ -303,6 +303,7 @@ static void test_http_transfer_chunked_output_valid(void)
 
                /* cleanup streams */
                test_out("payload chunk", ret > 0);
+               test_assert(o_stream_finish(ochunked) > 0);
                o_stream_destroy(&ochunked);
                o_stream_destroy(&output);
                i_stream_destroy(&input);