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 Example

  • Upload
    others

  • View
    20

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Tutorial Slides: mod perl 2.0 By Example

Tutorial Slides: mod_perl 2.0 By Example

by Philippe M. Chiasson http://gozer.ectoplasm.org/<[email protected]>

TicketMaster

ApacheCon US 2004Saturday, November 13th 2004

Las Vegas, Nevada, USA

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

Page 2: Tutorial Slides: mod perl 2.0 By Example

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

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

Page 3: Tutorial Slides: mod perl 2.0 By Example

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

Page 4: Tutorial Slides: mod perl 2.0 By Example

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

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

Page 5: Tutorial Slides: mod perl 2.0 By Example

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

Page 6: Tutorial Slides: mod perl 2.0 By Example

1 Getting Your Feet Wet Withmod_perl 2.0

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

Page 7: Tutorial Slides: mod perl 2.0 By Example

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

Page 8: Tutorial Slides: mod perl 2.0 By Example

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

Page 9: Tutorial Slides: mod perl 2.0 By Example

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

Page 10: Tutorial Slides: mod perl 2.0 By Example

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

Page 11: Tutorial Slides: mod perl 2.0 By Example

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

Page 12: Tutorial Slides: mod perl 2.0 By Example

1.6 Registry ScriptsConfiguration

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

Restart the server

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

Page 13: Tutorial Slides: mod perl 2.0 By Example

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

Page 14: Tutorial Slides: mod perl 2.0 By Example

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

Page 15: Tutorial Slides: mod perl 2.0 By Example

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:

<Location /rocks> SetHandler perl-script PerlResponseHandler MyApache::Rocks </Location>

Restart server

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

Page 16: Tutorial Slides: mod perl 2.0 By Example

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

Page 17: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonNew Concepts Slide 17

Page 18: Tutorial Slides: mod perl 2.0 By Example

2 New Concepts

Philippe M. ChiassonNew Concepts Slide 18

Page 19: Tutorial Slides: mod perl 2.0 By Example

2.1 AboutExceptions

Bucket Brigades

Philippe M. ChiassonNew Concepts Slide 19

Page 20: Tutorial Slides: mod perl 2.0 By Example

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

Page 21: Tutorial Slides: mod perl 2.0 By Example

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

Page 22: Tutorial Slides: mod perl 2.0 By Example

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

Page 23: Tutorial Slides: mod perl 2.0 By Example

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

Page 24: Tutorial Slides: mod perl 2.0 By Example

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

Page 25: Tutorial Slides: mod perl 2.0 By Example

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

Page 26: Tutorial Slides: mod perl 2.0 By Example

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

Page 27: Tutorial Slides: mod perl 2.0 By Example

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

Page 28: Tutorial Slides: mod perl 2.0 By Example

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

Page 29: Tutorial Slides: mod perl 2.0 By Example

More about BBs when we talk about protocols and filters

Philippe M. ChiassonNew Concepts Slide 29

Page 30: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonIntroducing mod_perl Handlers Slide 30

Page 31: Tutorial Slides: mod perl 2.0 By Example

3 Introducing mod_perlHandlers

Philippe M. ChiassonIntroducing mod_perl Handlers Slide 31

Page 32: Tutorial Slides: mod perl 2.0 By Example

3.1 AboutHandler Anatomy

mod_perl Handlers Categories

Single Phase’s Multiple Handlers Behavior

Philippe M. ChiassonIntroducing mod_perl Handlers Slide 32

Page 33: Tutorial Slides: mod perl 2.0 By Example

3.2 Handler AnatomyApache distinguishes between numerous phases

Each phase provides a hook: ap_hook_<phase_name>

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

Page 34: Tutorial Slides: mod perl 2.0 By Example

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

Page 35: Tutorial Slides: mod perl 2.0 By Example

Configuring the response handler:

PerlModule MyApache::CurrentTime <Location /time> SetHandler modperl PerlResponseHandler MyApache::CurrentTime </Location>

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

Philippe M. ChiassonIntroducing mod_perl Handlers Slide 35

Page 36: Tutorial Slides: mod perl 2.0 By Example

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

Page 37: Tutorial Slides: mod perl 2.0 By Example

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

Page 38: Tutorial Slides: mod perl 2.0 By Example

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

Page 39: Tutorial Slides: mod perl 2.0 By Example

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

Page 40: Tutorial Slides: mod perl 2.0 By Example

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

Page 41: Tutorial Slides: mod perl 2.0 By Example

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

Page 42: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonServer Life Cycle Handlers Slide 42

Page 43: Tutorial Slides: mod perl 2.0 By Example

4 Server Life Cycle Handlers

Philippe M. ChiassonServer Life Cycle Handlers Slide 43

Page 44: Tutorial Slides: mod perl 2.0 By Example

4.1 AboutServer Life Cycle

Startup Phases Demonstration Module

PerlOpenLogsHandler

PerlPostConfigHandler

PerlChildInitHandler

PerlChildExitHandler

Philippe M. ChiassonServer Life Cycle Handlers Slide 44

Page 45: Tutorial Slides: mod perl 2.0 By Example

4.2 2.0 Server Life Cycle

Philippe M. ChiassonServer Life Cycle Handlers Slide 45

Page 46: Tutorial Slides: mod perl 2.0 By Example

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

Page 47: Tutorial Slides: mod perl 2.0 By Example

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

Page 48: Tutorial Slides: mod perl 2.0 By Example

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

