On Thu, Dec 12, 2013 at 6:45 PM, Yann Ylavic <ylavic....@gmail.com> wrote:

> Here is a proposal (patch against ap_proxy_http_process_response) to
> address the double lifetime transformation of the buckets from the backend
> when its connection is released early (on EOS, before the last buckets are
> forwarded to the client).
>

Maybe this version is more safe should bb be (later) created with a
different pool/bucket_alloc than pass_bb :

Index: modules/proxy/mod_proxy_http.c
===================================================================
--- modules/proxy/mod_proxy_http.c    (revision 1550128)
+++ modules/proxy/mod_proxy_http.c    (working copy)
@@ -1729,12 +1729,8 @@ int ap_proxy_http_process_response(apr_pool_t * p,
                         break;
                     }

-                    /* Switch the allocator lifetime of the buckets */
-                    proxy_buckets_lifetime_transform(r, bb, pass_bb);
-
                     /* found the last brigade? */
-                    if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(pass_bb))) {
-
+                    if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
                         /* signal that we must leave */
                         finish = TRUE;

@@ -1742,19 +1738,17 @@ int ap_proxy_http_process_response(apr_pool_t * p,
                          * data that lives only as long as the backend
connection.
                          * Force a setaside so these transient buckets
become heap
                          * buckets that live as long as the request.
+                         * Calling ap_save_brigade with NULL as filter is
OK,
+                         * because pass_bb brigade already has been
created and
+                         * does not need to get created by ap_save_brigade.
                          */
-                        for (e = APR_BRIGADE_FIRST(pass_bb); e
-                                != APR_BRIGADE_SENTINEL(pass_bb); e
-                                = APR_BUCKET_NEXT(e)) {
-                            apr_bucket_setaside(e, r->pool);
+                        rv = ap_save_brigade(NULL, &pass_bb, &bb, r->pool);
+                        if (rv != APR_SUCCESS) {
+                            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
APLOGNO()
+                                          "Failed to save final output
brigade");
+                            return HTTP_INTERNAL_SERVER_ERROR;
                         }

-                        /* finally it is safe to clean up the brigade from
the
-                         * connection pool, as we have forced a setaside
on all
-                         * buckets.
-                         */
-                        apr_brigade_cleanup(bb);
-
                         /* make sure we release the backend connection as
soon
                          * as we know we are done, so that the backend
isn't
                          * left waiting for a slow client to eventually
@@ -1764,8 +1758,11 @@ int ap_proxy_http_process_response(apr_pool_t * p,
                                 backend, r->server);
                         /* Ensure that the backend is not reused */
                         *backend_ptr = NULL;
-
                     }
+                    else {
+                        /* Switch the allocator lifetime of the buckets */
+                        proxy_buckets_lifetime_transform(r, bb, pass_bb);
+                    }

                     /* try send what we read */
                     if (ap_pass_brigade(r->output_filters, pass_bb) !=
APR_SUCCESS
[EOS]

Index: modules/proxy/mod_proxy_http.c
===================================================================
--- modules/proxy/mod_proxy_http.c	(revision 1550128)
+++ modules/proxy/mod_proxy_http.c	(working copy)
@@ -1729,12 +1729,8 @@ int ap_proxy_http_process_response(apr_pool_t * p,
                         break;
                     }
 
-                    /* Switch the allocator lifetime of the buckets */
-                    proxy_buckets_lifetime_transform(r, bb, pass_bb);
-
                     /* found the last brigade? */
-                    if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(pass_bb))) {
-
+                    if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
                         /* signal that we must leave */
                         finish = TRUE;
 
@@ -1742,19 +1738,17 @@ int ap_proxy_http_process_response(apr_pool_t * p,
                          * data that lives only as long as the backend connection.
                          * Force a setaside so these transient buckets become heap
                          * buckets that live as long as the request.
+                         * Calling ap_save_brigade with NULL as filter is OK,
+                         * because pass_bb brigade already has been created and
+                         * does not need to get created by ap_save_brigade.
                          */
-                        for (e = APR_BRIGADE_FIRST(pass_bb); e
-                                != APR_BRIGADE_SENTINEL(pass_bb); e
-                                = APR_BUCKET_NEXT(e)) {
-                            apr_bucket_setaside(e, r->pool);
+                        rv = ap_save_brigade(NULL, &pass_bb, &bb, r->pool);
+                        if (rv != APR_SUCCESS) {
+                            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO()
+                                          "Failed to save final output brigade");
+                            return HTTP_INTERNAL_SERVER_ERROR;
                         }
 
-                        /* finally it is safe to clean up the brigade from the
-                         * connection pool, as we have forced a setaside on all
-                         * buckets.
-                         */
-                        apr_brigade_cleanup(bb);
-
                         /* make sure we release the backend connection as soon
                          * as we know we are done, so that the backend isn't
                          * left waiting for a slow client to eventually
@@ -1764,8 +1758,11 @@ int ap_proxy_http_process_response(apr_pool_t * p,
                                 backend, r->server);
                         /* Ensure that the backend is not reused */
                         *backend_ptr = NULL;
-
                     }
+                    else {
+                        /* Switch the allocator lifetime of the buckets */
+                        proxy_buckets_lifetime_transform(r, bb, pass_bb);
+                    }
 
                     /* try send what we read */
                     if (ap_pass_brigade(r->output_filters, pass_bb) != APR_SUCCESS

Reply via email to