Commit 69ad0f6f authored by Joe Orton's avatar Joe Orton
Browse files

* modules/proxy/proxy_http.c (ap_proxy_http_process_response): Use the

standard non-blocking-read/flush/blocking-read logic to ensure that
buffered content is flushed to the client if the next read will block.

PR: 19954


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@105751 13f79535-47bb-0310-9956-ffa450edef68
parent 91d26827
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -2,6 +2,10 @@ Changes with Apache 2.1.0-dev
  [Remove entries to the current 2.0 section below, when backported]
  *) mod_proxy_http: Stream content better - always flush buffered data to
     the client before blocking waiting for new data.  PR 19954.
     [Joe Orton]
  *) mod_ssl: Add support for command-line option "-t -DDUMP_CERTS" which
     will dump the filenames of all configured SSL certificates to stdout.
     [Joe Orton]
+33 −11
Original line number Diff line number Diff line
@@ -1022,15 +1022,41 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
             * of the page into the brigade
             */
            if (conf->error_override == 0 || ap_is_HTTP_SUCCESS(r->status)) {

                /* read the body, pass it to the output filters */
                apr_read_type_e mode = APR_NONBLOCK_READ;
                int finish = FALSE;
                while (ap_get_brigade(rp->input_filters, 
                                      bb, 
                                      AP_MODE_READBYTES, 
                                      APR_BLOCK_READ, 
                                      conf->io_buffer_size) == APR_SUCCESS) {

                do {
                    apr_off_t readbytes;
                    apr_status_t rv;

                    rv = ap_get_brigade(rp->input_filters, bb, 
                                        AP_MODE_READBYTES, mode,
                                        conf->io_buffer_size);

                    /* ap_get_brigade will return success with an empty brigade
                     * for a non-blocking read which would block: */
                    if (APR_STATUS_IS_EAGAIN(rv)
                        || (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))) {
                        /* flush to the client and switch to blocking mode */
                        e = apr_bucket_flush_create(c->bucket_alloc);
                        APR_BRIGADE_INSERT_TAIL(bb, e);
                        if (ap_pass_brigade(r->output_filters, bb)) {
                            backend->close = 1;
                            break;
                        }
                        apr_brigade_cleanup(bb);
                        mode = APR_BLOCK_READ;
                        continue;
                    }
                    else if (rv != APR_SUCCESS) {
                        ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c,
                                      "proxy: error reading response");
                        break;
                    }
                    /* next time try a non-blocking read */
                    mode = APR_NONBLOCK_READ;
                    
                    apr_brigade_length(bb, 0, &readbytes);
                    backend->worker->s->readed += readbytes;
#if DEBUGGING
@@ -1068,11 +1094,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
                    /* make sure we always clean up after ourselves */
                    apr_brigade_cleanup(bb);

                    /* if we are done, leave */
                    if (TRUE == finish) {
                        break;
                    }
                }
                } while (!finish);
            }
            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                         "proxy: end body send");