From 5e1e4f8777a37893360f204505a8993948ce8e79 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Tue, 6 Sep 2016 09:11:11 +0000 Subject: [PATCH] Prevent dangling buckets by safely (and always) cleanup passed out (master) brigades. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1759386 13f79535-47bb-0310-9956-ffa450edef68 --- modules/http2/h2_conn_io.c | 43 +++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/modules/http2/h2_conn_io.c b/modules/http2/h2_conn_io.c index df4aec1454..3f151f8578 100644 --- a/modules/http2/h2_conn_io.c +++ b/modules/http2/h2_conn_io.c @@ -269,9 +269,11 @@ static void check_write_size(h2_conn_io *io) } } -static apr_status_t pass_output(h2_conn_io *io, int flush, int eoc) +static apr_status_t pass_output(h2_conn_io *io, int flush, + h2_session *session_eoc) { conn_rec *c = io->c; + apr_bucket_brigade *bb = io->output; apr_bucket *b; apr_off_t bblen; apr_status_t status; @@ -279,28 +281,37 @@ static apr_status_t pass_output(h2_conn_io *io, int flush, int eoc) append_scratch(io); if (flush) { b = apr_bucket_flush_create(c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(io->output, b); + APR_BRIGADE_INSERT_TAIL(bb, b); } - if (APR_BRIGADE_EMPTY(io->output)) { + if (APR_BRIGADE_EMPTY(bb)) { return APR_SUCCESS; } ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, c, "h2_conn_io: pass_output"); ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, NULL); - apr_brigade_length(io->output, 0, &bblen); + apr_brigade_length(bb, 0, &bblen); - h2_conn_io_bb_log(c, 0, APLOG_TRACE2, "master conn pass", io->output); - status = ap_pass_brigade(c->output_filters, io->output); + h2_conn_io_bb_log(c, 0, APLOG_TRACE2, "master conn pass", bb); + status = ap_pass_brigade(c->output_filters, bb); + if (status == APR_SUCCESS) { + io->bytes_written += (apr_size_t)bblen; + io->last_write = apr_time_now(); + } + apr_brigade_cleanup(bb); - /* careful with access after this, as we might have flushed an EOC bucket - * that de-allocated us all. */ - if (!eoc) { - apr_brigade_cleanup(io->output); + if (session_eoc) { + apr_status_t tmp; + b = h2_bucket_eoc_create(c->bucket_alloc, session_eoc); + APR_BRIGADE_INSERT_TAIL(bb, b); + h2_conn_io_bb_log(c, 0, APLOG_TRACE2, "master conn pass", bb); + tmp = ap_pass_brigade(c->output_filters, bb); if (status == APR_SUCCESS) { - io->bytes_written += (apr_size_t)bblen; - io->last_write = apr_time_now(); + status = tmp; } + /* careful with access to io after this, we have flushed an EOC bucket + * that de-allocated us all. */ + apr_brigade_cleanup(bb); } if (status != APR_SUCCESS) { @@ -313,14 +324,12 @@ static apr_status_t pass_output(h2_conn_io *io, int flush, int eoc) apr_status_t h2_conn_io_flush(h2_conn_io *io) { - return pass_output(io, 1, 0); + return pass_output(io, 1, NULL); } apr_status_t h2_conn_io_write_eoc(h2_conn_io *io, h2_session *session) { - apr_bucket *b = h2_bucket_eoc_create(io->c->bucket_alloc, session); - APR_BRIGADE_INSERT_TAIL(io->output, b); - return pass_output(io, 1, 1); + return pass_output(io, 1, session); } apr_status_t h2_conn_io_write(h2_conn_io *io, const char *data, size_t length) @@ -413,7 +422,7 @@ apr_status_t h2_conn_io_pass(h2_conn_io *io, apr_bucket_brigade *bb) if (!APR_BRIGADE_EMPTY(io->output)) { apr_off_t len = h2_brigade_mem_size(io->output); if (len >= io->pass_threshold) { - return pass_output(io, 0, 0); + return pass_output(io, 0, NULL); } } } -- 2.40.0