]> granicus.if.org Git - apache/commitdiff
core: ap_filter_output_pending() to flush outer most filters first.
authorYann Ylavic <ylavic@apache.org>
Fri, 10 Aug 2018 16:15:50 +0000 (16:15 +0000)
committerYann Ylavic <ylavic@apache.org>
Fri, 10 Aug 2018 16:15:50 +0000 (16:15 +0000)
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

index e38a5af8e6a5b28cde82e61641d9bde97ba9e727..fe99ec8a396a8799e7ce5f1910a322460897ae1c 100644 (file)
@@ -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);