Overview Object-Oriented Perl Mechanics mod_perl Method Handlers - - PowerPoint PPT Presentation

overview
SMART_READER_LITE
LIVE PREVIEW

Overview Object-Oriented Perl Mechanics mod_perl Method Handlers - - PowerPoint PPT Presentation

Object-Oriented mod_perl ) Geoffrey Young geoff@modperlcookbook.org 1 http://www.modperlcookbook.org/ Overview Object-Oriented Perl Mechanics mod_perl Method Handlers Extending Core mod_perl Classes 2


slide-1
SLIDE 1

http://www.modperlcookbook.org/ 1

Object-Oriented mod_perl)

Geoffrey Young

geoff@modperlcookbook.org

slide-2
SLIDE 2

http://www.modperlcookbook.org/ 2

Overview

  • Object-Oriented Perl Mechanics
  • mod_perl Method Handlers
  • Extending Core mod_perl Classes
slide-3
SLIDE 3

http://www.modperlcookbook.org/ 3

  • Object-oriented programming has

many advantages

– subject of great debate

  • Programming mod_perl in OO makes

all kinds of wizardy possible

– also makes julienne fries

  • Let's have some fun using OOP

Objects, smobjects

slide-4
SLIDE 4

http://www.modperlcookbook.org/ 4

Perl OO Primer

  • Some basic object-oriented features

to understand

– classes – methods – objects – inheritance

slide-5
SLIDE 5

http://www.modperlcookbook.org/ 5

Pay Homage

  • The entire object-oriented Perl world
  • wes Damian Conway a huge debt of

gratitude

  • The definitions that follow are

essentially his...

  • Any mistakes are unquestionably

mine

slide-6
SLIDE 6

http://www.modperlcookbook.org/ 6

Perl Classes

  • "To create a class, build a package"
  • Perl packages associate variables and

subroutines together under a common namespace

package My::Dinghy; use 5.006; use strict; 1;

slide-7
SLIDE 7

http://www.modperlcookbook.org/ 7

Perl Methods

  • "To create a method, build a

subroutine"

  • Perl subroutines can be called as

functional subroutines

print $fh 'print() is a function';

  • or as methods

$fh->print('print() is a method'); sub print { my ($self, @data) = @_; }

slide-8
SLIDE 8

http://www.modperlcookbook.org/ 8

Perl Objects

  • "To create an object, bless a referent"
  • Perl has a special function bless()

that associates a variable with a class my $self = {}; return bless $self, $class;

  • It's the variable that is associated

with the class, not the reference to the variable

slide-9
SLIDE 9

http://www.modperlcookbook.org/ 9

Perl Inheritance

  • To create a subclass, populate @ISA

– I made that up for consistency

  • @ISA controls how Perl searches for

methods when it can't find any in the subclass

  • @ISA is a package global
  • ur @ISA = qw(My::Dinghy);

use vars qw(@ISA); @ISA = qw(My::Dinghy); @My::12Meter::ISA = qw(My::Dinghy);

slide-10
SLIDE 10

http://www.modperlcookbook.org/ 10

Guess What?

  • mod_perl has already introduced you

to most of Perl's OO semantics

my $r = Apache->request; my $host = $r->headers_in->get('Host');

  • In fact, mod_perl almost begs you to

use OO

slide-11
SLIDE 11

http://www.modperlcookbook.org/ 11

Handlers as Classes

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; }; 1;

slide-12
SLIDE 12

http://www.modperlcookbook.org/ 12

OO mod_perl

  • Programming using the mod_perl API

forces us to use most of Perl's OO tools already

  • We just need to fill in a few of the

gaps for phenomenal cosmic power...

slide-13
SLIDE 13

http://www.modperlcookbook.org/ 13

Step #1

  • Change our existing handlers to

method handlers

  • Method handlers are just normal

handlers called using OO syntax

  • Allow us to use OO techniques to our

advantage

slide-14
SLIDE 14

http://www.modperlcookbook.org/ 14

Prototyping

  • The classical way is to use Perl

prototypes

sub handler ($$) { ... }

  • Prototypes are deprecated in 2.0
