Let's now look at the same filter implemented using the stream-based filtering API (see Example 25-8).

Example 25-8. Book/InputRequestFilterLC2.pm

package Book::InputRequestFilterLC2;

use strict;
use warnings;

use base qw(Apache::Filter);

use Apache::Const -compile => 'OK';

use constant BUFF_LEN => 1024;

sub handler : FilterRequestHandler {
    my $filter = shift;

    while ($filter->read(my $buffer, BUFF_LEN)) {
        $filter->print(lc $buffer);
    }

    Apache::OK;
}
1;

You've probably asked yourself why we had to go through the bucket-brigade filters when all this can be done so much more easily. The reason is that we wanted you to understand how the filters work underneath, which will help you when you need to debug filters or optimize their speed. Also, in certain cases a bucket-brigade filter may be more efficient than a stream-based one. For example, if the filter applies a transformation to selected buckets, certain buckets may contain open file handles or pipes, rather than real data. When you call read( ) the buckets will be forced to read in that data, but if you don't want to modify these buckets, you can pass them as they are and let Apache use a faster technique for sending data from the file handles or pipes.

The logic is very simple here: the filter reads in a loop and prints the modified data, which at some point (when the internal mod_perl buffer is full or when the filter returns) will be sent to the next filter.

read( ) populates $buffer to a maximum of BUFF_LEN characters (1,024 in our example). Assuming that the current bucket brigade contains 2,050 characters, read( ) will get the first 1,024 characters, then 1,024 characters more, and finally the remaining two characters. Notice that even though the response handler may have sent more than 2,050 characters, every filter invocation operates on a single bucket brigade, so you have to wait for the next invocation to get more input. In one of the earlier examples, we showed that you can force the generation of several bucket brigades in the content handler by using rflush( ). For example:

$r->print("string");
$r->rflush( );
$r->print("another string");

It's possible to get more than one bucket brigade from the same filter handler invocation only if the filter is not using the streaming interface—simply call get_brigade( ) as many times as needed or until the EOS token is received.

The configuration section is pretty much identical:

<Location /lc_input2>
     SetHandler modperl
     PerlResponseHandler    +Book::Dump
     PerlInputFilterHandler +Book::InputRequestFilterLC2
 </Location>

When issuing a POST request:

% echo "mOd_pErl RuLeS" | POST 'http://localhost:8002/lc_input2?FoO=1&BAR=2'

we get a response like this:

args:
FoO=1&BAR=2
content:
mod_perl rules

Again, we can see that our filter lowercased the POST ed body before the content handler received it. The query string wasn't changed.