Commit a52be86f authored by Roy T. Fielding's avatar Roy T. Fielding
Browse files

In HTTP/1.1, whether or not a request message contains a body

is independent of the request method and based solely on the presence
of a Content-Length or Transfer-Encoding.  Therefore, our default
handlers need to be prepared to read a body even if they don't know
what to do with it; otherwise, the body would be mistaken for the
next request on a persistent connection.  discard_request_body()
has been added to take care of that.

PR: 378
Reviewed by: Dean Gaudet


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3@78677 13f79535-47bb-0310-9956-ffa450edef68
parent 998dc519
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
Changes with Apache 1.2.2

  *) API: In HTTP/1.1, whether or not a request message contains a body
     is independent of the request method and based solely on the presence
     of a Content-Length or Transfer-Encoding.  Therefore, our default
     handlers need to be prepared to read a body even if they don't know
     what to do with it; otherwise, the body would be mistaken for the
     next request on a persistent connection.  discard_request_body()
     has been added to take care of that.  [Roy Fielding] PR#378

  *) API: Symbol APACHE_RELEASE provides a numeric form of the Apache
     release version number, such that it always increases along the
     same lines as our source code branching.  [Roy Fielding]
+1 −0
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@ int index_of_response (int status);
int setup_client_block (request_rec *r, int read_policy);
int should_client_block (request_rec *r);
long get_client_block (request_rec *r, char *buffer, int bufsiz);
int discard_request_body (request_rec *r);

/* Sending a byterange */

+7 −2
Original line number Diff line number Diff line
@@ -1325,8 +1325,13 @@ int default_handler (request_rec *r)
    int rangestatus, errstatus;
    FILE *f;

    /* This handler has no use for a request body (yet), but we still
     * need to read and discard it if the client sent one.
     */
    if ((errstatus = discard_request_body(r)) != OK)
        return errstatus;

    r->allowed |= (1 << M_GET);
    r->allowed |= (1 << M_TRACE);
    r->allowed |= (1 << M_OPTIONS);

    if (r->method_number == M_INVALID) {
+53 −19
Original line number Diff line number Diff line
@@ -1087,34 +1087,31 @@ static void terminate_header (BUFF *client)
    bputs("\015\012", client);    /* Send the terminating empty line */
}

/* Build the Allow field-value from the request handler method mask.
 * Note that we always allow TRACE, since it is handled below.
 */
static char *make_allow(request_rec *r)
{
    int allowed = r->allowed;

    if( allowed == 0 ) {
	/* RFC2068 #14.7, Allow must contain at least one method.  So rather
	 * than deal with the possibility of trying not to emit an Allow:
	 * header, i.e. #10.4.6 says 405 Method Not Allowed MUST include
	 * an Allow header, we'll just say TRACE is valid.
	 */
	return( "TRACE" );
    }

    return 2 + pstrcat(r->pool, (allowed & (1 << M_GET)) ? ", GET, HEAD" : "",
		       (allowed & (1 << M_POST)) ? ", POST" : "",
		       (allowed & (1 << M_PUT)) ? ", PUT" : "",
		       (allowed & (1 << M_DELETE)) ? ", DELETE" : "",
		       (allowed & (1 << M_OPTIONS)) ? ", OPTIONS" : "",
		       (allowed & (1 << M_TRACE)) ? ", TRACE" : "",
    return 2 + pstrcat(r->pool,
                       (r->allowed & (1 << M_GET)) ? ", GET, HEAD" : "",
                       (r->allowed & (1 << M_POST)) ? ", POST" : "",
                       (r->allowed & (1 << M_PUT)) ? ", PUT" : "",
                       (r->allowed & (1 << M_DELETE)) ? ", DELETE" : "",
                       (r->allowed & (1 << M_OPTIONS)) ? ", OPTIONS" : "",
                       ", TRACE",
                       NULL);
    
}

int send_http_trace (request_rec *r)
{
    int rv;

    /* Get the original request */
    while (r->prev) r = r->prev;

    if ((rv = setup_client_block(r, REQUEST_NO_BODY)))
        return rv;

    hard_timeout("send TRACE", r);

    r->content_type = "message/http";
@@ -1514,6 +1511,43 @@ long get_client_block (request_rec *r, char *buffer, int bufsiz)
    return (chunk_start + len_read);
}

/* In HTTP/1.1, any method can have a body.  However, most GET handlers
 * wouldn't know what to do with a request body if they received one.
 * This helper routine tests for and reads any message body in the request,
 * simply discarding whatever it receives.  We need to do this because
 * failing to read the request body would cause it to be interpreted
 * as the next request on a persistent connection.  
 *
 * Since we return an error status if the request is malformed, this
 * routine should be called at the beginning of a no-body handler, e.g.,
 *
 *    if ((retval = discard_request_body(r)) != OK)
 *        return retval;
 */
int discard_request_body(request_rec *r)
{
    int rv;

    if ((rv = setup_client_block(r, REQUEST_CHUNKED_PASS)))
        return rv;

    if (should_client_block(r)) {
        char dumpbuf[HUGE_STRING_LEN];

        hard_timeout("reading request body", r);
        while ((rv = get_client_block(r, dumpbuf, HUGE_STRING_LEN)) > 0)
            continue;
        kill_timeout(r);

        if (rv < 0)
            return HTTP_BAD_REQUEST;
    }
    return OK;
}

/*
 * Send the body of a response to the client.
 */
long send_fd(FILE *f, request_rec *r) { return send_fd_length(f, r, -1); }

long send_fd_length(FILE *f, request_rec *r, long length)
+4 −2
Original line number Diff line number Diff line
@@ -910,7 +910,9 @@ void process_request_internal (request_rec *r)
         * we handle it specially.
         */
        if (r->method_number == M_TRACE) {
            send_http_trace(r);
            if ((access_status = send_http_trace(r)))
	        die(access_status, r);
            else
                finalize_request_protocol(r);
            return;
        }