httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Cliff Woolley <>
Subject Re: appending to the content brigade
Date Fri, 24 Aug 2001 20:00:46 GMT
On Fri, 24 Aug 2001, Eric Prud'hommeaux wrote:

> > > This works (the final bucket gets sent down the wire) but, if I
> > > understand the meaning of EOS I won't get into heaven this way.
> >
> > Yeah, that's definitely bad news.
> Is THE RULE that one should assume the end of data if one receives
> an EOS even if there are more buckets in the brigade?

The rule is that EOS is _only_ allowed to exist at the end of the brigade.
If there are buckets after it, it's broken.  The reason for that is that
it allows filters to just test the last bucket in the brigade for EOS
rather than having to test EVERY brigade in the bucket for EOS.  Besides,
by definition EOS means "no other buckets are coming, ever" so there's
never a (valid) reason to have any buckets afterward.

> > Note that if the last bucket is not eos, depending on how your filter is
> > supposed to work that might be an indication that you need to stash the
> > brigade away until you DO get an eos, because the content you're wrapping
> > with your mime headers hasn't all arrived yet.  Alternatively, you can
> > send down what you have now but a lack of eos means you shouldn't tack on
> > your boundary stuff yet.
> Is a filter guaranteed to get an EOS?

Eventually, yes (only once per request!).  But there might be many
intervening calls down the filter stack with partial data before that
final call which does have an EOS.

> Oops, I forgot to include the code snippet to which I was
> referring. From ap_byterange_filter:
>             if (apr_bucket_copy(ec, &foo) != APR_SUCCESS) {
>                 apr_bucket_read(ec, &str, &len, APR_BLOCK_READ);
>                 foo = apr_bucket_heap_create(str, len, 0, NULL);
>             }
> I assume there's no reason to do this if it doesn't accompany some
> fragmentation of ec.

Hooo, that's ugly.  You don't have to do that for what you want.  The
reason it's done here is that byteranges might overlap within the same
request, so rather than just moving buckets to where they need to go, it
has to make copies of all the requisite buckets for each of the ranges.
Some bucket types might not implement copy (Only buckets whose data can
only be read once (pipe and socket) don't implement it), so those that
don't need to be read (thereby morphing them into a copyable bucket eg
heap) and then THAT can be copied.  Actually, the block here is broken
because it puts str into two buckets at a time, which will double-free
str when the second bucket gets destroyed.  It should read:

    if ((rv = apr_bucket_copy(ec, &foo)) != APR_SUCCESS) {
        if (rv == APR_ENOTIMPL) {
            /* morph to a copyable bucket by reading */
            apr_bucket_read(ec, &str, &len, APR_BLOCK_READ);
            apr_bucket_copy(ec, &foo);
        else {
            return rv;

That way, ec and foo end up as two apr_buckets of type heap that share a
single apr_bucket_heap structure which points to str with a refcount of
2, rather than having two entirely separate apr_bucket/apr_bucket_heap
pairs both of which point to str and each of which has a refcount of
1.  I assume we're currently not hitting this bug because it's
probably rare to have a byterange request on a resource that gets sent
down the chain as a pipe or socket bucket.  Anyway, it's a bug... I'll go
fix it.

> > Hope this helps!  Let me know if you have more questions.
> Quite well, thank you kindly. I'm hacking up some docs to pass your
> help on. apr_buckets.h has func descriptions but I'd like to make a
> sybling of _Hook_Functions_ [1] with THE RULES and some common
> recipies.

Great!  I've been meaning to write up a "buckets 101" tutorial... maybe
this will give me a kick-start.  =-)


   Cliff Woolley
   Charlottesville, VA

View raw message