Commit 767deda8 authored by Yann Ylavic's avatar Yann Ylavic
Browse files

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
parent d24a295f
Loading
Loading
Loading
Loading
+14 −10
Changes for server/util_filter.c: 14 added lines, 10 removed lines.
Original line number Diff line number Diff line
@@ -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);