]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
http: Fix possible empty response with mod_ratelimit for HEAD requests.
authorYann Ylavic <ylavic@apache.org>
Wed, 20 Feb 2019 23:08:15 +0000 (23:08 +0000)
committerYann Ylavic <ylavic@apache.org>
Wed, 20 Feb 2019 23:08:15 +0000 (23:08 +0000)
Don't eat the EOS in ap_http_header_filter() if it comes in single brigade
with a full response to a HEAD request, otherwise mod_ratelimit will never
flush its pending data.

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

CHANGES
modules/http/http_filters.c

diff --git a/CHANGES b/CHANGES
index 066acbac77fb212c37edd33883b96e7780a78395..1504ba35f8a78e713bc117cc8f54029d7eede2ee 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.1
 
+  *) http: Fix possible empty response with mod_ratelimit for HEAD requests.
+     PR 63192. [Yann Ylavic]
+
   *) mod_cache_socache: Avoid reallocations and be safe with outgoing data
      lifetime. [Yann Ylavic]
 
index 7266fc169319afbcf07a9ff737a1b3349ade4bc7..26440e26ded528213c7f555224332673154c2067 100644 (file)
@@ -1234,6 +1234,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
 {
     request_rec *r = f->r;
     conn_rec *c = r->connection;
+    int header_only = (r->header_only || AP_STATUS_IS_HEADER_ONLY(r->status));
     const char *protocol = NULL;
     apr_bucket *e;
     apr_bucket_brigade *b2;
@@ -1251,7 +1252,7 @@ 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)) {
+        if (header_only) {
             /* Still next filters may be waiting for EOS, so pass it (alone)
              * when encountered and be done with this filter.
              */
@@ -1448,14 +1449,21 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
 
     terminate_header(b2);
 
-    rv = ap_pass_brigade(f->next, b2);
-    if (rv != APR_SUCCESS) {
-        goto out;
+    if (header_only) {
+        e = APR_BRIGADE_LAST(b);
+        if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) {
+            APR_BUCKET_REMOVE(e);
+            APR_BRIGADE_INSERT_TAIL(b2, e);
+            ap_remove_output_filter(f);
+        }
+        apr_brigade_cleanup(b);
     }
+
+    rv = ap_pass_brigade(f->next, b2);
+    apr_brigade_cleanup(b2);
     ctx->headers_sent = 1;
 
-    if (r->header_only || AP_STATUS_IS_HEADER_ONLY(r->status)) {
-        apr_brigade_cleanup(b);
+    if (rv != APR_SUCCESS || header_only) {
         goto out;
     }