mod_ratelimit: Don't interfere with "chunked" encoding.
authorYann Ylavic <ylavic@apache.org>
Tue, 31 Jul 2018 10:35:46 +0000 (10:35 +0000)
committerYann Ylavic <ylavic@apache.org>
Tue, 31 Jul 2018 10:35:46 +0000 (10:35 +0000)
By the time ap_http_header_filter() sends the header brigade and adds the
"CHUNK" filter, we need to garantee that the header went through all the
filters' stack, and more specifically above ap_http_chunk_filter() which
assumes that all it receives is content data.
Since rate_limit_filter() may retain the header brigade, make it run after
ap_http_chunk_filter(), just before AP_FTYPE_CONNECTION filters.

Also, ap_http_header_filter() shouldn't eat the EOS for HEAD/no-body responses.
For instance mod_ratelimit depends on it since r1835168, but any next request
filter may as well to flush and/or bail out approprietely.

This fixes the regression introduced in 2.4.34 (r1835168).
PR 62568.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1837130 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
modules/filters/mod_ratelimit.c
modules/http/chunk_filter.c
modules/http/http_filters.c

diff --git a/CHANGES b/CHANGES
index f5b8983352904872f10f75550760b25d7f3a4daf..c7867bf9e8c07ea6e1456daa0c8281a13ed625de 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.1
 
+  *) mod_ratelimit: Don't interfere with "chunked" encoding, fixing regression
+     introduced in 2.4.34.  PR 62568.  [Yann Ylavic]
+
   *) http: Enforce consistently no response body with both 204 and 304
      statuses.  [Yann Ylavic]
 
index cf79973120e21eb2f9830c4a65541baf9097aae8..d16eb390595acfe83e8ce3e51db1bda46be560b4 100644 (file)
@@ -65,7 +65,6 @@ rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *bb)
 
     /* Set up our rl_ctx_t on first use */
     if (ctx == NULL) {
-
         const char *rl = NULL;
         int ratelimit;
         int burst = 0;
@@ -327,7 +326,7 @@ static void register_hooks(apr_pool_t *p)
 {
     /* run after mod_deflate etc etc, but not at connection level, ie, mod_ssl. */
     ap_register_output_filter(RATE_LIMIT_FILTER_NAME, rate_limit_filter,
-                              NULL, AP_FTYPE_PROTOCOL + 3);
+                              NULL, AP_FTYPE_CONNECTION - 1);
 }
 
 AP_DECLARE_MODULE(ratelimit) = {
index 6f5f7c153e0c5167b894b0ad639491f8e87cb150..d18a84ec9b18681123d756c7e68ecdf615760b4a 100644 (file)
@@ -67,6 +67,7 @@ apr_status_t ap_http_chunk_filter(ap_filter_t *f, apr_bucket_brigade *b)
         {
             if (APR_BUCKET_IS_EOS(e)) {
                 /* there shouldn't be anything after the eos */
+                ap_remove_output_filter(f);
                 eos = e;
                 break;
             }
@@ -184,11 +185,11 @@ apr_status_t ap_http_chunk_filter(ap_filter_t *f, apr_bucket_brigade *b)
 
         /* pass the brigade to the next filter. */
         rv = ap_pass_brigade(f->next, b);
+        apr_brigade_cleanup(b);
         if (rv != APR_SUCCESS || eos != NULL) {
             return rv;
         }
         tmp = b;
-        apr_brigade_cleanup(tmp);
     }
     return APR_SUCCESS;
 }
index 0610154d681b9b68023d564310da1882d8a5e9a2..7266fc169319afbcf07a9ff737a1b3349ade4bc7 100644 (file)
@@ -1252,8 +1252,19 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
     else if (ctx->headers_sent) {
         /* Eat body if response must not have one. */
         if (r->header_only || AP_STATUS_IS_HEADER_ONLY(r->status)) {
+            /* Still next filters may be waiting for EOS, so pass it (alone)
+             * when encountered and be done with this filter.
+             */
+            e = APR_BRIGADE_LAST(b);
+            if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) {
+                APR_BUCKET_REMOVE(e);
+                apr_brigade_cleanup(b);
+                APR_BRIGADE_INSERT_HEAD(b, e);
+                ap_remove_output_filter(f);
+                rv = ap_pass_brigade(f->next, b);
+            }
             apr_brigade_cleanup(b);
-            return APR_SUCCESS;
+            return rv;
         }
     }