From bb40c198b879d3176712fe0d89268c91a24f2a0f Mon Sep 17 00:00:00 2001
From: Autobuild <abuild@thinkpad.bad.example>
Date: Mon, 11 Aug 2014 09:11:28 +0000
Subject: [PATCH] fate#317766

Backport to 2.2.15

---
 CHANGES                     |  3 +++
 include/ap_mmn.h            |  3 ++-
 include/http_core.h         | 10 ++++++++++
 modules/http/http_filters.c |  8 +++++++-
 server/core.c               | 35 +++++++++++++++++++++++++++++++++++
 server/protocol.c           | 24 ++++++++++++++++--------
 6 files changed, 73 insertions(+), 10 deletions(-)

diff --git a/CHANGES b/CHANGES
index c6a4d03..1f99fe3 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.2.12
 
+  *) Add HttpContentLengthHeadZero and HttpExpectStrict directives.
+     [Yehuda Sadeh <yehuda inktank com>, Justin Erenkrantz]
+
   *) SECURITY: CVE-2009-1891 (cve.mitre.org)
      Fix a potential Denial-of-Service attack against mod_deflate or other 
      modules, by forcing the server to consume CPU time in compressing a 
diff --git a/include/ap_mmn.h b/include/ap_mmn.h
index c58660d..2ca5c1e 100644
--- a/include/ap_mmn.h
+++ b/include/ap_mmn.h
@@ -138,14 +138,16 @@
  * 20051115.22 (2.2.12) Add ap_escape_html2 API, with additional option
  * 20051115.23 (2.2.12) Add ap_open_piped_log_ex API, with cmdtype option,
  *                      and conditional cmdtype member of piped_log struct
+ * 20051115.24 (2.5.0-dev)  cl_head_zero & expect_strict added to server_config,
+                            size changes
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503232UL /* "AP22" */
 
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20051115
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 23                    /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 24                    /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a
diff --git a/include/http_core.h b/include/http_core.h
index 1802cda..64507b9 100644
--- a/include/http_core.h
+++ b/include/http_core.h
@@ -613,6 +613,16 @@ typedef struct {
 #define AP_TRACE_EXTENDED  2
     int trace_enable;
 
+#define AP_HTTP_CL_HEAD_ZERO_UNSET    0
+#define AP_HTTP_CL_HEAD_ZERO_ENABLE   1
+#define AP_HTTP_CL_HEAD_ZERO_DISABLE  2
+    int http_cl_head_zero;
+
+#define AP_HTTP_EXPECT_STRICT_UNSET    0
+#define AP_HTTP_EXPECT_STRICT_ENABLE   1
+#define AP_HTTP_EXPECT_STRICT_DISABLE  2
+    int http_expect_strict;
+
 } core_server_config;
 
 /* for AddOutputFiltersByType in core.c */
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
index f7f86df..db4f8d0 100644
--- a/modules/http/http_filters.c
+++ b/modules/http/http_filters.c
@@ -1107,6 +1107,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
     header_filter_ctx *ctx = f->ctx;
     const char *ctype;
     ap_bucket_error *eb = NULL;
+    core_server_config *conf;
 
     AP_DEBUG_ASSERT(!r->main);
 
@@ -1247,10 +1247,18 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
      * 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.
      */
+    conf = ap_get_module_config(r->server->module_config,
+                                &core_module);
     if (r->header_only
         && (clheader = apr_table_get(r->headers_out, "Content-Length"))
-        && !strcmp(clheader, "0")) {
+        && !strcmp(clheader, "0")
+        && conf->http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE) {
         apr_table_unset(r->headers_out, "Content-Length");
     }
 
diff --git a/server/core.c b/server/core.c
index 471241e..c1c369f 100644
--- a/server/core.c
+++ b/server/core.c
@@ -534,6 +534,12 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
                          ? virt->trace_enable
                          : base->trace_enable;
 
+    if (virt->http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_UNSET)
+        conf->http_cl_head_zero = virt->http_cl_head_zero;
+
+    if (virt->http_expect_strict != AP_HTTP_EXPECT_STRICT_UNSET)
+        conf->http_expect_strict = virt->http_expect_strict;
+
     return conf;
 }
 
@@ -2988,6 +2994,32 @@ static const char *set_max_ranges(cmd_parms *cmd, void *conf_, const char *arg)
     return NULL;
 }
 
+static const char *set_cl_head_zero(cmd_parms *cmd, void *dummy, int arg)
+{
+    core_server_config *conf =
+        ap_get_module_config(cmd->server->module_config,
+                             &core_module);
+    if (arg) {
+        conf->http_cl_head_zero = AP_HTTP_CL_HEAD_ZERO_ENABLE;
+    } else {
+        conf->http_cl_head_zero = AP_HTTP_CL_HEAD_ZERO_DISABLE;
+    }
+    return NULL;
+}
+
+static const char *set_expect_strict(cmd_parms *cmd, void *dummy, int arg)
+{
+    core_server_config *conf =
+        ap_get_module_config(cmd->server->module_config,
+                             &core_module);
+
+    if (arg) {
+        conf->http_expect_strict = AP_HTTP_EXPECT_STRICT_ENABLE;
+    } else {
+        conf->http_expect_strict = AP_HTTP_EXPECT_STRICT_DISABLE;
+    }
+    return NULL;
+}
 
 AP_DECLARE(size_t) ap_get_limit_xml_body(const request_rec *r)
 {
@@ -3513,6 +3544,10 @@ AP_INIT_TAKE1("EnableExceptionHook", ap_mpm_set_exception_hook, NULL, RSRC_CONF,
 #endif
 AP_INIT_TAKE1("TraceEnable", set_trace_enable, NULL, RSRC_CONF,
               "'on' (default), 'off' or 'extended' to trace request body content"),
+AP_INIT_FLAG("HttpContentLengthHeadZero", set_cl_head_zero, NULL, OR_OPTIONS,
+  "whether to permit Content-Length of 0 responses to HEAD requests"),
+AP_INIT_FLAG("HttpExpectStrict", set_expect_strict, NULL, OR_OPTIONS,
+  "whether to return a 417 if a client doesn't send 100-Continue"),
 { NULL }
 };
 
diff --git a/server/protocol.c b/server/protocol.c
index 695c275..f438b9c 100644
--- a/server/protocol.c
+++ b/server/protocol.c
@@ -1081,14 +1081,23 @@ request_rec *ap_read_request(conn_rec *conn)
             r->expecting_100 = 1;
         }
         else {
-            r->status = HTTP_EXPECTATION_FAILED;
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
-                          "client sent an unrecognized expectation value of "
-                          "Expect: %s", expect);
-            ap_send_error_response(r, 0);
-            ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
-            ap_run_log_transaction(r);
-            return r;
+            core_server_config *conf;
+
+            conf = ap_get_module_config(r->server->module_config,
+                                        &core_module);
+            if (conf->http_expect_strict != AP_HTTP_EXPECT_STRICT_DISABLE) {
+                r->status = HTTP_EXPECTATION_FAILED;
+                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+                              "client sent an unrecognized expectation value "
+                              "of Expect: %s", expect);
+                ap_send_error_response(r, 0);
+                ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
+                ap_run_log_transaction(r);
+            } else {
+                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                              "client sent an unrecognized expectation value "
+                              "of Expect (not fatal): %s", expect);
+            }
         }
     }
 
