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.
*/
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);
}