From: Bill Stoddard Date: Thu, 25 Jan 2001 02:51:30 +0000 (+0000) Subject: Add the coalesce filter back in. It is NOT being installed anywhere right now. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=136a502989f8ac18e770f8821da2dca4fc05bdc2;p=apache Add the coalesce filter back in. It is NOT being installed anywhere right now. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@87825 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/http/http_core.c b/modules/http/http_core.c index 323ffe7ec2..4262c0e2e3 100644 --- a/modules/http/http_core.c +++ b/modules/http/http_core.c @@ -3034,6 +3034,143 @@ static int default_handler(request_rec *r) return ap_pass_brigade(r->output_filters, bb); } +/* + * coalesce_filter() + * This is a simple filter to coalesce many small buckets into one large + * bucket. + * + * Note: + * This implementation of coalesce_filter will only coalesce a single + * contiguous string of coalesable buckets. It will not coalesce multiple + * non-contiguous buckets. For example, if a brigade contains 10 small + * buckets followed by a large bucket (or a pipe or file bucket) followed + * by more small buckets, only the first 10 buckets will be coalesced. + */ +typedef struct COALESCE_FILTER_CTX { + char *buf; /* Start of buffer */ + char *cur; /* Pointer to next location to write */ + apr_size_t cnt; /* Number of bytes put in buf */ + apr_size_t avail; /* Number of bytes available in the buf */ +} coalesce_filter_ctx_t; +#define MIN_BUCKET_SIZE 200 +static apr_status_t coalesce_filter(ap_filter_t *f, apr_bucket_brigade *b) +{ + apr_status_t rv; + apr_pool_t *p = f->r->pool; + apr_bucket *e, *insert_before = NULL, *destroy_me = NULL; + coalesce_filter_ctx_t *ctx = f->ctx; + int pass_the_brigade = 0, insert_first = 0; + + if (ctx == NULL) { + f->ctx = ctx = apr_pcalloc(p, sizeof(coalesce_filter_ctx_t)); + ctx->avail = AP_MIN_BYTES_TO_WRITE; + } + + if (ctx->cnt) { + insert_first = 1; + } + + /* Iterate across the buckets, coalescing the small buckets into a + * single buffer + */ + APR_BRIGADE_FOREACH(e, b) { + if (destroy_me) { + apr_bucket_destroy(destroy_me); + destroy_me = NULL; + } + if (APR_BUCKET_IS_EOS(e) || APR_BUCKET_IS_FILE(e) || + APR_BUCKET_IS_PIPE(e) || APR_BUCKET_IS_FLUSH(e)) { + pass_the_brigade = 1; + } + else { + const char *str; + apr_size_t n; + rv = apr_bucket_read(e, &str, &n, APR_BLOCK_READ); + if (rv != APR_SUCCESS) { + /* XXX: log error */ + return rv; + } + if ((n < MIN_BUCKET_SIZE) && (n < ctx->avail)) { + /* Coalesce this bucket into the buffer */ + if (ctx->buf == NULL) { + ctx->buf = apr_palloc(p, AP_MIN_BYTES_TO_WRITE); + ctx->cur = ctx->buf; + ctx->cnt = 0; + } + memcpy(ctx->cur, str, n); + ctx->cnt += n; + ctx->cur += n; + ctx->avail -= n; + /* If this is the first bucket to be coalesced, don't remove it + * from the brigade. Save it as a marker for where to insert + * ctx->buf into the brigade when we're done. + */ + if (insert_before || insert_first){ + APR_BUCKET_REMOVE(e); + destroy_me = e; + } + else { + insert_before = e; + } + } + else if (insert_before || insert_first) { + /* This bucket was not able to be coalesced because it either + * exceeds MIN_BUCKET_SIZE or its contents will not fit into + * buf. We're done... + */ + pass_the_brigade = 1; + break; + } + else { + /* If there is even a single bucket that cannot be coalesced, + * then we must pass the brigade down to the next filter. + */ + pass_the_brigade = 1; + } + } + } + + if (destroy_me) { + apr_bucket_destroy(destroy_me); + destroy_me = NULL; + } + + if (pass_the_brigade) { + /* Insert ctx->buf into the correct spot in the brigade */ + e = apr_bucket_create_pool(ctx->buf, ctx->cnt, p); + if (insert_first) { + APR_BRIGADE_INSERT_HEAD(b, e); + } + else if (insert_before) { + APR_BUCKET_INSERT_BEFORE(e, insert_before); + APR_BUCKET_REMOVE(insert_before); + apr_bucket_destroy(insert_before); + insert_before = NULL; + } + rv = ap_pass_brigade(f->next, b); + if (rv != APR_SUCCESS) { + /* XXX: Log the error */ + return rv; + } + /* Get ctx->buf ready for the next brigade */ + if (ctx) { + ctx->cur = ctx->buf; + ctx->cnt = 0; + ctx->avail = AP_MIN_BYTES_TO_WRITE; + } + } + else { + if (insert_before) { + APR_BUCKET_REMOVE(insert_before); + apr_bucket_destroy(insert_before); + } + /* The brigade should be empty now because all the buckets + * were coalesced into the coalesce_filter buf + */ + } + + return APR_SUCCESS; +} /* * HTTP/1.1 chunked transfer encoding filter. */ @@ -3452,6 +3589,7 @@ static void register_hooks(apr_pool_t *p) ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter, AP_FTYPE_CONTENT); ap_register_output_filter("CHUNK", chunk_filter, AP_FTYPE_TRANSCODE); + ap_register_output_filter("COALESCE", coalesce_filter, AP_FTYPE_CONTENT); ap_register_output_filter("OLD_WRITE", ap_old_write_filter, AP_FTYPE_CONTENT - 1); }