From d90cbe8650a35057be3b3645f6c65d4fd08e3b08 Mon Sep 17 00:00:00 2001 From: "William A. Rowe Jr" Date: Fri, 1 Jul 2005 19:59:59 +0000 Subject: [PATCH] Plug AllowTrace extended|on|off into proxy and http core. It still is not 'correct' until REQUEST_CHUNKED_PASS is reimplemented and passes some chunk headers, since we aren't echoing the entire request. But it gets me further on testing 1.3 -> 2.0 -> 2.1 -> 2.0 -> 1.3 proxy behaviors. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@208787 13f79535-47bb-0310-9956-ffa450edef68 --- modules/http/http_filters.c | 86 +++++++++++++++++++++++++++++++++--- modules/http/http_protocol.c | 8 +++- modules/proxy/mod_proxy.c | 16 +++++++ 3 files changed, 101 insertions(+), 9 deletions(-) diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c index 0b28d0a703..7d354ae5c9 100644 --- a/modules/http/http_filters.c +++ b/modules/http/http_filters.c @@ -759,9 +759,16 @@ static void terminate_header(apr_bucket_brigade *bb) AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r) { + core_server_config *conf; int rv; - apr_bucket_brigade *b; + apr_bucket_brigade *bb; header_struct h; + apr_bucket *b; + int body; + char *bodyread, *bodyoff; + apr_size_t bodylen = 0; + apr_size_t bodybuf; + long res; if (r->method_number != M_TRACE) { return DECLINED; @@ -771,23 +778,87 @@ AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r) while (r->prev) { r = r->prev; } + conf = (core_server_config *)ap_get_module_config(r->server->module_config, + &core_module); + + if (conf->trace_enable == AP_TRACE_DISABLE) { + apr_table_setn(r->notes, "error-notes", + "TRACE denied by server configuration"); + return HTTP_FORBIDDEN; + } - if ((rv = ap_setup_client_block(r, REQUEST_NO_BODY))) { + if (conf->trace_enable == AP_TRACE_EXTENDED) + /* XX should be = REQUEST_CHUNKED_PASS */ + body = REQUEST_CHUNKED_DECHUNK; + else + body = REQUEST_NO_BODY; + + if ((rv = ap_setup_client_block(r, body))) { + if (rv == HTTP_REQUEST_ENTITY_TOO_LARGE) + apr_table_setn(r->notes, "error-notes", + "TRACE with a request body is not allowed"); return rv; } + if (ap_should_client_block(r)) { + + if (r->remaining > 0) { + if (r->remaining > 65536) { + apr_table_setn(r->notes, "error-notes", + "Extended TRACE request bodies cannot exceed 64k\n"); + return HTTP_REQUEST_ENTITY_TOO_LARGE; + } + /* always 32 extra bytes to catch chunk header exceptions */ + bodybuf = (apr_size_t)r->remaining + 32; + } + else { + /* Add an extra 8192 for chunk headers */ + bodybuf = 73730; + } + + bodyoff = bodyread = apr_palloc(r->pool, bodybuf); + + /* only while we have enough for a chunked header */ + while ((!bodylen || bodybuf >= 32) && + (res = ap_get_client_block(r, bodyoff, bodybuf)) > 0) { + bodylen += res; + bodybuf -= res; + bodyoff += res; + } + if (res > 0 && bodybuf < 32) { + /* discard_rest_of_request_body into our buffer */ + while (ap_get_client_block(r, bodyread, bodylen) > 0) + ; + apr_table_setn(r->notes, "error-notes", + "Extended TRACE request bodies cannot exceed 64k\n"); + return HTTP_REQUEST_ENTITY_TOO_LARGE; + } + + if (res < 0) { + return HTTP_BAD_REQUEST; + } + } + ap_set_content_type(r, "message/http"); /* Now we recreate the request, and echo it back */ - b = apr_brigade_create(r->pool, r->connection->bucket_alloc); - apr_brigade_putstrs(b, NULL, NULL, r->the_request, CRLF, NULL); + bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); + apr_brigade_putstrs(bb, NULL, NULL, r->the_request, CRLF, NULL); h.pool = r->pool; - h.bb = b; + h.bb = bb; apr_table_do((int (*) (void *, const char *, const char *)) form_header_field, (void *) &h, r->headers_in, NULL); - apr_brigade_puts(b, NULL, NULL, CRLF); - ap_pass_brigade(r->output_filters, b); + apr_brigade_puts(bb, NULL, NULL, CRLF); + + /* If configured to accept a body, echo the body */ + if (bodylen) { + b = apr_bucket_pool_create(bodyread, bodylen, + r->pool, bb->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, b); + } + + ap_pass_brigade(r->output_filters, bb); return DONE; } @@ -1089,6 +1160,7 @@ AP_DECLARE(int) ap_discard_request_body(request_rec *r) * REQUEST_NO_BODY Send 413 error if message has any body * REQUEST_CHUNKED_ERROR Send 411 error if body without Content-Length * REQUEST_CHUNKED_DECHUNK If chunked, remove the chunks for me. + * REQUEST_CHUNKED_PASS If chunked, pass the chunk headers with body. * * In order to use the last two options, the caller MUST provide a buffer * large enough to hold a chunk-size line, including any extensions. diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c index d4b0429f52..1ee501aea9 100644 --- a/modules/http/http_protocol.c +++ b/modules/http/http_protocol.c @@ -754,6 +754,9 @@ static char *make_allow(request_rec *r) apr_int64_t mask; apr_array_header_t *allow = apr_array_make(r->pool, 10, sizeof(char *)); apr_hash_index_t *hi = apr_hash_first(r->pool, methods_registry); + /* For TRACE below */ + core_server_config *conf = + ap_get_module_config(r->server->module_config, &core_module); mask = r->allowed_methods->method_mask; @@ -771,8 +774,9 @@ static char *make_allow(request_rec *r) } } - /* TRACE is always allowed */ - *(const char **)apr_array_push(allow) = "TRACE"; + /* TRACE is tested on a per-server basis */ + if (conf->trace_enable != AP_TRACE_DISABLE) + *(const char **)apr_array_push(allow) = "TRACE"; list = apr_array_pstrcat(r->pool, allow, ','); diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 7f09042957..4ac61ccc81 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -541,7 +541,23 @@ static int proxy_handler(request_rec *r) if (maxfwd < 1) { switch (r->method_number) { case M_TRACE: { + core_server_config *coreconf = (core_server_config *) + ap_get_module_config(sconf, &core_module); int access_status; + + if (coreconf->trace_enable == AP_TRACE_DISABLE) + return ap_proxyerror(r, HTTP_NOT_IMPLEMENTED, + "TRACE denied by server configuration"); + + /* Can't test ap_should_client_block, we aren't ready to send + * the client a 100 Continue response till the connection has + * been established + */ + if (coreconf->trace_enable != AP_TRACE_EXTENDED + && (r->read_length || (!r->read_chunked && (r->remaining <= 0)))) + return ap_proxyerror(r, HTTP_REQUEST_ENTITY_TOO_LARGE, + "TRACE with request body is not allowed"); + r->proxyreq = PROXYREQ_NONE; if ((access_status = ap_send_http_trace(r))) ap_die(access_status, r); -- 2.40.0