stas 2002/08/27 02:48:59 Modified: src/docs/2.0/user/handlers handlers.pod Log: - more filter examples tweaks - add PerlPostReadRequestHandler example Revision Changes Path 1.13 +229 -55 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.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- handlers.pod 22 Aug 2002 11:26:42 -0000 1.12 +++ handlers.pod 27 Aug 2002 09:48:59 -0000 1.13 @@ -218,9 +218,10 @@ I<error_log>, and therefore any messages to that stream will be printed to the console the server is starting from (if such exists). -This phase is of type C<RUN_ALL>. +This phase is of type C<L<RUN_ALL|/item_RUN_ALL>>. -The handler's configuration scope is C<SRV>. +The handler's configuration scope is +C<L<SRV|docs::2.0::user::config::config/item_SRV>>. As we have seen in the C<MyApache::StartupLog::open_logs> handler, the I<open_logs> phase handlers accept four arguments: the configuration @@ -265,9 +266,10 @@ META: once mod_perl will have the API for that. -This phase is of type C<RUN_ALL>. +This phase is of type C<L<RUN_ALL|/item_RUN_ALL>>. -The handler's configuration scope is C<SRV>. +The handler's configuration scope is +C<L<SRV|docs::2.0::user::config::config/item_SRV>>. In our C<MyApache::StartupLog> example we used the I<post_config()> handler: @@ -299,9 +301,10 @@ C<Apache::DBI> pre-opens database connections during this phase and C<Apache::Resource> sets the process' resources limits. -This phase is of type C<VOID>. +This phase is of type C<L<VOID|/item_VOID>>. -The handler's configuration scope is C<SRV>. +The handler's configuration scope is +C<L<SRV|docs::2.0::user::config::config/item_SRV>>. In our C<MyApache::StartupLog> example we used the I<child_init()> handler: @@ -441,10 +444,11 @@ interpreter won't be available to other threads while the images are being served. -This phase is of type C<RUN_ALL>. +This phase is of type C<L<RUN_ALL|/item_RUN_ALL>>. -The handler's configuration scope is C<SRV>, because it's not known -yet which resource the request will be mapped to. +The handler's configuration scope is +C<L<SRV|docs::2.0::user::config::config/item_SRV>>, because it's not +known yet which resource the request will be mapped to. XXX: As of this moment C<PerlPreConnectionHandler> is not being executed by mod_perl. Stay tuned. @@ -469,11 +473,12 @@ processing with processing for some other protocols (e.g., POP3, FTP, etc.). -This phase is of type C<RUN_FIRST>. +This phase is of type C<L<RUN_FIRST|/item_RUN_FIRST>>. -The handler's configuration scope is C<SRV>. Therefore the only way to -run protocol servers different than the core HTTP is inside dedicated -virtual hosts. +The handler's configuration scope is +C<L<SRV|docs::2.0::user::config::config/item_SRV>>. Therefore the only +way to run protocol servers different than the core HTTP is inside +dedicated virtual hosts. A I<process_connection> handler accepts a connection record object as its only argument, a socket object can be retrieved from the @@ -616,7 +621,7 @@ And try the new connection handler in action: - panic% telnet localhost 8010 + panic% telnet localhost 8011 Trying 127.0.0.1... Connected to localhost (127.0.0.1). Escape character is '^]'. @@ -633,7 +638,7 @@ connection and the filter handlers. file:MyApache/EchoBB.pm - ------------------- + ----------------------- package MyApache::EchoBB; use strict; @@ -774,7 +779,9 @@ Those familiar with mod_perl 1.0 will find the HTTP request cycle in mod_perl 2.0 to be almost identical to the mod_perl 1.0's model. The only difference is in the I<response> phase which now includes -filtering. +filtering. Also the C<PerlHandler> directive has been renamed to +C<PerlResponseHandler> to better match the corresponding Apache phase +name (I<response>). The following diagram depicts the HTTP request life cycle and highlights which handlers are available to mod_perl 2.0: @@ -833,13 +840,77 @@ This phase is usually used to do processings that must happen once per request. -This phase is of type C<RUN_ALL>. +This phase is of type C<L<RUN_ALL|/item_RUN_ALL>>. -The handler's configuration scope is C<SRV>, because at this phase the -request has not yet been associated with a particular filename or -directory. +The handler's configuration scope is +C<L<SRV|docs::2.0::user::config::config/item_SRV>>, because at this +phase the request has not yet been associated with a particular +filename or directory. + +Consider the following registry script: + + touch.pl + -------- + use strict; + use warnings; + + use Apache::ServerUtil (); + use File::Spec::Functions qw(catfile); + + my $r = shift; + $r->content_type('text/plain'); + + my $conf_file = catfile Apache::server_root_relative($r->pool, 'conf'), + "httpd.conf"; + + printf "$conf_file is %0.2f minutes old", 60*24*(-M $conf_file); + +This registry script is supposed to print when the last time +I<httpd.conf> has been modified. If you run this script several times +you might be surprised that it reports the same thing all the +time. Unless you happen to hit a recently started child process which +will then report a different value. + +This happens because the C<-M> operator reports the difference between +file's modification time and the value of a special perl variable +C<$^T>. When we run scripts from the command line, this variable is +always set to the time when the script gets invoked. Under mod_perl +this variable is getting preset once when the child process starts and +doesn't change since then, so all requests see the same time + +Armed with this knowledge, in order to make our code behave like the +command line programs we need to reset C<$^T> to the request's start +time, before C<-M> is used. We can change the script itself, but what +if we need to do the same change for several other scripts and +handlers? A simple C<PerlPostReadRequestHandler> handler, which will +be executed as the very first thing of each requests, comes handy +here: + + package MyApache::TimeReset; + + use Apache::RequestRec (); + + use Apache::Const -compile => 'OK'; + + sub handler { + my $r = shift; + $^T = $r->request_time; + return Apache::OK; + } + 1; + +We could do: + + $^T = time(); + +But to make things more efficient we use C<$r-E<gt>request_time> which +already stores the request's start time, and returns it without doing +an additional system call. + +To enable it just add to I<httpd.conf>: + + PerlPostReadRequestHandler MyApache::TimeReset -Example: =head2 PerlTransHandler @@ -853,11 +924,12 @@ If no custom handlers is provided, the server's default rules (C<Alias> directives and the like) will continue to be followed. -This phase is of type C<RUN_FIRST>. +This phase is of type C<L<RUN_FIRST|/item_RUN_FIRST>>. -The handler's configuration scope is C<SRV>, because at this phase the -request has not yet been associated with a particular filename or -directory. +The handler's configuration scope is +C<L<SRV|docs::2.0::user::config::config/item_SRV>>, because at this +phase the request has not yet been associated with a particular +filename or directory. Example: @@ -871,7 +943,7 @@ It is the first handler to be invoked when serving a request. -This phase is of type C<RUN_ALL>. +This phase is of type C<L<RUN_ALL|/item_RUN_ALL>>. Example: @@ -887,9 +959,10 @@ can be used to block evil clients, while little resources were wasted on these. -This phase is of type C<RUN_ALL>. +This phase is of type C<L<RUN_ALL|/item_RUN_ALL>>. -The handler's configuration scope is C<DIR>. +The handler's configuration scope is +C<L<DIR|docs::2.0::user::config::config/item_DIR>>. Example: @@ -906,9 +979,10 @@ time of the day or any other rule not connected to the user's identity. -This phase is of type C<RUN_ALL>. +This phase is of type C<L<RUN_ALL|/item_RUN_ALL>>. -The handler's configuration scope is C<DIR>. +The handler's configuration scope is +C<L<DIR|docs::2.0::user::config::config/item_DIR>>. Example: @@ -928,9 +1002,10 @@ browser will normally pop up a dialog box that prompts the user for login information. -This phase is of type C<RUN_FIRST>. +This phase is of type C<L<RUN_FIRST|/item_RUN_FIRST>>. -The handler's configuration scope is C<DIR>. +The handler's configuration scope is +C<L<DIR|docs::2.0::user::config::config/item_DIR>>. =head2 PerlAuthzHandler @@ -947,9 +1022,10 @@ C<AUTH_REQUIRED> to indicate that the user is not authorized to access the requested document. -This phase is of type C<RUN_FIRST>. +This phase is of type C<L<RUN_FIRST|/item_RUN_FIRST>>. -The handler's configuration scope is C<DIR>. +The handler's configuration scope is +C<L<DIR|docs::2.0::user::config::config/item_DIR>>. Example: @@ -966,9 +1042,10 @@ Of course later phases may override the mime type set in this phase. -This phase is of type C<RUN_FIRST>. +This phase is of type C<L<RUN_FIRST|/item_RUN_FIRST>>. -The handler's configuration scope is C<DIR>. +The handler's configuration scope is +C<L<DIR|docs::2.0::user::config::config/item_DIR>>. Example: @@ -982,9 +1059,10 @@ environment with variables configured with I<SetEnv> and I<PassEnv> directives. -This phase is of type C<RUN_ALL>. +This phase is of type C<L<RUN_ALL|/item_RUN_ALL>>. -The handler's configuration scope is C<DIR>. +The handler's configuration scope is +C<L<DIR|docs::2.0::user::config::config/item_DIR>>. Example: @@ -999,7 +1077,7 @@ mod_perl. For example: <Location /perl> - SetHandler perl-script + SetHandler perl-script PerlResponseHandler Apache::Registry </Location> @@ -1007,9 +1085,10 @@ response generation. C<PerlResponseHandler> tells mod_perl which handler is going to do the job. -This phase is of type C<RUN_FIRST>. +This phase is of type C<L<RUN_FIRST|/item_RUN_FIRST>>. -The handler's configuration scope is C<DIR>. +The handler's configuration scope is +C<L<DIR|docs::2.0::user::config::config/item_DIR>>. Example: @@ -1028,9 +1107,10 @@ information in various ways (e.g., logging to a flat file or a database). -This phase is of type C<RUN_ALL>. +This phase is of type C<L<RUN_ALL|/item_RUN_ALL>>. -The handler's configuration scope is C<DIR>. +The handler's configuration scope is +C<L<DIR|docs::2.0::user::config::config/item_DIR>>. Example: @@ -1043,6 +1123,13 @@ The handler's configuration scope is C<XXX>. + + + + + + + =head1 I/O Filtering Apache 2.0 considers all incoming and outgoing data as chunks of @@ -1135,7 +1222,8 @@ This accomplishes the configuration of the connection input and output filters. -[META: +[META: This belongs to the Apache::Filter manpage and should be moved +there when this page is created. Inside a connection filter the current connection object can be retrieved with: @@ -1147,9 +1235,6 @@ my $r = $filter->r; -This belongs to the Apache::Filter manpage and should be moved there -when this page is created. - ] mod_perl provides two interfaces to filtering: a direct bucket @@ -1164,9 +1249,10 @@ The C<PerlInputFilterHandler> handler registers a filter for input filtering. -This handler is of type C<VOID>. +This handler is of type C<L<VOID|/item_VOID>>. -The handler's configuration scope is C<DIR>. +The handler's configuration scope is +C<L<DIR|docs::2.0::user::config::config/item_DIR>>. The following sections include several examples of the C<PerlInputFilterHandler> handler. @@ -1176,9 +1262,10 @@ The C<PerlOutputFilterHandler> handler registers and configures output filters. -This handler is of type C<VOID>. +This handler is of type C<L<VOID|/item_VOID>>. -The handler's configuration scope is C<DIR>. +The handler's configuration scope is +C<L<DIR|docs::2.0::user::config::config/item_DIR>>. The following sections include several examples of the C<PerlOutputFilterHandler> handler. @@ -1693,8 +1780,89 @@ that's why the content length is reported as 25 and not 24 as in the real GET request. + + =head2 Request Input Filter +Request filters are really non-different from connection filters, +other than that they are working on request and response bodies and +have an access to a request object. The filter implementation is +pretty much identical. Let's look at the request input filter that +lowercases the request's body C<MyApache::InputRequestFilterLC>: + + file:MyApache/InputRequestFilterLC.pm + ------------------------------------- + package MyApache::InputRequestFilterLC; + + use strict; + use warnings; + + use base qw(Apache::Filter); + + use APR::Brigade (); + use APR::Bucket (); + + use Apache::Const -compile => 'OK'; + use APR::Const -compile => ':common'; + + sub handler : FilterRequestHandler { + my($filter, $bb, $mode, $block, $readbytes) = @_; + + my $c = $filter->c; + my $bb_ctx = APR::Brigade->new($c->pool, $c->bucket_alloc); + my $rv = $filter->next->get_brigade($bb_ctx, $mode, $block, $readbytes); + return $rv unless $rv == APR::SUCCESS; + + while (!$bb_ctx->empty) { + my $b = $bb_ctx->first; + + $b->remove; + + if ($b->is_eos) { + $bb->insert_tail($b); + last; + } + + my $data; + my $status = $b->read($data); + return $status unless $status == APR::SUCCESS; + + $b = APR::Bucket->new(lc $data) if $data; + + $bb->insert_tail($b); + } + + Apache::OK; + } + + 1; + +Now if we use the C<MyApache::Dump> response handler, we have +developed before in this chapter, which dumps the query string and the +content body as a response, and configure the server as follows: + + <Location /lc_input> + SetHandler modperl + PerlResponseHandler +MyApache::Dump + PerlInputFilterHandler +MyApache::InputRequestFilterLC + </Location> + +When issuing a POST request: + + % echo "mOd_pErl RuLeS" | POST 'http://localhost:8002/dump_input?FoO=1&BAR=2' + +we get a response: + + args: + FoO=1&BAR=2 + content: + mod_perl rules + +indeed we can see that our filter has lowercased the POSTed body, +before the content handler received it. You can see that the query +string wasn't changed. + + =head2 Bucket Brigades and Stream-Oriented Request Output Filters As mentioned earlier output filters can be written using the bucket @@ -1853,7 +2021,7 @@ my($filter, $bb) = @_; my $c = $filter->c; - my $new_bb = APR::Brigade->new($c->pool, $c->bucket_alloc); + my $bb_ctx = APR::Brigade->new($c->pool, $c->bucket_alloc); while (!$bb->empty) { my $bucket = $bb->first; @@ -1861,7 +2029,7 @@ $bucket->remove; if ($bucket->is_eos) { - $new_bb->insert_tail($bucket); + $bb_ctx->insert_tail($bucket); last; } @@ -1875,10 +2043,10 @@ $bucket = APR::Bucket->new($data); } - $new_bb->insert_tail($bucket); + $bb_ctx->insert_tail($bucket); } - my $rv = $filter->next->pass_brigade($new_bb); + my $rv = $filter->next->pass_brigade($bb_ctx); return $rv unless $rv == APR::SUCCESS; Apache::OK; @@ -1917,6 +2085,8 @@ of the new bucket brigade and break the loop. Finally we pass the created brigade with modified data to the next filter and return. + + =head2 Filter Tips Various tips to use in filters. @@ -1934,6 +2104,10 @@ Request filters have an access to the request object, so we simply modify it. + + + + =head1 Handler (Hook) Types
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]