]> granicus.if.org Git - apache/commitdiff
http: Don't remove the Content-Length of zero from a HEAD response if
authorYann Ylavic <ylavic@apache.org>
Thu, 7 May 2015 14:05:25 +0000 (14:05 +0000)
committerYann Ylavic <ylavic@apache.org>
Thu, 7 May 2015 14:05:25 +0000 (14:05 +0000)
it comes from an origin server, module or script.

Instead of removing the C-L in ap_http_header_filter() after it has been
set by ap_content_length_filter(), just don't set it in the latter.

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

CHANGES
modules/http/http_filters.c
server/protocol.c

diff --git a/CHANGES b/CHANGES
index 351deff5553085590e4859076f98c72928c5c260..b6b5fea2e5c788531d9b8cd39002a21352a52a00 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.0
 
+  *) http: Don't remove the Content-Length of zero from a HEAD response if
+     it comes from an origin server, module or script.  [Yann Ylavic]
+
   *) core/util_script: make REDIRECT_URL a full URL.  PR 57785. [Nick Kew]
 
   *) mod_ssl: Check for the Entropy Gathering Daemon (EGD) availability at
index 4bc7c821130c570e56efa738e200201ce71aa196..7ebb619f556b53c32e05c4c3b531d20067f865c0 100644 (file)
@@ -1127,7 +1127,6 @@ 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;
-    const char *clheader;
     const char *protocol = NULL;
     apr_bucket *e;
     apr_bucket_brigade *b2;
@@ -1274,30 +1273,6 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
         apr_table_addn(r->headers_out, "Expires", date);
     }
 
-    /* This is a hack, but I can't find anyway around it.  The idea is that
-     * we don't want to send out 0 Content-Lengths if it is a head request.
-     * This happens when modules try to outsmart the server, and return
-     * if they see a HEAD request.  Apache 1.3 handlers were supposed to
-     * just return in that situation, and the core handled the HEAD.  In
-     * 2.0, if a handler returns, then the core sends an EOS bucket down
-     * the filter stack, and the content-length filter computes a C-L of
-     * zero and that gets put in the headers, and we end up sending a
-     * zero C-L to the client.  We can't just remove the C-L filter,
-     * because well behaved 2.0 handlers will send their data down the stack,
-     * and we will compute a real C-L for the head request. RBB
-     *
-     * Allow modification of this behavior through the
-     * HttpContentLengthHeadZero directive.
-     *
-     * The default (unset) behavior is to squelch the C-L in this case.
-     */
-    if (r->header_only
-        && (clheader = apr_table_get(r->headers_out, "Content-Length"))
-        && !strcmp(clheader, "0")
-        && conf->http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE) {
-        apr_table_unset(r->headers_out, "Content-Length");
-    }
-
     b2 = apr_brigade_create(r->pool, c->bucket_alloc);
     basic_http_header(r, b2, protocol);
 
index 9c05108ada6253c43c0d258fa6890ffcc26a9fdf..5759f69afac54aac5489daedb004b75786c2a434 100644 (file)
@@ -1533,10 +1533,35 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_content_length_filter(
      * We can only set a C-L in the response header if we haven't already
      * sent any buckets on to the next output filter for this request.
      */
-    if (ctx->data_sent == 0 && eos &&
+    if (ctx->data_sent == 0 && eos) {
+        core_server_config *conf =
+            ap_get_core_module_config(r->server->module_config);
+
+        /* This is a hack, but I can't find anyway around it.  The idea is that
+         * we don't want to send out 0 Content-Lengths if it is a HEAD request.
+         * [Unless the corresponding body (for a GET) would really be empty!]
+         * This happens when modules try to outsmart the server, and return
+         * if they see a HEAD request.  Apache 1.3 handlers were supposed to
+         * just return in that situation, and the core handled the HEAD.  From
+         * 2.0, if a handler returns, then the core sends an EOS bucket down
+         * the filter stack, and this content-length filter computes a length
+         * of zero and we would end up sending a zero C-L to the client.
+         * We can't just remove the this C-L filter, because well behaved 2.0+
+         * handlers will send their data down the stack, and we will compute
+         * a real C-L for the head request. RBB
+         *
+         * Allow modification of this behavior through the
+         * HttpContentLengthHeadZero directive.
+         *
+         * The default (unset) behavior is to squelch the C-L in this case.
+         */
+
         /* don't whack the C-L if it has already been set for a HEAD
          * by something like proxy.  the brigade only has an EOS bucket
-         * in this case, making r->bytes_sent zero.
+         * in this case, making r->bytes_sent zero, and either there is
+         * an existing C-L we want to preserve, or r->sent_bodyct is not
+         * zero (the empty body is being sent) thus we don't want to add
+         * a C-L of zero (the backend did not provide it, neither do we).
          *
          * if r->bytes_sent > 0 we have a (temporary) body whose length may
          * have been changed by a filter.  the C-L header might not have been
@@ -1544,9 +1569,13 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_content_length_filter(
          * such filters update or remove the C-L header, and just use it
          * if present.
          */
-        !(r->header_only && r->bytes_sent == 0 &&
-            apr_table_get(r->headers_out, "Content-Length"))) {
-        ap_set_content_length(r, r->bytes_sent);
+        if (!(r->header_only
+              && !r->bytes_sent
+              && (r->sent_bodyct
+                  || conf->http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE
+                  || apr_table_get(r->headers_out, "Content-Length")))) {
+            ap_set_content_length(r, r->bytes_sent);
+        }
     }
 
     ctx->data_sent = 1;