You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by wr...@apache.org on 2005/09/20 20:14:40 UTC

svn commit: r290502 - in /httpd/httpd/branches/2.0.x: CHANGES STATUS include/ap_mmn.h include/http_core.h modules/http/http_protocol.c modules/proxy/mod_proxy.c server/core.c

Author: wrowe
Date: Tue Sep 20 11:14:29 2005
New Revision: 290502

URL: http://svn.apache.org/viewcvs?rev=290502&view=rev
Log:

  Backport TraceEnable option, correcting RFC violation by mod_proxy as this
  now drops any proxied TRACE request which tries to pass a body, unless
  the user explicitly forces 'TraceEnable extended'.

  Per colm; removed \n's from error_notes, docs coming next.

Reviewed by: jimj, colm

Modified:
    httpd/httpd/branches/2.0.x/CHANGES
    httpd/httpd/branches/2.0.x/STATUS
    httpd/httpd/branches/2.0.x/include/ap_mmn.h
    httpd/httpd/branches/2.0.x/include/http_core.h
    httpd/httpd/branches/2.0.x/modules/http/http_protocol.c
    httpd/httpd/branches/2.0.x/modules/proxy/mod_proxy.c
    httpd/httpd/branches/2.0.x/server/core.c

Modified: httpd/httpd/branches/2.0.x/CHANGES
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.0.x/CHANGES?rev=290502&r1=290501&r2=290502&view=diff
==============================================================================
--- httpd/httpd/branches/2.0.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.0.x/CHANGES [utf-8] Tue Sep 20 11:14:29 2005
@@ -1,6 +1,12 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.0.55
 
+  *) Added TraceEnable [on|off|extended] per-server directive to alter
+     the behavior of the TRACE method.  This addresses a flaw in proxy
+     conformance to RFC 2616 - previously the proxy server would accept
+     a TRACE request body although the RFC prohibited it.  The default
+     remains 'TraceEnable on'.  [William Rowe]
+
   *) Add ap_log_cerror() for logging messages associated with particular
      client connections.  [Jeff Trawick]
 

Modified: httpd/httpd/branches/2.0.x/STATUS
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.0.x/STATUS?rev=290502&r1=290501&r2=290502&view=diff
==============================================================================
--- httpd/httpd/branches/2.0.x/STATUS (original)
+++ httpd/httpd/branches/2.0.x/STATUS Tue Sep 20 11:14:29 2005
@@ -211,18 +211,6 @@
        +1: jorton, wrowe
        wrowe cautions to backport to 2.2.x branch as well.
 
-    *) Correct RFC 2616 non-compliance by refusing to proxy a request body 
-       in a TRACE request, unless TraceEnable extended is configured.
-       Introduces TraceEnable [on|off|extended] to give the administrator
-       full control of TRACE request handling.  RFC 2616 does NOT require
-       TRACE (although to disable remains silly).  Current patch at;
-          http://people.apache.org/~wrowe/httpd-2.0-trace.patch
-       +1 wrowe, jimjag, colm
-         colm notes: There are some \n's in apr_table_setn calls that are
-                     not consistent with other calls to apr_table_setn.
-                     There is no documentation for TraceEnable in trunk to 
-                     backport, shouldn't release while still undocumented.
-
     *) mod_headers: Support {...}s tag for SSL variable lookup.
        http://www.apache.org/~jorton/mod_headers-2.0-ssl.diff
        +1: jorton, trawick

Modified: httpd/httpd/branches/2.0.x/include/ap_mmn.h
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.0.x/include/ap_mmn.h?rev=290502&r1=290501&r2=290502&view=diff
==============================================================================
--- httpd/httpd/branches/2.0.x/include/ap_mmn.h (original)
+++ httpd/httpd/branches/2.0.x/include/ap_mmn.h Tue Sep 20 11:14:29 2005
@@ -84,6 +84,7 @@
  * 20020903.9 (2.0.51-dev) create pcommands and initialize arrays before
  *                         calling ap_setup_prelinked_modules
  * 20020903.10 (2.0.55-dev) add ap_log_cerror()
+ * 20020903.11 (2.0.55-dev) added trace_enable to core_server_config
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503230UL /* "AP20" */
@@ -91,7 +92,7 @@
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20020903
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 10                    /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 11                    /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a

Modified: httpd/httpd/branches/2.0.x/include/http_core.h
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.0.x/include/http_core.h?rev=290502&r1=290501&r2=290502&view=diff
==============================================================================
--- httpd/httpd/branches/2.0.x/include/http_core.h (original)
+++ httpd/httpd/branches/2.0.x/include/http_core.h Tue Sep 20 11:14:29 2005
@@ -549,6 +549,14 @@
     /* recursion backstopper */
     int redirect_limit; /* maximum number of internal redirects */
     int subreq_limit;   /* maximum nesting level of subrequests */
+
+    /* TRACE control */
+#define AP_TRACE_UNSET    -1
+#define AP_TRACE_DISABLE   0
+#define AP_TRACE_ENABLE    1
+#define AP_TRACE_EXTENDED  2
+    int trace_enable;
+
 } core_server_config;
 
 /* for AddOutputFiltersByType in core.c */

Modified: httpd/httpd/branches/2.0.x/modules/http/http_protocol.c
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.0.x/modules/http/http_protocol.c?rev=290502&r1=290501&r2=290502&view=diff
==============================================================================
--- httpd/httpd/branches/2.0.x/modules/http/http_protocol.c (original)
+++ httpd/httpd/branches/2.0.x/modules/http/http_protocol.c Tue Sep 20 11:14:29 2005
@@ -1321,6 +1321,9 @@
     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;
 
