From: Joe Orton A filter can tell whether a bucket represents either data or
metadata using the APR_BUCKET_IS_METADATA
macro.
- Generally, all metadata buckets should be passed up the filter
+ Generally, all metadata buckets should be passed down the filter
chain by an output filter. Filters may transform, delete, and
insert data buckets as appropriate.
FLUSH
buckets are sent when the
- content generator (or a downstream filter) knows that there may be
+ content generator (or an upstream filter) knows that there may be
a delay before more content can be sent. By passing
- FLUSH
buckets up the filter chain immediately,
+ FLUSH
buckets down the filter chain immediately,
filters ensure that the client is not kept waiting for pending
data longer than necessary.Filters can create FLUSH
buckets and pass these up
- the filter chain if desired. Generating FLUSH
+
Filters can create FLUSH
buckets and pass these
+ down the filter chain if desired. Generating FLUSH
buckets unnecessarily, or too frequently, can harm network
utilisation since it may force large numbers of small packets to
be sent, rather than a small number of larger packets. The
@@ -94,9 +94,9 @@
For any given request, an output filter might be invoked only - once and be given a single brigade representing the entire response. + once and be given a single brigade representing the entire response. It is also possible that the number of times a filter is invoked - for single response is proportional to the size of the content + for a single response is proportional to the size of the content being filtered, with the filter being passed a brigade containing a single bucket each time. Filters must operate correctly in either case.
@@ -112,7 +112,7 @@ the brigade. Any buckets in the brigade after an EOS should be ignored. -An output filter should never pass an empty brigade up the +
An output filter should never pass an empty brigade down the filter chain. But, for good defensive programming, filters should be prepared to accept an empty brigade, and do nothing.
@@ -169,15 +169,18 @@ first invocation per request, and store that brigade in its state structure. -It is generally never advisable to use
apr_brigade_destroy
to "destroy" a brigade. The
memory used by the brigade structure will not be released by
calling this function (since it comes from a pool), but the
associated pool cleanup is unregistered. Using
apr_brigade_destroy
can in fact cause memory leaks;
- if a "destroyed" brigade contains still contains buckets when its
+ if a "destroyed" brigade contains buckets when its
containing pool is destroyed, those buckets will not be
- immediately destroyed.
In general, filters should use apr_brigade_cleanup
+ in preference to apr_brigade_destroy
.
->length
field is set to
- the value (apr_size_t)-1
. The PIPE
- bucket type is an example of a bucket type has an indeterminate
- length; it represents the output from a pipe, .(apr_size_t)-1
. For example, buckets of
+ the PIPE
bucket type have an indeterminate length;
+ they represent the output from a pipe.
FILE
bucket type, for example,
@@ -255,7 +258,7 @@ return ap_pass_brigade(bb);
apr_bucket_read
call morphed a FILE
bucket into a HEAP
bucket.
- In contrast, the implementation below will use consume a fixed +
In contrast, the implementation below will consume a fixed amount of memory to filter any brigade; a temporary brigade is needed and must be allocated only once per response, see the Maintaining state section.
@@ -272,8 +275,8 @@ while ((e = APR_BRIGADE_FIRST(bb)) != APR_BRIGADE_SENTINEL(bb)) { /* Remove bucket e from bb. */ APR_BUCKET_REMOVE(e); /* Insert it into temporary brigade. */ - APR_BRIGADE_INSERT_HEAD(tmpbb); - /* Pass brigade upstream. */ + APR_BRIGADE_INSERT_HEAD(tmpbb, e); + /* Pass brigade downstream. */ rv = ap_pass_brigade(f->next, tmpbb); if (rv) ...; apr_brigade_cleanup(tmpbb); @@ -334,17 +337,33 @@ apr_status_t dummy_filter(ap_filter_t *f, apr_bucket_brigade *bb)apr_bucket_setaside
function.
Alternatively, the ap_save_brigade
function can be
- used, which will create a new brigade containing buckets with a
- lifetime as long as the given pool argument. This function must
- be used with great care, however: on return it guarantees that all
- the buckets in the returned brigade will represent data mapped
- into memory. If given an input brigade containing, for example, a
- PIPE bucket, ap_save_brigade
will consume an
- arbitrary amount of memory to store the entire output of the
- pipe.
ap_save_brigade
guarantees that all
+ the buckets in the returned brigade will represent data mapped
+ into memory. If given an input brigade containing, for example,
+ a PIPE
bucket, ap_save_brigade
will
+ consume an arbitrary amount of memory to store the entire output
+ of the pipe.ap_save_brigade
reads from buckets which
+ cannot be setaside, it will always perform blocking reads,
+ removing the opportunity to use Non-blocking
+ bucket reads.ap_save_brigade
is used without passing a
+ non-NULL "saveto
" (destination) brigade parameter,
+ the function will create a new brigade, which may cause memory
+ use to be proportional to content size as described in the Brigade structure section.APR_EAGAIN
, then send a FLUSH
- bucket up the filter chain, and retry using a blocking read.
+ bucket down the filter chain, and retry using a blocking read.
- This mode of operation ensure that any filters further up the +
This mode of operation ensure that any filters further down the filter chain will flush any buffered buckets if a slow content source is being used.
@@ -382,7 +401,7 @@ while ((e = APR_BRIGADE_FIRST(bb)) != APR_BRIGADE_SENTINEL(bb)) { rv = apr_bucket_read(e, &data, &length, mode); if (rv == APR_EAGAIN && mode == APR_NONBLOCK_READ) { - /* Pass up a brigade containing a flush bucket: */ + /* Pass down a brigade containing a flush bucket: */ APR_BRIGADE_INSERT_TAIL(tmpbb, apr_bucket_flush_create(...)); rv = ap_pass_brigade(f->next, tmpbb); apr_brigade_cleanup(tmpbb); @@ -409,29 +428,28 @@ while ((e = APR_BRIGADE_FIRST(bb)) != APR_BRIGADE_SENTINEL(bb)) { follow:FLUSH
buckets should be respected by passing
- any pending or buffered buckets up the filter chain.EOS
bucket.ap_pass_brigade
to pass a brigade
- up the filter chain, output filters should call
- apr_brigade_clear
to ensure the brigade is empty
+ down the filter chain, output filters should call
+ apr_brigade_cleanup
to ensure the brigade is empty
before reusing that brigade structure; output filters should
never use apr_brigade_destroy
to "destroy"
brigades.ap_pass_brigade
, and must return appropriate errors
- back down the filter chain.FLUSH
bucket up the
+ each data bucket, and send a FLUSH
bucket down the
filter chain if the read blocks, before retrying with a blocking
read.