Commit 7db37186 authored by Yann Ylavic's avatar Yann Ylavic
Browse files

mod_proxy_http: common function for stream_reqbody_{cl,chunked}()

Since stream_reqbody_cl() and stream_reqbody_chunked}() now have the same
structure, join them into a single stream_reqbody() function which is passed
the rb_method to handle only CL vs chunked cases differently.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1853953 13f79535-47bb-0310-9956-ffa450edef68
parent 8546789d
Loading
Loading
Loading
Loading
+51 −114
Original line number Diff line number Diff line
@@ -303,17 +303,17 @@ static int stream_reqbody_read(proxy_http_req_t *req, apr_bucket_brigade *bb,
    return OK;
}

static int stream_reqbody_chunked(proxy_http_req_t *req)
static int stream_reqbody(proxy_http_req_t *req, rb_methods rb_method)
{
    request_rec *r = req->r;
    int seen_eos = 0, rv = OK;
    apr_size_t hdr_len;
    apr_off_t bytes;
    char chunk_hdr[20];  /* must be here due to transient bucket. */
    proxy_conn_rec *p_conn = req->backend;
    apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc;
    apr_bucket_brigade *header_brigade = req->header_brigade;
    apr_bucket_brigade *input_brigade = req->input_brigade;
    apr_off_t bytes, bytes_streamed = 0;
    apr_bucket *e;

    do {
@@ -336,6 +336,9 @@ static int stream_reqbody_chunked(proxy_http_req_t *req)
            }

            apr_brigade_length(input_brigade, 1, &bytes);
            bytes_streamed += bytes;

            if (rb_method == RB_STREAM_CHUNKED) {
                if (bytes) {
                    /*
                     * Prepend the size of the chunk
@@ -354,7 +357,6 @@ static int stream_reqbody_chunked(proxy_http_req_t *req)
                    e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc);
                    APR_BRIGADE_INSERT_TAIL(input_brigade, e);
                }

                if (seen_eos) {
                    /*
                     * Append the tailing 0-size chunk
@@ -364,70 +366,9 @@ static int stream_reqbody_chunked(proxy_http_req_t *req)
                                                   CRLF_ASCII,
                                                   5, bucket_alloc);
                    APR_BRIGADE_INSERT_TAIL(input_brigade, e);

                if (apr_table_get(r->subprocess_env, "proxy-sendextracrlf")) {
                    e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc);
                    APR_BRIGADE_INSERT_TAIL(input_brigade, e);
                }
            }
        }

        /* If we never sent the header brigade, so go ahead and
         * take care of that now by prepending it.
         */
        APR_BRIGADE_PREPEND(input_brigade, header_brigade);

        /* Flush here on EOS because we won't stream_reqbody_read() again */
        rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, req->origin,
                                   input_brigade, seen_eos);
        if (rv != OK) {
            return rv;
        }
    } while (!seen_eos);

    return OK;
}

static int stream_reqbody_cl(proxy_http_req_t *req)
{
    request_rec *r = req->r;
    int seen_eos = 0, rv = OK;
    proxy_conn_rec *p_conn = req->backend;
    apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc;
    apr_bucket_brigade *header_brigade = req->header_brigade;
    apr_bucket_brigade *input_brigade = req->input_brigade;
    apr_bucket *e;
    apr_off_t bytes;
    apr_off_t bytes_streamed = 0;

    do {
        if (APR_BRIGADE_EMPTY(input_brigade)
                && APR_BRIGADE_EMPTY(header_brigade)) {
            rv = stream_reqbody_read(req, input_brigade, 1);
            if (rv != OK) {
                return rv;
            }
        }

        if (!APR_BRIGADE_EMPTY(input_brigade)) {
            apr_brigade_length(input_brigade, 1, &bytes);
            bytes_streamed += bytes;

            /* If this brigade contains EOS, either stop or remove it. */
            if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
                seen_eos = 1;

                /* We can't pass this EOS to the output_filters. */
                e = APR_BRIGADE_LAST(input_brigade);
                apr_bucket_delete(e);

                if (apr_table_get(r->subprocess_env, "proxy-sendextracrlf")) {
                    e = apr_bucket_immortal_create(CRLF_ASCII, 2,
                                                   bucket_alloc);
                    APR_BRIGADE_INSERT_TAIL(input_brigade, e);
                }
            }

            else if (bytes_streamed > req->cl_val) {
                /* C-L < bytes streamed?!?
                 * We will error out after the body is completely
                 * consumed, but we can't stream more bytes at the
@@ -437,18 +378,25 @@ static int stream_reqbody_cl(proxy_http_req_t *req)
                 *
                 * Prevents HTTP Response Splitting.
                 */
            if (bytes_streamed > req->cl_val) {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01086)
                              "read more bytes of request body than expected "
                              "(got %" APR_OFF_T_FMT ", expected "
                              "%" APR_OFF_T_FMT ")",
                              bytes_streamed, req->cl_val);
                /* XXX: probably more a HTTP_BAD_REQUEST (like below) */
                return HTTP_INTERNAL_SERVER_ERROR;
            }

            if (seen_eos && apr_table_get(r->subprocess_env,
                                          "proxy-sendextracrlf")) {
                e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc);
                APR_BRIGADE_INSERT_TAIL(input_brigade, e);
            }
        }

        /* If we never sent the header brigade, so go ahead and
         * take care of that now by prepending it.
        /* If we never sent the header brigade, go ahead and take care of
         * that now by prepending it (once only since header_brigade will be
         * empty afterward).
         */
        APR_BRIGADE_PREPEND(input_brigade, header_brigade);

@@ -460,7 +408,7 @@ static int stream_reqbody_cl(proxy_http_req_t *req)
        }
    } while (!seen_eos);

    if (bytes_streamed != req->cl_val) {
    if (rb_method == RB_STREAM_CL && bytes_streamed != req->cl_val) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01087)
                      "client %s given Content-Length did not match"
                      " number of body bytes read", r->connection->client_ip);
@@ -888,23 +836,14 @@ static int ap_proxy_http_request(proxy_http_req_t *req)

    /* send the request header/body, if any. */
    switch (req->rb_method) {
    case RB_STREAM_CHUNKED:
        if (req->do_100_continue) {
            rv = ap_proxy_pass_brigade(bucket_alloc, r, req->backend,
                                       req->origin, header_brigade, 1);
        }
        else {
            rv = stream_reqbody_chunked(req);
        }
        break;

    case RB_STREAM_CL:
    case RB_STREAM_CHUNKED:
        if (req->do_100_continue) {
            rv = ap_proxy_pass_brigade(bucket_alloc, r, req->backend,
                                       req->origin, header_brigade, 1);
        }
        else {
            rv = stream_reqbody_cl(req);
            rv = stream_reqbody(req, req->rb_method);
        }
        break;

@@ -1623,10 +1562,8 @@ int ap_proxy_http_process_response(proxy_http_req_t *req)
                /* Send the request body (fully). */
                switch(req->rb_method) {
                case RB_STREAM_CL:
                    status = stream_reqbody_cl(req);
                    break;
                case RB_STREAM_CHUNKED:
                    status = stream_reqbody_chunked(req);
                    status = stream_reqbody(req, req->rb_method);
                    break;
                case RB_SPOOL_CL:
                    /* Prefetch has spooled the whole body, flush it. */