288
Tutorial Slides: mod_perl 2.0 By Example by Philippe M. Chiasson http://gozer.ectoplasm.org/ <[email protected]> TicketMaster ApacheCon US 2004 Saturday, November 13th 2004 Las Vegas, Nevada, USA Philippe M. Chiasson Tutorial Slides: mod_perl 2.0 By Example Slide 1

Tutorial Slides: mod perl 2.0 By Examplegozer.ectoplasm.org/Talks/mod_perl-2.0-tutorial-slides.pdf · Last modified Sat Nov 13 09:20:48 2004 GMT Tutorial Slides: mod_perl 2.0 By Example

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

  • Tutorial Slides: mod_perl 2.0 By Example

    by Philippe M. Chiasson http://gozer.ectoplasm.org/

    TicketMaster

    ApacheCon US 2004Saturday, November 13th 2004

    Las Vegas, Nevada, USA

    Philippe M. ChiassonTutorial Slides: mod_perl 2.0 By Example Slide 1

  • This talk is available from:http://gozer.ectoplasm.org/talks/

    Philippe M. ChiassonTutorial Slides: mod_perl 2.0 By Example Slide 2

  • Philippe M. ChiassonTutorial Slides: mod_perl 2.0 By Example Slide 3

  • Last modified Sat Nov 13 09:20:48 2004 GMT

    Philippe M. ChiassonTutorial Slides: mod_perl 2.0 By Example Slide 4

  • Philippe M. ChiassonGetting Your Feet Wet With mod_perl 2.0 Slide 5

  • 1 Getting Your Feet Wet Withmod_perl 2.0

    Philippe M. ChiassonGetting Your Feet Wet With mod_perl 2.0 Slide 6

  • 1.1 AboutPrerequisites

    Installation

    Configuration

    Server Launch and Shutdown

    Registry Scripts

    Handler Modules

    Philippe M. ChiassonGetting Your Feet Wet With mod_perl 2.0 Slide 7

  • 1.2 PrerequisitesApache 2.0 is required.

    Perl, depending on MPM:

    prefork: 5.6.0, better 5.6.1

    threaded: 5.8.0 + ithreads

    The installation details are in the handouts

    Philippe M. ChiassonGetting Your Feet Wet With mod_perl 2.0 Slide 8

  • 1.3 mod_perl Installation % lwp-download \ http://perl.apache.org/dist/mod_perl-2.0.01.tar.gz % tar -xvzf mod_perl-2.x.xx.tar.gz % cd modperl-2.0 % perl Makefile.PL MP_APXS=$HOME/httpd/bin/apxs \ MP_INST_APACHE2=1 % make && make test && make install

    MP_APXS is a full path to the apxs executable

    Philippe M. ChiassonGetting Your Feet Wet With mod_perl 2.0 Slide 9

  • 1.4 ConfigurationEnable DSO:

    LoadModule perl_module modules/mod_perl.so

    Find 2.0 modules

    PerlModule Apache2

    Enable the 1.0 compatibility layer

    PerlModule Apache::compat

    Philippe M. ChiassonGetting Your Feet Wet With mod_perl 2.0 Slide 10

  • 1.5 Server Launch and ShutdownStart:

    % $HOME/httpd/prefork/bin/apachectl start

    % tail -f $HOME/httpd/prefork/logs/error_log

    [Tue May 25 09:24:28 2004] [notice] Apache/2.0.50-dev (Unix) mod_perl/1.99_15-dev Perl/v5.8.4 mod_ssl/2.0.50-dev OpenSSL/0.9.7c DAV/2 configured -- resuming normal operations

    Stop:

    % $HOME/httpd/prefork/bin/apachectl stop

    Philippe M. ChiassonGetting Your Feet Wet With mod_perl 2.0 Slide 11

  • 1.6 Registry ScriptsConfiguration

    Alias /perl/ /home/httpd/httpd-2.0/perl/ SetHandler perl-script PerlResponseHandler ModPerl::Registry PerlOptions +ParseHeaders Options +ExecCGI

    Restart the server

    Philippe M. ChiassonGetting Your Feet Wet With mod_perl 2.0 Slide 12

  • A simple script:

    #!/usr/bin/perl print "Content-type: text/plain\n\n"; print "mod_perl 2.0 rocks!\n";

    Make it executable and readable:

    % chmod a+rx /home/httpd/httpd-2.0/perl/rock.pl

    Request:

    % lwp-request http://localhost/perl/rock.pl mod_perl 2.0 rocks!

    Philippe M. ChiassonGetting Your Feet Wet With mod_perl 2.0 Slide 13

  • 1.7 Handler Modules # /home/httpd/httpd-2.0/perl/MyApache/Rocks.pm # package MyApache::Rocks; use strict; use warnings; use Apache::RequestRec (); use Apache::RequestIO (); use Apache::Const -compile => qw(OK); sub handler { my $r = shift; $r->content_type(’text/plain’); print "mod_perl 2.0 rocks!\n"; return Apache::OK; } 1;

    Philippe M. ChiassonGetting Your Feet Wet With mod_perl 2.0 Slide 14

  • Adjust @INC via a startup file

    use lib qw(/home/httpd/httpd-2.0/perl);

    loaded from httpd.conf:

    PerlRequire /home/httpd/httpd-2.0/perl/startup.pl

    Configure:

    SetHandler perl-script PerlResponseHandler MyApache::Rocks

    Restart server

    Philippe M. ChiassonGetting Your Feet Wet With mod_perl 2.0 Slide 15

  • Issue request:

    % lwp-request http://localhost/rocks mod_perl 2.0 rocks!

    Philippe M. ChiassonGetting Your Feet Wet With mod_perl 2.0 Slide 16

  • Philippe M. ChiassonNew Concepts Slide 17

  • 2 New Concepts

    Philippe M. ChiassonNew Concepts Slide 18

  • 2.1 AboutExceptions

    Bucket Brigades

    Philippe M. ChiassonNew Concepts Slide 19

  • 2.2 ExceptionsApache and APR API return a status code for almost all methods

    In C you must check return value of each call

    It makes it really hard/slow to prototype things

    It makes the code hard to read

    It’s easy to forget to check the return values -- causingproblems later

    It complicates the API, when you may want to return other values

    Philippe M. ChiassonNew Concepts Slide 20

  • APR::Error handles APR/Apache/mod_perl exceptions foryou, while leaving you in control.

    Instead of returning status codes, we throw exceptions

    Philippe M. ChiassonNew Concepts Slide 21

  • If you don’t catch those exceptions, everything works transparently

    my $rlen = $sock->recv(my $buff, 1024);

    Perl will intercept the exception object and die() with aproper error message.

    [Wed Jun 09 07:25:25 2004] [error] [client 127.0.0.1] APR::Socket::recv: (11) Resource temporarily unavailable at .../TestError/runtime.pm line 124

    Philippe M. ChiassonNew Concepts Slide 22

  • If you want to catch an exception -- you can.

    use APR::Const -compile => qw(TIMEUP); # my $tries = 0; RETRY: my $rlen = eval { $sock->recv($buff, 1024) }; if ($@) { die $@ unless ref $@ && $@ == APR::TIMEUP; if ($tries++ < 3) { # sleep 250msec select undef, undef, undef, 0.25; goto RETRY; } } warn "read $rlen bytes\n";

    Philippe M. ChiassonNew Concepts Slide 23

  • APR::Error uses Perl operator overloading:

    in boolean and numerical contexts -- gives the status code

    in the string context -- the full error message

    it is called APR::Error as it is used by

    mod_perl

    APR apps written in Perl

    Philippe M. ChiassonNew Concepts Slide 24

  • 2.3 Bucket BrigadesApache 2.0 implements request and response data flow filtering

    Modules can filter each other’s output

    No need to modify Apache to accomodate SSL,compressions, transformation filters.

    The Bucket Brigades technology was introduced to make IOfiltering efficient and avoid unnecessary copying.

    Philippe M. ChiassonNew Concepts Slide 25

  • Buckets :

    A bucket represents a chunk of data.

    Buckets linked together comprise a brigade.

    Each bucket in a brigade can be modified, removed andreplaced with another bucket.

    Bucket types: files, data blocks, flush and end of streamindicators, pools, etc.

    To manipulate a bucket one doesn’t need to know its internal representation.

    Philippe M. ChiassonNew Concepts Slide 26

  • Bucket Brigades :

    A stream of data is represented by bucket brigades.

    Filters manipulate brigades one by one(adding/modifying/removing buckets)

    ... and pass the brigade to the next filter on the stack

    Philippe M. ChiassonNew Concepts Slide 27

  • Here’s an imaginary bucket brigade after it has passedthrough several filters.

    Some buckets were removed, some modified and some added.

    Philippe M. ChiassonNew Concepts Slide 28

  • More about BBs when we talk about protocols and filters

    Philippe M. ChiassonNew Concepts Slide 29

  • Philippe M. ChiassonIntroducing mod_perl Handlers Slide 30

  • 3 Introducing mod_perlHandlers

    Philippe M. ChiassonIntroducing mod_perl Handlers Slide 31

  • 3.1 AboutHandler Anatomy

    mod_perl Handlers Categories

    Single Phase’s Multiple Handlers Behavior

    Philippe M. ChiassonIntroducing mod_perl Handlers Slide 32

  • 3.2 Handler AnatomyApache distinguishes between numerous phases

    Each phase provides a hook: ap_hook_

    These hooks are used by modules to alter the default Apache behavior

    Hooks are usually referred to as handlers or callbacks

    Naming convention: PerlFooHandler

    e.g. PerlResponseHandler configures the response callback.

    Philippe M. ChiassonIntroducing mod_perl Handlers Slide 33

  • package MyApache::CurrentTime; use strict; 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("The time is: " . scalar(localtime) . "\n"); return Apache::OK; } 1;

    Philippe M. ChiassonIntroducing mod_perl Handlers Slide 34

  • Configuring the response handler:

    PerlModule MyApache::CurrentTime SetHandler modperl PerlResponseHandler MyApache::CurrentTime

    A request to http://localhost/time returns the curent time

    Philippe M. ChiassonIntroducing mod_perl Handlers Slide 35

    http://localhost/time

  • 3.3 mod_perl Handler CategoriesThe mod_perl handlers can be divided by their application scopein several categories:

    Server life cycle PerlOpenLogsHandler PerlPostConfigHandler PerlChildInitHandler PerlChildExitHandler

    Protocols PerlPreConnectionHandler PerlProcessConnectionHandler

    Philippe M. ChiassonIntroducing mod_perl Handlers Slide 36

  • Filters PerlInputFilterHandler PerlOutputFilterHandler

    HTTP Protocol PerlPostReadRequestHandler PerlTransHandler PerlMapToStorageHandler PerlInitHandler PerlHeaderParserHandler PerlAccessHandler PerlAuthenHandler PerlAuthzHandler PerlTypeHandler PerlFixupHandler PerlResponseHandler PerlLogHandler PerlCleanupHandler

    Philippe M. ChiassonIntroducing mod_perl Handlers Slide 37

  • 3.4 Stacked HandlersPhases’ behavior varies when there is more then one handlerregistered to run for the same phase.

    The following table specifies each handler’s behavior in this situation:

    Philippe M. ChiassonIntroducing mod_perl Handlers Slide 38

  • Directive Type # -------------------------------------- PerlOpenLogsHandler RUN_ALL PerlPostConfigHandler RUN_ALL PerlChildInitHandler VOID PerlChildExitHandler RUN_ALL PerlPreConnectionHandler RUN_ALL PerlProcessConnectionHandler RUN_FIRST PerlPostReadRequestHandler RUN_ALL PerlTransHandler RUN_FIRST PerlMapToStorageHandler RUN_FIRST PerlInitHandler RUN_ALL PerlHeaderParserHandler RUN_ALL PerlAccessHandler RUN_ALL PerlAuthenHandler RUN_FIRST PerlAuthzHandler RUN_FIRST PerlTypeHandler RUN_FIRST PerlFixupHandler RUN_ALL PerlResponseHandler RUN_FIRST PerlLogHandler RUN_ALL PerlCleanupHandler RUN_ALL PerlInputFilterHandler VOID PerlOutputFilterHandler VOID

    Philippe M. ChiassonIntroducing mod_perl Handlers Slide 39

  • The types :

    VOID

    Executed in the order they have been registereddisregarding their return values.

    Though in mod_perl they are expected to return Apache::OK.

    RUN_ALL

    Executed in the order they have been registered until thefirst handler that returns something other than Apache::OK or Apache::DECLINED.

    Philippe M. ChiassonIntroducing mod_perl Handlers Slide 40

  • RUN_FIRST

    Executed in the order they have been registered until thefirst handler that returns something other than Apache::DECLINED.

    If the return value is Apache::DECLINED, the nexthandler in the chain will be run.

    If the return value is Apache::OK the next phase willstart.

    In all other cases the execution will be aborted.

    Philippe M. ChiassonIntroducing mod_perl Handlers Slide 41

  • Philippe M. ChiassonServer Life Cycle Handlers Slide 42

  • 4 Server Life Cycle Handlers

    Philippe M. ChiassonServer Life Cycle Handlers Slide 43

  • 4.1 AboutServer Life Cycle

    Startup Phases Demonstration Module

    PerlOpenLogsHandler

    PerlPostConfigHandler

    PerlChildInitHandler

    PerlChildExitHandler

    Philippe M. ChiassonServer Life Cycle Handlers Slide 44

  • 4.2 2.0 Server Life Cycle

    Philippe M. ChiassonServer Life Cycle Handlers Slide 45

  • 1. Parse the configuration file, open_logs, post_config

    2. Restart to test graceful restarts

    3. Parse the configuration file, open_logs, post_config

    4. Spawn workers: procs, threads, mix

    Run child_init for each spawned process

    5. Process requests over connections

    6. Shutdown: child_exit

    Philippe M. ChiassonServer Life Cycle Handlers Slide 46

  • 4.2.1 Startup Phases Demonstration Module package MyApache::StartupLog; # use strict; use warnings; use Apache::Log (); use Apache::ServerUtil (); use Fcntl qw(:flock); use File::Spec::Functions; use Apache::Const -compile => ’OK’; my $log_file = catfile "logs", "startup_log"; my $log_fh;

    Philippe M. ChiassonServer Life Cycle Handlers Slide 47

  • sub open_logs { my($conf_pool, $log_pool, $temp_pool, $s) = @_; my $log_path = catfile Apache::ServerUtil::server_root, $log_file; $s->warn("opening the log file: $log_path"); open $log_fh, ">>$log_path" or die "can’t open $log_path: $!"; my $oldfh = select($log_fh); $| = 1; select($oldfh); say("process $$ is born to reproduce"); return Apache::OK; } sub post_config { my($conf_pool, $log_pool, $temp_pool, $s) = @_; say("configuration is completed"); return Apache::OK; } sub child_init { # my($child_pool, $s) = @_; say("process $$ is born to serve"); return Apache::OK; }

    Philippe M. ChiassonServer Life Cycle Handlers Slide 48

  • sub child_exit { my($child_pool, $s) = @_; say("process $$ now exits"); return Apache::OK; } sub say { # my($caller) = (caller(1))[3] =~ /([^:]+)$/; if (defined $log_fh) { flock $log_fh, LOCK_EX; printf $log_fh "[%s] - %-11s: %s\n", scalar(localtime), $caller, $_[0]; flock $log_fh, LOCK_UN; } else { # when the log file is not open warn __PACKAGE__ . " says: $_[0]\n"; } }

    Philippe M. ChiassonServer Life Cycle Handlers Slide 49

  • my $parent_pid = $$; # END { my $msg = "process $$ is shutdown"; $msg .= "\n". "-" x 20 if $$ == $parent_pid; say($msg); } 1;

    Philippe M. ChiassonServer Life Cycle Handlers Slide 50

  • And the httpd.conf configuration section:

    PerlModule MyApache::StartupLog PerlOpenLogsHandler MyApache::StartupLog::open_logs PerlPostConfigHandler MyApache::StartupLog::post_config PerlChildInitHandler MyApache::StartupLog::child_init PerlChildExitHandler MyApache::StartupLog::child_exit

    Philippe M. ChiassonServer Life Cycle Handlers Slide 51

  • % bin/apachectl start

    # logs/startup_log>: [Sun Jun 6 01:50:06 2004] - open_logs : process 24189 is born to reproduce [Sun Jun 6 01:50:06 2004] - post_config: configuration is completed [Sun Jun 6 01:50:07 2004] - END : process 24189 is shutdown -------------------- [Sun Jun 6 01:50:08 2004] - open_logs : process 24190 is born to reproduce [Sun Jun 6 01:50:08 2004] - post_config: configuration is completed [Sun Jun 6 01:50:09 2004] - child_init : process 24192 is born to serve [Sun Jun 6 01:50:09 2004] - child_init : process 24193 is born to serve [Sun Jun 6 01:50:09 2004] - child_init : process 24194 is born to serve [Sun Jun 6 01:50:09 2004] - child_init : process 24195 is born to serve

    Apache restarts itself

    Philippe M. ChiassonServer Life Cycle Handlers Slide 52

  • % bin/apachectl stop

    [Sun Jun 6 01:50:10 2004] - child_exit : process 24193 now exits [Sun Jun 6 01:50:10 2004] - END : process 24193 is shutdown [Sun Jun 6 01:50:10 2004] - child_exit : process 24194 now exits [Sun Jun 6 01:50:10 2004] - END : process 24194 is shutdown [Sun Jun 6 01:50:10 2004] - child_exit : process 24195 now exits [Sun Jun 6 01:50:10 2004] - child_exit : process 24192 now exits [Sun Jun 6 01:50:10 2004] - END : process 24192 is shutdown [Sun Jun 6 01:50:10 2004] - END : process 24195 is shutdown [Sun Jun 6 01:50:10 2004] - END : process 24190 is shutdown --------------------

    All processes run the END block on shutdown

    Philippe M. ChiassonServer Life Cycle Handlers Slide 53

  • The presented behavior varies from MPM to MPM.

    I used worker MPM for this demo

    MPMs, like winnt, may run open_logs and post_config morethan once

    the END blocks may be run more times, when threads are involved.

    The only sure thing -- each of these phases run at least once

    Philippe M. ChiassonServer Life Cycle Handlers Slide 54

  • Philippe M. ChiassonProtocol Handlers Slide 55

  • 5 Protocol Handlers

    Philippe M. ChiassonProtocol Handlers Slide 56

  • 5.1 AboutConnection Cycle Phases

    PerlPreConnectionHandler

    PerlProcessConnectionHandler

    Socket-based Protocol Module

    Bucket Brigades-based Protocol Module

    Philippe M. ChiassonProtocol Handlers Slide 57

  • 5.2 Connection Cycle PhasesEach child server is engaged in processing connections.

    Each connection may be served by different connection protocols,

    e.g., HTTP, POP3, SMTP, etc.

    Each connection may include more than one request,

    e.g., several HTTP requests can be served over a singleconnection, when a response includes several images.

    Philippe M. ChiassonProtocol Handlers Slide 58

  • Connection Life Cycle diagram:

    Philippe M. ChiassonProtocol Handlers Slide 59

  • 5.2.1 PerlPreConnectionHandlerThe pre_connection phase happens just after the serveraccepts the connection, but before it is handed off to aprotocol module to be served.

    It gives modules an opportunity to modify the connection assoon as possible and insert filters if needed.

    The core server uses this phase to setup the connectionrecord based on the type of connection that is being used.

    mod_perl itself uses this phase to register the connectioninput and output filters.

    Philippe M. ChiassonProtocol Handlers Slide 60

  • Apache::Reload :

    In mod_perl 1.0 Apache::Reload was used to automaticallyreload modified since the last request Perl modules.

    It was invoked during post_read_request, the first HTTPrequest’s phase.

    In mod_perl 2.0 pre_connection is the earliest general phase

    So now we can invoke the Apache::Reload handler duringthe pre_connection phase if the interpreter’s scope is:

    PerlInterpScope connection

    Philippe M. ChiassonProtocol Handlers Slide 61

  • Though this is not good for a production server,

    where there are several requests coming on the same connection

    and only one handled by mod_perl

    and the others by the default images handler

    the Perl interpreter won’t be available to other threads whilethe images are being served.

    Philippe M. ChiassonProtocol Handlers Slide 62

  • This phase is of type RUN_ALL.

    The handler’s configuration scope is SRV, because it’s notknown yet which resource the request will be mapped to.

    Philippe M. ChiassonProtocol Handlers Slide 63

  • Skeleton :

    sub handler { my ($c, $socket) = @_; # ... return Apache::OK; }

    A pre_connection handler accepts two arguments:

    connection record

    and socket objects

    Philippe M. ChiassonProtocol Handlers Slide 64

  • Block by IP example :

    package MyApache::BlockIP2; # use Apache::Connection (); use Apache::Const -compile => qw(FORBIDDEN OK); my %bad_ips = map {$_ => 1} qw(127.0.0.1 10.0.0.4); sub handler { my $c = shift; my $ip = $c->remote_ip; if (exists $bad_ips{$ip}) { warn "IP $ip is blocked\n"; return Apache::FORBIDDEN; } return Apache::OK; } 1;

    Philippe M. ChiassonProtocol Handlers Slide 65

  • Configuration

    PerlPreConnectionHandler MyApache::BlockIP2

    Apache simply drops the connection if the IP is blacklisted

    Almost no resources are wasted

    Philippe M. ChiassonProtocol Handlers Slide 66

  • 5.2.2 PerlProcessConnectionHandlerThe process_connection phase is used to process incoming connections.

    Only protocol modules should assign handlers for this phase,as it gives them an opportunity to replace the standard HTTPprocessing with processing for some other protocols (e.g.,POP3, FTP, etc.).

    This phase is of type RUN_FIRST.

    The handler’s configuration scope is SRV.

    Therefore the only way to run protocol servers differentthan the core HTTP is inside dedicated virtual hosts.

    Philippe M. ChiassonProtocol Handlers Slide 67

  • process_connection skeleton :

    sub handler { my ($c) = @_; my $socket = $c->client_socket; $sock->opt_set(APR::SO_NONBLOCK, 0); # ... return Apache::OK; }

    arg1: a connection record object

    a socket object: retrieved from $c

    must set the socket to blocking IO mode

    Philippe M. ChiassonProtocol Handlers Slide 68

  • Let’s look at the following two examples of connection handlers:

    1. Using the connection socket to read and write the data.

    2. Using bucket brigades to accomplish the same and allowfor connection filters to do their work.

    Philippe M. ChiassonProtocol Handlers Slide 69

  • 5.2.2.1 Socket-based Protocol Module

    The MyApache::EchoSocket module simply echoes thedata read back to the client.

    This module’s implementation works directly with theconnection socket and therefore bypasses connection filters if any.

    Philippe M. ChiassonProtocol Handlers Slide 70

  • Configuration :

    Listen 8010 PerlModule MyApache::EchoSocket PerlProcessConnectionHandler MyApache::EchoSocket

    use the Listen and directives to bind tothe non-standard port 8010:

    Philippe M. ChiassonProtocol Handlers Slide 71

  • Demo :

    panic% httpd panic% telnet localhost 8010 Trying 127.0.0.1... Connected to localhost (127.0.0.1). Escape character is ’^]’. Hello Hello fOo BaR fOo BaR

    Connection closed by foreign host.

    Philippe M. ChiassonProtocol Handlers Slide 72

  • The code :

    package MyApache::EchoSocket; # use strict; use warnings FATAL => ’all’; use Apache::Connection (); use APR::Socket (); use Apache::Const -compile => ’OK’; use APR::Const -compile => ’SO_NONBLOCK’; use constant BUFF_LEN => 1024;

    Philippe M. ChiassonProtocol Handlers Slide 73

  • sub handler { # my $c = shift; my $sock = $c->client_socket; $sock->opt_set(APR::SO_NONBLOCK => 0); while ($sock->recv(my $buff, BUFF_LEN)) { last if $buff =~ /^[\r\n]+$/; $sock->send($buff); } Apache::OK; } 1;

    Philippe M. ChiassonProtocol Handlers Slide 74

  • 5.2.2.2 Bucket Brigades-based Protocol Module

    The same module, but this time implemented by manipulatingbucket brigades,

    and which runs its output through a connection output filterthat turns all uppercase characters into their lowercase equivalents.

    Philippe M. ChiassonProtocol Handlers Slide 75

  • Configuration :

    Listen 8011 PerlModule MyApache::EchoBB PerlProcessConnectionHandler MyApache::EchoBB PerlOutputFilterHandler MyApache::EchoBB::lowercase_filter

    Philippe M. ChiassonProtocol Handlers Slide 76

  • Demo :

    panic% httpd panic% telnet localhost 8011 Trying 127.0.0.1... Connected to localhost (127.0.0.1). Escape character is ’^]’. Hello hello fOo BaR foo bar

    As you can see the response now was all in lower case,because of the output filter.

    Philippe M. ChiassonProtocol Handlers Slide 77

  • The code :

    package MyApache::EchoBB; # use strict; use warnings FATAL => ’all’; use Apache::Connection (); use APR::Socket (); use APR::Bucket (); use APR::Brigade (); use APR::Error (); use APR::Const -compile => qw(SUCCESS EOF SO_NONBLOCK); use Apache::Const -compile => qw(OK MODE_GETLINE);

    Philippe M. ChiassonProtocol Handlers Slide 78

  • sub handler { # my $c = shift; $c->client_socket->opt_set(APR::SO_NONBLOCK => 0); my $bb_in = APR::Brigade->new($c->pool, $c->bucket_alloc); my $bb_out = APR::Brigade->new($c->pool, $c->bucket_alloc); my $ba = $c->bucket_alloc; my $last = 0; while (1) { my $rc = $c->input_filters->get_brigade($bb_in, Apache::MODE_GETLINE); last if $rc == APR::EOF; die APR::Error::strerror($rc) unless $rc == APR::SUCCESS;

    Philippe M. ChiassonProtocol Handlers Slide 79

  • while (!$bb_in->empty) { # my $b = $bb_in->first; $b->remove; if ($b->is_eos) { $bb_out->insert_tail($b); last; } if ($b->read(my $data)) { $last++ if $data =~ /^[\r\n]+$/; # could do some transformation on data here $b = APR::Bucket->new($ba, $data); } $bb_out->insert_tail($b); }

    Philippe M. ChiassonProtocol Handlers Slide 80

  • my $fb = APR::Bucket::flush_create($c->bucket_alloc); # $bb_out->insert_tail($fb); $c->output_filters->pass_brigade($bb_out); last if $last; } $bb_in->destroy; $bb_out->destroy; Apache::OK; }

    Philippe M. ChiassonProtocol Handlers Slide 81

  • use base qw(Apache::Filter); # use constant BUFF_LEN => 1024; sub lowercase_filter : FilterConnectionHandler { my $filter = shift; while ($filter->read(my $buffer, BUFF_LEN)) { $filter->print(lc $buffer); } return Apache::OK; } 1;

    Philippe M. ChiassonProtocol Handlers Slide 82

  • A simplified pseudo-code handler:

    while ($bb_in = get_brigade()) { while ($b_in = $bb_in->get_bucket()) { # $b_in->read(my $data); # do something with $data $b_out = new_bucket($data); $bb_out->insert_tail($b_out); } $bb_out->insert_tail($flush_bucket); pass_brigade($bb_out); }

    Philippe M. ChiassonProtocol Handlers Slide 83

  • Use fflush -- replace:

    my $fb = APR::Bucket::flush_create($c->bucket_alloc); # $bb_out->insert_tail($fb); $c->output_filters->pass_brigade($bb_out);

    with just one line:

    $c->output_filters->fflush($bb_out); #

    Philippe M. ChiassonProtocol Handlers Slide 84

  • This handler could be much simpler, since we don’t modifythe data.

    $c->client_socket->opt_set(APR::SO_NONBLOCK => 0); my $bb = APR::Brigade->new($c->pool, $c->bucket_alloc); while (1) { my $rc = $c->input_filters->get_brigade($bb, Apache::MODE_GETLINE); last if $rc == APR::EOF; die APR::Error::strerror($rc) unless $rc == APR::SUCCESS; $c->output_filters->fflush($bb); } $bb->destroy;

    but it won’t work in the telnet mode, since /[\r\n]/ that wetype to end the line will keep this loop running forever

    Philippe M. ChiassonProtocol Handlers Slide 85

  • And here is another version which slurps all the data andworks with telnet

    my $bb = APR::Brigade->new($c->pool, $c->bucket_alloc); my $ba = $c->bucket_alloc; while (1) { my $rc = $c->input_filters->get_brigade($bb, Apache::MODE_GETLINE); last if $rc == APR::EOF; die APR::Error::strerror($rc) unless $rc == APR::SUCCESS; next unless $bb->flatten(my $data); $bb->cleanup; last if $data =~ /^[\r\n]+$/; $bb->insert_tail(APR::Bucket->new($ba, $data)); $c->output_filters->fflush($bb); } $bb->destroy;

    Philippe M. ChiassonProtocol Handlers Slide 86

  • We will discuss the filters next

    Philippe M. ChiassonProtocol Handlers Slide 87

  • Philippe M. ChiassonInput and Output Filters Slide 88

  • 6 Input and Output Filters

    Philippe M. ChiassonInput and Output Filters Slide 89

  • 6.1 AboutYour First Filter

    I/O Filtering Concepts

    Two Methods for Manipulating Data

    HTTP Request Versus Connection Filters

    Multiple Invocations of Filter Handlers

    Blocking Calls

    Philippe M. ChiassonInput and Output Filters Slide 90

  • mod_perl Filters Declaration and Configuration

    Filter Priority Types

    PerlInputFilterHandler

    PerlOutputFilterHandler

    PerlSetInputFilter

    PerlSetOutputFilter

    HTTP Request vs. Connection Filters

    Filter Initialization Phase

    Philippe M. ChiassonInput and Output Filters Slide 91

  • All-in-One Filter

    Input Filters Examples

    Output Filters Examples

    Philippe M. ChiassonInput and Output Filters Slide 92

  • 6.2 Your First FilterYou certainly already know how filters work.

    That’s because you encounter filters so often in real life.

    Philippe M. ChiassonInput and Output Filters Slide 93

  • Philippe M. ChiassonInput and Output Filters Slide 94

  • Philippe M. ChiassonInput and Output Filters Slide 95

  • Philippe M. ChiassonInput and Output Filters Slide 96

  • Philippe M. ChiassonInput and Output Filters Slide 97

  • Philippe M. ChiassonInput and Output Filters Slide 98

  • Philippe M. ChiassonInput and Output Filters Slide 99

  • Philippe M. ChiassonInput and Output Filters Slide 100

  • Why using I/O filters?

    Instead of making the response handler code complex

    adjust its output with filters:

    each doing a simple transformation

    and can be:

    stacked

    repeated

    added/removed dynamically at run-time

    Philippe M. ChiassonInput and Output Filters Slide 101

  • A simple obfuscation filter :

    turn HTML pages into a one-liner

    disregarding cases where new lines must be preserved,

    as in ...

    config:

    PerlOutputFilterHandler MyApache::FilterObfuscate

    Philippe M. ChiassonInput and Output Filters Slide 102

  • package MyApache::FilterObfuscate; # use Apache::Filter (); use Apache::RequestRec (); use APR::Table (); use Apache::Const -compile => qw(OK); sub handler { my $f = shift; unless ($f->ctx) { $f->r->headers_out->unset(’Content-Length’); $f->ctx(1); } while ($f->read(my $buffer, 1024)) { $buffer =~ s/[\r\n]//g; $f->print($buffer); } return Apache::OK; } 1;

    Philippe M. ChiassonInput and Output Filters Slide 103

  • Will talk about details shortly...

    Philippe M. ChiassonInput and Output Filters Slide 104

  • 6.3 I/O Filtering ConceptsBefore getting to the real filter examples

    a few concepts to help you wrap your head around ...

    Philippe M. ChiassonInput and Output Filters Slide 105

  • 6.3.1 2 Ways to Manipulate DataApache 2.0 considers all incoming and outgoing data aschunks of information,

    disregarding their kind and source or storage methods.

    These data chunks are stored in buckets, which form bucket brigades.

    Both input and output filters, filter the data in bucket brigades.

    Philippe M. ChiassonInput and Output Filters Slide 106

  • Philippe M. ChiassonInput and Output Filters Slide 107

  • mod_perl 2.0 filters can :

    directly manipulate the bucket brigades

    use a simplified streaming interface

    the filter object acts similar to a filehandle,

    which can be read from and printed to.

    Philippe M. ChiassonInput and Output Filters Slide 108

  • 6.3.2 HTTP Request vs Connection FiltersHTTP Request filters

    are applied on:

    HTTP requests body (POST) (if consumed by the content handler)

    HTTP response body

    HTTP headers are not passed through the HTTP Request filters.

    Philippe M. ChiassonInput and Output Filters Slide 109

  • Connections filters :

    are applied at the connection level.

    can modify all the incoming and outgoing data.

    including HTTP headers if HTTP protocol is used

    Philippe M. ChiassonInput and Output Filters Slide 110

  • 6.3.3 Multiple Invocations of Filter Handlers

    a filter gets invoked as many times as the number of bucketbrigades sent from an upstream filter or a content provider.

    Response handler example, buffered STDOUT ($|==0):

    $r->print("foo"); $r->rflush; $r->print("bar");

    Apache generates 3 bucket brigades => 3 filter invocations

    Philippe M. ChiassonInput and Output Filters Slide 111

  • print and rflush => two buckets:

    bucket type data ---------------------- 1st transient foo 2nd flush

    print => one bucket:

    bucket type data ---------------------- 1st transient bar

    when the response handler returns => one bucket:

    bucket type data ---------------------- 1st eos

    Philippe M. ChiassonInput and Output Filters Slide 112

  • EOS may come as a last bucket in bb with data

    Philippe M. ChiassonInput and Output Filters Slide 113

  • Three Filter Stages :

    Philippe M. ChiassonInput and Output Filters Slide 114

  • Filter skeleton demonstrating all 3 stages :

    sub handler { my $f = shift; unless ($f->ctx) { # runs on the first invocation init($f); $f->ctx(1); } process($f); # runs on all invocations if ($f->seen_eos) { # runs on the last invocation finalize($f); } return Apache::OK; }

    Philippe M. ChiassonInput and Output Filters Slide 115

  • Init example :

    response filters changing data length have to unset the C-Lheader (runs once)

    unless ($f->ctx) { $f->r->headers_out->unset(’Content-Length’); $f->ctx(1); }

    Philippe M. ChiassonInput and Output Filters Slide 116

  • Processing example :

    lower the data case (runs on all invocations)

    while ($f->read(my $data, 1024)) { $f->print(lc $data); }

    in complex cases may need to store data in context betweenfilter invocations

    Philippe M. ChiassonInput and Output Filters Slide 117

  • Finalization example :

    After all data was sent out, print how many times the filter was invoked

    my $ctx = $f->ctx; $ctx->{invoked}++; $f->ctx($ctx); # store while ($f->read(my $data, READ_SIZE)) { $f->print(lc $data); } if ($f->seen_eos) { $f->print("Filter invocated $ctx->{invoked} times"); }

    Philippe M. ChiassonInput and Output Filters Slide 118

  • 6.3.4 Blocking CallsData propogates in stages through the filter chain (there is no pipeline)

    The input filter’s get_brigade() call blocks

    Philippe M. ChiassonInput and Output Filters Slide 119

  • The output filter’s pass_brigade() call blocks

    Philippe M. ChiassonInput and Output Filters Slide 120

  • Transparent input filter :

    sub in { my ($f, $bb, $mode, $block, $readbytes) = @_; my $rv = $f->next->get_brigade($bb, $mode, $block, $readbytes); return $rv unless $rv == APR::SUCCESS; return Apache::OK; }

    Transparent output filter :

    sub out { my ($f, $bb) = @_; my $rv = $f->next->pass_brigade($bb); # return $rv unless $rv == APR::SUCCESS; return Apache::OK; } 1;

    Philippe M. ChiassonInput and Output Filters Slide 121

  • 6.4 mod_perl Filters Declarationand Configuration

    Now let’s see how mod_perl filters are declared and configured.

    Philippe M. ChiassonInput and Output Filters Slide 122

  • 6.4.1 Filter Priority TypesFilters are inserted into the filter chain based on their priority

    mod_perl provides 2 filters types:

    Handler Priority Value ------------------------------------------------- FilterRequestHandler AP_FTYPE_RESOURCE 10 FilterConnectionHandler AP_FTYPE_PROTOCOL 30

    Apache provides others as well

    Philippe M. ChiassonInput and Output Filters Slide 123

  • 6.4.2 PerlInputFilterHandlerThe PerlInputFilterHandler handler registers a filter forinput filtering.

    This handler is of type VOID.

    The handler’s configuration scope is DIR

    Philippe M. ChiassonInput and Output Filters Slide 124

  • 6.4.3 PerlOutputFilterHandlerThe PerlOutputFilterHandler handler registers andconfigures output filters.

    This handler is of type VOID.

    The handler’s configuration scope is DIR

    Philippe M. ChiassonInput and Output Filters Slide 125

  • 6.4.4 PerlSetInputFiltermod_perl equivalent for SetInputFilter

    makes sure that mod_perl and non-mod_perl input filters ofthe same priority get inserted in the order they are configured

    Philippe M. ChiassonInput and Output Filters Slide 126

  • For example:

    PerlSetInputFilter FILTER_FOO PerlInputFilterHandler MyApache::FilterInputFoo

    response handler /\ FILTER_FOO /\ MyApache::FilterInputFoo /\ core input filters /\ network

    Philippe M. ChiassonInput and Output Filters Slide 127

  • 6.4.5 PerlSetOutputFiltermod_perl equivalent for SetOutputFilter

    makes sure that mod_perl and non-mod_perl output filters ofthe same priority get inserted in the order they are configured

    Philippe M. ChiassonInput and Output Filters Slide 128

  • For example:

    PerlSetOutputFilter INCLUDES PerlOutputFilterHandler MyApache::FilterOutputFoo

    response handler \/ INCLUDES \/ MyApache::FilterOutputFoo \/ core output filters \/ network

    Philippe M. ChiassonInput and Output Filters Slide 129

  • If filters have different priorities the insertion order might be different:

    PerlSetOutputFilter DEFLATE PerlSetOutputFilter INCLUDES PerlOutputFilterHandler MyApache::FilterOutputFoo

    response handler \/ INCLUDES \/ MyApache::FilterOutputFoo \/ DEFLATE \/ core output filters \/ network

    Philippe M. ChiassonInput and Output Filters Slide 130

  • 6.4.6 HTTP Request vs. Connection Filters

    method attributes set the filter type:

    sub handler : FilterRequestHandler { ... } sub handler : FilterConnectionHandler { ... }

    Philippe M. ChiassonInput and Output Filters Slide 131

  • HTTP Request filter handlers are declared using the FilterRequestHandler attribute.

    HTTP request input and output filters skeleton:

    package MyApache::FilterRequestFoo; use base qw(Apache::Filter); sub input : FilterRequestHandler { my($f, $bb, $mode, $block, $readbytes) = @_; #... } sub output : FilterRequestHandler { my($f, $bb) = @_; #... } 1;

    Philippe M. ChiassonInput and Output Filters Slide 132

  • If the attribute is not specified, the default FilterRequestHandler attribute is assumed.

    Filters specifying subroutine attributes must sub-class Apache::Filter, others only need to:

    use Apache::Filter ();

    Philippe M. ChiassonInput and Output Filters Slide 133

  • Request filters are usually configured in the orequivalent sections:

    PerlModule MyApache::FilterRequestFoo PerlModule MyApache::NiceResponse SetHandler modperl PerlResponseHandler MyApache::NiceResponse PerlInputFilterHandler MyApache::FilterRequestFoo::input PerlOutputFilterHandler MyApache::FilterRequestFoo::output

    Philippe M. ChiassonInput and Output Filters Slide 134

  • Connection filter handlers are declared using the FilterConnectionHandler attribute.

    Connection input and output filters skeleton:

    package MyApache::FilterConnectionBar; use base qw(Apache::Filter); sub input : FilterConnectionHandler { my($f, $bb, $mode, $block, $readbytes) = @_; #... } sub output : FilterConnectionHandler { my($f, $bb) = @_; #... } 1;

    Philippe M. ChiassonInput and Output Filters Slide 135

  • This time the configuration must be done outside the or equivalent sections,

    usually within the or the global server configuration:

    Listen 8005 PerlModule MyApache::FilterConnectionBar PerlModule MyApache::NiceResponse PerlInputFilterHandler MyApache::FilterConnectionBar::input PerlOutputFilterHandler MyApache::FilterConnectionBar::output SetHandler modperl PerlResponseHandler MyApache::NiceResponse

    Philippe M. ChiassonInput and Output Filters Slide 136

  • For HTTP requests the only difference between connectionfilters and request filters is that the former see everything: theheaders and the body, whereas the latter see only the body.

    mod_perl provides two interfaces to filtering:

    a direct mapping to buckets and bucket brigades

    and a simpler, stream-oriented interface

    Following examples will explain the difference

    Philippe M. ChiassonInput and Output Filters Slide 137

  • 6.4.7 Filter Initialization PhaseThere is a special attribute duet FilterHasInitHandler/FilterInitHandler but it’s leftfor your offline reading.

    Philippe M. ChiassonInput and Output Filters Slide 138

  • 6.5 All-in-One FilterThe MyApache::FilterSnoop handler silently snoops onthe data that goes through request and connection filters, inthe input and output modes.

    First let’s develop a simple response handler that simplydumps the request’s args and content as strings:

    package MyApache::Dump; use strict; use warnings FATAL => ’all’; use Apache::RequestRec (); use Apache::RequestIO ();

    Philippe M. ChiassonInput and Output Filters Slide 139

  • use Apache::Const -compile => qw(OK M_POST); sub handler { my $r = shift; $r->content_type(’text/plain’); $r->print("args:\n", $r->args, "\n"); if ($r->method_number == Apache::M_POST) { my $data = content($r); $r->print("content:\n$data\n"); } return Apache::OK; }

    Philippe M. ChiassonInput and Output Filters Slide 140

  • sub content { # see your handouts, the details are unimportant here } 1;

    Philippe M. ChiassonInput and Output Filters Slide 141

  • which is configured as:

    PerlModule MyApache::Dump SetHandler modperl PerlResponseHandler MyApache::Dump

    Philippe M. ChiassonInput and Output Filters Slide 142

  • If we issue the following request:

    % echo "mod_perl rules" | POST ’http://localhost:8002/dump?foo=1&bar=2’

    the response will be:

    args: foo=1&bar=2 content: mod_perl rules

    As you can see it simply dumped the query string and theposted data.

    Philippe M. ChiassonInput and Output Filters Slide 143

  • Now let’s write the snooping filter:

    package MyApache::FilterSnoop; use strict; use warnings; use base qw(Apache::Filter); use Apache::FilterRec (); use APR::Brigade (); use APR::Bucket (); use APR::BucketType (); use Apache::Const -compile => qw(OK DECLINED); use APR::Const -compile => ’:common’; sub connection : FilterConnectionHandler { snoop("connection", @_) } sub request : FilterRequestHandler { snoop("request", @_) }

    Philippe M. ChiassonInput and Output Filters Slide 144

  • sub snoop { my $type = shift; my($f, $bb, $mode, $block, $readbytes) = @_; # filter args # $mode, $block, $readbytes are passed only for input filters my $stream = defined $mode ? "input" : "output"; # read the data and pass-through the bucket brigades unchanged if (defined $mode) { # input filter my $rv = $f->next->get_brigade($bb, $mode, $block, $readbytes); return $rv unless $rv == APR::SUCCESS; bb_dump($type, $stream, $bb); } else { # output filter bb_dump($type, $stream, $bb); my $rv = $f->next->pass_brigade($bb); return $rv unless $rv == APR::SUCCESS; } return Apache::OK; }

    Philippe M. ChiassonInput and Output Filters Slide 145

  • sub bb_dump { my($type, $stream, $bb) = @_; my @data; for (my $b = $bb->first; $b; $b = $bb->next($b)) { $b->read(my $bdata); push @data, $b->type->name, $bdata; } # send the sniffed info to STDERR so not to interfere with normal # output my $direction = $stream eq ’output’ ? ">>>" : "

  • We want to use this somewhat complicated filter to visualizehow various kind of filters work.

    Since this module combines several kind of filters it’s the bestto try to understand its implementation after you understandstandalone filters’ implementation.

    At this stage what’s important is to see it at work.

    Philippe M. ChiassonInput and Output Filters Slide 147

  • Let’s snoop on connection and request filter levels in bothdirections by applying the following configuration:

    Listen 8008 PerlModule MyApache::FilterSnoop PerlModule MyApache::Dump # Connection filters PerlInputFilterHandler MyApache::FilterSnoop::connection PerlOutputFilterHandler MyApache::FilterSnoop::connection SetHandler modperl PerlResponseHandler MyApache::Dump # Request filters PerlInputFilterHandler MyApache::FilterSnoop::request PerlOutputFilterHandler MyApache::FilterSnoop::request

    Philippe M. ChiassonInput and Output Filters Slide 148

  • If we issue the following request:

    % echo "mod_perl rules" | POST ’http://localhost:8008/dump?foo=1&bar=2’

    the response doesn’t get affected by the snooping filter

    though we can see all the diagnostics in error_log

    Philippe M. ChiassonInput and Output Filters Slide 149

  • First we can see the connection input filter at work, as itprocesses the HTTP headers.

    We can see that for this request each header is put into aseparate brigade with a single bucket.

    The data is conveniently enclosed by [] so you can see thenew line characters as well.

  • [Content-Length: 14 ]

  • So far all the buckets were of the HEAP type, meaning thatthey were allocated from the heap memory.

    Notice that the HTTP request input filters will never see thebucket brigades with HTTP headers, as it has been consumed bythe last core connection filter.

    Philippe M. ChiassonInput and Output Filters Slide 153

  • The following two entries are generated when MyApache::Dump::handler reads the POSTed content:

  • Both filters see the same data, since they don’t modify it

    The bucket of type EOS indicates the end of stream.

    Philippe M. ChiassonInput and Output Filters Slide 155

  • Next we can see that MyApache::Dump::handler hasgenerated its response.

    However only the request output filter is filtering it at this point:

    >>> request output filter o bucket 1: TRANSIENT [args: foo=1&bar=2 content: mod_perl rules ]

    Philippe M. ChiassonInput and Output Filters Slide 156

  • Next, Apache injects the HTTP headers:

    >>> connection output filter o bucket 1: HEAP [HTTP/1.1 200 OK Date: Fri, 04 Jun 2004 09:13:26 GMT Server: Apache/2.0.50-dev (Unix) mod_perl/1.99_15-dev Perl/v5.8.4 mod_ssl/2.0.50-dev OpenSSL/0.9.7c DAV/2 Connection: close Transfer-Encoding: chunked Content-Type: text/plain; charset=ISO-8859-1 ]

    Philippe M. ChiassonInput and Output Filters Slide 157

  • the first response body’s brigade inside the connection output filter:

    >>> connection output filter o bucket 1: TRANSIENT [2b ] o bucket 2: TRANSIENT [args: foo=1&bar=2 content: mod_perl rules ] o bucket 3: IMMORTAL [ ]

    Philippe M. ChiassonInput and Output Filters Slide 158

  • Finally the output is flushed,

    to make sure that any buffered output is sent to the client:

    >>> connection output filter o bucket 1: IMMORTAL [0 ] o bucket 2: EOS []

    Philippe M. ChiassonInput and Output Filters Slide 159

  • This module helps to understand that each filter handler canbe called many time during each request and connection.

    It’s called for each bucket brigade.

    the HTTP request input filter is called only if there is somePOSTed data to read

    If you run the same request without POSTing any data orsimply running a GET request, the request input filter won’t be called.

    Philippe M. ChiassonInput and Output Filters Slide 160

  • 6.6 Input Filtersmod_perl supports 2 kinds of input filters:

    1. Connection input filters

    2. HTTP Request input filters

    Philippe M. ChiassonInput and Output Filters Slide 161

  • 6.6.1 Connection Input FiltersLet’s write a poor man’s s/GET/HEAD/ rewrite handler

    The handler looks for the data like:

    GET /perl/test.pl HTTP/1.1

    and turns it into:

    HEAD /perl/test.pl HTTP/1.1

    Philippe M. ChiassonInput and Output Filters Slide 162

  • package MyApache::InputFilterGET2HEAD; # 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’;

    Philippe M. ChiassonInput and Output Filters Slide 163

  • sub handler : FilterConnectionHandler { # my($f, $bb, $mode, $block, $readbytes) = @_; return Apache::DECLINED if $f->ctx; my $rv = $f->next->get_brigade($bb, $mode, $block, $readbytes); return $rv unless $rv == APR::SUCCESS; my $ba = $f->c->bucket_alloc; for (my $b = $bb->first; $b; $b = $bb->next($b)) { $b->read(my $data); warn("data: $data\n"); if ($data and $data =~ s|^GET|HEAD|) { my $bn = APR::Bucket->new($ba, $data); $b->insert_after($bn); $b->remove; # no longer needed $f->ctx(1); # flag that that we have done the job last; } } Apache::OK; } 1;

    Philippe M. ChiassonInput and Output Filters Slide 164

  • For example, consider the following response handler:

    package MyApache::RequestType; # use Apache::RequestIO (); use Apache::RequestRec (); use Apache::Response (); use Apache::Const -compile => ’OK’; sub handler { my $r = shift; $r->content_type(’text/plain’); my $response = "the request type was " . $r->method; $r->set_content_length(length $response); $r->print($response); Apache::OK; } 1;

    Philippe M. ChiassonInput and Output Filters Slide 165

  • which returns to the client the request type it has issued.

    In the case of the HEAD request Apache will discard theresponse body, but it’ll will still set the correct Content-Length header, which will be 24 in case of the GET request and 25 for HEAD.

    Philippe M. ChiassonInput and Output Filters Slide 166

  • Therefore if this response handler is configured as:

    Listen 8005 SetHandler modperl PerlResponseHandler +MyApache::RequestType

    and a GET request is issued to /:

    panic% perl -MLWP::UserAgent -le \ ’$r = LWP::UserAgent->new()->get("http://localhost:8005/"); \ print $r->headers->content_length . ": ". $r->content’ 24: the request type was GET

    Philippe M. ChiassonInput and Output Filters Slide 167

  • where the response’s body is:

    the request type was GET

    And the Content-Length header is set to 24.

    Philippe M. ChiassonInput and Output Filters Slide 168

  • However if we enable the MyApache::InputFilterGET2HEAD input connection filter:

    Listen 8005 PerlInputFilterHandler +MyApache::InputFilterGET2HEAD SetHandler modperl PerlResponseHandler +MyApache::RequestType

    And issue the same GET request, we get only:

    25:

    Philippe M. ChiassonInput and Output Filters Slide 169

  • which means that the body was discarded by Apache,because our filter turned the GET request into a HEAD request.

    If Apache wasn’t discarding the body on HEAD, the responsewould be:

    the request type was HEAD

    that’s why the content length is reported as 25 and not 24 asin the real GET request.

    Philippe M. ChiassonInput and Output Filters Slide 170

  • 6.6.2 HTTP Request Input FiltersRequest filters are similar to connection filters, but have anaccess to a request object and they don’t see the headers.

    Philippe M. ChiassonInput and Output Filters Slide 171

  • 6.6.3 Bucket Brigade-based Input Filters

    Here is the request input filter that lowercases the request’s body:

    package MyApache::InputRequestFilterLC; # use strict; use warnings; use base qw(Apache::Filter); use Apache::Connection (); use APR::Brigade (); use APR::Bucket (); use Apache::Const -compile => ’OK’; use APR::Const -compile => ’:common’;

    Philippe M. ChiassonInput and Output Filters Slide 172

  • sub handler : FilterRequestHandler { my($f, $bb, $mode, $block, $readbytes) = @_; my $bb_ctx = APR::Brigade->new($f->c->pool, $f->c->bucket_alloc); my $rv = $f->next->get_brigade($bb_ctx, $mode, $block, $readbytes); return $rv unless $rv == APR::SUCCESS; my $ba = $f->c->bucket_alloc; while (!$bb_ctx->is_empty) { my $b = $bb_ctx->first; $b->remove; if ($b->is_eos) { $bb->insert_tail($b); last; } $b->read(my $data); $b = APR::Bucket->new($ba, lc $data); $bb->insert_tail($b); } Apache::OK; } 1;

    Philippe M. ChiassonInput and Output Filters Slide 173

  • the MyApache::Dump response handler dumps the querystring and the content body as a response

    Using the following configuration:

    SetHandler modperl PerlResponseHandler +MyApache::Dump PerlInputFilterHandler +MyApache::InputRequestFilterLC

    Philippe M. ChiassonInput and Output Filters Slide 174

  • When issuing a POST request:

    % echo "mOd_pErl RuLeS" | POST ’http://localhost:8002/lc_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 POSTedbody, before the content handler received it.

    The query string didn’t change, since the filter didn’t operateon headers.

    Philippe M. ChiassonInput and Output Filters Slide 175

  • 6.6.4 Stream-oriented Input Filters package MyApache::InputRequestFilterLC2; # use base qw(Apache::Filter); use Apache::Const -compile => ’OK’; sub handler : FilterRequestHandler { my $f = shift; while ($f->read(my $buffer, 1024)) { $f->print(lc $buffer); } Apache::OK; } 1;

    Philippe M. ChiassonInput and Output Filters Slide 176

  • Configuration:

    SetHandler modperl PerlResponseHandler +MyApache::Dump PerlInputFilterHandler +MyApache::InputRequestFilterLC2

    We get the same results as from using the bucket brigades filter

    Philippe M. ChiassonInput and Output Filters Slide 177

  • 6.7 Output Filtersmod_perl supports 2 kinds of output filters:

    1. Connection input filters

    2. HTTP Request input filters

    Philippe M. ChiassonInput and Output Filters Slide 178

  • 6.7.1 Connection Output FiltersConnection filters are similar to HTTP Request filters,

    but can see all the data that is going through the server.

    We will concentrate on HTTP request filters

    Philippe M. ChiassonInput and Output Filters Slide 179

  • 6.7.2 HTTP Request Output FiltersOutput filters can be written using the bucket brigadesmanipulation or the simplified stream-oriented interface.

    Here is a response handler that send two lines of output in asingle string:

    1. numerals: 1234567890

    2. the English alphabet

    Philippe M. ChiassonInput and Output Filters Slide 180

  • package MyApache::SendAlphaNum; # use Apache::RequestRec (); use Apache::RequestIO (); use Apache::Const -compile => qw(OK);

    sub handler { my $r = shift; $r->content_type(’text/plain’); $r->print(1..9, "0\n"); $r->print(’a’..’z’, "\n"); Apache::OK; } 1;

    Philippe M. ChiassonInput and Output Filters Slide 181

  • The purpose of our request output filter is to reverse everyline of the response, preserving the new line characters intheir places.

    Since we want to reverse characters only in the responsebody we will use the HTTP request output filter.

    Philippe M. ChiassonInput and Output Filters Slide 182

  • 6.7.3 Stream-oriented Output Filter package MyApache::FilterReverse1; # use Apache::Filter (); use Apache::Const -compile => qw(OK); sub handler : FilterRequestHandler { my $f = shift; while ($f->read(my $buffer, 1024)) { for (split "\n", $buffer) { $f->print(scalar reverse $_); $f->print("\n"); } } Apache::OK; } 1;

    Philippe M. ChiassonInput and Output Filters Slide 183

  • Add the following configuration to httpd.conf:

    PerlModule MyApache::FilterReverse1 PerlModule MyApache::SendAlphaNum SetHandler modperl PerlResponseHandler MyApache::SendAlphaNum PerlOutputFilterHandler MyApache::FilterReverse1

    Philippe M. ChiassonInput and Output Filters Slide 184

  • Now when a request to /reverse1 is made, the responsehandler MyApache::SendAlphaNum::handler() sends:

    1234567890 abcdefghijklmnopqrstuvwxyz

    as a response and the output filter handler MyApache::FilterReverse1::handler reverses thelines, so the client gets:

    0987654321 zyxwvutsrqponmlkjihgfedcba

    Philippe M. ChiassonInput and Output Filters Slide 185

  • 6.7.4 Bucket Brigade-based Output Filters

    The bucket brigades filtering API implementation:

    package MyApache::FilterReverse2; # 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($f, $bb) = @_;

    Philippe M. ChiassonInput and Output Filters Slide 186

  • my $bb_ctx = APR::Brigade->new($f->c->pool, $f->c->bucket_alloc); # my $ba = $f->c->bucket_alloc; while (!$bb->is_empty) { my $b = $bb->first; $b->remove; if ($b->is_eos) { $bb_ctx->insert_tail($b); last; } if ($b->read(my $data)) { $data = join "", map {scalar(reverse $_), "\n"} split "\n", $data; $b = APR::Bucket->new($ba, $data); } $bb_ctx->insert_tail($b); } my $rv = $f->next->pass_brigade($bb_ctx); return $rv unless $rv == APR::SUCCESS; Apache::OK; } 1;

    Philippe M. ChiassonInput and Output Filters Slide 187

  • And the corresponding configuration:

    PerlModule MyApache::FilterReverse2 PerlModule MyApache::SendAlphaNum SetHandler modperl PerlResponseHandler MyApache::SendAlphaNum PerlOutputFilterHandler MyApache::FilterReverse2

    Philippe M. ChiassonInput and Output Filters Slide 188

  • Now when a request to /reverse2 is made, the client gets:

    0987654321 zyxwvutsrqponmlkjihgfedcba

    as expected.

    Philippe M. ChiassonInput and Output Filters Slide 189

  • Philippe M. ChiassonHTTP Handlers Slide 190

  • 7 HTTP Handlers

    Philippe M. ChiassonHTTP Handlers Slide 191

  • 7.1 AboutHTTP Request Cycle Phases

    PerlPostReadRequestHandler

    PerlTransHandler

    PerlMapToStorageHandler

    PerlHeaderParserHandler

    PerlInitHandler

    PerlAccessHandler

    Philippe M. ChiassonHTTP Handlers Slide 192

  • PerlAuthenHandler

    PerlAuthzHandler

    PerlTypeHandler

    PerlFixupHandler

    PerlResponseHandler

    PerlLogHandler

    PerlCleanupHandler

    Philippe M. ChiassonHTTP Handlers Slide 193

  • 7.2 HTTP Request Cycle PhasesAlmost indentical to mod_perl 1.0. The differences are:

    new phase: PerlMapToStorageHandler

    rename: PerlHandler => PerlResponseHandler

    PerlResponseHandler now includes filtering

    Here is the HTTP request life cycle in mod_perl 2.0:

    Philippe M. ChiassonHTTP Handlers Slide 194

  • Philippe M. ChiassonHTTP Handlers Slide 195

  • an HTTP request is processes by 12 phases:

    1. PerlPostReadRequestHandler (PerlInitHandler)

    2. PerlTransHandler

    3. PerlMapToStorageHandler

    4. PerlHeaderParserHandler (PerlInitHandler)

    5. PerlAccessHandler

    6. PerlAuthenHandler

    7. PerlAuthzHandler

    Philippe M. ChiassonHTTP Handlers Slide 196

  • 8. PerlTypeHandler

    9. PerlFixupHandler

    10. PerlResponseHandler

    11. PerlLogHandler

    12. PerlCleanupHandler

    Philippe M. ChiassonHTTP Handlers Slide 197

  • 7.2.1 PerlPostReadRequestHandlerThe post_read_request phase is the first request phase andhappens immediately after the request has been read andHTTP headers were parsed.

    This phase is usually used to do processing that must happenonce per request.

    For example Apache::Reload is usually invoked at thisphase to reload modified Perl modules.

    This phase is of type RUN_ALL.

    The handler’s configuration scope is SRV

    Philippe M. ChiassonHTTP Handlers Slide 198

  • The following ModPerl::Registry script prints when thelast time httpd.conf has been modified, compared to the startof the request process time:

    use strict; use warnings; use Apache::ServerUtil (); use Apache::RequestIO (); use File::Spec::Functions qw(catfile); my $r = shift; $r->content_type(’text/plain’); my $conf_file = catfile Apache::ServerUtil::server_root, "conf", "httpd.conf"; printf "$conf_file is %0.2f minutes old\n", 60*24*(-M $conf_file);

    Philippe M. ChiassonHTTP Handlers Slide 199

  • The script reports incorrect time most of the time

    Because -M reports the difference between file’s modificationtime and $^T

    Under mod_perl $^T is set when the process starts anddoesn’t change after that.

    Solution: Reset $^T on each request

    Philippe M. ChiassonHTTP Handlers Slide 200

  • package MyApache::TimeReset; use strict; use warnings; use Apache::RequestRec (); use Apache::Const -compile => ’OK’; sub handler { my $r = shift; $^T = $r->request_time; return Apache::OK; } 1;

    Philippe M. ChiassonHTTP Handlers Slide 201

  • We could do:

    $^T = time();

    But $r->request_time already stores the request’s starttime, so we get it without performing an additional system call.

    Philippe M. ChiassonHTTP Handlers Slide 202

  • To enable it just add to httpd.conf:

    PerlPostReadRequestHandler MyApache::TimeReset

    either to the global section, or to the section ifyou want this handler to be run only for a specific virtual host.

    Philippe M. ChiassonHTTP Handlers Slide 203

  • 7.2.2 PerlTransHandlerThe translate phase is used to manipulate a request’s URI

    If no custom handler is provided, the server’s standardtranslation rules (e.g., Alias directives, mod_rewrite, etc.)will continue to be used.

    Also used to modify the URI itself and the request method.

    This is also a good place to register new handlers for thefollowing phases based on the URI.

    This phase is of type RUN_FIRST / config scope is SRV.

    Philippe M. ChiassonHTTP Handlers Slide 204

  • mod_rewrite ala mod_perl :

    e.g. if the previously static pages are now autogenerated, and

    http://example.com/news/20021031/09/index.html _

    is now handled by:

    http://example.com/perl/news.pl?date=20021031&id=09&page=index.html

    we can keep using the old URI, transparent to news.pl and users

    Philippe M. ChiassonHTTP Handlers Slide 205

  • package MyApache::RewriteURI; use strict; use warnings; use Apache::RequestRec (); use Apache::Const -compile => qw(DECLINED); sub handler { my $r = shift; my($date, $id, $page) = $r->uri =~ m|^/news/(\d+)/(\d+)/(.*)|; $r->uri("/perl/news.pl"); $r->args("date=$date&id=$id&page=$page"); return Apache::DECLINED; } 1;

    Philippe M. ChiassonHTTP Handlers Slide 206

  • To configure this module simply add to httpd.conf:

    PerlTransHandler +MyApache::RewriteURI

    Philippe M. ChiassonHTTP Handlers Slide 207

  • 7.2.3 PerlMapToStorageHandlerThe map_to_storage phase is used to translate request’s URIinto a corresponding filename

    If no custom handler is provided, the server will try to walk thefilesystem trying to find what file or directory corresponds tothe request’s URI.

    most likely you want to shortcut this phase for mod_perl

    This phase is of type RUN_FIRST / config scope is SRV.

    Philippe M. ChiassonHTTP Handlers Slide 208

  • The Don’t-waste-time handler:

    package MyApache::NoTranslation; # use strict; use warnings FATAL => ’all’; use Apache::Const -compile => qw(OK); sub handler { my $r = shift; # skip ap_directory_walk stat() calls return Apache::OK; } 1;

    config:

    PerlMapToStorageHandler MyApache::NoTranslation

    Philippe M. ChiassonHTTP Handlers Slide 209

  • same handler but support TRACE calls

    package MyApache::NoTranslation2; # use strict; use warnings FATAL => ’all’; use Apache::RequestRec ();

    use Apache::Const -compile => qw(DECLINED OK M_TRACE); sub handler { my $r = shift; return Apache::DECLINED if $r->method_number == Apache::M_TRACE; # skip ap_directory_walk stat() calls return Apache::OK; } 1;

    Philippe M. ChiassonHTTP Handlers Slide 210

  • Another way to prevent the core translation:

    $r->filename(__FILE__);

    this can be done in PerlTransHandler as well

    Philippe M. ChiassonHTTP Handlers Slide 211

  • 7.2.4 PerlHeaderParserHandlerThe header_parser phase is the first phase to happen afterthe request has been mapped to its (or anequivalent container).

    At this phase the handler can examine the request headersand to take a special action based on these.

    e.g., this phase can be used to block evil clients targetingcertain resources, while few resources were wasted so far.

    This phase is of type RUN_ALL.

    The handler’s configuration scope is DIR.

    Philippe M. ChiassonHTTP Handlers Slide 212

  • Apache handles the HEAD, GET, POST and several otherHTTP methods.

    But you can invent your own methods and make Apacheaccept them.

    e.g., emails are very similar to HTTP messages: they have aset of headers and a body, sometimes a multi-part body.

    MyApache::SendEmail extends HTTP by adding a supportfor the EMAIL method.

    It enables the new extension and pushes the real contenthandler during the PerlHeaderParserHandler phase:

    PerlHeaderParserHandler MyApache::SendEmail

    Philippe M. ChiassonHTTP Handlers Slide 213

  • package MyApache::SendEmail; # use strict; use warnings; use Apache::RequestRec (); use Apache::RequestIO (); use Apache::RequestUtil (); use Apache::Server (); use Apache::Process (); use APR::Table (); use Apache::Const -compile => qw(DECLINED OK); use constant METHOD => ’EMAIL’; use constant SMTP_HOSTNAME => "localhost";

    sub handler { # my $r = shift; return Apache::DECLINED unless $r->method eq METHOD; Apache::RequestUtil::method_register($r->server->process->pconf, METHOD); $r->handler("perl-script");

    Philippe M. ChiassonHTTP Handlers Slide 214

  • $r->push_handlers(PerlResponseHandler => \&send_email_handler); return Apache::OK; } sub send_email_handler { # my $r = shift; my %headers = map {$_ => $r->headers_in->get($_)} qw(To From Subject); my $content = content($r); my $status = send_email(\%headers, \$content); $r->content_type(’text/plain’); $r->print($status ? "ACK" : "NACK"); return Apache::OK; }

    sub send_email { # my($rh_headers, $r_body) = @_; require MIME::Lite; MIME::Lite->send("smtp", SMTP_HOSTNAME, Timeout => 60); my $msg = MIME::Lite->new(%$rh_headers, Data => $$r_body);

    Philippe M. ChiassonHTTP Handlers Slide 215

  • $msg->send; } sub content { # my $r = shift; # unimportant here, see your handouts return $buf; } 1;

    Philippe M. ChiassonHTTP Handlers Slide 216

  • when you extend an HTTP protocol you need to have a clientthat knows how to use the extension.

    So here is a simple client that uses LWP::UserAgent toissue an EMAIL method request over HTTP protocol:

    Philippe M. ChiassonHTTP Handlers Slide 217

  • require LWP::UserAgent; # my $url = "http://localhost:8000/email/"; my %headers = ( From => ’[email protected]’, To => ’[email protected]’, Subject => ’3 weeks in Tibet’, ); my $content = new("EMAIL", $url, $headers, $content); my $res = LWP::UserAgent->new->request($req); print $res->is_success ? $res->content : "failed";

    Philippe M. ChiassonHTTP Handlers Slide 218

  • 7.2.5 PerlInitHandlerWhen configured inside any container directive, except , this handler is an alias for PerlHeaderParserHandler described earlier.

    Otherwise it acts as an alias for PerlPostReadRequestHandler described earlier.

    It is the first handler to be invoked when serving a request.

    This phase is of type RUN_ALL.

    The best example here would be to use Apache::Reloadwhich takes the benefit of this directive.

    Philippe M. ChiassonHTTP Handlers Slide 219

  • Usually Apache::Reload is configured as:

    PerlInitHandler Apache::Reload PerlSetVar ReloadAll Off PerlSetVar ReloadModules "MyApache::*"

    which during the current HTTP request will monitor and reloadall MyApache::* modules that have been modified since thelast HTTP request.

    Philippe M. ChiassonHTTP Handlers Slide 220

  • However if we move the global configuration into a container:

    PerlInitHandler Apache::Reload PerlSetVar ReloadAll Off PerlSetVar ReloadModules "MyApache::*" SetHandler perl-script PerlResponseHandler ModPerl::Registry Options +ExecCGI

    Apache::Reload will reload the modified modules, onlywhen a request to the /devel namespace is issued, because PerlInitHandler plays the role of PerlHeaderParserHandler here.

    Philippe M. ChiassonHTTP Handlers Slide 221

  • 7.2.6 PerlAccessHandlerThe access_checker phase is the first of three handlers thatare involved in what’s known as AAA: Authentication andAuthorization, and Access control.

    This phase can be used to restrict access from a certain IPaddress, time of the day or any other rule not connected tothe user’s identity.

    This phase is of type RUN_ALL.

    The handler’s configuration scope is DIR.

    Philippe M. ChiassonHTTP Handlers Slide 222

  • The concept behind access checker handler is very simple:

    return Apache::FORBIDDEN if the access is not allowed,

    otherwise return Apache::OK.

    Philippe M. ChiassonHTTP Handlers Slide 223

  • This handler denies requests made from IPs on the blacklist:

    package MyApache::BlockByIP; # use Apache::RequestRec (); use Apache::Connection (); use Apache::Const -compile => qw(FORBIDDEN OK); my %bad_ips = map {$_ => 1} qw(127.0.0.1 10.0.0.4); sub handler { my $r = shift; return exists $bad_ips{$r->connection->remote_ip} ? Apache::FORBIDDEN : Apache::OK; } 1;

    Philippe M. ChiassonHTTP Handlers Slide 224

  • To enable the handler simply add it to the container thatneeds to be protected.

    For example to protect an access to the registry scriptsexecuted from the base location /perl add:

    SetHandler perl-script PerlResponseHandler ModPerl::Registry PerlAccessHandler MyApache::BlockByIP Options +ExecCGI

    Philippe M. ChiassonHTTP Handlers Slide 225

  • 7.2.7 PerlAuthenHandlerThe check_user_id (authen) phase is called whenever therequested file or directory is password protected.

    This, in turn, requires that the directory be associated with AuthName, AuthType and at least one require directive.

    This phase is usually used to verify a user’s identification credentials.

    If the credentials are verified to be correct, the handler shouldreturn Apache::OK.

    Otherwise the handler returns Apache::HTTP_UNAUTHORIZED to indicate that the userhas not authenticated successfully.

    Philippe M. ChiassonHTTP Handlers Slide 226

  • When Apache sends the HTTP header with this code, thebrowser will normally pop up a dialog box that prompts the user forlogin information.

    This phase is of type RUN_FIRST.

    The handler’s configuration scope is DIR.

    The following example handler verifies that:

    SECRET_LENGTH == length join " ", $username, $password;

    Philippe M. ChiassonHTTP Handlers Slide 227

  • package MyApache::SecretLengthAuth; # use Apache::Access (); use Apache::RequestUtil (); use Apache::Const -compile => qw(OK DECLINED HTTP_UNAUTHORIZED); use constant SECRET_LENGTH => 14; sub handler { my $r = shift; my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == Apache::OK; return Apache::OK if SECRET_LENGTH == length join " ", $r->user, $password; $r->note_basic_auth_failure; return Apache::HTTP_UNAUTHORIZED; } 1;

    Philippe M. ChiassonHTTP Handlers Slide 228

  • To enable this handler you have to tell Apache:

    what authentication scheme to use (AuthType: Basicor Digest)

    what’s the authentication realm (AuthName: any string)

    the Require directive is needed to specify whichusernames are allowed to authenticate. If you set it to valid-user any username will do.

    Philippe M. ChiassonHTTP Handlers Slide 229

  • SetHandler perl-script PerlResponseHandler ModPerl::Registry PerlAuthenHandler MyApache::SecretLengthAuth Options +ExecCGI AuthType Basic AuthName "The Gate" Require valid-user

    Philippe M. ChiassonHTTP Handlers Slide 230

  • 7.2.8 PerlAuthzHandlerThe auth_checker (authz) phase is used for authorization control.

    This phase requires a successful authentication from theprevious phase, because a username is needed in order todecide whether a user is authorized to access the requested resource.

    As this phase is tightly connected to the authentication phase,the handlers registered for this phase are only called whenthe requested resource is password protected, similar to theauth phase.

    Philippe M. ChiassonHTTP Handlers Slide 231

  • The handler is expected to return:

    Apache::DECLINED to defer the decision,

    Apache::OK to indicate its acceptance of the user’s authorization,

    or Apache::HTTP_UNAUTHORIZED to indicate that theuser is not authorized to access the requested document.

    This phase is of type RUN_FIRST.

    The handler’s configuration scope is DIR.

    Philippe M. ChiassonHTTP Handlers Slide 232

  • The MyApache::SecretResourceAuthz handler grantsaccess to certain resources only to certain users who havealready properly authenticated:

    package MyApache::SecretResourceAuthz; # use strict; use warnings; use Apache::Access (); use Apache::RequestUtil (); use Apache::Const -compile => qw(OK HTTP_UNAUTHORIZED); my %protected = ( ’admin’ => [’gozer’], ’report’ => [qw(gozer boss)], );

    Philippe M. ChiassonHTTP Handlers Slide 233

  • sub handler { # my $r = shift; my $user = $r->user; if ($user) { my($section) = $r->uri =~ m|^/company/(\w+)/|; if (defined $section && exists $protected{$section}) { my $users = $protected{$section}; return Apache::OK if grep { $_ eq $user } @$users; } else { return Apache::OK; } } $r->note_basic_auth_failure; return Apache::HTTP_UNAUTHORIZED; } 1;

    Philippe M. ChiassonHTTP Handlers Slide 234

  • The configuration is similar to PerlAuthenHandler, thistime we just add the PerlAuthzHandler setting. The restdoesn’t change.

    Alias /company/ /home/httpd/httpd-2.0/perl/ SetHandler perl-script PerlResponseHandler ModPerl::Registry PerlAuthenHandler MyApache::SecretLengthAuth PerlAuthzHandler MyApache::SecretResourceAuthz Options +ExecCGI AuthType Basic AuthName "The Secret Gate" Require valid-user

    Philippe M. ChiassonHTTP Handlers Slide 235

  • 7.2.9 PerlTypeHandlerThe type_checker phase is used to set the response MIMEtype (Content-type) and sometimes other bits of documenttype information like the document language.

    e.g., mod_autoindex, which performs automatic directoryindexing, uses this phase to map the filename extensions tothe corresponding icons which will be later used in the listingof files.

    Of course later phases may override the mime type set in this phase.

    This phase is of type RUN_FIRST.

    Philippe M. ChiassonHTTP Handlers Slide 236

  • The handler’s configuration scope is DIR.

    When overriding the default type_checker handler, which isusually the mod_mime handler, don’t forget to set the response handler:

    $r->handler(’perl-script’); # or $r->handler(’modperl’); $r->set_handlers(PerlResponseHandler => \&handler);

    It’s the easiest to leave this stage alone and do any desiredsettings in the fixups phase.

    Philippe M. ChiassonHTTP Handlers Slide 237

  • 7.2.10 PerlFixupHandlerThe fixups phase is happening just before the contenthandling phase.

    It gives the last chance to do things before the response is generated.

    For example in this phase mod_env populates theenvironment with variables configured with SetEnv and PassEnv directives.

    This phase is of type RUN_ALL.

    The handler’s configuration scope is DIR.

    Philippe M. ChiassonHTTP Handlers Slide 238

  • This fixup handler tells Apache at run time which handler andcallback should be used to process the request based on thefile extension of the request’s URI.

    package MyApache::FileExtDispatch; # use strict; use warnings; use Apache::RequestIO (); use Apache::RequestRec (); use Apache::RequestUtil (); use Apache::Const -compile => ’OK’; use constant HANDLER => 0; use constant CALLBACK => 1; my %exts = ( cgi => [’perl-script’, \&cgi_handler], pl => [’modperl’, \&pl_handler ], tt => [’perl-script’, \&tt_handler ], txt => [’default-handler’, undef ], );

    Philippe M. ChiassonHTTP Handlers Slide 239

  • sub handler { # my $r = shift; my($ext) = $r->uri =~ /\.(\w+)$/; $ext = ’txt’ unless defined $ext and exists $exts{$ext}; $r->handler($exts{$ext}->[HANDLER]); if (defined $exts{$ext}->[CALLBACK]) { $r->set_handlers(PerlResponseHandler => $exts{$ext}->[CALLBACK]); } return Apache::OK; } sub cgi_handler { content_handler($_[0], ’cgi’) } sub pl_handler { content_handler($_[0], ’pl’) } sub tt_handler { content_handler($_[0], ’tt’) }

    Philippe M. ChiassonHTTP Handlers Slide 240

  • sub content_handler { # my($r, $type) = @_; $r->content_type(’text/plain’); $r->print("A handler of type ’$type’ was called"); return Apache::OK; } 1;

    Philippe M. ChiassonHTTP Handlers Slide 241

  • Here is how this handler is configured:

    Alias /dispatch/ /home/httpd/httpd-2.0/htdocs/ PerlFixupHandler MyApache::FileExtDispatch

    Notice that there is no need to specify anything, but the fixup handler.

    It applies the rest of the settings dynamically at run-time.

    Philippe M. ChiassonHTTP Handlers Slide 242

  • 7.2.11 PerlResponseHandlerThe handler (response) phase is used for generating the response.

    This is arguably the most important phase and most of theexisting Apache modules do most of their work at this phase.

    This is the only phase that requires two directives under mod_perl:

    SetHandler perl-script PerlResponseHandler MyApache::WorldDomination

    Philippe M. ChiassonHTTP Handlers Slide 243

  • SetHandler set to perl-script or modperl tells Apachethat mod_perl is going to handle the response generation.

    PerlResponseHandler tells mod_perl which callback isgoing to do the job.

    This phase is of type RUN_FIRST.

    The handler’s configuration scope is DIR.

    Philippe M. ChiassonHTTP Handlers Slide 244

  • This handler prints itself:

    package MyApache::Deparse; use strict; use warnings; use Apache::RequestRec (); use Apache::RequestIO (); use B::Deparse (); use Apache::Const -compile => ’OK’; sub handler { my $r = shift; $r->content_type(’text/plain’); $r->print(’sub handler ’, B::Deparse->new->coderef2text(\&handler)); return Apache::OK; } 1;

    Philippe M. ChiassonHTTP Handlers Slide 245

  • To enable this handler add to httpd.conf:

    SetHandler modperl PerlResponseHandler MyApache::Deparse

    Philippe M. ChiassonHTTP Handlers Slide 246

  • Now when the server is restarted and we issue a request to http://localhost/deparse we get the following response:

    sub handler { package MyApache::Deparse; use warnings; use strict ’refs’; my $r = shift @_; $r->content_type(’text/plain’); $r->print(’sub handler ’, ’B::Deparse’->new->coderef2text(\&handler)); return 0; }

    If you compare it to the source code, it’s pretty much thesame code. B::Deparse is fun to play with!

    Philippe M. ChiassonHTTP Handlers Slide 247

    http://localhost/deparse

  • 7.2.12 PerlLogHandlerThe log_transaction phase is always executed.

    Even if the previous phases were aborted.

    At this phase log handle