stas 2003/05/06 01:26:53 Modified: src/docs/2.0/user config.cfg src/docs/2.0/user/handlers filters.pod Added: src/docs/2.0/user/handlers filter_life_camera.jpg filter_life_cigarrette.jpg filter_life_coffee.jpg filter_life_goggles.jpg filter_life_mask.jpg filter_life_player.jpg filter_life_shower.jpg Log: add an introduction section on filters, including some images to spice things up Revision Changes Path 1.23 +1 -0 modperl-docs/src/docs/2.0/user/config.cfg Index: config.cfg =================================================================== RCS file: /home/cvs/modperl-docs/src/docs/2.0/user/config.cfg,v retrieving revision 1.22 retrieving revision 1.23 diff -u -r1.22 -r1.23 --- config.cfg 11 Apr 2003 03:20:09 -0000 1.22 +++ config.cfg 6 May 2003 08:26:53 -0000 1.23 @@ -56,6 +56,7 @@ copy_glob => [qw( handlers/*.gif + handlers/*.jpg )], changes => 'Changes.pod', 1.25 +190 -0 modperl-docs/src/docs/2.0/user/handlers/filters.pod Index: filters.pod =================================================================== RCS file: /home/cvs/modperl-docs/src/docs/2.0/user/handlers/filters.pod,v retrieving revision 1.24 retrieving revision 1.25 diff -u -r1.24 -r1.25 --- filters.pod 10 Apr 2003 02:50:14 -0000 1.24 +++ filters.pod 6 May 2003 08:26:53 -0000 1.25 @@ -7,6 +7,196 @@ This chapter discusses mod_perl's input and output filter handlers. +=head1 Your First Filter + +You certainly already know how filters work. That's because you +encounter filters so often in the real life. If you are unfortunate to +live in smog-filled cities like Saigon or Bangkok you are probably +used to wear a dust filter mask: + +=for html +<img src="filter_life_mask.jpg" width="150" height="159" + align="center" valign="middle" alt="dust mask"><br><br> + +If you are smoker, chances are that you smoke cigarettes with filters: + +=for html +<img src="filter_life_cigarrette.jpg" width="95" height="116" + align="center" valign="middle" alt="cigarrette filter"><br><br> + +If you are a coffee gourmand, you have certainly tried a filter coffee: + +=for html +<img src="filter_life_coffee.jpg" width="179" height="190" + align="center" valign="middle" alt="coffee machine"><br><br> + +The shower that you use, may have a water filter: + +=for html +<img src="filter_life_shower.jpg" width="180" height="168" + align="center" valign="middle" alt="shower filter"><br><br> + +When the sun is too bright, you protect your eyes by wearing sun +goggles with UV filter: + +=for html +<img src="filter_life_goggles.jpg" width="200" height="86" + align="center" valign="middle" alt="sun goggles"><br><br> + +If are a photographer you can't go a step without using filter lenses: + +=for html +<img src="filter_life_camera.jpg" width="191" height="160" + align="center" valign="middle" alt="photo camera"><br><br> + +If you love music, you might be unaware of it, but your super-modern +audio system is literally loaded with various electronic filters: + +=for html +<img src="filter_life_player.jpg" width="277" height="150" + align="center" valign="middle" alt="LP player"><br><br> + +There are many more places in our lives where filters are used. The +purpose of all filters is to apply some transformation to what's +coming into the filter, letting something different out of the +filter. Certainly in some cases it's possible to modify the source +itself, but that makes things unflexible, and but most of the time we +have no control over the source. The advantage of using filters to +modify something is that they can be replaced when requirements change +Filters also can be stacked, which allows us to make each filter do +simple transformations. For example by combining several different +filters, we can apply multiple transformations. In certain situations +combining several filters of the same kind let's us achieve a better +quality output. + +The mod_perl filters are not any different, they receive some data, +modify it and send it out. In the case of filtering the output of the +response handler, we could certainly change the response handler's +logic to do something different, since we control the response +handler. But this may make the code unnecessary complex. If we can +apply transformations to the response handler's output, it certainly +gives us more flexibility and simplifies things. For example if a +response needs to be compressed before sent out, it'd be very +inconvenient and inefficient to code in the response handler +itself. Using a filter for that purpose is a perfect +solution. Similarly, in certain cases, using an input filter to +transform the incoming request data is the most wise solution. Think +of the same example of having the incoming data coming compressed. + +Just like with real life filters, you can pipe several filters to +modify each other's output. You can also customize a selection of +different filters at run time. + +Without much further ado, let's write a simple but useful obfuscation +filter for our HTML documents. + +We are going to use a very simple obfuscation -- turn the document +into a one liner, which will make it harder to read the source +code. To accomplish that we are going to remove characters \012 +(C<\n>) and \015 (C<\r>). + +And here is the code: + + #file:MyApache/FilterObfuscate.pm + #-------------------------- + package MyApache::FilterObfuscate; + + use strict; + use warnings; + + use Apache::Filter (); + + use Apache::Const -compile => qw(OK); + + use constant BUFF_LEN => 1024; + + sub handler { + my $f = shift; + + unless ($f->ctx) { + $f->r->headers_out->unset('Content-Length'); + $f->ctx(1); + } + + while ($f->read(my $buffer, BUFF_LEN)) { + $buffer =~ s/[\r\n]//g; + $f->print($buffer); + } + + Apache::OK; + } + 1; + +Next we add it to the configuration file: + + <Files ~ "\.html"> + PerlOutputFilterHandler MyApache::FilterObfuscate + </Files> + +restart the server, and now whenever a file with an I<".html"> +extension is requested, its content will be passed through the +C<MyApache::FilterObfuscate> filter. + +The filter handler is similar to HTTP handlers, as it's expected to +return C<Apache::OK> or C<Apache::DECLINED>, but it receives the +filter object C<$f> as the first argument and not the request object +C<$r> as is the case with HTTP handlers. + +The core of this filter is the read-modify-print expression which +happens in the while loop. The logic is very simple: read at most +C<BUFF_LEN> characters of data into C<$buffer>, apply the regex to +remove any occurences of C<\n> and C<\r> in it, and print the +resulting data out. The input data may come from a response handler, +or from an upstream filter. The output data goes to the next filter in +the output chain. Even though in this example we haven't configured +any more filters, internally Apache by itself uses several core +filters to manipulate the data and send it out to the client. + +The second important chunk of logic is the unsetting of the +C<Content-Length> response header. Since the +C<MyApache::FilterObfuscate> filter modifies the length of the data +(shrinks it), if the response handler has set the C<Content-Length> +header the client may have problems receiving the data since it'd +expect more data then we have sent. + +As we are going to explain in great detail in the next sections, the +same filter may be called many times during a single requests, every +time receiving a chunk of data. For example if the HTML page is 64k +long, a filter could be invoked 4 times, each time receiving 16k of +data. The while loop that we just saw is going to read these 16k in 16 +calls, since it requests 1k on every read() call. Since it's enough to +unset the C<Content-Length> header when the filter is called the first +time, we need to have some flag telling us whether we have done the +job. The method C<ctx> provides this functionality: + + unless ($f->ctx) { + $f->r->headers_out->unset('Content-Length'); + $f->ctx(1); + } + +the unset() call will be made only on the first filter call for each +request. Of course you can store any perl data structures in +C<$f-E<gt>ctx> and retrieve it later in future filter invocations. We +will show plenty of examples using this method in the following +sections. + +Of course the C<MyApache::FilterObfuscate> filter logic should take +into account situations where removing new line characters will break +the correct rendering, as is the case if there are multi-line +C<E<lt>preE<gt>>...C<E<lt>/preE<gt>> entries, but since it escalates +the complexity of the filter, we will disregard this requirement for +now. A positive side effect of this obfuscation algorithm is in +shrinking the length of the data sent to the client. If you want to +look at the production ready implementation, which takes into account +the HTML markup specifics, the C<Apache::Clean> module, available from +CPAN, does just that. + +mod_perl I/O filtering follows the Perl's principle of making simple +things easy and difficult things possible. You have seen that it's +trivial to write simple filters. As you read through this tutorial you +will see that much more difficult things are possible, even though a +more elaborated code will be needed. + =head1 I/O Filtering Concepts Before introducing the APIs, mod_perl provides for Apache Filtering, 1.1 modperl-docs/src/docs/2.0/user/handlers/filter_life_camera.jpg <<Binary file>> 1.1 modperl-docs/src/docs/2.0/user/handlers/filter_life_cigarrette.jpg <<Binary file>> 1.1 modperl-docs/src/docs/2.0/user/handlers/filter_life_coffee.jpg <<Binary file>> 1.1 modperl-docs/src/docs/2.0/user/handlers/filter_life_goggles.jpg <<Binary file>> 1.1 modperl-docs/src/docs/2.0/user/handlers/filter_life_mask.jpg <<Binary file>> 1.1 modperl-docs/src/docs/2.0/user/handlers/filter_life_player.jpg <<Binary file>> 1.1 modperl-docs/src/docs/2.0/user/handlers/filter_life_shower.jpg <<Binary file>>
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]