On 05/24/2008 12:10 AM, Adam Woodworth wrote:
Thanks Ruediger.  Keep us posted.

Is this mod_proxy patch going to get into 2.2.9, or wait until another
2.2.x release when the deflate issue can be resolved?

Cheers,
Adam

Can you please test the attached patch in addition to my other patches, but
without removing mod_deflate from the chain as you did in your application?
Thanks.

Regards

RĂ¼diger

Index: modules/http/http_filters.c
===================================================================
--- modules/http/http_filters.c	(Revision 659651)
+++ modules/http/http_filters.c	(Arbeitskopie)
@@ -1569,13 +1569,24 @@
     return bufsiz;
 }
 
+/* Context struct for ap_http_outerror_filter */
+typedef struct {
+    int seen_eoc;
+} outerror_filter_ctx_t;
+
 /* Filter to handle any error buckets on output */
 apr_status_t ap_http_outerror_filter(ap_filter_t *f,
                                      apr_bucket_brigade *b)
 {
     request_rec *r = f->r;
+    outerror_filter_ctx_t *ctx = (outerror_filter_ctx_t *)(f->ctx);
     apr_bucket *e;
 
+    /* Create context if none is present */
+    if (!ctx) {
+        ctx = apr_pcalloc(r->pool, sizeof(outerror_filter_ctx_t));
+        f->ctx = ctx;
+    }
     for (e = APR_BRIGADE_FIRST(b);
          e != APR_BRIGADE_SENTINEL(b);
          e = APR_BUCKET_NEXT(e))
@@ -1589,8 +1600,42 @@
                 /* stream aborted and we have not ended it yet */
                 r->connection->keepalive = AP_CONN_CLOSE;
             }
+            continue;
         }
+        /* Detect EOC buckets and memorize this in the context. */
+        if (AP_BUCKET_IS_EOC(e)) {
+            ctx->seen_eoc = 1;
+        }
     }
+    /*
+     * Remove all data buckets that are in a brigade after an EOC bucket
+     * was seen, as an EOC bucket tells us that no (further) resource
+     * and protocol data should go out to the client. OTOH meta buckets
+     * are still welcome as they might trigger needed actions down in
+     * the chain (e.g. in network filters like SSL).
+     * Remark 1: It is needed to dump ALL data buckets in the brigade
+     *           since an filter in between might have inserted data
+     *           buckets BEFORE the EOC bucket sent by the original
+     *           sender and we do NOT want this data to be sent.
+     * Remark 2: Dumping all data buckets here does not necessarily mean
+     *           that no further data is send to the client as:
+     *           1. Network filters like SSL can still be triggered via
+     *              meta buckets to talk with the client e.g. for a
+     *              clean shutdown.
+     *           2. There could be still data that was buffered before
+     *              down in the chain that gets flushed by a FLUSH or an
+     *              EOS bucket.
+     */
+    if (ctx->seen_eoc) {
+        for (e = APR_BRIGADE_FIRST(b);
+             e != APR_BRIGADE_SENTINEL(b);
+             e = APR_BUCKET_NEXT(e))
+        {
+            if (!APR_BUCKET_IS_METADATA(e)) {
+                APR_BUCKET_REMOVE(e);
+            }
+        }
+    }
 
     return ap_pass_brigade(f->next,  b);
 }
Index: modules/proxy/mod_proxy_http.c
===================================================================
--- modules/proxy/mod_proxy_http.c	(Revision 659651)
+++ modules/proxy/mod_proxy_http.c	(Arbeitskopie)
@@ -1364,6 +1364,8 @@
              * not do a retry.
              */
             if (r->proxyreq == PROXYREQ_REVERSE && c->keepalives) {
+                apr_bucket *eos;
+
                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
                               "proxy: Closing connection to client because"
                               " reading from backend server %s failed. Number"
@@ -1372,10 +1374,26 @@
                 ap_proxy_backend_broke(r, bb);
                 /*
                  * Add an EOC bucket to signal the ap_http_header_filter
-                 * that it should get out of our way
+                 * that it should get out of our way, BUT ensure that the
+                 * EOC bucket is inserted BEFORE an EOS bucket in bb as
+                 * some resource filters like mod_deflate pass everything
+                 * up to the EOS down the chain immediately and sent the
+                 * remainder of the brigade later. But in this case the
+                 * ap_http_header_filter does not get out of our way soon
+                 * enough.
                  */
                 e = ap_bucket_eoc_create(c->bucket_alloc);
-                APR_BRIGADE_INSERT_TAIL(bb, e);
+                eos = APR_BRIGADE_LAST(bb);
+                while ((APR_BRIGADE_SENTINEL(bb) != eos)
+                       && !APR_BUCKET_IS_EOS(eos)) {
+                    eos = APR_BUCKET_PREV(eos);
+                }
+                if (eos == APR_BRIGADE_SENTINEL(bb)) {
+                    APR_BRIGADE_INSERT_TAIL(bb, e);
+                }
+                else {
+                    APR_BUCKET_INSERT_BEFORE(eos, e);
+                }
                 ap_pass_brigade(r->output_filters, bb);
                 /* Need to return OK to avoid sending an error message */
                 return OK;

Reply via email to