You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by yl...@apache.org on 2018/08/10 16:15:50 UTC

svn commit: r1837822 - /httpd/httpd/trunk/server/util_filter.c

Author: ylavic
Date: Fri Aug 10 16:15:50 2018
New Revision: 1837822

URL: http://svn.apache.org/viewvc?rev=1837822&view=rev
Log:
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.

Modified:
    httpd/httpd/trunk/server/util_filter.c

Modified: httpd/httpd/trunk/server/util_filter.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util_filter.c?rev=1837822&r1=1837821&r2=1837822&view=diff
==============================================================================
--- httpd/httpd/trunk/server/util_filter.c (original)
+++ httpd/httpd/trunk/server/util_filter.c Fri Aug 10 16:15:50 2018
@@ -818,6 +818,12 @@ AP_DECLARE(apr_status_t) ap_filter_reins
     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_reins
  
     *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_
     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_p
         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);