I'm including a patch that fixes this problem. It does what I mentioned below. In the input filter, it moves the buckets rather than creating a new brigade and then concatenate. In the output filter it splits the brigade after a flush bucket only if there are buckets after the flush.
What you are really wanting to do is a partial concatenation of the brigade. Something like (not there, but it could be easily added):
APR_BRIGADE_CONCAT_UNTIL(b, ctx->b, e)
The difference between APR_BRIGADE_CONCAT_UNTIL and APR_BRIGADE_CONCAT would be that ctx->b may still have content if e is encountered. APR_BRIGADE_CONCAT (and APR_RING_CONCAT) are O(1), but this'd be O(n), but that's okay as it'd save the space of the new brigade in comparison to apr_brigade_split/apr_brigade_concat, I guess.
You should reconstruct the AP_MODE_SPECULATIVE case to do a partial for loop rather than apr_brigade_split, etc. An APR_BRIGADE_CONCAT_UNTIL isn't enough as you want to copy the buckets, but a simple for-loop should do.
Skip the APR_BRIGADE_CONCAT at the end as newbb should be empty if you follow the above strategies.
I think the output FLUSH part looks okay.
I'd also suggest reading over our style guide. Please watch your indention, C++-style comments, and tabs. It makes your patch almost impossible to review. Since it's attached with application/octet-stream I can't review it inline either.
Back to my mad-paper-writing cave... -- justin
