From 93143eb07b685c6104c6f0169e6f040a60b99e2f Mon Sep 17 00:00:00 2001 From: Justin Erenkrantz Date: Mon, 30 Dec 2013 20:01:14 +0000 Subject: [PATCH] Add directives to control two protocol options: HttpContentLengthHeadZero - allow Content-Length of 0 to be returned on HEAD HttpExpectStrict - allow admin to control whether we must see "100-continue" This is helpful when using Ceph's radosgw and httpd. Inspired by: Yehuda Sadeh See https://github.com/ceph/apache2/commits/precise * include/http_core.h (core_server_config): Add http_cl_head_zero and http_expect_strict fields. * modules/http/http_filters.c (ap_http_header_filter): Only clear out the C-L if http_cl_head_zero is not explictly set. * server/core.c (merge_core_server_configs): Add new fields. (set_cl_head_zero, set_expect_strict): New config helpers. (HttpContentLengthHeadZero, HttpExpectStrict): Declare new directives. * server/protocol.c (ap_read_request): Allow http_expect_strict to control if we return 417. * include/ap_mmn.h (MODULE_MAGIC_NUMBER_MAJOR, MODULE_MAGIC_NUMBER_MINOR): Bump. * CHANGES: Add a brief description. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1554303 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 3 +++ include/ap_mmn.h | 5 +++-- include/http_core.h | 10 ++++++++++ modules/http/http_filters.c | 8 +++++++- server/core.c | 36 ++++++++++++++++++++++++++++++++++++ server/protocol.c | 25 +++++++++++++++++-------- 6 files changed, 76 insertions(+), 11 deletions(-) diff --git a/CHANGES b/CHANGES index 93431803b5..8de8e42cc2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.0 + *) Add HttpContentLengthHeadZero and HttpExpectStrict directives. + [Yehuda Sadeh , Justin Erenkrantz] + *) core: Support named groups and backreferences within the LocationMatch, DirectoryMatch, FilesMatch and ProxyMatch directives. [Graham Leggett] diff --git a/include/ap_mmn.h b/include/ap_mmn.h index ec1a189b5d..0ba05f90fb 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -444,14 +444,15 @@ * 20131112.0 (2.5.0-dev) Add parse_errorlog_arg to ap_errorlog_provider * 20131112.1 (2.5.0-dev) Add suspend_connection and resume_connection hooks * 20131112.2 (2.5.0-dev) Add ap_regname + * 20131230.0 (2.5.0-dev) cl_head_zero & expect_strict added to server_config */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ #ifndef MODULE_MAGIC_NUMBER_MAJOR -#define MODULE_MAGIC_NUMBER_MAJOR 20131112 +#define MODULE_MAGIC_NUMBER_MAJOR 20131230 #endif -#define MODULE_MAGIC_NUMBER_MINOR 2 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 0 /* 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 371e54d4bf..47cd98fb45 100644 --- a/include/http_core.h +++ b/include/http_core.h @@ -682,6 +682,16 @@ typedef struct { #define AP_HTTP_CONFORMANCE_STRICT 2 #define AP_HTTP_CONFORMANCE_LOGONLY 4 char http_conformance; + +#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 1224914108..dc3220e344 100644 --- a/modules/http/http_filters.c +++ b/modules/http/http_filters.c @@ -1245,10 +1245,16 @@ 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. */ 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 bb528832f3..f7bef0fe09 100644 --- a/server/core.c +++ b/server/core.c @@ -519,6 +519,12 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv) if (virt->http_conformance != AP_HTTP_CONFORMANCE_UNSET) conf->http_conformance = virt->http_conformance; + 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; + /* no action for virt->accf_map, not allowed per-vhost */ if (virt->protocol) @@ -3774,6 +3780,32 @@ static const char *set_http_method(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_core_module_config(cmd->server->module_config); + + 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_core_module_config(cmd->server->module_config); + + if (arg) { + conf->http_expect_strict = AP_HTTP_EXPECT_STRICT_ENABLE; + } else { + conf->http_expect_strict = AP_HTTP_EXPECT_STRICT_DISABLE; + } + return NULL; +} + static apr_hash_t *errorlog_hash; static int log_constant_item(const ap_errorlog_info *info, const char *arg, @@ -4331,6 +4363,10 @@ AP_INIT_ITERATE("HttpProtocol", set_http_protocol, NULL, RSRC_CONF, "'liberal', 'strict', 'strict,log-only'"), AP_INIT_ITERATE("RegisterHttpMethod", set_http_method, NULL, RSRC_CONF, "Registers non-standard HTTP methods"), +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 18f0afb88c..ab1b2d0d12 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -1221,14 +1221,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, APLOGNO(00570) - "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); - goto traceout; + core_server_config *conf; + + conf = ap_get_core_module_config(r->server->module_config); + if (conf->http_expect_strict != AP_HTTP_EXPECT_STRICT_DISABLE) { + r->status = HTTP_EXPECTATION_FAILED; + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00570) + "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); + goto traceout; + } else { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00570) + "client sent an unrecognized expectation value " + "of Expect (not fatal): %s", expect); + } } } -- 2.50.1