Bug 37920

Summary: mod_proxy does not flush data on POST requests from client
Product: Apache httpd-2 Reporter: Marcello Vezzelli <m.vezzelli>
Component: mod_proxyAssignee: Apache HTTPD Bugs Mailing List <bugs>
Status: RESOLVED LATER    
Severity: major CC: ylavic.dev
Priority: P2 Keywords: FixedInTrunk, MassUpdate
Version: 2.2.0   
Target Milestone: ---   
Hardware: PC   
OS: All   

Description Marcello Vezzelli 2005-12-15 17:41:57 UTC
When apache receives POST data from a client and mod_proxy is enabled, apache 
should pass data to mod_proxy without buffering and mod_proxy should pass data 
to backend server without buffering.
This issue was already discussed in 19954 and 33029 concerning GET requests and 
tunnels.
GET requests are working: if backend server responds 1 byte, this byte arrives 
to the client.
How to reproduce:
a client must make a POST request with a large content-size but a single byte 
is sent for the body. This byte will never reach backend server.
Windows binary client that reproduces the problem is available under request.
Comment 1 Marcello Vezzelli 2005-12-16 12:31:27 UTC
I can't get POST data even with nph-cgi.... could it be an apache core issue?
Comment 2 rahul 2007-02-09 08:11:09 UTC
The behavior is due to the following logic in mod_proxy_http.c
We read the data using ap_get_bridade, 
Now ap_get_brigade will return an EOS only if the remaining data 
( as calculated as content-length - current read in 
http_filters.c:ap_http_filter: [ lenp = apr_table_get(f->r->headers_in, 
"Content-Length");] )
is '0'

Since our condition for exiting the while loop is APR_BUCKET_IS_EOS, we do not 
exit before reading the entire data as specified in content length. Since we do 
not write the data to the client side any where in this loop, the client never 
gets any data.

The way to fix this would be to move up the part where we send the 
stream_reqbody_cl, and change it to keep sending the data to client side during 
the loop. 


--846 - 898
    /* Prefetch MAX_MEM_SPOOL bytes
     *
     * This helps us avoid any election of C-L v.s. T-E
     * request bodies, since we are willing to keep in
     * memory this much data, in any case.  This gives
     * us an instant C-L election if the body is of some
     * reasonable size.
     */
    temp_brigade = apr_brigade_create(p, bucket_alloc);
    do {
        status = ap_get_brigade(r->input_filters, temp_brigade,
                                AP_MODE_READBYTES, APR_BLOCK_READ,
                                MAX_MEM_SPOOL - bytes_read);
        if (status != APR_SUCCESS) {
            ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
                         "proxy: prefetch 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;
        }

        apr_brigade_length(temp_brigade, 1, &bytes);
        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
     * (an arbitrary value.)
     */
    } while ((bytes_read < MAX_MEM_SPOOL - 80)
              && !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)));

    /* Use chunked request body encoding or send a content-length body?
Comment 3 Ruediger Pluem 2007-02-09 13:39:21 UTC
As far as I can remember the whole request body needs to be buffered to avoid
HTTP Request Smuggling (see
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2005-2088). So if I remember
correctly this cannot be changed to a "non-buffering" behaviour.
Comment 4 Joe Orton 2007-02-27 09:25:44 UTC
The buffering is just an optimisation to  avoid the cases where the proxy
decides it is a good idea to send chunked request bodies, there is no security
requirement to do so.
Comment 5 Andre W. 2014-06-04 14:01:45 UTC
Hello,

currently we are running into some problems with this behaviour, because  we have long response times, within the first request by transmitting audio data.

To get more in detail, we are trying to send small voice packages over the apache to a backend system where we want to analyse the audio data (audio recognition). In this case we are sending audio data as transfer-encoding chunked, ~3,6KBps HTTP requests, based on normally 1024bytes sized packages.

Which leads to an delay of 4-5 seconds until the request gets proxied to the backend.

From my point of view it would be good to have an parameter, which we would be able to configure the size of the data, which will be pooled/buffered so that we would be able to resize it.

In my suggestion that could be an overall server parameter or something bind on the balancermember or proxypass directive e.g. maxmempoolssize=bytes; 

Best regards,
André
Comment 6 Yann Ylavic 2014-06-06 06:39:51 UTC
Andre, can you try the patches (trunk/2.4.x/2.2.x) available in Bug 56541?
By using "SetEnv proxy-flushall", you can bypass the request body prefetch.
Comment 7 Andre W. 2014-11-21 09:26:28 UTC
Hello Yann,

Sorry for the late response, i just recognized last week that already somebody anwsered with a patch.

I tried the patches you attached and they seem to work for me, if i set the flag the requests will be directly proxied to the backend and so I have less delay for the data.

Is there any ability to bring that patch into the standard branch so that I'm able to upgrade easily in future? 

Best regards,
André
Comment 8 Andre W. 2014-11-21 09:27:27 UTC
Missed that i tried the patch only for 2.4.10, because we are currently using the latest release in this use case.

Cheers,
André
Comment 9 Yann Ylavic 2015-02-01 00:51:57 UTC
Patch from bug 56541 committed in r1656259 (trunk).
Comment 10 Rainer Jung 2018-02-25 20:41:04 UTC
Undo spam change
Comment 11 William A. Rowe Jr. 2018-11-07 21:09:48 UTC
Please help us to refine our list of open and current defects; this is a mass update of old and inactive Bugzilla reports which reflect user error, already resolved defects, and still-existing defects in httpd.

As repeatedly announced, the Apache HTTP Server Project has discontinued all development and patch review of the 2.2.x series of releases. The final release 2.2.34 was published in July 2017, and no further evaluation of bug reports or security risks will be considered or published for 2.2.x releases. All reports older than 2.4.x have been updated to status RESOLVED/LATER; no further action is expected unless the report still applies to a current version of httpd.

If your report represented a question or confusion about how to use an httpd feature, an unexpected server behavior, problems building or installing httpd, or working with an external component (a third party module, browser etc.) we ask you to start by bringing your question to the User Support and Discussion mailing list, see [https://httpd.apache.org/lists.html#http-users] for details. Include a link to this Bugzilla report for completeness with your question.

If your report was clearly a defect in httpd or a feature request, we ask that you retest using a modern httpd release (2.4.33 or later) released in the past year. If it can be reproduced, please reopen this bug and change the Version field above to the httpd version you have reconfirmed with.

Your help in identifying defects or enhancements still applicable to the current httpd server software release is greatly appreciated.