stas 2002/08/13 08:57:07
Modified: src/docs/2.0/user/handlers handlers.pod
Log:
more output filter examples
Revision Changes Path
1.9 +182 -54 modperl-docs/src/docs/2.0/user/handlers/handlers.pod
Index: handlers.pod
===================================================================
RCS file: /home/cvs/modperl-docs/src/docs/2.0/user/handlers/handlers.pod,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- handlers.pod 13 Aug 2002 14:26:19 -0000 1.8
+++ handlers.pod 13 Aug 2002 15:57:07 -0000 1.9
@@ -747,7 +747,9 @@
If the attribute is not specified, the default C<FilterRequestHandler>
attribute is assumed. Filters specifying subroutine attributes must
-subclass C<Apache::Filter>.
+subclass C<Apache::Filter>, others only need to:
+
+ use Apache::Filter ();
The request filters are usually configured in the
C<E<lt>LocationE<gt>> or equivalent sections:
@@ -836,6 +838,9 @@
The handler's configuration scope is C<DIR>.
+The following sections include several examples of the
+C<PerlInputFilterHandler> handler.
+
=head2 PerlOutputFilterHandler
The C<PerlOutputFilterHandler> handler registers and configures output
@@ -845,16 +850,20 @@
The handler's configuration scope is C<DIR>.
-=head2 Filters All-in-One
+The following sections include several examples of the
+C<PerlOutputFilterHandler> handler.
+
+
+=head2 All-in-One Filter
Before we delve into the details of how to write filters that do
-something, lets first write a simple filter that does nothing but
-snooping on the data that goes through it. We are going to develop the
-C<MyApache::FilterSnoop> handler which can snoop on request and
-connection filters, in input and output modes.
+something with the data, lets first write a simple filter that does
+nothing but snooping on the data that goes through it. We are going to
+develop the C<MyApache::FilterSnoop> handler which can snoop on
+request and connection filters, in input and output modes.
But first let's develop a simple response handler that simply dumps
-the request's I<args> and I<content> strings:
+the request's I<args> and I<content> as strings:
file:MyApache/Dump.pm
---------------------
@@ -917,8 +926,7 @@
content:
mod_perl rules
-As you can see it has simply dumped the query string and the posted
-data.
+As you can see it simply dumped the query string and the posted data.
Now let's write the snooping filter:
@@ -1015,8 +1023,8 @@
Finally we dump to STDERR the information about the type of the
current mode, and the content of the bucket bridage.
-Let's snoop on connection and request levels in both directions, by
-applying the following configuration:
+Let's snoop on connection and request filter levels in both
+directions by applying the following configuration:
Listen 8008
<VirtualHost _default_:8008>
@@ -1030,6 +1038,7 @@
<Location /dump>
SetHandler modperl
PerlResponseHandler MyApache::Dump
+ # Request filters
PerlInputFilterHandler MyApache::FilterSnoop::request
PerlOutputFilterHandler MyApache::FilterSnoop::request
</Location>
@@ -1137,7 +1146,8 @@
HEAP:
HTTP/1.1 200 OK
Date: Tue, 13 Aug 2002 12:36:52 GMT
- Server: Apache/2.0.40-dev (Unix) mod_perl/1.99_05-dev Perl/v5.8.0
mod_ssl/2.0.40-dev OpenSSL/0.9.6d DAV/2
+ Server: Apache/2.0.40-dev (Unix) mod_perl/1.99_05-dev
+ Perl/v5.8.0 mod_ssl/2.0.40-dev OpenSSL/0.9.6d DAV/2
Content-Length: 43
Connection: close
Content-Type: text/plain; charset=ISO-8859-1
@@ -1171,37 +1181,64 @@
without POSTing any data or simply running a GET request, the request
input filter won't be called.
-=head2 XXX
-The stream-orientered output filter in the following example reverses
-every line of the response, preserving the new line characters in
-their places:
-
- file:httpd.conf
- ---------------
- PerlModule Apache::ReverseFilter
- <Location /reverse>
- SetHandler modperl
- PerlResponseHandler Apache::ReverseFilter::response
- PerlOutputFilterHandler Apache::ReverseFilter::output_filter
- </Location>
- file:Apache/ReverseFilter.pm
- ----------------------------
- package Apache::ReverseFilter;
+=head2 Bucket Brigades and Stream-Oriented Request Output Filters
+
+As mentioned earlier output filters can be written using the bucket
+brigades manipulation or the simplified stream-oriented interface.
+
+First let's develop a response handler that send two lines of output:
+numerals 0-9 and the English alphabet:
+
+ file:MyApache/SendAlphaNum.pm
+ -------------------------------
+ package MyApache::SendAlphaNum;
use strict;
- use warnings FATAL => 'all';
+ use warnings;
use Apache::RequestRec ();
use Apache::RequestIO ();
+
+ use Apache::Const -compile => qw(OK);
+
+ sub handler {
+ my $r = shift;
+
+ $r->content_type('text/plain');
+
+ $r->print(0..9, "0\n");
+ $r->print('a'..'z', "\n");
+
+ Apache::OK;
+ }
+ 1;
+
+The purpose of our request output filter is to reverse every line of
+the response, preserving the new line characters in their places.
+
+
+
+=head3 Stream-oriented Output Filter
+
+The first filter that we are going to implement is using the
+stream-oriented interface:
+
+ file:MyApache/FilterReverse1.pm
+ ----------------------------
+ package MyApache::FilterReverse1;
+
+ use strict;
+ use warnings;
+
use Apache::Filter ();
use Apache::Const -compile => qw(OK);
use constant BUFF_LEN => 1024;
- sub output_filter {
+ sub handler {
my $filter = shift;
while ($filter->read(my $buffer, BUFF_LEN)) {
@@ -1213,43 +1250,51 @@
Apache::OK;
}
-
- sub response {
- my $r = shift;
-
- $r->content_type('text/plain');
- $r->puts(1..9, "0\n");
- $r->puts('a'..'z', "\n");
-
- Apache::OK;
- }
1;
+Next, we add the following configuration to I<httpd.conf>:
+
+ PerlModule MyApache::FilterReverse1
+ PerlModule MyApache::SendAlphaNum
+ <Location /reverse1>
+ SetHandler modperl
+ PerlResponseHandler MyApache::SendAlphaNum
+ PerlOutputFilterHandler MyApache::FilterReverse1
+ </Location>
-In this example when a request to I</reverse> is made, the response
-handler C<Apache::ReverseFilter::response()> sends:
+Now when a request to I</reverse1> is made, the response handler
+C<MyApache::SendAlphaNum::handler()> sends:
1234567890
abcdefghijklmnopqrstuvwxyz
as a response and the output filter handler
-C<Apache::ReverseFilter::output_filter> reverses the lines, so the
-client gets:
+C<MyApache::FilterReverse1::handler> reverses the lines, so the client
+gets:
0987654321
zyxwvutsrqponmlkjihgfedcba
-The reversing filter is quite simple: it reads from the output stream
-in the I<readline()> mode in chunks up to the buffer length (1024 in
-our example), and then prints each line reversed while preserving the
-new line control characters at the end of each line. In order not to
-distract the reader from the purpose of the example the used code is
-oversimplified and won't handle correctly input lines which are longer
-than 1024 characters and possibly using a different line termination
-pattern. So here is an example of a more complete handler, which does
-takes care of these issues:
+The C<Apache::Filter> module loads the C<read()> and C<print()>
+methods which encapsulate the stream-oriented filtering interface.
- sub output_filter {
+The reversing filter is quite simple: in the loop it reads the data in
+the I<readline()> mode in chunks up to the buffer length (1024 in our
+example), and then prints each line reversed while preserving the new
+line control characters at the end of each line. Behind the scenes
+C<$filter-E<gt>read()> retrieves the incoming brigade and gets the
+data from it, whereas C<$filter-E<gt>print()> appends to the new
+brigade which is then sent to the next filter in the stack. C<read()>
+breaks the while loop, when the brigade is emptied or the end of
+stream is received.
+
+In order not to distract the reader from the purpose of the example
+the used code is oversimplified and won't handle correctly input lines
+which are longer than 1024 characters and possibly using a different
+line termination pattern. So here is an example of a more complete
+handler, which does takes care of these issues:
+
+ sub handler {
my $filter = shift;
my $left_over = '';
@@ -1273,9 +1318,92 @@
+=head3 Bucket Brigades Output Filter
+
+The second filter that we are going to implement is using the bucket
+brigades interface to accomplish exactly the same task as the first
+filter.
+
+ package MyApache::FilterReverse2;
+
+ use strict;
+ use warnings;
+
+ use Apache::Filter;
+
+ use APR::Brigade ();
+ use APR::Bucket ();
+
+ use Apache::Const -compile => 'OK';
+ use APR::Const -compile => ':common';
+
+ sub handler {
+ my($filter, $bb) = @_;
+
+ my $c = $filter->c;
+ my $new_bb = APR::Brigade->new($c->pool, $c->bucket_alloc);
+
+ while (!$bb->empty) {
+ my $bucket = $bb->first;
+
+ $bucket->remove;
+
+ if ($bucket->is_eos) {
+ $new_bb->insert_tail($bucket);
+ last;
+ }
+
+ my $data;
+ my $status = $bucket->read($data);
+ return $status unless $status == APR::SUCCESS;
+
+ if ($data) {
+ $data = join "",
+ map {scalar(reverse $_), "\n"} split "\n", $data;
+ $bucket = APR::Bucket->new($data);
+ }
+
+ $new_bb->insert_tail($bucket);
+ }
+
+ my $rv = $filter->next->pass_brigade($new_bb);
+ return $rv unless $rv == APR::SUCCESS;
+
+ Apache::OK;
+ }
+ 1;
+
+and the corresponding configuration:
+
+ PerlModule MyApache::FilterReverse2
+ PerlModule MyApache::SendAlphaNum
+ <Location /reverse2>
+ SetHandler modperl
+ PerlResponseHandler MyApache::SendAlphaNum
+ PerlOutputFilterHandler MyApache::FilterReverse2
+ </Location>
+
+Now when a request to I</reverse2> is made, the client gets:
+ 0987654321
+ zyxwvutsrqponmlkjihgfedcba
+as expected.
+The bucket brigades output filter version is just a bit more
+complicated than the stream-oriented one. The handler receives the
+incoming bucket brigade C<$bb> as its second argument. Since when the
+handler is completed it must pass a brigade to the next filter in the
+stack, we create a new bucket brigade into which we are going to put
+the modified buckets and which eventually we pass to the next filter.
+
+The core of the handler is in removing buckets from the head of the
+bucket brigade C<$bb> while there are some, reading the data from the
+buckets, reversing and putting it into a newly created bucket which is
+inserted to the end of the new bucket brigade. If we see a bucket
+which designates the end of stream, we insert that bucket to the tail
+of the new bucket brigade and break the loop. Finally we pass the
+created brigade with modified data to the next filter and return.
=head1 Handler (Hook) Types
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]