diff options
Diffstat (limited to 'modules/http')
-rw-r--r-- | modules/http/http_filters.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c index 0bf3bc0d94..5787c85a3a 100644 --- a/modules/http/http_filters.c +++ b/modules/http/http_filters.c @@ -1569,13 +1569,24 @@ AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, 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,6 +1600,40 @@ apr_status_t ap_http_outerror_filter(ap_filter_t *f, /* 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); + } } } |