Page 49: Tutorial Slides: mod perl 2.0 By Example

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

Page 50: Tutorial Slides: mod perl 2.0 By Example

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

Page 51: Tutorial Slides: mod perl 2.0 By Example

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

Page 52: Tutorial Slides: mod perl 2.0 By Example

% 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

Page 53: Tutorial Slides: mod perl 2.0 By Example

% 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

Page 54: Tutorial Slides: mod perl 2.0 By Example

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

Page 55: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonProtocol Handlers Slide 55

Page 56: Tutorial Slides: mod perl 2.0 By Example

5 Protocol Handlers

Philippe M. ChiassonProtocol Handlers Slide 56

Page 57: Tutorial Slides: mod perl 2.0 By Example

5.1 AboutConnection Cycle Phases

PerlPreConnectionHandler

PerlProcessConnectionHandler

Socket-based Protocol Module

Bucket Brigades-based Protocol Module

Philippe M. ChiassonProtocol Handlers Slide 57

Page 58: Tutorial Slides: mod perl 2.0 By Example

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

Page 59: Tutorial Slides: mod perl 2.0 By Example

Connection Life Cycle diagram:

Philippe M. ChiassonProtocol Handlers Slide 59

Page 60: Tutorial Slides: mod perl 2.0 By Example

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

Page 61: Tutorial Slides: mod perl 2.0 By Example

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

Page 62: Tutorial Slides: mod perl 2.0 By Example

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

Page 63: Tutorial Slides: mod perl 2.0 By Example

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

Page 64: Tutorial Slides: mod perl 2.0 By Example

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

Page 65: Tutorial Slides: mod perl 2.0 By Example

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

Page 66: Tutorial Slides: mod perl 2.0 By Example

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

Page 67: Tutorial Slides: mod perl 2.0 By Example

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

Page 68: Tutorial Slides: mod perl 2.0 By Example

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

Page 69: Tutorial Slides: mod perl 2.0 By Example

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

Page 70: Tutorial Slides: mod perl 2.0 By Example

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

Page 71: Tutorial Slides: mod perl 2.0 By Example

Configuration :

Listen 8010 <VirtualHost _default_:8010> PerlModule MyApache::EchoSocket PerlProcessConnectionHandler MyApache::EchoSocket </VirtualHost>

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

Philippe M. ChiassonProtocol Handlers Slide 71

Page 72: Tutorial Slides: mod perl 2.0 By Example

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

Page 73: Tutorial Slides: mod perl 2.0 By Example

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

Page 74: Tutorial Slides: mod perl 2.0 By Example

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

Page 75: Tutorial Slides: mod perl 2.0 By Example

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

Page 76: Tutorial Slides: mod perl 2.0 By Example

Configuration :

Listen 8011 <VirtualHost _default_:8011> PerlModule MyApache::EchoBB PerlProcessConnectionHandler MyApache::EchoBB PerlOutputFilterHandler MyApache::EchoBB::lowercase_filter </VirtualHost>

Philippe M. ChiassonProtocol Handlers Slide 76

Page 77: Tutorial Slides: mod perl 2.0 By Example

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

Page 78: Tutorial Slides: mod perl 2.0 By Example

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

Page 79: Tutorial Slides: mod perl 2.0 By Example

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

Page 80: Tutorial Slides: mod perl 2.0 By Example

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

Page 81: Tutorial Slides: mod perl 2.0 By Example

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

Page 82: Tutorial Slides: mod perl 2.0 By Example

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

Page 83: Tutorial Slides: mod perl 2.0 By Example

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

Page 84: Tutorial Slides: mod perl 2.0 By Example

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

Page 85: Tutorial Slides: mod perl 2.0 By Example

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

Page 86: Tutorial Slides: mod perl 2.0 By Example

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

Page 87: Tutorial Slides: mod perl 2.0 By Example

We will discuss the filters next

Philippe M. ChiassonProtocol Handlers Slide 87

Page 88: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonInput and Output Filters Slide 88

Page 89: Tutorial Slides: mod perl 2.0 By Example

6 Input and Output Filters

Philippe M. ChiassonInput and Output Filters Slide 89

Page 90: Tutorial Slides: mod perl 2.0 By Example

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

Page 91: Tutorial Slides: mod perl 2.0 By Example

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

Page 92: Tutorial Slides: mod perl 2.0 By Example

All-in-One Filter

Input Filters Examples

Output Filters Examples

Philippe M. ChiassonInput and Output Filters Slide 92

Page 93: Tutorial Slides: mod perl 2.0 By Example

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

Page 94: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonInput and Output Filters Slide 94

Page 95: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonInput and Output Filters Slide 95

Page 96: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonInput and Output Filters Slide 96

Page 97: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonInput and Output Filters Slide 97

Page 98: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonInput and Output Filters Slide 98

Page 99: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonInput and Output Filters Slide 99

Page 100: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonInput and Output Filters Slide 100

Page 101: Tutorial Slides: mod perl 2.0 By Example

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

Page 102: Tutorial Slides: mod perl 2.0 By Example

A simple obfuscation filter :

turn HTML pages into a one-liner

disregarding cases where new lines must be preserved,

as in <pre>...</pre>

config:

<Files ~ "\.html"> PerlOutputFilterHandler MyApache::FilterObfuscate </Files>

Philippe M. ChiassonInput and Output Filters Slide 102

Page 103: Tutorial Slides: mod perl 2.0 By Example

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

Page 104: Tutorial Slides: mod perl 2.0 By Example

