From 3c7f5e2a32a54a12931f413b99c0633aee7414b5 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Fri, 10 Aug 2018 16:15:50 +0000 Subject: [PATCH] core: ap_filter_output_pending() to flush outer most filters first. Since previous output filters may use ap_filter_should_yield() to determine whether they should send more data (e.g. ap_request_core_filter), we need to flush pending data from the core output filter first, and so on up the chain. Otherwise we may enter an infinite loop where ap_request_core_filter() does nothing on ap_filter_output_pending() called from MPM event. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1837822 13f79535-47bb-0310-9956-ffa450edef68 --- server/util_filter.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/server/util_filter.c b/server/util_filter.c index e38a5af8e6..fe99ec8a39 100644 --- a/server/util_filter.c +++ b/server/util_filter.c @@ -818,6 +818,12 @@ AP_DECLARE(apr_status_t) ap_filter_reinstate_brigade(ap_filter_t *f, int eor_buckets_in_brigade, morphing_bucket_in_brigade; core_server_config *conf; + ap_log_cerror(APLOG_MARK, APLOG_TRACE6, 0, f->c, + "reinstate %s brigade to %s brigade in '%s' output filter", + (!f->bb || APR_BRIGADE_EMPTY(f->bb) ? "empty" : "full"), + (APR_BRIGADE_EMPTY(bb) ? "empty" : "full"), + f->frec->name); + if (f->bb && !APR_BRIGADE_EMPTY(f->bb)) { APR_BRIGADE_PREPEND(bb, f->bb); } @@ -828,12 +834,6 @@ AP_DECLARE(apr_status_t) ap_filter_reinstate_brigade(ap_filter_t *f, *flush_upto = NULL; - ap_log_cerror(APLOG_MARK, APLOG_TRACE6, 0, f->c, - "reinstate %s brigade to %s brigade in '%s' output filter", - (!f->bb || APR_BRIGADE_EMPTY(f->bb) ? "empty" : "full"), - (APR_BRIGADE_EMPTY(bb) ? "empty" : "full"), - f->frec->name); - /* * Determine if and up to which bucket we need to do a blocking write: * @@ -1005,9 +1005,13 @@ AP_DECLARE_NONSTD(int) ap_filter_output_pending(conn_rec *c) bb = ap_reuse_brigade_from_pool("ap_fop_bb", c->pool, c->bucket_alloc); - for (f = APR_RING_FIRST(c->pending_filters); + /* Flush outer most filters first for ap_filter_should_yield(f->next) + * to be relevant in the previous ones (e.g. ap_request_core_filter() + * won't pass its buckets if its next filters yields already). + */ + for (f = APR_RING_LAST(c->pending_filters); f != APR_RING_SENTINEL(c->pending_filters, ap_filter_t, pending); - f = APR_RING_NEXT(f, pending)) { + f = APR_RING_PREV(f, pending)) { if (f->frec->direction == AP_FILTER_OUTPUT && f->bb && !APR_BRIGADE_EMPTY(f->bb)) { apr_status_t rv; @@ -1038,9 +1042,9 @@ AP_DECLARE_NONSTD(int) ap_filter_input_pending(conn_rec *c) return DECLINED; } - for (f = APR_RING_FIRST(c->pending_filters); + for (f = APR_RING_LAST(c->pending_filters); f != APR_RING_SENTINEL(c->pending_filters, ap_filter_t, pending); - f = APR_RING_NEXT(f, pending)) { + f = APR_RING_PREV(f, pending)) { if (f->frec->direction == AP_FILTER_INPUT && f->bb) { apr_bucket *e = APR_BRIGADE_FIRST(f->bb); -- 2.50.1