Commit e0580534 authored by William A. Rowe Jr's avatar William A. Rowe Jr
Browse files

  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


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.0.x@290502 13f79535-47bb-0310-9956-ffa450edef68
parent 055c18ec
Loading
Loading
Loading
Loading
+6 −0
Changes for CHANGES: 6 added lines, 0 removed lines.
Original line number Diff line number Diff line
                                                         -*- 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]
+0 −12
Changes for STATUS: 0 added lines, 12 removed lines.
Original line number Diff line number Diff line
@@ -211,18 +211,6 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK:
       +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
+2 −1
Changes for include/ap_mmn.h: 2 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -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
+8 −0
Changes for include/http_core.h: 8 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -549,6 +549,14 @@ typedef struct {
    /* 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 */
+83 −8
Changes for modules/http/http_protocol.c: 83 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -1321,6 +1321,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;

@@ -1338,7 +1341,8 @@ static char *make_allow(request_rec *r)
        }
    }

    /* TRACE is always allowed */
    /* 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 @@ static char *make_allow(request_rec *r)

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 @@ 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");
                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;
}
Loading