Will talk about details shortly...

Philippe M. ChiassonInput and Output Filters Slide 104

Page 105: Tutorial Slides: mod perl 2.0 By Example

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

Page 106: Tutorial Slides: mod perl 2.0 By Example

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

Page 107: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonInput and Output Filters Slide 107

Page 108: Tutorial Slides: mod perl 2.0 By Example

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

Page 109: Tutorial Slides: mod perl 2.0 By Example

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

Page 110: Tutorial Slides: mod perl 2.0 By Example

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

Page 111: Tutorial Slides: mod perl 2.0 By Example

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

Page 112: Tutorial Slides: mod perl 2.0 By Example

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

Page 113: Tutorial Slides: mod perl 2.0 By Example

EOS may come as a last bucket in bb with data

Philippe M. ChiassonInput and Output Filters Slide 113

Page 114: Tutorial Slides: mod perl 2.0 By Example

Three Filter Stages :

Philippe M. ChiassonInput and Output Filters Slide 114

Page 115: Tutorial Slides: mod perl 2.0 By Example

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

Page 116: Tutorial Slides: mod perl 2.0 By Example

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

Page 117: Tutorial Slides: mod perl 2.0 By Example

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

Page 118: Tutorial Slides: mod perl 2.0 By Example

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

Page 119: Tutorial Slides: mod perl 2.0 By Example

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

Page 120: Tutorial Slides: mod perl 2.0 By Example

The output filter’s pass_brigade() call blocks

Philippe M. ChiassonInput and Output Filters Slide 120

Page 121: Tutorial Slides: mod perl 2.0 By Example

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

Page 122: Tutorial Slides: mod perl 2.0 By Example

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

Page 123: Tutorial Slides: mod perl 2.0 By Example

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

Page 124: Tutorial Slides: mod perl 2.0 By Example

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

Page 125: Tutorial Slides: mod perl 2.0 By Example

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

Page 126: Tutorial Slides: mod perl 2.0 By Example

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

Page 127: Tutorial Slides: mod perl 2.0 By Example

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

Page 128: Tutorial Slides: mod perl 2.0 By Example

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

Page 129: Tutorial Slides: mod perl 2.0 By Example

For example:

PerlSetOutputFilter INCLUDES PerlOutputFilterHandler MyApache::FilterOutputFoo

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

Philippe M. ChiassonInput and Output Filters Slide 129

Page 130: Tutorial Slides: mod perl 2.0 By Example

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

Page 131: Tutorial Slides: mod perl 2.0 By Example

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

Page 132: Tutorial Slides: mod perl 2.0 By Example

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

Page 133: Tutorial Slides: mod perl 2.0 By Example

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

Page 134: Tutorial Slides: mod perl 2.0 By Example

Request filters are usually configured in the <Location> orequivalent sections:

PerlModule MyApache::FilterRequestFoo PerlModule MyApache::NiceResponse <Location /filter_foo> SetHandler modperl PerlResponseHandler MyApache::NiceResponse PerlInputFilterHandler MyApache::FilterRequestFoo::input PerlOutputFilterHandler MyApache::FilterRequestFoo::output </Location>

Philippe M. ChiassonInput and Output Filters Slide 134

Page 135: Tutorial Slides: mod perl 2.0 By Example

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

Page 136: Tutorial Slides: mod perl 2.0 By Example

This time the configuration must be done outside the <Location> or equivalent sections,

usually within the <VirtualHost> or the global server configuration:

Listen 8005 <VirtualHost _default_:8005> PerlModule MyApache::FilterConnectionBar PerlModule MyApache::NiceResponse PerlInputFilterHandler MyApache::FilterConnectionBar::input PerlOutputFilterHandler MyApache::FilterConnectionBar::output <Location /> SetHandler modperl PerlResponseHandler MyApache::NiceResponse </Location> </VirtualHost>

Philippe M. ChiassonInput and Output Filters Slide 136

Page 137: Tutorial Slides: mod perl 2.0 By Example

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

Page 138: Tutorial Slides: mod perl 2.0 By Example

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

Page 139: Tutorial Slides: mod perl 2.0 By Example

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

Page 140: Tutorial Slides: mod perl 2.0 By Example

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

Page 141: Tutorial Slides: mod perl 2.0 By Example

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

Philippe M. ChiassonInput and Output Filters Slide 141

Page 142: Tutorial Slides: mod perl 2.0 By Example

which is configured as:

PerlModule MyApache::Dump <Location /dump> SetHandler modperl PerlResponseHandler MyApache::Dump </Location>

Philippe M. ChiassonInput and Output Filters Slide 142

Page 143: Tutorial Slides: mod perl 2.0 By Example

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

Page 144: Tutorial Slides: mod perl 2.0 By Example

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

Page 145: Tutorial Slides: mod perl 2.0 By Example

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

Page 146: Tutorial Slides: mod perl 2.0 By Example

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’ ? ">>>" : "<<<"; print STDERR "\n$direction $type $stream filter\n"; my $c = 1; while (my($btype, $data) = splice @data, 0, 2) { print STDERR " o bucket $c: $btype\n"; print STDERR "[$data]\n"; $c++; } } 1;

Philippe M. ChiassonInput and Output Filters Slide 146

Page 147: Tutorial Slides: mod perl 2.0 By Example

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

Page 148: Tutorial Slides: mod perl 2.0 By Example

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