slide-15
SLIDE 15

http://www.modperlcookbook.org/ 15

Attributes

  • The new way is to use subroutine

attributes

sub handler : method { ... }

  • See the attributes manpage
slide-16
SLIDE 16

http://www.modperlcookbook.org/ 16

Step #2

  • Change our handler() method to be

able to receive an OO call

sub handler : method { my ($self, $r) = @_; }

  • $self is the invoking class

– most of the time

  • $r is the same old Apache request
  • bject
slide-17
SLIDE 17

http://www.modperlcookbook.org/ 17

Step #3

  • Call the handler using a method

syntax

PerlModule My::MethodHandler PerlInitHandler My::MethodHandler->handler

  • Pre-loading is required
  • The arrow syntax is not
slide-18
SLIDE 18

http://www.modperlcookbook.org/ 18

So What?

  • Normal handlers and method handlers

are equivalent in nearly all areas...

  • ... but now you have the ability to

inherit from other classes using OO techniques

slide-19
SLIDE 19

http://www.modperlcookbook.org/ 19

For Example

  • Apache::SSI provides a Perl

implementation of Server Side Includes

<Files *.shtml> SetHandler perl-script PerlHandler Apache::SSI </Files>

  • Equivalent to mod_include except it

adds a few important features...

slide-20
SLIDE 20

http://www.modperlcookbook.org/ 20

Apache::SSI

  • Integrates with Apache::Filter to

provide filtered content generation

<Location /pipeline> SetHandler perl-script PerlHandler My::Content Apache::SSI Apache::Clean PerlSetVar Filter On </Location>

  • Pipelining like this is impossible using

mod_cgi and mod_include

– in Apache 1.3 at least

slide-21
SLIDE 21

http://www.modperlcookbook.org/ 21

Drawbacks

  • Apache::SSI is a huge win for people

who like to modularize processing

  • There is one rather limiting drawback

to the current implementation

  • If you use the exec or include SSI

tag Apache::SSI must be the final filter in the chain

PerlHandler My::Content Apache::SSI

– due to implementation constraints

slide-22
SLIDE 22

http://www.modperlcookbook.org/ 22

There is Hope

  • Fortunately, Apache::SSI is implemented

using method handlers

  • We can subclass Apache::SSI and provide
  • ur own exec and include

implementations that fix the problem

  • We leave all the document parsing and
  • ther tag implementations alone

* Apache::SSI now includes Apache::FakeSSI which

accomplishes almost the same thing

slide-23
SLIDE 23

http://www.modperlcookbook.org/ 23 package Cookbook::SSI; use Apache::SSI; use HTTP::Request; use LWP::UserAgent; use strict; @Cookbook::SSI::ISA = qw(Apache::SSI); sub ssi_include { my ($self, $args) = @_; return $self->error("Include must be of type 'virtual'") unless $args->{virtual}; my $uri = Apache::URI->parse(Apache->request); if ($args->{virtual} =~ m!^/!) { $uri->path($args->{virtual}); # path is absolute } else { my ($base) = $uri->path =~ m!(.*/)!; # path is relative $uri->path($base . $args->{virtual}); } my $request = HTTP::Request->new(GET => $uri->unparse); my $response = LWP::UserAgent->new->request($request); return $self->error("Could not Include virtual URL"); unless $response->is_success; return $response->content; } 1;

slide-24
SLIDE 24

http://www.modperlcookbook.org/ 24

Setup

  • Just use our module wherever we

used to use Apache::SSI

PerlModule Cookbook::SSI <Location /pipeline> SetHandler perl-script PerlHandler My::Content Cookbook::SSI Apache::Clean PerlSetVar Filter On </Location>

  • the Apache::SSI engine takes care
  • f everything but our new <!--#include

virtual="/foo.pl" --> implementation

slide-25
SLIDE 25

http://www.modperlcookbook.org/ 25

But wait, there's more...

  • Method handlers are a nice thing to

have

  • Not very interesting in themselves
  • Overriding core mod_perl classes is

where the real fun begins

slide-26
SLIDE 26

http://www.modperlcookbook.org/ 26

The Apache Class

  • The Apache class is at the heart of all

