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

  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
parent ee854961
Loading
Loading
Loading
Loading
+79 −7
Changes for modules/http/http_filters.c: 79 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -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.
+5 −1
Changes for modules/http/http_protocol.c: 5 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -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,7 +774,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, ',');
+16 −0
Changes for modules/proxy/mod_proxy.c: 16 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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);