Listen 8008 <VirtualHost _default_:8008> PerlModule MyApache::FilterSnoop PerlModule MyApache::Dump # Connection filters PerlInputFilterHandler MyApache::FilterSnoop::connection PerlOutputFilterHandler MyApache::FilterSnoop::connection <Location /dump> SetHandler modperl PerlResponseHandler MyApache::Dump # Request filters PerlInputFilterHandler MyApache::FilterSnoop::request PerlOutputFilterHandler MyApache::FilterSnoop::request </Location> </VirtualHost>

Philippe M. ChiassonInput and Output Filters Slide 148

Page 149: Tutorial Slides: mod perl 2.0 By Example

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

Page 150: Tutorial Slides: mod perl 2.0 By Example

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.

<<< connection input filter o bucket 1: HEAP [POST /dump?foo=1&bar=2 HTTP/1.1 ] <<< connection input filter o bucket 1: HEAP [TE: deflate,gzip;q=0.3 ]

Philippe M. ChiassonInput and Output Filters Slide 150

Page 151: Tutorial Slides: mod perl 2.0 By Example

<<< connection input filter o bucket 1: HEAP [Connection: TE, close ] <<< connection input filter o bucket 1: HEAP [Host: localhost:8008 ] <<< connection input filter o bucket 1: HEAP [User-Agent: lwp-request/2.01 ] <<< connection input filter o bucket 1: HEAP

Philippe M. ChiassonInput and Output Filters Slide 151

Page 152: Tutorial Slides: mod perl 2.0 By Example

[Content-Length: 14 ] <<< connection input filter o bucket 1: HEAP [Content-Type: application/x-www-form-urlencoded ] <<< connection input filter o bucket 1: HEAP [ ]

Here the HTTP header has been terminated by a double new line.

Philippe M. ChiassonInput and Output Filters Slide 152

Page 153: Tutorial Slides: mod perl 2.0 By Example

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

Page 154: Tutorial Slides: mod perl 2.0 By Example

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

<<< connection input filter o bucket 1: HEAP [mod_perl rules] <<< request input filter o bucket 1: HEAP [mod_perl rules] o bucket 2: EOS []

The connection input filter is run before the request input filter.

Philippe M. ChiassonInput and Output Filters Slide 154

Page 155: Tutorial Slides: mod perl 2.0 By Example

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

Page 156: Tutorial Slides: mod perl 2.0 By Example

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

Page 157: Tutorial Slides: mod perl 2.0 By Example

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

Page 158: Tutorial Slides: mod perl 2.0 By Example

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

Page 159: Tutorial Slides: mod perl 2.0 By Example

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

Page 160: Tutorial Slides: mod perl 2.0 By Example

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

Page 161: Tutorial Slides: mod perl 2.0 By Example

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

Page 162: Tutorial Slides: mod perl 2.0 By Example

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

Page 163: Tutorial Slides: mod perl 2.0 By Example

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

Page 164: Tutorial Slides: mod perl 2.0 By Example

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

Page 165: Tutorial Slides: mod perl 2.0 By Example

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

Page 166: Tutorial Slides: mod perl 2.0 By Example

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

Page 167: Tutorial Slides: mod perl 2.0 By Example

Therefore if this response handler is configured as:

Listen 8005 <VirtualHost _default_:8005> <Location /> SetHandler modperl PerlResponseHandler +MyApache::RequestType </Location> </VirtualHost>

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

Page 168: Tutorial Slides: mod perl 2.0 By Example

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

Page 169: Tutorial Slides: mod perl 2.0 By Example

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

Listen 8005 <VirtualHost _default_:8005> PerlInputFilterHandler +MyApache::InputFilterGET2HEAD <Location /> SetHandler modperl PerlResponseHandler +MyApache::RequestType </Location> </VirtualHost>

And issue the same GET request, we get only:

25:

Philippe M. ChiassonInput and Output Filters Slide 169

Page 170: Tutorial Slides: mod perl 2.0 By Example

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

Page 171: Tutorial Slides: mod perl 2.0 By Example

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

Page 172: Tutorial Slides: mod perl 2.0 By Example

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

Page 173: Tutorial Slides: mod perl 2.0 By Example

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

Page 174: Tutorial Slides: mod perl 2.0 By Example

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

Using the following configuration:

<Location /lc_input> SetHandler modperl PerlResponseHandler +MyApache::Dump PerlInputFilterHandler +MyApache::InputRequestFilterLC </Location>

Philippe M. ChiassonInput and Output Filters Slide 174

Page 175: Tutorial Slides: mod perl 2.0 By Example

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

Page 176: Tutorial Slides: mod perl 2.0 By Example

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

Page 177: Tutorial Slides: mod perl 2.0 By Example

Configuration:

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

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

Philippe M. ChiassonInput and Output Filters Slide 177

Page 178: Tutorial Slides: mod perl 2.0 By Example

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

Page 179: Tutorial Slides: mod perl 2.0 By Example

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

Page 180: Tutorial Slides: mod perl 2.0 By Example

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

Page 181: Tutorial Slides: mod perl 2.0 By Example

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

Page 182: Tutorial Slides: mod perl 2.0 By Example

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

Page 183: Tutorial Slides: mod perl 2.0 By Example

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

Page 184: Tutorial Slides: mod perl 2.0 By Example

Add the following configuration to httpd.conf:

PerlModule MyApache::FilterReverse1 PerlModule MyApache::SendAlphaNum <Location /reverse1> SetHandler modperl PerlResponseHandler MyApache::SendAlphaNum PerlOutputFilterHandler MyApache::FilterReverse1 </Location>

