Commit d69e69b5 authored by Ruediger Pluem's avatar Ruediger Pluem
Browse files

* Fix PR37145 (data loss with httpd-2.0.55 reverse proxy method=post) by

  exchanging APR_BRIGADE_CONCAT with ap_save_brigade to ensure that
  transient buckets get setaside correctly between various iterations of
  ap_get_brigade calls.

Reviewed by: Joe Orton, William Rowe, Jim Jagielski, Jeff Trawick


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@327590 13f79535-47bb-0310-9956-ffa450edef68
parent 224d92bc
Loading
Loading
Loading
Loading
+4 −0
Changes for CHANGES: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -27,6 +27,10 @@ Changes with Apache 2.3.0
Changes with Apache 2.1.9
  *) mod_proxy_http: Prevent data corruption of POST request bodies when
     client accesses proxied resources with SSL. PR37145.
     [Ruediger Pluem, William Rowe]
  *) mod_proxy_balancer: BalancerManager and proxies correctly handle
     member workers with paths. PR36816. [Ruediger Pluem, Jim Jagielski]
+64 −4
Changes for modules/proxy/mod_proxy_http.c: 64 added lines, 4 removed lines.
Original line number Diff line number Diff line
@@ -247,7 +247,21 @@ static apr_status_t stream_reqbody_chunked(apr_pool_t *p,
             * take care of that now
             */
            bb = header_brigade;
            APR_BRIGADE_CONCAT(bb, input_brigade);

            /*
             * Save input_brigade in bb brigade. (At least) in the SSL case
             * input_brigade contains transient buckets whose data would get
             * overwritten during the next call of ap_get_brigade in the loop.
             * ap_save_brigade ensures these buckets to be set aside.
             * Calling ap_save_brigade with NULL as filter is OK, because
             * bb brigade already has been created and does not need to get
             * created by ap_save_brigade.
             */
            status = ap_save_brigade(NULL, &bb, &input_brigade, p);
            if (status != APR_SUCCESS) {
                return status;
            }

            header_brigade = NULL;
        }
        else {
@@ -354,7 +368,21 @@ static apr_status_t stream_reqbody_cl(apr_pool_t *p,
             * take care of that now
             */
            bb = header_brigade;
            APR_BRIGADE_CONCAT(bb, input_brigade);

            /*
             * Save input_brigade in bb brigade. (At least) in the SSL case
             * input_brigade contains transient buckets whose data would get
             * overwritten during the next call of ap_get_brigade in the loop.
             * ap_save_brigade ensures these buckets to be set aside.
             * Calling ap_save_brigade with NULL as filter is OK, because
             * bb brigade already has been created and does not need to get
             * created by ap_save_brigade.
             */
            status = ap_save_brigade(NULL, &bb, &input_brigade, p);
            if (status != APR_SUCCESS) {
                return status;
            }

            header_brigade = NULL;
        }
        else {
@@ -476,7 +504,21 @@ static apr_status_t spool_reqbody_cl(apr_pool_t *p,
            apr_brigade_cleanup(input_brigade);
        }
        else {
            APR_BRIGADE_CONCAT(body_brigade, input_brigade);

            /*
             * Save input_brigade in body_brigade. (At least) in the SSL case
             * input_brigade contains transient buckets whose data would get
             * overwritten during the next call of ap_get_brigade in the loop.
             * ap_save_brigade ensures these buckets to be set aside.
             * Calling ap_save_brigade with NULL as filter is OK, because
             * body_brigade already has been created and does not need to get
             * created by ap_save_brigade.
             */
            status = ap_save_brigade(NULL, &body_brigade, &input_brigade, p);
            if (status != APR_SUCCESS) {
                return status;
            }

        }
        
        bytes_spooled += bytes;
@@ -832,9 +874,27 @@ apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
        }

        apr_brigade_length(temp_brigade, 1, &bytes);
        APR_BRIGADE_CONCAT(input_brigade, temp_brigade);
        bytes_read += bytes;

        /*
         * Save temp_brigade in input_brigade. (At least) in the SSL case
         * temp_brigade contains transient buckets whose data would get
         * overwritten during the next call of ap_get_brigade in the loop.
         * ap_save_brigade ensures these buckets to be set aside.
         * Calling ap_save_brigade with NULL as filter is OK, because
         * input_brigade already has been created and does not need to get
         * created by ap_save_brigade.
         */
        status = ap_save_brigade(NULL, &input_brigade, &temp_brigade, p);
        if (status != APR_SUCCESS) {
            ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
                         "proxy: processing prefetched request body failed"
                         " to %pI (%s) from %s (%s)",
                         p_conn->addr, p_conn->hostname ? p_conn->hostname: "",
                         c->remote_ip, c->remote_host ? c->remote_host: "");
            return status;
        }

    /* Ensure we don't hit a wall where we have a buffer too small
     * for ap_get_brigade's filters to fetch us another bucket,
     * surrender once we hit 80 bytes less than MAX_MEM_SPOOL