we do in mod_perl

  • Implements most of the amazing

things we associate with the mod_perl API

  • You can make mod_perl do your own

evil bidding by extending and

  • verriding Apache
slide-27
SLIDE 27

http://www.modperlcookbook.org/ 27

Subclassing Apache

  • Let's make $r->bytes_sent() return

KB instead of bytes

  • How? Create a simple subclass that

does the calculation for us

slide-28
SLIDE 28

http://www.modperlcookbook.org/ 28

package Cookbook::Apache; use Apache; use strict; @Cookbook::Apache::ISA = qw(Apache); sub new { my ($class, $r) = @_; $r ||= Apache->request; return bless { r => $r }, $class; } sub bytes_sent { return sprintf("%.0f", shift->SUPER::bytes_sent / 1024); } 1;

slide-29
SLIDE 29

http://www.modperlcookbook.org/ 29

H'wa?

  • What's going on here?
  • ur @ISA = qw(Apache);

return bless { r => $r }, $class;

– ask Doug if you see him – typemap r = sv2request_rec($arg, \"$ntype\", cv) – sv2request_rec checks %$arg for _r or r keys calls sv2request_rec using _r or r for $arg

  • Hey, it works
slide-30
SLIDE 30

http://www.modperlcookbook.org/ 30

package My::Bytes; use Apache::Constants qw(OK); use Cookbook::Apache; use strict; sub handler { my $r = shift; my $c = Cookbook::Apache->new($r); $c->log_error($c->bytes_sent, ' KB sent for ', $c->uri); $r->log_error($r->bytes_sent, ' bytes sent for ', $r->uri); return OK; } 1;

Sample Usage

slide-31
SLIDE 31

http://www.modperlcookbook.org/ 31

Let's Simplify

  • We only used both $r and $c in this

example to show the difference

  • Most of the time, you only need one

request object, since your subclass inherits all the normal Apache methods

sub handler { my $r = Cookbook::Apache->new(shift);

slide-32
SLIDE 32

http://www.modperlcookbook.org/ 32

Kick it up a notch

  • Our sample Apache subclass isn't

terribly interesting or terribly useful

  • Time to add a little heat
slide-33
SLIDE 33

http://www.modperlcookbook.org/ 33

Cross-Site Scripting

  • As web developers, we should always check

end-user input before using it

  • For system() calls, that means making sure

no input is tainted

– running with -T switch – PerlTaintCheck On

  • For HTML output, that means escaping

input (< to &lt;) before displaying

– HTML::Entities::escape() – Apache::Util::escape_html()

slide-34
SLIDE 34

http://www.modperlcookbook.org/ 34

Lots of Overhead

  • For CGI or mod_perl developers, that

means remembering lots of calls to encode() or escape_html()

– which, of course, everyone does. Right?

  • By subclassing the Apache class we can

escape output automatically

  • We don't want to escape all output, just the

stuff from the end-user

  • Get help from Taint.pm
slide-35
SLIDE 35

http://www.modperlcookbook.org/ 35

Background

  • We need to add PerlTaintCheck On

to our httpd.conf to mimic the -T switch

  • Use Taint::tainted() to determine

whether data is tainted

not eval { join("",@_), kill 0; 1 };

  • "send the data along"
slide-36
SLIDE 36

http://www.modperlcookbook.org/ 36

package Cookbook::TaintRequest; use Apache; use Apache::Util qw(escape_html); # Module load will die if PerlTaintCheck Off use Taint qw(tainted); use strict; @Cookbook::TaintRequest::ISA = qw(Apache); sub print { my ($self, @data) = @_; foreach my $value (@data) { # Dereference scalar references. $value = $$value if ref $value eq 'SCALAR'; # Escape any HTML content if the data is tainted. $value = escape_html($value) if tainted($value); } $self->SUPER::print(@data); }

slide-37
SLIDE 37

http://www.modperlcookbook.org/ 37

What's missing?

  • So far all we have done is override

mod_perl's $r->print()

  • We still have to create a constructor

for our class

  • But what about just plain print()?

print "<script>Heh!</script>";

  • Our constructor needs to be special
slide-38
SLIDE 38

http://www.modperlcookbook.org/ 38

package My::Tie; sub TIEHANDLE { return bless {}, shift; } sub READLINE { return "reading...\n"; } tie *HANDLE, My::Tie; while (my $line = <HANDLE>) { print $line; }

slide-39
SLIDE 39

http://www.modperlcookbook.org/ 39

The TIEHANDLE Interface

  • Perl provides the TIEHANDLE interface

as a way to override how filehandles behave when written to or read from

print "foo"; print STDOUT "foo";

  • mod_perl uses tied filehandles to our

advantage

slide-40
SLIDE 40

http://www.modperlcookbook.org/ 40

More mod_perl Magic

  • $r->print() sends data to the client

– wrapper around Apache API calls that write data

  • ver the wire
  • mod_perl ties standard streams to the

Apache class

– writes to STDOUT use $r->print()

  • why Apache::Registry works

– reads from STDIN use Apache API calls to get data from the wire

slide-41
SLIDE 41

http://www.modperlcookbook.org/ 41

Back to our example...

  • So far we subclassed the Apache class

to override mod_perl's $r->print()

  • We still have to create a constructor

for our class

  • We need to intercept both

$r_>print() and print()s to STDOUT

slide-42
SLIDE 42

http://www.modperlcookbook.org/ 42

Apache's TIEHANDLE

  • The Apache class already provides a

TIEHANDLE interface

  • When subclassing the Apache class,

we can override the PRINT part of the interface

  • Leave the other TIEHANDLE parts in

tact

slide-43
SLIDE 43

http://www.modperlcookbook.org/ 43

sub new { my ($class, $r) = @_; $r ||= Apache->request; tie *STDOUT, $class, $r; return tied *STDOUT; }

slide-44
SLIDE 44

http://www.modperlcookbook.org/ 44

package Cookbook::TaintTest; use Apache::Constants qw(OK); use Cookbook::TaintRequest; use strict; sub handler { my $r = Cookbook::TaintRequest->new(shift); my @data = $r->args; # Untaint input data if magic word "override" is present. $data[1] =~ m/(.*override.*)/; $data[1] = $1 if $1; $r->send_http_header('text/html'); $r->print("<html>You entered ", @data, "<br/></html>"); return OK; } 1;

slide-45
SLIDE 45

http://www.modperlcookbook.org/ 45

/tainted?x=<script>alert("Hi!")</script>

slide-46
SLIDE 46

http://www.modperlcookbook.org/ 46

/tainted?x=<script>alert("override Hi!")</script>

slide-47
SLIDE 47

http://www.modperlcookbook.org/ 47

Registry has issues...

  • Apache::Registry is incredibly cool
  • But it's not perfect

Apache::Registry - Run unaltered CGI scrips under mod_perl

  • Scripts that work perfectly well under

mod_cgi balk with Apache::Registry

– that's why there's Apache::PerlRun

  • Not even PerlRun can save you from some
  • f the issues
slide-48
SLIDE 48

http://www.modperlcookbook.org/ 48

For instance...

  • Mixing mod_perl with legacy CGI code

can be difficult

– now you can isolate processing in phases

  • ther than content-generation
  • What happens when you need POST

data in other phases and legacy Apache::Registry code?

  • What we need is a way to cache POST

data that makes it accessible to legacy CGI scripts

slide-49
SLIDE 49

http://www.modperlcookbook.org/ 49

Registry: The Next Generation

  • Apache::Registry is pretty complex and

difficult to alter

  • Apache::RegistryNG behaves almost the

same, but is object-oriented and a much better candidate for subclassing

  • Apache::RegistryNG is actually a subclass of

Apache::PerlRun

slide-50
SLIDE 50

http://www.modperlcookbook.org/ 50

More Subclasses!

  • Let's fix the problem by subclassing

Apache::RegistryNG

  • tie STDIN instead...
slide-51
SLIDE 51

http://www.modperlcookbook.org/ 51

package Apache::CachePOSTRegistry; use Apache::RegistryNG; use Apache::Request; use strict; @Apache::CachePOSTRegistry::ISA = qw(Apache::RegistryNG); sub new { my ($class, $r) = @_; $r = Apache::Request->instance($r || Apache->request); tie *STDIN, $class, $r; return tied *STDIN; } sub TIEHANDLE { my ($class, $r) = @_; return bless { r => $r }, $class; }

slide-52
SLIDE 52

http://www.modperlcookbook.org/ 52

Apache::Request->instance()

  • Same as Apache::Request->new()
  • Stores away an Apache::Request object

(with the POST data) and uses it for future

instantiations

sub instance { my $class = shift; my $r = shift; if (my $apreq = $r->pnotes('apreq')) { return $apreq; } my $new_req = $class->new($r, @_); $r->pnotes('apreq', $new_req); return $new_req; }

slide-53
SLIDE 53

http://www.modperlcookbook.org/ 53

sub READ { my $self = shift; my $buf = \($_[0]); shift; my $len = shift; my $offset = shift || 0; my @args = (); $self->{r}->param->do(sub { push @args, join '=', @_; 1; }); my $input = join '&', @args; $input =~ s! !+!g; substr($$buf, $offset) = substr($input, 0, $len); substr($input, 0, $len) = ''; return length substr($$buf, $offset); } 1;

slide-54
SLIDE 54

http://www.modperlcookbook.org/ 54

Setup

Alias /perl-bin /usr/local/apache/perl-bin <Location /perl-bin> SetHandler perl-script PerlHandler Apache::Registry Options +ExecCGI PerlSendHeader On </Location>

slide-55
SLIDE 55

http://www.modperlcookbook.org/ 55

It Works!

sub My::InitHandler { my $r = Apache::Request->instance(shift); my @post = $r->param; ... return Apache::Constants::OK; } 1; #!/usr/bin/perl read(STDIN, my $posted, $ENV{'CONTENT_LENGTH'}); print "Content-type: text/plain\n\n"; print $posted;

slide-56
SLIDE 56

http://www.modperlcookbook.org/ 56

It Works!

sub My::InitHandler { my $r = Apache::Request->instance(shift); my @post = $r->param; ... return Apache::Constants::OK; } 1; #!/usr/bin/perl use CGI; my $q = CGI->new; print $q->header(-type=>'text/plain'); print $q->param;

slide-57
SLIDE 57

http://www.modperlcookbook.org/ 57

XS Anyone?

  • Just for kicks, let's throw some XS into the

mix

  • XS is the glue that ties Apache and Perl

together

– most of the mod_perl API lives in Apache.xs

  • Unfortunately, mod_perl 1.3 doesn't offer

up all the Apache API, only selected parts

  • With XS, we can open up the rest...
slide-58
SLIDE 58

http://www.modperlcookbook.org/ 58

Assbackwards

  • In Apache-speak, a request that is

assbackwards is an HTTP/0.9 request

  • Apache still supports HTTP/0.9

$ telnet localhost 80 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. GET /cgi-bin/sayhello.cgi

slide-59
SLIDE 59

http://www.modperlcookbook.org/ 59

The assbackwards Flag

  • Apache marks HTTP/0.9 requests with the

assbackwards flag in the request record

  • If r->assbackwards is set, Apache doesn't

send any headers

  • mod_perl does not provide a way to access

the assbackwards flag

  • but it uses it when convenient

my $sub = $r->lookup_uri('/layline.html'); $sub->run(1);

  • You can too!
slide-60
SLIDE 60

http://www.modperlcookbook.org/ 60

Approach

  • Accessing parts of the Apache API

that mod_perl does not natively support requires XS

– Assbackwards.pm – Assbackwards.xs – typemap – Makefile.PL

  • Fortunately, in this case, all the parts

are simple

slide-61
SLIDE 61

http://www.modperlcookbook.org/ 61

The Perl Part

slide-62
SLIDE 62

http://www.modperlcookbook.org/ 62

package Apache::Assbackwards; use 5.006; use strict; use warnings; use DynaLoader;

  • ur @ISA = qw(DynaLoader Apache);
  • ur $VERSION = '0.01';

__PACKAGE__->bootstrap($VERSION); sub new { my ($class, $r) = @_; $r ||= Apache->request; return bless { r => $r }, $class; } 1;

slide-63
SLIDE 63

http://www.modperlcookbook.org/ 63

The XS Part

slide-64
SLIDE 64

http://www.modperlcookbook.org/ 64

#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "mod_perl.h" #include "mod_perl_xs.h" MODULE = Apache::Assbackwards PACKAGE = Apache::Assbackwards PROTOTYPES: ENABLE int assbackwards(r, ...) Apache r CODE: get_set_IV(r->assbackwards); OUTPUT: RETVAL

slide-65
SLIDE 65

http://www.modperlcookbook.org/ 65

The typemap Part

TYPEMAP Apache T_APACHEOBJ OUTPUT T_APACHEOBJ sv_setref_pv($arg, \"${ntype}\", (void*)$var); INPUT T_APACHEOBJ r = sv2request_rec($arg, \"$ntype\", cv)

slide-66
SLIDE 66

http://www.modperlcookbook.org/ 66

The Makefile.PL Part

use Apache::src (); WriteMakefile( NAME => 'Apache::Assbackwards', VERSION_FROM => 'Assbackwards.pm', INC => Apache::src->new->inc, }

slide-67
SLIDE 67

http://www.modperlcookbook.org/ 67

make

  • Just use the canonical

$ perl Makefile.PL $ make $ sudo make install

and you're good to go

slide-68
SLIDE 68

http://www.modperlcookbook.org/ 68

How do we use it?

package My::Assbackwards; use Apache::Assbackwards; use strict; sub handler { my $r = Apache::Assbackwards->new(shift); $r->assbackwards(1); return Apache::Constants::OK; } 1;

slide-69
SLIDE 69

http://www.modperlcookbook.org/ 69

$ telnet localhost 80 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. GET /cgi-bin/sayhello.cgi HTTP/1.0 HTTP/1.1 200 OK Date: Sat, 15 Jun 2002 19:08:48 GMT Server: Apache/1.3.25-dev (Unix) mod_perl/1.27_01-dev Perl/v5.8.0 Expires: Sat, 15 Jun 2002 19:08:50 GMT Connection: close Content-Type: text/plain; charset=ISO-8859-1 Hi $ telnet localhost 80 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. GET /cgi-bin/sayhello.cgi HTTP/1.0 Hi

slide-70
SLIDE 70

http://www.modperlcookbook.org/ 70

That was fun, but...

  • Ok, the assbackwards flag is amusing

but not all too practical

  • How about something more

applicable?

– ap_note_digest_auth_failure

slide-71
SLIDE 71

http://www.modperlcookbook.org/ 71

The XS Part

#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "mod_perl.h" MODULE = Apache::AuthDigest::API PACKAGE = Apache::AuthDigest::API PROTOTYPES: ENABLE void note_digest_auth_failure(r) Apache r CODE: ap_note_digest_auth_failure(r);

slide-72
SLIDE 72

http://www.modperlcookbook.org/ 72

The Perl Part

...

  • ur $VERSION = '0.01';
  • ur @ISA = qw(DynaLoader Apache);

__PACKAGE__->bootstrap($VERSION); ... sub new { my ($class, $r) = @_; $r ||= Apache->request; return bless { r => $r }, $class; } ... unless ($response) { $log->info("Client did not supply a Digest response"); $r->note_digest_auth_failure; return AUTH_REQUIRED }

slide-73
SLIDE 73

http://www.modperlcookbook.org/ 73

More?

  • Apache provides for something called

"registered cleanups"

$r->register_cleanup(\&cleanup); PerlCleanupHandler My::Cleanup Apache->server->register_cleanup(\&cleanup);

  • Cleanups allow you to schedule

processing at various end points in the Apache runtime

  • All use Apache's concept of memory

pools

slide-74
SLIDE 74

http://www.modperlcookbook.org/ 74

Keepalives

  • HTTP/1.1 allows for more than one

request per connection

Connection: Keep-Alive

  • Connections are interfaces with the

Apache::Connection class

my $c = $r->connection;

  • Apache creates a per-connection

memory pool

  • mod_perl provides no way to register

per-connection cleanups

slide-75
SLIDE 75

http://www.modperlcookbook.org/ 75

Per-connection Cleanups

  • Unfortunately, mod_perl wasn't

designed so you could subclass the Apache::Connection class

  • Let's subclass the Apache class and

re-bless $r->connection into our class

slide-76
SLIDE 76

http://www.modperlcookbook.org/ 76

package Apache::ConnectionCleanup; use 5.006; use strict; use Apache; use Apache::ConnectionCleanup::RegisterCleanup;

  • ur @ISA = qw(Apache);

sub new { my ($class, $r) = @_; $r ||= Apache->request; return bless { r => $r }, $class; } sub connection { my $connection = shift->SUPER::connection; return bless $connection, 'Apache::ConnectionCleanup::RegisterCleanup'; } 1;

slide-77
SLIDE 77

http://www.modperlcookbook.org/ 77

package Apache::ConnectionCleanup::RegisterCleanup; use 5.006; use strict; use warnings; use Apache::Connection; use DynaLoader;

  • ur @ISA = qw(DynaLoader Apache::Connection);
  • ur $VERSION = '0.01';

__PACKAGE__->bootstrap($VERSION); 1;

slide-78
SLIDE 78

http://www.modperlcookbook.org/ 78

#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "mod_perl.h" ... static void ApacheConnection_register_cleanup(conn_rec *c, SV *cv) { pool *p = c->pool; ... register_cleanup(p, conn, conn_cleanup_handler, mod_perl_noop); } ... void register_cleanup(conn, cv) Apache::Connection conn SV *cv CODE: ApacheConnection_register_cleanup(conn, cv);

slide-79
SLIDE 79

http://www.modperlcookbook.org/ 79

How Do We Use It?

slide-80
SLIDE 80

http://www.modperlcookbook.org/ 80

use Apache::ConnectionCleanup; use strict; sub handler { my $r = Apache::ConnectionCleanup->new(shift); $r->connection->register_cleanup(\&cleanup); return OK; } sub cleanup { # do something }

slide-81
SLIDE 81

http://www.modperlcookbook.org/ 81

Problems?

  • This particular interface presents an

interesting problem

– the cleanup is added by getting the connection from the request record – multiple requests are involved in KeepAlive connections – so, we end up registering multiple connection cleanups

  • This may or may not be a problem for

you...

slide-82
SLIDE 82

http://www.modperlcookbook.org/ 82

One way around it...

  • There is a solution

– tricky one – probably not the only one – probably not the best one – but it works

slide-83
SLIDE 83

http://www.modperlcookbook.org/ 83

package My::Single; use Apache::Constants qw(OK); use Apache::ConnectionCleanup; use strict; $My::Single::Run = 0; sub handler { my $r = Apache::ConnectionCleanup->new(shift); # increment the counter for each request $My::Single::Run++; # and create a closure to reset the counter after the first run my $marker = bless {}, 'My::Single'; $r->connection->register_cleanup(sub { single($marker) }); return OK; }

slide-84
SLIDE 84

http://www.modperlcookbook.org/ 84

sub single { my $marker = shift; # only run if we're allowed return unless $My::Single::Run; # do stuff... } sub DESTROY { # after the first closure is complete, reset the # counter to make sure we only run once $My::Single::Run = 0; } 1;

slide-85
SLIDE 85

http://www.modperlcookbook.org/ 85

Fine Manuals

  • Writing Apache Modules with Perl and C

– http://www.modperl.com/

  • mod_perl Developer's Cookbook

– http://www.modperlcookbook.org/

  • mod_perl Pocket Reference

– http://www.refcards.com/

  • mod_perl Guide

– http://perl.apache.org/guide/ – http://www.modperlbook.org/

  • mod_perl at the ASF

– http://perl.apache.org/

slide-86
SLIDE 86

http://www.modperlcookbook.org/ 86

Materials

These slides

http://www.modperlcookbook.org/~geoff/slides/ApacheCon

My modules

http://www.modperlcookbook.org/~geoff/modules

slide-87
SLIDE 87

http://www.modperlcookbook.org/ 87