Philippe M. ChiassonInput and Output Filters Slide 184

Page 185: Tutorial Slides: mod perl 2.0 By Example

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

Page 186: Tutorial Slides: mod perl 2.0 By Example

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

Page 187: Tutorial Slides: mod perl 2.0 By Example

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

Page 188: Tutorial Slides: mod perl 2.0 By Example

And the corresponding configuration:

PerlModule MyApache::FilterReverse2 PerlModule MyApache::SendAlphaNum <Location /reverse2> SetHandler modperl PerlResponseHandler MyApache::SendAlphaNum PerlOutputFilterHandler MyApache::FilterReverse2 </Location>

Philippe M. ChiassonInput and Output Filters Slide 188

Page 189: Tutorial Slides: mod perl 2.0 By Example

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

0987654321 zyxwvutsrqponmlkjihgfedcba

as expected.

Philippe M. ChiassonInput and Output Filters Slide 189

Page 190: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonHTTP Handlers Slide 190

Page 191: Tutorial Slides: mod perl 2.0 By Example

7 HTTP Handlers

Philippe M. ChiassonHTTP Handlers Slide 191

Page 192: Tutorial Slides: mod perl 2.0 By Example

7.1 AboutHTTP Request Cycle Phases

PerlPostReadRequestHandler

PerlTransHandler

PerlMapToStorageHandler

PerlHeaderParserHandler

PerlInitHandler

PerlAccessHandler

Philippe M. ChiassonHTTP Handlers Slide 192

Page 193: Tutorial Slides: mod perl 2.0 By Example

PerlAuthenHandler

PerlAuthzHandler

PerlTypeHandler

PerlFixupHandler

PerlResponseHandler

PerlLogHandler

PerlCleanupHandler

Philippe M. ChiassonHTTP Handlers Slide 193

Page 194: Tutorial Slides: mod perl 2.0 By Example

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

Page 195: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonHTTP Handlers Slide 195

Page 196: Tutorial Slides: mod perl 2.0 By Example

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

Page 197: Tutorial Slides: mod perl 2.0 By Example

8. PerlTypeHandler

9. PerlFixupHandler

10. PerlResponseHandler

11. PerlLogHandler

12. PerlCleanupHandler

Philippe M. ChiassonHTTP Handlers Slide 197

Page 198: Tutorial Slides: mod perl 2.0 By Example

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

Page 199: Tutorial Slides: mod perl 2.0 By Example

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

Page 200: Tutorial Slides: mod perl 2.0 By Example

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

Page 201: Tutorial Slides: mod perl 2.0 By Example

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

Page 202: Tutorial Slides: mod perl 2.0 By Example

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

Page 203: Tutorial Slides: mod perl 2.0 By Example

To enable it just add to httpd.conf:

PerlPostReadRequestHandler MyApache::TimeReset

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

Philippe M. ChiassonHTTP Handlers Slide 203

Page 204: Tutorial Slides: mod perl 2.0 By Example

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

Page 205: Tutorial Slides: mod perl 2.0 By Example

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

Page 206: Tutorial Slides: mod perl 2.0 By Example

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

Page 207: Tutorial Slides: mod perl 2.0 By Example

To configure this module simply add to httpd.conf:

PerlTransHandler +MyApache::RewriteURI

Philippe M. ChiassonHTTP Handlers Slide 207

Page 208: Tutorial Slides: mod perl 2.0 By Example

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

Page 209: Tutorial Slides: mod perl 2.0 By Example

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

Page 210: Tutorial Slides: mod perl 2.0 By Example

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

Page 211: Tutorial Slides: mod perl 2.0 By Example

Another way to prevent the core translation:

$r->filename(__FILE__);

this can be done in PerlTransHandler as well

Philippe M. ChiassonHTTP Handlers Slide 211

Page 212: Tutorial Slides: mod perl 2.0 By Example