@@ -1338,8 +1341,9 @@
         }
     }
 
-    /* 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, ',');
 
@@ -1364,9 +1368,16 @@
 
 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;
@@ -1376,23 +1387,87 @@
     while (r->prev) {
         r = r->prev;
     }
+    conf = (core_server_config *)ap_get_module_config(r->server->module_config,
+                                                      &core_module);
 
-    if ((rv = ap_setup_client_block(r, REQUEST_NO_BODY))) {
+    if (conf->trace_enable == AP_TRACE_DISABLE) {
+	apr_table_setn(r->notes, "error-notes",
+                      "TRACE denied by server configuration");
+        return HTTP_FORBIDDEN;
+    }
+
+    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");
+                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");
+            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;
 }

Modified: httpd/httpd/branches/2.0.x/modules/proxy/mod_proxy.c
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.0.x/modules/proxy/mod_proxy.c?rev=290502&r1=290501&r2=290502&view=diff
==============================================================================
--- httpd/httpd/branches/2.0.x/modules/proxy/mod_proxy.c (original)
+++ httpd/httpd/branches/2.0.x/modules/proxy/mod_proxy.c Tue Sep 20 11:14:29 2005
@@ -350,6 +350,42 @@
     apr_table_set(r->headers_in, "Max-Forwards", 
                   apr_psprintf(r->pool, "%ld", (maxfwd > 0) ? maxfwd : 0));
 
+    if (r->method_number == M_TRACE) {
+        core_server_config *coreconf = (core_server_config *)
+                            ap_get_module_config(sconf, &core_module);
+
+        if (coreconf->trace_enable == AP_TRACE_DISABLE) 
+        {
+            /* Allow "error-notes" string to be printed by ap_send_error_response()
+             * Note; this goes nowhere, canned error response need an overhaul.
+             */
+            apr_table_setn(r->notes, "error-notes",
+                           "TRACE forbidden by server configuration");
+            apr_table_setn(r->notes, "verbose-error-to", "*");
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                          "proxy: TRACE forbidden by server configuration");
+            return HTTP_FORBIDDEN;
+        }
+
+        /* 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))
+        {
+            /* Allow "error-notes" string to be printed by ap_send_error_response()
+             * Note; this goes nowhere, canned error response need an overhaul.
+             */
+            apr_table_setn(r->notes, "error-notes",
+                           "TRACE with request body is not allowed");
+            apr_table_setn(r->notes, "verbose-error-to", "*");
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                          "proxy: TRACE with request body is not allowed");
+            return HTTP_REQUEST_ENTITY_TOO_LARGE;
+        }
+    }
+
     url = r->filename + 6;
     p = strchr(url, ':');
     if (p == NULL)

Modified: httpd/httpd/branches/2.0.x/server/core.c
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/2.0.x/server/core.c?rev=290502&r1=290501&r2=290502&view=diff
==============================================================================
--- httpd/httpd/branches/2.0.x/server/core.c (original)
+++ httpd/httpd/branches/2.0.x/server/core.c Tue Sep 20 11:14:29 2005
@@ -458,6 +458,8 @@
     conf->redirect_limit = 0; /* 0 == unset */
     conf->subreq_limit = 0;
 
+    conf->trace_enable = AP_TRACE_UNSET;
+
     return (void *)conf;
 }
 
@@ -489,6 +491,10 @@
                          ? virt->subreq_limit
                          : base->subreq_limit;
 
+    conf->trace_enable = (virt->trace_enable != AP_TRACE_UNSET)
+                         ? virt->trace_enable
+                         : base->trace_enable;
+
     return conf;
 }
 
@@ -1587,7 +1593,7 @@
         methnum = ap_method_number_of(method);
 
         if (methnum == M_TRACE && !tog) {
-            return "TRACE cannot be controlled by <Limit>";
+            return "TRACE cannot be controlled by <Limit>, see TraceEnable";
         }
         else if (methnum == M_INVALID) {
             /* method has not been registered yet, but resorce restriction
@@ -3113,6 +3119,28 @@
     return rv;
 }
 
+static const char *set_trace_enable(cmd_parms *cmd, void *dummy,
+                                    const char *arg1)
+{
+    core_server_config *conf = ap_get_module_config(cmd->server->module_config,
+                                                    &core_module);
+    
+    if (strcasecmp(arg1, "on") == 0) {
+        conf->trace_enable = AP_TRACE_ENABLE;
+    }
+    else if (strcasecmp(arg1, "off") == 0) {
+        conf->trace_enable = AP_TRACE_DISABLE;
+    }
+    else if (strcasecmp(arg1, "extended") == 0) {
+        conf->trace_enable = AP_TRACE_EXTENDED;
+    }
+    else {
+        return "TraceEnable must be one of 'on', 'off', or 'extended'";
+    }
+
+    return NULL;
+}
+
 /* Note --- ErrorDocument will now work from .htaccess files.
  * The AllowOverride of Fileinfo allows webmasters to turn it off
  */
@@ -3338,6 +3366,8 @@
 AP_INIT_TAKE1("EnableExceptionHook", ap_mpm_set_exception_hook, NULL, RSRC_CONF,
               "Controls whether exception hook may be called after a crash"),
 #endif
+AP_INIT_TAKE1("TraceEnable", set_trace_enable, NULL, RSRC_CONF, 
+              "'on' (default), 'off' or 'extended' to trace request body content"),
 { NULL }
 };