On Wed, Apr 26, 2017 at 11:26 AM, Stefan Eissing <stefan.eiss...@greenbytes.de> wrote: > >> Am 26.04.2017 um 11:14 schrieb Plüm, Rüdiger, Vodafone Group >> <ruediger.pl...@vodafone.com>: >> >> >> >>> -----Ursprüngliche Nachricht----- >>> Von: Stefan Eissing [mailto:stefan.eiss...@greenbytes.de] >>> Gesendet: Mittwoch, 26. April 2017 10:55 >>> An: dev@httpd.apache.org >>> Betreff: Re: svn commit: r1707087 - >>> /httpd/httpd/trunk/modules/debugging/mod_bucketeer.c >>> >>> Eh, not really into mod_bucketeer and its use cases, but some >>> observations after a quick scan: >>> >>> line 99: >>> rv = ap_pass_brigade(f->next, ctx->bb); >>> apr_brigade_cleanup(ctx->bb); >>> >>> line 146: >>> rv = ap_pass_brigade(f->next, ctx->bb); >>> if (rv) { >>> return rv; >>> } >>> apr_brigade_cleanup(ctx->bb); >>> >>> such things only work if an EOS always comes *before* an EOR >>> bucket (case 1) or of no DATA bucket of any kind follows an EOR. >> >> Correct, but with the BUCKETEER filter being a resource filter that >> should not happen. > > Because the implementations of everything else in the server do not > do it? Should we then add a filter that checks exactly that?
I don't think that EOR before EOS can happen in HTTP/1, because ap_finalize_request_protocol() is always called before ap_process_request_after_handler(). EOS is the signal for request filters to get out of the way, so this is probably what ap_request_core_filter() should do too, and the purpose of the attached patch. This patch could use EOR instead, but I find EOS more "semantically" correct for a request filter (we don't need to set aside anything after it), while EOR would be crash safe only... Jacob, does it work better? Regards, Yann.
Index: server/request.c =================================================================== --- server/request.c (revision 1791747) +++ server/request.c (working copy) @@ -2057,12 +2057,27 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_request_co tmp_bb = f->ctx = apr_brigade_create(f->r->pool, f->c->bucket_alloc); } + /* Use the given bb downstream (purposedly scoped), hence move the + * buckets into tmp_bb to walk through them locally. + */ + APR_BRIGADE_CONCAT(tmp_bb, bb); + /* Reinstate any buffered content */ - ap_filter_reinstate_brigade(f, bb, &flush_upto); + ap_filter_reinstate_brigade(f, tmp_bb, &flush_upto); - while (!APR_BRIGADE_EMPTY(bb)) { - apr_bucket *bucket = APR_BRIGADE_FIRST(bb); + while (!APR_BRIGADE_EMPTY(tmp_bb)) { + apr_bucket *bucket = APR_BRIGADE_FIRST(tmp_bb); + int eos = APR_BUCKET_IS_EOS(bucket); + if (eos) { + /* pass everything down the chain, this request is over (and will + * possibly be destroyed before we leave, should the EOR be aside), + * not this filter's business anymore. + */ + APR_BRIGADE_CONCAT(bb, tmp_bb); + ap_remove_output_filter(f); + } + else { /* if the core has set aside data, back off and try later */ if (!flush_upto) { if (ap_filter_should_yield(f)) { @@ -2088,20 +2103,19 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_request_co } } } - /* pass each bucket down the chain */ APR_BUCKET_REMOVE(bucket); - APR_BRIGADE_INSERT_TAIL(tmp_bb, bucket); + APR_BRIGADE_INSERT_TAIL(bb, bucket); + } - status = ap_pass_brigade(f->next, tmp_bb); - if (!APR_STATUS_IS_EOF(status) && (status != APR_SUCCESS)) { + status = ap_pass_brigade(f->next, bb); + if (status != APR_SUCCESS || eos) { return status; } - + apr_brigade_cleanup(bb); } - ap_filter_setaside_brigade(f, bb); - return status; + return ap_filter_setaside_brigade(f, tmp_bb); } extern APR_OPTIONAL_FN_TYPE(authz_some_auth_required) *ap__authz_ap_some_auth_required;