Index: server/protocol.c =================================================================== --- server/protocol.c (revision 1808035) +++ server/protocol.c (working copy) @@ -1712,58 +1712,71 @@ */ e = APR_BRIGADE_FIRST(b); while (e != APR_BRIGADE_SENTINEL(b)) { + apr_status_t rv; + if (APR_BUCKET_IS_EOS(e)) { eos = 1; break; } - if (e->length == (apr_size_t)-1) { + + /* For determinate length data buckets and non-FLUSH metadata + * buckets, count the length and continue. */ + if ((!APR_BUCKET_IS_METADATA(e) && e->length != (apr_size_t)-1) + || (APR_BUCKET_IS_METADATA(e) && !APR_BUCKET_IS_FLUSH(e))) { + r->bytes_sent += e->length; + e = APR_BUCKET_NEXT(e); + continue; + } + + /* For indeterminate length data buckets, perform one read. */ + if (!APR_BUCKET_IS_METADATA(e) && e->length == (apr_size_t)-1) { apr_size_t len; const char *ignored; - apr_status_t rv; - - /* This is probably a pipe bucket. Send everything - * prior to this, and then read the data for this bucket. - */ + rv = apr_bucket_read(e, &ignored, &len, eblock); + if ((rv != APR_SUCCESS) && !APR_STATUS_IS_EAGAIN(rv)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00574) + "ap_content_length_filter: " + "apr_bucket_read() failed"); + return rv; + } if (rv == APR_SUCCESS) { - /* Attempt a nonblocking read next time through */ + /* Similar to the case above, the morphed to the HEAP; + * continue with the next bucket, but next time a + * non-blocking read. */ eblock = APR_NONBLOCK_READ; r->bytes_sent += len; + e = APR_BUCKET_NEXT(e); + continue; } else if (APR_STATUS_IS_EAGAIN(rv)) { - /* Output everything prior to this bucket, and then - * do a blocking read on the next batch. - */ - if (e != APR_BRIGADE_FIRST(b)) { - apr_bucket *flush; - apr_brigade_split_ex(b, e, ctx->tmpbb); - flush = apr_bucket_flush_create(r->connection->bucket_alloc); - - APR_BRIGADE_INSERT_TAIL(b, flush); - rv = ap_pass_brigade(f->next, b); - if (rv != APR_SUCCESS || f->c->aborted) { - return rv; - } - apr_brigade_cleanup(b); - APR_BRIGADE_CONCAT(b, ctx->tmpbb); - e = APR_BRIGADE_FIRST(b); - - ctx->data_sent = 1; - } eblock = APR_BLOCK_READ; - continue; } - else { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00574) - "ap_content_length_filter: " - "apr_bucket_read() failed"); - return rv; - } } - else { - r->bytes_sent += e->length; + + /* If we reach here, pass on everything in the brigade up to + * this point. */ + apr_brigade_split_ex(b, e, ctx->tmpbb); + + if (eblock == APR_BLOCK_READ) { + /* If the next read will block, flush first. */ + apr_bucket *flush = apr_bucket_flush_create(f->c->bucket_alloc); + + APR_BRIGADE_INSERT_TAIL(b, flush); } - e = APR_BUCKET_NEXT(e); + + rv = ap_pass_brigade(f->next, b); + if (rv != APR_SUCCESS) { + return rv; + } + else if (f->c->aborted) { + return APR_ECONNABORTED; + } + apr_brigade_cleanup(b); + APR_BRIGADE_CONCAT(b, ctx->tmpbb); + e = APR_BRIGADE_FIRST(b); + + ctx->data_sent = 1; } /* If we've now seen the entire response and it's otherwise