You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2016/02/25 09:59:36 UTC

svn commit: r1732266 - in /httpd/httpd/branches/2.4.x: include/ap_mmn.h modules/proxy/mod_proxy.h modules/proxy/mod_proxy_connect.c modules/proxy/mod_proxy_http.c modules/proxy/mod_proxy_wstunnel.c modules/proxy/proxy_util.c

Author: icing
Date: Thu Feb 25 08:59:36 2016
New Revision: 1732266

URL: http://svn.apache.org/viewvc?rev=1732266&view=rev
Log:
mod_proxy_wstunnel, mod_proxy_connect: Use the correct pool and allocator
     lifetime when sending brigades and buckets down the filter chain

Modified:
    httpd/httpd/branches/2.4.x/include/ap_mmn.h
    httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.h
    httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_connect.c
    httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_http.c
    httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_wstunnel.c
    httpd/httpd/branches/2.4.x/modules/proxy/proxy_util.c

Modified: httpd/httpd/branches/2.4.x/include/ap_mmn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/include/ap_mmn.h?rev=1732266&r1=1732265&r2=1732266&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/include/ap_mmn.h (original)
+++ httpd/httpd/branches/2.4.x/include/ap_mmn.h Thu Feb 25 08:59:36 2016
@@ -458,6 +458,9 @@
  *                          Added ap_parse_token_list_strict() to httpd.h
  * 20120211.52 (2.4.17-dev) Add master conn_rec* member in conn_rec.
  * 20120211.53 (2.4.19-dev) Add epxr_hander to core_dir_config.
+ * 20120211.54 (2.4.19-dev) Add ap_proxy_buckets_lifetime_transform and
+ *                          ap_proxy_transfer_between_connections to
+ *                          mod_proxy.h
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
@@ -465,7 +468,7 @@
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20120211
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 53                   /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 54                   /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a

Modified: httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.h?rev=1732266&r1=1732265&r2=1732266&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.h (original)
+++ httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.h Thu Feb 25 08:59:36 2016
@@ -1042,6 +1042,62 @@ PROXY_DECLARE(apr_port_t) ap_proxy_port_
  */
 PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url);
 
+/*
+ * Transform buckets from one bucket allocator to another one by creating a
+ * transient bucket for each data bucket and let it use the data read from
+ * the old bucket. Metabuckets are transformed by just recreating them.
+ * Attention: Currently only the following bucket types are handled:
+ *
+ * All data buckets
+ * FLUSH
+ * EOS
+ *
+ * If an other bucket type is found its type is logged as a debug message
+ * and APR_EGENERAL is returned.
+ *
+ * @param r     request_rec of the actual request. Used for logging purposes
+ * @param from  the bucket brigade to take the buckets from
+ * @param to    the bucket brigade to store the transformed buckets
+ * @return      apr_status_t of the operation. Either APR_SUCCESS or
+ *              APR_EGENERAL
+ */
+PROXY_DECLARE(apr_status_t) ap_proxy_buckets_lifetime_transform(request_rec *r,
+                                                      apr_bucket_brigade *from,
+                                                      apr_bucket_brigade *to);
+
+/*
+ * Sends all data that can be read non blocking from the input filter chain of
+ * c_i and send it down the output filter chain of c_o. For reading it uses
+ * the bucket brigade bb_i which should be created from the bucket allocator
+ * associated with c_i. For sending through the output filter chain it uses
+ * the bucket brigade bb_o which should be created from the bucket allocator
+ * associated with c_o. In order to get the buckets from bb_i to bb_o
+ * ap_proxy_buckets_lifetime_transform is used.
+ *
+ * @param r     request_rec of the actual request. Used for logging purposes
+ * @param c_i   inbound connection conn_rec
+ * @param c_o   outbound connection conn_rec
+ * @param bb_i  bucket brigade for pulling data from the inbound connection
+ * @param bb_o  bucket brigade for sending data through the outbound connection
+ * @param name  string for logging from where data was pulled
+ * @param sent  if not NULL will be set to 1 if data was sent through c_o
+ * @param bsize maximum amount of data pulled in one iteration from c_i
+ * @param after if set flush data on c_o only once after the loop
+ * @return      apr_status_t of the operation. Could be any error returned from
+ *              either the input filter chain of c_i or the output filter chain
+ *              of c_o. APR_EPIPE if the outgoing connection was aborted.
+ */
+PROXY_DECLARE(apr_status_t) ap_proxy_transfer_between_connections(
+                                                       request_rec *r,
+                                                       conn_rec *c_i,
+                                                       conn_rec *c_o,
+                                                       apr_bucket_brigade *bb_i,
+                                                       apr_bucket_brigade *bb_o,
+                                                       const char *name,
+                                                       int *sent,
+                                                       apr_off_t bsize,
+                                                       int after);
+
 extern module PROXY_DECLARE_DATA proxy_module;
 
 #endif /*MOD_PROXY_H*/

