]> granicus.if.org Git - apache/commitdiff
Plug AllowTrace extended|on|off into proxy and http core.
authorWilliam A. Rowe Jr <wrowe@apache.org>
Fri, 1 Jul 2005 19:59:59 +0000 (19:59 +0000)
committerWilliam A. Rowe Jr <wrowe@apache.org>
Fri, 1 Jul 2005 19:59:59 +0000 (19:59 +0000)
  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
modules/http/http_protocol.c
modules/proxy/mod_proxy.c

index 0b28d0a7033f8e4ec67142573d7283a5ef1b776b..7d354ae5c94c21e5c17cb0b993b773640348a1e2 100644 (file)
@@ -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.
index d4b0429f52dd4c46e93817290706675794a6087c..1ee501aea98716f2666d1bce53604938fcd4b3d5 100644 (file)
@@ -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, ',');
 
index 7f09042957f4b903d03ab6addbdd20539dc91179..4ac61ccc816899842c915f12259698555bad89f9 100644 (file)
@@ -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);