7.2.4 PerlHeaderParserHandlerThe header_parser phase is the first phase to happen afterthe request has been mapped to its <Location> (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

Page 213: Tutorial Slides: mod perl 2.0 By Example

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:

<Location /email> PerlHeaderParserHandler MyApache::SendEmail </Location>

Philippe M. ChiassonHTTP Handlers Slide 213

Page 214: Tutorial Slides: mod perl 2.0 By Example

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

Page 215: Tutorial Slides: mod perl 2.0 By Example

$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

Page 216: Tutorial Slides: mod perl 2.0 By Example

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

Philippe M. ChiassonHTTP Handlers Slide 216

Page 217: Tutorial Slides: mod perl 2.0 By Example

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

Page 218: Tutorial Slides: mod perl 2.0 By Example

require LWP::UserAgent; # my $url = "http://localhost:8000/email/"; my %headers = ( From => ’[email protected]’, To => ’[email protected]’, Subject => ’3 weeks in Tibet’, ); my $content = <<EOI; I didn’t have an email software, but could use HTTP so I’m sending it over HTTP EOI my $headers = HTTP::Headers->new(%headers); my $req = HTTP::Request->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

Page 219: Tutorial Slides: mod perl 2.0 By Example

7.2.5 PerlInitHandlerWhen configured inside any container directive, except <VirtualHost>, 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

Page 220: Tutorial Slides: mod perl 2.0 By Example

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

Page 221: Tutorial Slides: mod perl 2.0 By Example

However if we move the global configuration into a <Location> container:

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

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

Page 222: Tutorial Slides: mod perl 2.0 By Example

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

Page 223: Tutorial Slides: mod perl 2.0 By Example

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

Page 224: Tutorial Slides: mod perl 2.0 By Example

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

Page 225: Tutorial Slides: mod perl 2.0 By Example

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:

<Location /perl/> SetHandler perl-script PerlResponseHandler ModPerl::Registry PerlAccessHandler MyApache::BlockByIP Options +ExecCGI </Location>

Philippe M. ChiassonHTTP Handlers Slide 225

Page 226: Tutorial Slides: mod perl 2.0 By Example

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

Page 227: Tutorial Slides: mod perl 2.0 By Example

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

Page 228: Tutorial Slides: mod perl 2.0 By Example

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

Page 229: Tutorial Slides: mod perl 2.0 By Example

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

Page 230: Tutorial Slides: mod perl 2.0 By Example

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

Philippe M. ChiassonHTTP Handlers Slide 230

Page 231: Tutorial Slides: mod perl 2.0 By Example

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

Page 232: Tutorial Slides: mod perl 2.0 By Example

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

Page 233: Tutorial Slides: mod perl 2.0 By Example

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

Page 234: Tutorial Slides: mod perl 2.0 By Example

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

Page 235: Tutorial Slides: mod perl 2.0 By Example

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/ <Location /company/> SetHandler perl-script PerlResponseHandler ModPerl::Registry PerlAuthenHandler MyApache::SecretLengthAuth PerlAuthzHandler MyApache::SecretResourceAuthz Options +ExecCGI AuthType Basic AuthName "The Secret Gate" Require valid-user </Location>

Philippe M. ChiassonHTTP Handlers Slide 235

Page 236: Tutorial Slides: mod perl 2.0 By Example

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

Page 237: Tutorial Slides: mod perl 2.0 By Example

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

Page 238: Tutorial Slides: mod perl 2.0 By Example

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

Page 239: Tutorial Slides: mod perl 2.0 By Example

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

Page 240: Tutorial Slides: mod perl 2.0 By Example

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

Page 241: Tutorial Slides: mod perl 2.0 By Example

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

Page 242: Tutorial Slides: mod perl 2.0 By Example

Here is how this handler is configured:

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

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

Page 243: Tutorial Slides: mod perl 2.0 By Example

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:

<Location /perl> SetHandler perl-script PerlResponseHandler MyApache::WorldDomination </Location>

Philippe M. ChiassonHTTP Handlers Slide 243

Page 244: Tutorial Slides: mod perl 2.0 By Example

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

Page 245: Tutorial Slides: mod perl 2.0 By Example

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

Page 246: Tutorial Slides: mod perl 2.0 By Example

To enable this handler add to httpd.conf:

<Location /deparse> SetHandler modperl PerlResponseHandler MyApache::Deparse </Location>

Philippe M. ChiassonHTTP Handlers Slide 246

Page 247: Tutorial Slides: mod perl 2.0 By Example

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

Page 248: Tutorial Slides: mod perl 2.0 By Example

7.2.12 PerlLogHandlerThe log_transaction phase is always executed.

Even if the previous phases were aborted.

At this phase log handlers usually log various informationabout the request and the response.

This phase is of type RUN_ALL.

The handler’s configuration scope is DIR.

Philippe M. ChiassonHTTP Handlers Slide 248

Page 249: Tutorial Slides: mod perl 2.0 By Example

The following handler logs the request data into user-specific files.

We assume that all URIs include the username in the form of: /users/username/

package MyApache::LogPerUser; # use strict; use warnings; use Apache::RequestRec (); use Apache::Connection (); use Fcntl qw(:flock); use Apache::Const -compile => qw(OK DECLINED);

Philippe M. ChiassonHTTP Handlers Slide 249

Page 250: Tutorial Slides: mod perl 2.0 By Example

sub handler { # my $r = shift; my($username) = $r->uri =~ m|^/users/([^/]+)|; return Apache::DECLINED unless defined $username; my $entry = sprintf qq(%s [%s] "%s" %d %d\n), $r->connection->remote_ip, scalar(localtime), $r->uri, $r->status, $r->bytes_sent; my $log_path = catfile Apache::ServerUtil::server_root, "logs", "$username.log"; open my $fh, ">>$log_path" or die "can’t open $log_path: $!"; flock $fh, LOCK_EX; print $fh $entry; close $fh; return Apache::OK; } 1;

Philippe M. ChiassonHTTP Handlers Slide 250

Page 251: Tutorial Slides: mod perl 2.0 By Example

Configuration:

<Location /users/> SetHandler perl-script PerlResponseHandler ModPerl::Registry PerlLogHandler MyApache::LogPerUser Options +ExecCGI </Location>

Philippe M. ChiassonHTTP Handlers Slide 251

Page 252: Tutorial Slides: mod perl 2.0 By Example

After restarting the server and issuing requests to thefollowing URIs:

http://localhost/users/gozer/test.pl http://localhost/users/eric/test.pl http://localhost/users/gozer/date.pl

The MyApache::LogPerUser handler will append to logs/gozer.log:

127.0.0.1 [Sat Aug 31 01:50:38 2002] "/users/gozer/test.pl" 200 8 127.0.0.1 [Sat Aug 31 01:50:40 2002] "/users/gozer/date.pl" 200 44

and to logs/eric.log:

127.0.0.1 [Sat Aug 31 01:50:39 2002] "/users/eric/test.pl" 200 8

Philippe M. ChiassonHTTP Handlers Slide 252

Page 253: Tutorial Slides: mod perl 2.0 By Example

7.2.13 PerlCleanupHandlerThere is no cleanup Apache phase,

It’s a mod_perl convenience invention

It runs immediately after the request has been served

and before the request object is destroyed.

Used to run cleanup code

or to do some time consuming work after the client has gone

This phase is of type RUN_ALL / config scope is DIR

Philippe M. ChiassonHTTP Handlers Slide 253

Page 254: Tutorial Slides: mod perl 2.0 By Example

Usage :

a cleanup() callback accepts $r as its only argument.

PerlCleanupHandler MyApache::Cleanup

or:

$r->push_handlers(PerlCleanupHandler => \&cleanup);

a cleanup() callback accepts an optional arbitrary argument

$r->pool->cleanup_register(\&cleanup, $arg);

Philippe M. ChiassonHTTP Handlers Slide 254

Page 255: Tutorial Slides: mod perl 2.0 By Example

Example: delete a temporary file in the cleanup handler

package MyApache::Cleanup1; # use strict; use warnings FATAL => ’all’; use File::Spec::Functions qw(catfile); use Apache::RequestRec (); use Apache::RequestIO (); use Apache::RequestUtil (); use Apache::Const -compile => qw(OK DECLINED); use APR::Const -compile => ’SUCCESS’; my $file = catfile "/tmp", "data";

Philippe M. ChiassonHTTP Handlers Slide 255

Page 256: Tutorial Slides: mod perl 2.0 By Example

sub handler { # my $r = shift; $r->content_type(’text/plain’); local @ENV{qw(PATH BASH_ENV)}; qx(/bin/ls -l > $file); my $status = $r->sendfile($file); die "sendfile has failed" unless $status == APR::SUCCESS; $r->push_handlers(PerlCleanupHandler => \&cleanup); return Apache::OK; } sub cleanup { my $r = shift; die "Can’t find file: $file" unless -e $file; unlink $file or die "failed to unlink $file"; return Apache::OK; } 1;

Philippe M. ChiassonHTTP Handlers Slide 256

Page 257: Tutorial Slides: mod perl 2.0 By Example

Next we add the following configuration:

<Location /cleanup1> SetHandler modperl PerlResponseHandler MyApache::Cleanup1 </Location>

Now when requesting /cleanup1

the contents of the current directory will be printed

and once the request is over the temporary file is deleted.

Philippe M. ChiassonHTTP Handlers Slide 257

Page 258: Tutorial Slides: mod perl 2.0 By Example

The problem in Multi-processes/threads env

MyApache::Cleanup1 is problematic for it uses the same filename

Better use a unique filename ($$ + APR::OS::thread_current())

Even better, use a non-predictable name: rand, APR::UUID

But how do we pass the filename to the cleanup handler?

MyApache::Cleanup2 solves the problem with:

$r->pool->cleanup_register(\&cleanup, $file);

Philippe M. ChiassonHTTP Handlers Slide 258

Page 259: Tutorial Slides: mod perl 2.0 By Example

package MyApache::Cleanup2; # use strict; use warnings FATAL => ’all’; use File::Spec::Functions qw(catfile); use Apache::RequestRec (); use Apache::RequestIO (); use Apache::RequestUtil (); use APR::UUID (); use APR::Pool (); use Apache::Const -compile => qw(OK DECLINED); use APR::Const -compile => ’SUCCESS’; my $file_base = catfile "/tmp", "data-";

Philippe M. ChiassonHTTP Handlers Slide 259

Page 260: Tutorial Slides: mod perl 2.0 By Example

sub handler { # my $r = shift; $r->content_type(’text/plain’); my $file = $file_base . APR::UUID->new->format; local @ENV{qw(PATH BASH_ENV)}; qx(/bin/ls -l > $file); my $status = $r->sendfile($file); die "sendfile has failed" unless $status == APR::SUCCESS; $r->pool->cleanup_register(\&cleanup, $file); return Apache::OK; } sub cleanup { my $file = shift; die "Can’t find file: $file" unless -e $file; unlink $file or die "failed to unlink $file"; return Apache::OK; } 1;

Philippe M. ChiassonHTTP Handlers Slide 260

Page 261: Tutorial Slides: mod perl 2.0 By Example

Similarly to the first handler, we add the configuration:

<Location /cleanup2> SetHandler modperl PerlResponseHandler MyApache::Cleanup2 </Location>

Philippe M. ChiassonHTTP Handlers Slide 261

Page 262: Tutorial Slides: mod perl 2.0 By Example

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 262

Page 263: Tutorial Slides: mod perl 2.0 By Example

8 mod_perl 1.0 to mod_perl2.0 Migration

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 263

Page 264: Tutorial Slides: mod perl 2.0 By Example

8.1 AboutConfiguration Directives Changes

mod_perl API Changes

mod_perl Modules Changes

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 264

Page 265: Tutorial Slides: mod perl 2.0 By Example

8.2 Migrating from mod_perl 1.0to mod_perl 2.0

Some configuration directives were renamed or removed

Several APIs have changed, renamed, removed, or moved tonew packages.

...

But there is a back-compatibility layer!

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 265

Page 266: Tutorial Slides: mod perl 2.0 By Example

8.3 The Shortest Migration Pathfrom 1.0 use Apache2; use Apache::compat;

Certain Configuration directives and APIs have changed

See http://perl.apache.org/docs/2.0/user/compat/compat.html

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 266

Page 267: Tutorial Slides: mod perl 2.0 By Example

8.4 Migrating Configuration FilesSeveral configuration directives are deprecated in 2.0

but still available for backwards compatibility

Otherwise, consider using the directives that have replaced them.

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 267

Page 268: Tutorial Slides: mod perl 2.0 By Example

8.4.1 PerlHandler PerlHandler => PerlResponseHandler

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 268

Page 269: Tutorial Slides: mod perl 2.0 By Example

8.4.2 PerlSendHeader PerlSendHeader On => PerlOptions +ParseHeaders PerlSendHeader Off => PerlOptions -ParseHeaders

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 269

Page 270: Tutorial Slides: mod perl 2.0 By Example

8.4.3 PerlSetupEnv PerlSetupEnv On => PerlOptions +SetupEnv PerlSetupEnv Off => PerlOptions -SetupEnv

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 270

Page 271: Tutorial Slides: mod perl 2.0 By Example

8.4.4 PerlTaintCheckThe taint mode now can be turned on with:

PerlSwitches -T

It’s disabled by default.

You cannot disable it once it’s enabled.

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 271

Page 272: Tutorial Slides: mod perl 2.0 By Example

8.4.5 PerlWarnWarnings now can be enabled globally with:

PerlSwitches -w

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 272

Page 273: Tutorial Slides: mod perl 2.0 By Example

8.4.6 PerlFreshRestartPerlFreshRestart is a mod_perl 1.0 legacy

In mod_perl 2.0 a full tear-down and startup of interpreters isdone on restart.

To reuse the same httpd.conf for 1.0 and 2.0:

<IfDefine !MODPERL2> PerlFreshRestart </IfDefine>

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 273

Page 274: Tutorial Slides: mod perl 2.0 By Example

8.5 Code PortingCertain APIs couldn’t be preserved in 2.0, hence:

use Apache::compat;

which is slower, because it’s implemented in Perl.

Consider getting rid of using the compat layer

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 274

Page 275: Tutorial Slides: mod perl 2.0 By Example

Remember the installation?

% perl Makefile.PL ... MP_INST_APACHE2=1

Now mod_perl 1.0 and 2.0 can co-exist on the same machine

mod_perl 2.0 modules go into the dir Apache2/

use Apache2;

looks for path(s) with Apache2/ using @INC

prepends them to @INC

mp2doc replaces perldoc to find mp2 manpages

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 275

Page 276: Tutorial Slides: mod perl 2.0 By Example

8.5.1 Finding Which Modules NeedTo Be LoadedThe Poison:

$r->content_type(’text/plain’); $r->print("Hello cruel world!");

the execution fails with:

can’t find method ’content_type’ ...

One has to load modules containing mod_perl methodsbefore they can be used

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 276

Page 277: Tutorial Slides: mod perl 2.0 By Example

The Remedy :

% perl -MApache2 -MModPerl::MethodLookup -e print_method content_type to use method ’content_type’ add: use Apache::RequestRec ();

Alias :

# c-style shell % alias lookup "perl -MApache2 -MModPerl::MethodLookup -e print_method" # bash-style shell % alias lookup="perl -MApache2 -MModPerl::MethodLookup -e print_method" % lookup content_type to use method ’content_type’ add: use Apache::RequestRec ();

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 277

Page 278: Tutorial Slides: mod perl 2.0 By Example

8.6 ModPerl::Registry Familys/Apache::Registry/ModPerl::Registry/

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

Issues with chdir(), which affects all threads

MPM doesn’t matter, should work the same everywhere

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 278

Page 279: Tutorial Slides: mod perl 2.0 By Example

Cook your own registry with ModPerl::RegistryCooker

is-a: Subclass one of the classes

has-a: Build your own using aliasing

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 279

Page 280: Tutorial Slides: mod perl 2.0 By Example

8.7 Method Handlers$$ doesn’t work since some callbacks accepts more than 2 args

package Bird; @ISA = qw(Eagle); sub handler : method { my($class, $r) = @_; ...; }

See the attributes manpage.

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 280

Page 281: Tutorial Slides: mod perl 2.0 By Example

8.8 Apache::StatINC Replacement

Replace:

PerlInitHandler Apache::StatINC

with:

PerlInitHandler Apache::Reload

Apache::Reload provides an extra functionality

See the module’s manpage.

Philippe M. Chiassonmod_perl 1.0 to mod_perl 2.0 Migration Slide 281

Page 282: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonThat’s all folks! Slide 282

Page 283: Tutorial Slides: mod perl 2.0 By Example

9 That’s all folks!

Philippe M. ChiassonThat’s all folks! Slide 283

Page 284: Tutorial Slides: mod perl 2.0 By Example

9.1 ThanksThanks to TicketMaster for sponsoring some of my work on mod_perl

Philippe M. ChiassonThat’s all folks! Slide 284

Page 285: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonThat’s all folks! Slide 285

Page 286: Tutorial Slides: mod perl 2.0 By Example

9.2 Referencesmod_perl 2.0 information can be found at:

http://perl.apache.org/docs/2.0/

Further Questions?

Grab me at the corridor and demand answers

Ask at [email protected]

Philippe M. ChiassonThat’s all folks! Slide 286

Page 287: Tutorial Slides: mod perl 2.0 By Example

9.3 A Shameless Plug

Philippe M. ChiassonThat’s all folks! Slide 287

Page 288: Tutorial Slides: mod perl 2.0 By Example

Philippe M. ChiassonThat’s all folks! Slide 288