Modified: httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_connect.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_connect.c?rev=1732266&r1=1732265&r2=1732266&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_connect.c (original)
+++ httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_connect.c Thu Feb 25 08:59:36 2016
@@ -143,53 +143,6 @@ static int proxy_connect_canon(request_r
     return OK;
 }
 
-/* read available data (in blocks of CONN_BLKSZ) from c_i and copy to c_o */
-static int proxy_connect_transfer(request_rec *r, conn_rec *c_i, conn_rec *c_o,
-                                  apr_bucket_brigade *bb, char *name)
-{
-    int rv;
-#ifdef DEBUGGING
-    apr_off_t len;
-#endif
-
-    do {
-        apr_brigade_cleanup(bb);
-        rv = ap_get_brigade(c_i->input_filters, bb, AP_MODE_READBYTES,
-                            APR_NONBLOCK_READ, CONN_BLKSZ);
-        if (rv == APR_SUCCESS) {
-            if (c_o->aborted)
-                return APR_EPIPE;
-            if (APR_BRIGADE_EMPTY(bb))
-                break;
-#ifdef DEBUGGING
-            len = -1;
-            apr_brigade_length(bb, 0, &len);
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01016)
-                          "read %" APR_OFF_T_FMT
-                          " bytes from %s", len, name);
-#endif
-            rv = ap_pass_brigade(c_o->output_filters, bb);
-            if (rv == APR_SUCCESS) {
-                ap_fflush(c_o->output_filters, bb);
-            }
-            else {
-                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01017)
-                              "error on %s - ap_pass_brigade",
-                              name);
-            }
-        } else if (!APR_STATUS_IS_EAGAIN(rv)) {
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(01018)
-                          "error on %s - ap_get_brigade",
-                          name);
-        }
-    } while (rv == APR_SUCCESS);
-
-    if (APR_STATUS_IS_EAGAIN(rv)) {
-        rv = APR_SUCCESS;
-    }
-    return rv;
-}
-
 /* CONNECT handler */
 static int proxy_connect_handler(request_rec *r, proxy_worker *worker,
                                  proxy_server_conf *conf,
@@ -205,7 +158,8 @@ static int proxy_connect_handler(request
     conn_rec *backconn;
     int done = 0;
 
-    apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc);
+    apr_bucket_brigade *bb_front = apr_brigade_create(p, c->bucket_alloc);
+    apr_bucket_brigade *bb_back;
     apr_status_t rv;
     apr_size_t nbytes;
     char buffer[HUGE_STRING_LEN];
@@ -360,6 +314,9 @@ static int proxy_connect_handler(request
     apr_table_setn(r->notes, "proxy-source-port", apr_psprintf(r->pool, "%hu",
                    backconn->local_addr->port));
 
+
+    bb_back = apr_brigade_create(p, backconn->bucket_alloc);
+
     /* If we are connecting through a remote proxy, we need to pass
      * the CONNECT request on to it.
      */
@@ -368,24 +325,24 @@ static int proxy_connect_handler(request
      */
         ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
                       "sending the CONNECT request to the remote proxy");
-        ap_fprintf(backconn->output_filters, bb,
+        ap_fprintf(backconn->output_filters, bb_back,
                    "CONNECT %s HTTP/1.0" CRLF, r->uri);
-        ap_fprintf(backconn->output_filters, bb,
+        ap_fprintf(backconn->output_filters, bb_back,
                    "Proxy-agent: %s" CRLF CRLF, ap_get_server_banner());
-        ap_fflush(backconn->output_filters, bb);
+        ap_fflush(backconn->output_filters, bb_back);
     }
     else {
         ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "Returning 200 OK");
         nbytes = apr_snprintf(buffer, sizeof(buffer),
                               "HTTP/1.0 200 Connection Established" CRLF);
         ap_xlate_proto_to_ascii(buffer, nbytes);
-        ap_fwrite(c->output_filters, bb, buffer, nbytes);
+        ap_fwrite(c->output_filters, bb_front, buffer, nbytes);
         nbytes = apr_snprintf(buffer, sizeof(buffer),
                               "Proxy-agent: %s" CRLF CRLF,
                               ap_get_server_banner());
         ap_xlate_proto_to_ascii(buffer, nbytes);
-        ap_fwrite(c->output_filters, bb, buffer, nbytes);
-        ap_fflush(c->output_filters, bb);
+        ap_fwrite(c->output_filters, bb_front, buffer, nbytes);
+        ap_fflush(c->output_filters, bb_front);
 #if 0
         /* This is safer code, but it doesn't work yet.  I'm leaving it
          * here so that I can fix it later.
@@ -439,8 +396,12 @@ static int proxy_connect_handler(request
                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01025)
                                   "sock was readable");
 #endif
-                    done |= proxy_connect_transfer(r, backconn, c, bb,
-                                                   "sock") != APR_SUCCESS;
+                    done |= ap_proxy_transfer_between_connections(r, backconn,
+                                                                  c, bb_back,
+                                                                  bb_front,
+                                                                  "sock", NULL,
+                                                                  CONN_BLKSZ, 1)
+                                                                 != APR_SUCCESS;
                 }
                 else if (pollevent & APR_POLLERR) {
                     ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(01026)
@@ -456,8 +417,14 @@ static int proxy_connect_handler(request
                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01027)
                                   "client was readable");
 #endif
-                    done |= proxy_connect_transfer(r, c, backconn, bb,
-                                                   "client") != APR_SUCCESS;
+                    done |= ap_proxy_transfer_between_connections(r, c,
+                                                                  backconn,
+                                                                  bb_front,
+                                                                  bb_back,
+                                                                  "client",
+                                                                  NULL,
+                                                                  CONN_BLKSZ, 1)
+                                                                 != APR_SUCCESS;
                 }
                 else if (pollevent & APR_POLLERR) {
                     ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02827)

Modified: httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_http.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_http.c?rev=1732266&r1=1732265&r2=1732266&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_http.c (original)
+++ httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_http.c Thu Feb 25 08:59:36 2016
@@ -644,55 +644,6 @@ static int spool_reqbody_cl(apr_pool_t *
     return(ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, header_brigade, 1));
 }
 
-/*
- * Transform buckets from one bucket allocator to another one by creating a
- * transient bucket for each data bucket and let it use the data read from
- * the old bucket. Metabuckets are transformed by just recreating them.
- * Attention: Currently only the following bucket types are handled:
- *
- * All data buckets
- * FLUSH
- * EOS
- *
- * If an other bucket type is found its type is logged as a debug message
- * and APR_EGENERAL is returned.
- */
-static apr_status_t proxy_buckets_lifetime_transform(request_rec *r,
-        apr_bucket_brigade *from, apr_bucket_brigade *to)
-{
-    apr_bucket *e;
-    apr_bucket *new;
-    const char *data;
-    apr_size_t bytes;
-    apr_status_t rv = APR_SUCCESS;
-
-    apr_brigade_cleanup(to);
-    for (e = APR_BRIGADE_FIRST(from);
-         e != APR_BRIGADE_SENTINEL(from);
-         e = APR_BUCKET_NEXT(e)) {
-        if (!APR_BUCKET_IS_METADATA(e)) {
-            apr_bucket_read(e, &data, &bytes, APR_BLOCK_READ);
-            new = apr_bucket_transient_create(data, bytes, r->connection->bucket_alloc);
-            APR_BRIGADE_INSERT_TAIL(to, new);
-        }
-        else if (APR_BUCKET_IS_FLUSH(e)) {
-            new = apr_bucket_flush_create(r->connection->bucket_alloc);
-            APR_BRIGADE_INSERT_TAIL(to, new);
-        }
-        else if (APR_BUCKET_IS_EOS(e)) {
-            new = apr_bucket_eos_create(r->connection->bucket_alloc);
-            APR_BRIGADE_INSERT_TAIL(to, new);
-        }
-        else {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00964)
-                          "Unhandled bucket type of type %s in"
-                          " proxy_buckets_lifetime_transform", e->type->name);
-            rv = APR_EGENERAL;
-        }
-    }
-    return rv;
-}
-
 static
 int ap_proxy_http_request(apr_pool_t *p, request_rec *r,
                                    proxy_conn_rec *p_conn, proxy_worker *worker,
@@ -1779,7 +1730,7 @@ apr_status_t ap_proxy_http_process_respo
                     }
 
                     /* Switch the allocator lifetime of the buckets */
-                    proxy_buckets_lifetime_transform(r, bb, pass_bb);
+                    ap_proxy_buckets_lifetime_transform(r, bb, pass_bb);
 
                     /* found the last brigade? */
                     if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(pass_bb))) {

Modified: httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_wstunnel.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_wstunnel.c?rev=1732266&r1=1732265&r2=1732266&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_wstunnel.c (original)
+++ httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_wstunnel.c Thu Feb 25 08:59:36 2016
@@ -89,61 +89,6 @@ static int proxy_wstunnel_canon(request_
     return OK;
 }
 
-
-static apr_status_t proxy_wstunnel_transfer(request_rec *r, conn_rec *c_i, conn_rec *c_o,
-                                     apr_bucket_brigade *bb, char *name, int *sent)
-{
-    apr_status_t rv;
-#ifdef DEBUGGING
-    apr_off_t len;
-#endif
-
-    do {
-        apr_brigade_cleanup(bb);
-        rv = ap_get_brigade(c_i->input_filters, bb, AP_MODE_READBYTES,
-                            APR_NONBLOCK_READ, AP_IOBUFSIZE);
-        if (rv == APR_SUCCESS) {
-            if (c_o->aborted) {
-                return APR_EPIPE;
-            }
-            if (APR_BRIGADE_EMPTY(bb)) {
-                break;
-            }
-#ifdef DEBUGGING
-            len = -1;
-            apr_brigade_length(bb, 0, &len);
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02440)
-                          "read %" APR_OFF_T_FMT
-                          " bytes from %s", len, name);
-#endif
-            if (sent) {
-                *sent = 1;
-            }
-            rv = ap_pass_brigade(c_o->output_filters, bb);
-            if (rv == APR_SUCCESS) {
-                ap_fflush(c_o->output_filters, bb);
-            }
-            else {
-                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02441)
-                              "error on %s - ap_pass_brigade",
-                              name);
-            }
-        } else if (!APR_STATUS_IS_EAGAIN(rv) && !APR_STATUS_IS_EOF(rv)) {
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(02442)
-                          "error on %s - ap_get_brigade",
-                          name);
-        }
-    } while (rv == APR_SUCCESS);
-
-    ap_log_rerror(APLOG_MARK, APLOG_TRACE2, rv, r, "wstunnel_transfer complete");
-
-    if (APR_STATUS_IS_EAGAIN(rv)) {
-        rv = APR_SUCCESS;
-    }
-
-    return rv;
-}
-
 /*
  * process the request and write the response.
  */
@@ -188,10 +133,12 @@ static int proxy_wstunnel_request(apr_po
     e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
     APR_BRIGADE_INSERT_TAIL(header_brigade, e);
 
-    if ((rv = ap_proxy_pass_brigade(c->bucket_alloc, r, conn, backconn,
+    if ((rv = ap_proxy_pass_brigade(backconn->bucket_alloc, r, conn, backconn,
                                     header_brigade, 1)) != OK)
         return rv;
 
+    apr_brigade_cleanup(header_brigade);
+
     ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "setting up poll()");
 
     if ((rv = apr_pollset_create(&pollset, 2, p, 0)) != APR_SUCCESS) {
@@ -248,8 +195,14 @@ static int proxy_wstunnel_request(apr_po
                 if (pollevent & (APR_POLLIN | APR_POLLHUP)) {
                     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02446)
                                   "sock was readable");
-                    done |= proxy_wstunnel_transfer(r, backconn, c, bb,
-                                                    "sock", NULL) != APR_SUCCESS;
+                    done |= ap_proxy_transfer_between_connections(r, backconn,
+                                                                  c,
+                                                                  header_brigade,
+                                                                  bb, "sock",
+                                                                  NULL,
+                                                                  AP_IOBUFSIZE,
+                                                                  0)
+                                                                 != APR_SUCCESS;
                 }
                 else if (pollevent & APR_POLLERR) {
                     ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02447)
@@ -268,8 +221,14 @@ static int proxy_wstunnel_request(apr_po
                 if (pollevent & (APR_POLLIN | APR_POLLHUP)) {
                     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02448)
                                   "client was readable");
-                    done |= proxy_wstunnel_transfer(r, c, backconn, bb,
-                                                    "client", &replied) != APR_SUCCESS;
+                    done |= ap_proxy_transfer_between_connections(r, c,
+                                                                  backconn, bb,
+                                                                  header_brigade,
+                                                                  "client",
+                                                                  &replied,
+                                                                  AP_IOBUFSIZE,
+                                                                  0)
+                                                                 != APR_SUCCESS;
                 }
                 else if (pollevent & APR_POLLERR) {
                     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02607)

Modified: httpd/httpd/branches/2.4.x/modules/proxy/proxy_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/proxy_util.c?rev=1732266&r1=1732265&r2=1732266&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/proxy/proxy_util.c (original)
+++ httpd/httpd/branches/2.4.x/modules/proxy/proxy_util.c Thu Feb 25 08:59:36 2016
@@ -3631,6 +3631,128 @@ PROXY_DECLARE(apr_port_t) ap_proxy_port_
     return 0;
 }
 
+PROXY_DECLARE(apr_status_t) ap_proxy_buckets_lifetime_transform(request_rec *r,
+                                                      apr_bucket_brigade *from,
+                                                      apr_bucket_brigade *to)
+{
+    apr_bucket *e;
+    apr_bucket *new;
+    const char *data;
+    apr_size_t bytes;
+    apr_status_t rv = APR_SUCCESS;
+    apr_bucket_alloc_t *bucket_alloc = to->bucket_alloc;
+
+    apr_brigade_cleanup(to);
+    for (e = APR_BRIGADE_FIRST(from);
+         e != APR_BRIGADE_SENTINEL(from);
+         e = APR_BUCKET_NEXT(e)) {
+        if (!APR_BUCKET_IS_METADATA(e)) {
+            apr_bucket_read(e, &data, &bytes, APR_BLOCK_READ);
+            new = apr_bucket_transient_create(data, bytes, bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(to, new);
+        }
+        else if (APR_BUCKET_IS_FLUSH(e)) {
+            new = apr_bucket_flush_create(bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(to, new);
+        }
+        else if (APR_BUCKET_IS_EOS(e)) {
+            new = apr_bucket_eos_create(bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(to, new);
+        }
+        else {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(03304)
+                          "Unhandled bucket type of type %s in"
+                          " ap_proxy_buckets_lifetime_transform", e->type->name);
+            rv = APR_EGENERAL;
+        }
+    }
+    return rv;
+}
+
+PROXY_DECLARE(apr_status_t) ap_proxy_transfer_between_connections(
+                                                       request_rec *r,
+                                                       conn_rec *c_i,
+                                                       conn_rec *c_o,
+                                                       apr_bucket_brigade *bb_i,
+                                                       apr_bucket_brigade *bb_o,
+                                                       const char *name,
+                                                       int *sent,
+                                                       apr_off_t bsize,
+                                                       int after)
+{
+    apr_status_t rv;
+#ifdef DEBUGGING
+    apr_off_t len;
+#endif
+
+    do {
+        apr_brigade_cleanup(bb_i);
+        rv = ap_get_brigade(c_i->input_filters, bb_i, AP_MODE_READBYTES,
+                            APR_NONBLOCK_READ, bsize);
+        if (rv == APR_SUCCESS) {
+            if (c_o->aborted) {
+                return APR_EPIPE;
+            }
+            if (APR_BRIGADE_EMPTY(bb_i)) {
+                break;
+            }
+#ifdef DEBUGGING
+            len = -1;
+            apr_brigade_length(bb_i, 0, &len);
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO()
+                          "ap_proxy_transfer_between_connections: "
+                          "read %" APR_OFF_T_FMT
+                          " bytes from %s", len, name);
+#endif
+            if (sent) {
+                *sent = 1;
+            }
+            ap_proxy_buckets_lifetime_transform(r, bb_i, bb_o);
+            if (!after) {
+                apr_bucket *b;
+
+                /*
+                 * Do not use ap_fflush here since this would cause the flush
+                 * bucket to be sent in a separate brigade afterwards which
+                 * causes some filters to set aside the buckets from the first
+                 * brigade and process them when the flush arrives in the second
+                 * brigade. As set asides of our transformed buckets involve
+                 * memory copying we try to avoid this. If we have the flush
+                 * bucket in the first brigade they directly process the
+                 * buckets without setting them aside.
+                 */
+                b = apr_bucket_flush_create(bb_o->bucket_alloc);
+                APR_BRIGADE_INSERT_TAIL(bb_o, b);
+            }
+            rv = ap_pass_brigade(c_o->output_filters, bb_o);
+            if (rv != APR_SUCCESS) {
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO()
+                              "ap_proxy_transfer_between_connections: "
+                              "error on %s - ap_pass_brigade",
+                              name);
+            }
+        } else if (!APR_STATUS_IS_EAGAIN(rv) && !APR_STATUS_IS_EOF(rv)) {
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO()
+                          "ap_proxy_transfer_between_connections: "
+                          "error on %s - ap_get_brigade",
+                          name);
+        }
+    } while (rv == APR_SUCCESS);
+
+    if (after) {
+        ap_fflush(c_o->output_filters, bb_o);
+    }
+
+    ap_log_rerror(APLOG_MARK, APLOG_TRACE2, rv, r,
+                  "ap_proxy_transfer_between_connections complete");
+
+    if (APR_STATUS_IS_EAGAIN(rv)) {
+        rv = APR_SUCCESS;
+    }
+
+    return rv;
+}
+
 void proxy_util_register_hooks(apr_pool_t *p)
 {
     APR_REGISTER_OPTIONAL_FN(ap_proxy_retry_worker);