do_more-mod_perl.gz - The mod_perl Developer`s Cookbook

mod_perl: do more)
Geoffrey Young
[email protected]
http://www.modperlcookbook.org/
1
3 hours of mod_perl stuff
®
rejected by OSCon
Geoffrey Young
[email protected]
http://www.modperlcookbook.org/
2
http://www.modperlcookbook.org/
3
Just the facts
http://www.modperlcookbook.org/
4
Just the facts
• OSCon theme this year is doing more
with less
http://www.modperlcookbook.org/
5
Just the facts
• OSCon theme this year is doing more
with less
• If you ask Joe Developer what
mod_perl is, he quacks "It's basically
just faster CGI"
http://www.modperlcookbook.org/
6
Just the facts
• OSCon theme this year is doing more
with less
• If you ask Joe Developer what
mod_perl is, he quacks "It's basically
just faster CGI"
• That's not exactly right...
http://www.modperlcookbook.org/
7
Request Phases
http://www.modperlcookbook.org/
8
Request Phases
• Apache breaks down request processing
into separate, logical parts called phases
http://www.modperlcookbook.org/
9
Request Phases
• Apache breaks down request processing
into separate, logical parts called phases
client request
logging
content
fixups
MIME setting
http://www.modperlcookbook.org/
URI-based init
URI translation
file-based init
resource control
10
Request Phases
• Apache breaks down request processing
into separate, logical parts called phases
• Each request is stepped through the phases
in turn until...
http://www.modperlcookbook.org/
11
Request Phases
• Apache breaks down request processing
into separate, logical parts called phases
• Each request is stepped through the phases
in turn until...
– all processing is complete
http://www.modperlcookbook.org/
12
Request Phases
• Apache breaks down request processing
into separate, logical parts called phases
• Each request is stepped through the phases
in turn until...
– all processing is complete
– somebody throws an "error"
http://www.modperlcookbook.org/
13
So What?
• Most Apache users don't worry about
the request cycle too much
http://www.modperlcookbook.org/
14
So What?
• Most Apache users don't worry about
the request cycle too much...
• ...but they do use modules that plug
into it
http://www.modperlcookbook.org/
15
... for instance
client request
URI-based init
mod_rewrite:
URI translation
RewriteRule /favicon.ico$ /images/favicon.ico
http://www.modperlcookbook.org/
16
... for instance
client request
URI-based init
URI translation
file-based init
mod_auth:
resource control
AuthUserFile .htpasswd
http://www.modperlcookbook.org/
17
... for instance
client request
mod_cgi:
URI-based init
SetHandler cgi-script
content
fixups
MIME setting
http://www.modperlcookbook.org/
URI translation
file-based init
resource control
18
That's great, but…
• Breaking down the request into
distinct phases has many benefits
http://www.modperlcookbook.org/
19
That's great, but…
• Breaking down the request into
distinct phases has many benefits
– gives each processing point a role that
can be easily managed and programmed
http://www.modperlcookbook.org/
20
That's great, but…
• Breaking down the request into
distinct phases has many benefits
– gives each processing point a role that
can be easily managed and programmed
– makes Apache more like an application
framework rather than a content engine
http://www.modperlcookbook.org/
21
That's great, but...
• Breaking down the request into
distinct phases has many benefits
– gives each processing point a role that
can be easily managed and programmed
– makes Apache more like an application
framework rather than a content engine
• but you have to code in C
http://www.modperlcookbook.org/
22
Enter mod_perl
http://www.modperlcookbook.org/
23
Enter mod_perl
• mod_perl embeds a perl interpreter
directly within the Apache runtime
http://www.modperlcookbook.org/
24
Enter mod_perl
• mod_perl embeds a perl interpreter
directly within the Apache runtime
– opens up the Apache API to Perl code
http://www.modperlcookbook.org/
25
Enter mod_perl
• mod_perl embeds a perl interpreter
directly within the Apache runtime
– opens up the Apache API to Perl code
– offers an interface to each phase of the
request cycle
http://www.modperlcookbook.org/
26
Enter mod_perl
• mod_perl embeds a perl interpreter
directly within the Apache runtime
– opens up the Apache API to Perl code
– offers an interface to each phase of the
request cycle
• We like Perl
http://www.modperlcookbook.org/
27
Registry is just a handler
http://www.modperlcookbook.org/
28
Registry is just a handler
• Apache::Registry is merely a set of
(incredibly clever) Perl subroutines
that interact with the request cycle
http://www.modperlcookbook.org/
29
Registry is just a handler
• Apache::Registry is merely a set of
(incredibly clever) Perl subroutines
that interact with the request cycle
• Performance gains are made possible
due to what mod_perl really is
http://www.modperlcookbook.org/
30
Registry is just a handler
• Apache::Registry is merely a set of
(incredibly clever) Perl subroutines
that interact with the request cycle
• Performance gains are made possible
due to what mod_perl really is
• Let's take a peek inside...
http://www.modperlcookbook.org/
31
Apache::Registry
http://www.modperlcookbook.org/
32
Apache::Registry
• Client side
– http://localhost/perl-bin/bar.pl
http://www.modperlcookbook.org/
33
Apache::Registry
• Client side
– http://localhost/perl-bin/bar.pl
• Server side
http://www.modperlcookbook.org/
34
Apache::Registry
• Client side
– http://localhost/perl-bin/bar.pl
• Server side
– mod_perl intercepts content generation
http://www.modperlcookbook.org/
35
Apache::Registry
• Client side
– http://localhost/perl-bin/bar.pl
• Server side
– mod_perl intercepts content generation
– searches @INC for Apache/Registry.pm
http://www.modperlcookbook.org/
36
Apache::Registry
• Client side
– http://localhost/perl-bin/bar.pl
• Server side
– mod_perl intercepts content generation
– searches @INC for Apache/Registry.pm
– calls
Apache::Registry::handler(Apache->request)
http://www.modperlcookbook.org/
37
Apache::Registry
• Client side
– http://localhost/perl-bin/bar.pl
• Server side
– mod_perl intercepts content generation
– searches @INC for Apache/Registry.pm
– calls
Apache::Registry::handler(Apache->request)
– inserts wizardry
http://www.modperlcookbook.org/
38
Apache::Registry
• Client side
– http://localhost/perl-bin/bar.pl
• Server side
– mod_perl intercepts content generation
– searches @INC for Apache/Registry.pm
– calls
Apache::Registry::handler(Apache->request)
– inserts wizardry
– returns response to client (a la CGI)
http://www.modperlcookbook.org/
39
Wizardry, you say?
http://www.modperlcookbook.org/
40
Wizardry, you say?
• The wizardry is basically just putting the
CGI script into it's own package
http://www.modperlcookbook.org/
41
Wizardry, you say?
• The wizardry is basically just putting the
CGI script into it's own package
package Apache::ROOT::perl_2dbin::foo_2epl;
sub handler {
BEGIN {
$^W = 1;
};
$^W = 1;
... your script here...
}
1;
http://www.modperlcookbook.org/
42
Wizardry, you say?
• The wizardry is basically just putting the
CGI script into it's own package
package Apache::ROOT::perl_2dbin::foo_2epl;
sub handler {
BEGIN {
$^W = 1;
};
$^W = 1;
... your script here...
}
1;
http://www.modperlcookbook.org/
43
Wizardry, you say?
• The wizardry is basically just putting the
CGI script into it's own package
package Apache::ROOT::perl_2dbin::foo_2epl;
sub handler {
BEGIN {
$^W = 1;
};
$^W = 1;
... your script here...
}
1;
http://www.modperlcookbook.org/
44
Wizardry, you say?
• The wizardry is basically just putting the
CGI script into it's own package
package Apache::ROOT::perl_2dbin::foo_2epl;
sub handler {
BEGIN {
$^W = 1;
};
$^W = 1;
... your script here...
}
1;
http://www.modperlcookbook.org/
45
Wizardry, you say?
• The wizardry is basically just putting the
CGI script into it's own package
package Apache::ROOT::perl_2dbin::foo_2epl;
sub handler {
BEGIN {
$^W = 1;
};
$^W = 1;
... your script here...
}
1;
• Because the perl interpreter is persistent
within Apache the (compiled) package is
already in memory when called
http://www.modperlcookbook.org/
46
Do more with less?
http://www.modperlcookbook.org/
47
Do more with less?
• Most developer's haven't even
scratched the surface of what's
possible with mod_perl
http://www.modperlcookbook.org/
48
Do more with less?
• Most developer's haven't even
scratched the surface of what's
possible with mod_perl
• Almost 25% of Apache servers are
running mod_perl
http://www.modperlcookbook.org/
49
Do more with less?
• Most developer's haven't even
scratched the surface of what's
possible with mod_perl
• Almost 25% of Apache servers are
running mod_perl
• Why do more with less?
http://www.modperlcookbook.org/
50
Do more with less?
• Most developer's haven't even
scratched the surface of what's
possible with mod_perl
• Almost 25% of Apache servers are
running mod_perl
• Why do more with less?
• Do more with what you already have
http://www.modperlcookbook.org/
51
Do more
• mod_perl allows you to interact with and
directly alter server behavior
http://www.modperlcookbook.org/
52
Do more
• mod_perl allows you to interact with and
directly alter server behavior
• Gives you the ability to "program within
Apache's framework instead of around it"
http://www.modperlcookbook.org/
53
Do more
• mod_perl allows you to interact with and
directly alter server behavior
• Gives you the ability to "program within
Apache's framework instead of around it"
• Allows you to intercept basic Apache
functions and replace them with your own
(sometimes devious) Perl substitutes
http://www.modperlcookbook.org/
54
Do more
• mod_perl allows you to interact with and
directly alter server behavior
• Gives you the ability to "program within
Apache's framework instead of around it"
• Allows you to intercept basic Apache
functions and replace them with your own
(sometimes devious) Perl substitutes
• Lets you do it all in Perl instead of C
http://www.modperlcookbook.org/
55
For Instance...
• With mod_perl, it's easy to protect
our name-based virtual hosts from
HTTP/1.0 requests Apache can't
handle
http://www.modperlcookbook.org/
56
For Instance...
• With mod_perl, it's easy to protect
our name-based virtual hosts from
HTTP/1.0 requests Apache can't
handle
http://www.modperlcookbook.org/
57
HTTP/1.0 and Host
http://www.modperlcookbook.org/
58
HTTP/1.0 and Host
• HTTP/1.0 does not require a Host
header
http://www.modperlcookbook.org/
59
HTTP/1.0 and Host
• HTTP/1.0 does not require a Host
header
• assumes a "one host per IP"
configuration
http://www.modperlcookbook.org/
60
HTTP/1.0 and Host
• HTTP/1.0 does not require a Host
header
• assumes a "one host per IP"
configuration
• this limitation breaks name-based
virtual host servers for browsers that
follow HTTP/1.0 to the letter
http://www.modperlcookbook.org/
61
HTTP/1.0 and Host
• HTTP/1.0 does not require a Host
header
• assumes a "one host per IP"
configuration
• this limitation breaks name-based
virtual host servers for browsers that
follow HTTP/1.0 to the letter
– most send the Host header, so all is well
http://www.modperlcookbook.org/
62
$ telnet www.apache.org 80
Trying 63.251.56.142...
Connected to www.apache.org.
Escape character is '^]'.
GET /foo.html HTTP/1.0
http://www.modperlcookbook.org/
63
$ telnet www.apache.org 80
Trying 63.251.56.142...
Connected to www.apache.org.
Escape character is '^]'.
GET /foo.html HTTP/1.0
http://www.modperlcookbook.org/
64
$ telnet www.apache.org 80
Trying 63.251.56.142...
Connected to www.apache.org.
Escape character is '^]'.
GET /foo.html HTTP/1.0
HTTP/1.1 302 Found
Date: Tue, 04 Jun 2002 00:52:55 GMT
Server: Apache/2.0.37-dev (Unix)
Location: http://httpd.apache.org/dev/
Content-Length: 289
Connection: close
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a
href="http://httpd.apache.org/dev/">here</a>.</p>
<hr />
<address>Apache/2.0.37-dev Server at dev.apache.org Port
80</address>
</body></html>
http://www.modperlcookbook.org/
65
$ telnet www.apache.org 80
Trying 63.251.56.142...
Connected to www.apache.org.
Escape character is '^]'.
GET /foo.html HTTP/1.0
Host: www.apache.org
http://www.modperlcookbook.org/
66
$ telnet www.apache.org 80
Trying 63.251.56.142...
Connected to www.apache.org.
Escape character is '^]'.
GET /foo.html HTTP/1.0
Host: www.apache.org
http://www.modperlcookbook.org/
67
$ telnet www.apache.org 80
Trying 63.251.56.142...
Connected to www.apache.org.
Escape character is '^]'.
GET /foo.html HTTP/1.0
Host: www.apache.org
http://www.modperlcookbook.org/
68
$ telnet www.apache.org 80
Trying 63.251.56.142...
Connected to www.apache.org.
Escape character is '^]'.
GET /foo.html HTTP/1.0
Host: www.apache.org
HTTP/1.1 404 Not Found
Date: Tue, 04 Jun 2002 00:56:40 GMT
Server: Apache/2.0.37-dev (Unix)
Content-Length: 283
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /foo.html was not found on this server.</p>
<hr />
<address>Apache/2.0.37-dev Server at www.apache.org Port
80</address>
</body></html>
http://www.modperlcookbook.org/
69
Let's fix it
http://www.modperlcookbook.org/
70
Let's fix it
• Intercept every request prior to
content-generation and return an
error unless...
http://www.modperlcookbook.org/
71
Let's fix it
• Intercept every request prior to
content-generation and return an
error unless...
– there is a Host header
http://www.modperlcookbook.org/
72
Let's fix it
• Intercept every request prior to
content-generation and return an
error unless...
– there is a Host header
– the request is an absolute URI
http://www.modperlcookbook.org/
73
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
74
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
75
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
76
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
77
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
78
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
79
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
80
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
81
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
82
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
83
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
84
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
85
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
86
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
87
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
88
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST);
use Apache::URI;
use strict;
sub handler {
my $r = shift;
# Valid requests for name based virtual hosting are:
# requests with a Host header, or
# requests that are absolute URIs.
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;
http://www.modperlcookbook.org/
89
Setup
• add TrapNoHost.pm to @INC
http://www.modperlcookbook.org/
90
Setup
• add TrapNoHost.pm to @INC
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm
http://www.modperlcookbook.org/
91
Setup
• add TrapNoHost.pm to @INC
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm
• add to httpd.conf
http://www.modperlcookbook.org/
92
Setup
• add TrapNoHost.pm to @INC
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm
• add to httpd.conf
PerlModule Cookbook::TrapNoHost
http://www.modperlcookbook.org/
93
Setup
• add TrapNoHost.pm to @INC
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm
• add to httpd.conf
PerlModule Cookbook::TrapNoHost
PerlTransHandler Cookbook::TrapNoHost
http://www.modperlcookbook.org/
94
Setup
• add TrapNoHost.pm to @INC
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm
• add to httpd.conf
PerlModule Cookbook::TrapNoHost
PerlTransHandler Cookbook::TrapNoHost
• that's it!
http://www.modperlcookbook.org/
95
Apache Request Cycle
client request
logging
content
fixups
MIME setting
http://www.modperlcookbook.org/
URI-based init
URI translation
file-based init
resource control
96
Intercept the Request
client request
URI-based init
PerlTransHandler
http://www.modperlcookbook.org/
97
Intercept the Request
client request
URI-based init
PerlTransHandler
HTTP/1.1 400 Bad Request
Date: Tue, 04 Jun 2002 01:17:52 GMT
Server: Apache/1.3.25-dev (Unix) mod_perl/1.27_01-dev Perl/v5.8.0
Connection: close
Content-Type: text/html; charset=iso-8859-1
Oops!
Did you mean to omit a Host header?
http://www.modperlcookbook.org/
98
Intercept the Request
client request
URI-based init
PerlTransHandler
HTTP/1.1 400 Bad Request
Date: Tue, 04 Jun 2002 01:17:52 GMT
Server: Apache/1.3.25-dev (Unix) mod_perl/1.27_01-dev Perl/v5.8.0
Connection: close
Content-Type: text/html; charset=iso-8859-1
Oops!
Did you mean to omit a Host header?
http://www.modperlcookbook.org/
99
Intercept the Request
client request
logging
URI-based init
PerlTransHandler
http://www.modperlcookbook.org/
100
http://www.modperlcookbook.org/
101
What else?
http://www.modperlcookbook.org/
102
Modularize Processing
http://www.modperlcookbook.org/
103
Modularize Processing
• Parsing out the query string or POST
data on each request is a pain
http://www.modperlcookbook.org/
104
Modularize Processing
• Parsing out the query string or POST
data on each request is a pain
• For the most part, you know you need
it for every request to a given
<Location>
http://www.modperlcookbook.org/
105
Modularize Processing
• Parsing out the query string or POST
data on each request is a pain
• For the most part, you know you need
it for every request to a given
<Location>
• Take advantage of the request cycle
http://www.modperlcookbook.org/
106
Modularize Processing
• Parsing out the query string or POST
data on each request is a pain
• For the most part, you know you need
it for every request to a given
<Location>
• Take advantage of the request cycle
• Modularize the parsing code
http://www.modperlcookbook.org/
107
Apache::RequestNotes
http://www.modperlcookbook.org/
108
Apache::RequestNotes
• Apache::RequestNotes parses
cookies and input parameters
http://www.modperlcookbook.org/
109
Apache::RequestNotes
• Apache::RequestNotes parses
cookies and input parameters
• stores the data in pnotes() for later
retrieval
http://www.modperlcookbook.org/
110
Setup
http://www.modperlcookbook.org/
111
Setup
Alias /perl-bin /usr/local/apache/perl-bin
<Location /perl-bin/>
SetHandler perl-script
PerlHandler Apache::Registry
Options +ExecCGI
PerlInitHandler Apache::RequestNotes
</Location>
http://www.modperlcookbook.org/
112
Setup
Alias /perl-bin /usr/local/apache/perl-bin
<Location /perl-bin/>
SetHandler perl-script
PerlHandler Apache::Registry
Options +ExecCGI
PerlInitHandler Apache::RequestNotes
</Location>
http://www.modperlcookbook.org/
113
<Location> Processing
client request
URI-based init
URI translation
PerlInitHandler
http://www.modperlcookbook.org/
114
<Location> Processing
client request
URI-based init
URI translation
PerlInitHandler
my $input
= $r->pnotes('INPUT');
# Apache::Table reference
my $uploads = $r->pnotes('UPLOADS'); # Apache::Upload array ref
my $cookies = $r->pnotes('COOKIES'); # hash reference
http://www.modperlcookbook.org/
115
User Authentication
http://www.modperlcookbook.org/
116
User Authentication
• Some .htaccess file or httpd.conf
http://www.modperlcookbook.org/
117
User Authentication
• Some .htaccess file or httpd.conf
AuthUserFile .htpasswd
AuthName "my site"
AuthType Basic
Require valid-user
http://www.modperlcookbook.org/
118
User Authentication
• Some .htaccess file or httpd.conf
AuthUserFile .htpasswd
AuthName "my site"
AuthType Basic
Require valid-user
geoff:zzpEyL0tbgwwk
http://www.modperlcookbook.org/
119
User Authentication
• Some .htaccess file or httpd.conf
AuthUserFile .htpasswd
AuthName "my site"
AuthType Basic
Require valid-user
geoff:zzpEyL0tbgwwk
http://www.modperlcookbook.org/
120
User Authentication
• Some .htaccess file or httpd.conf
AuthUserFile .htpasswd
AuthName "my site"
AuthType Basic
Require valid-user
http://www.modperlcookbook.org/
121
Who Uses Flat Files?
http://www.modperlcookbook.org/
122
Who Uses Flat Files?
• flat files are limiting, hard to manage,
difficult to integrate, and just plain
boring
http://www.modperlcookbook.org/
123
Who Uses Flat Files?
• flat files are limiting, hard to manage,
difficult to integrate, and just plain
boring
• we can do more and replace flat files
with our own authentication
mechanism
http://www.modperlcookbook.org/
124
package My::Authenticate;
use Apache::Constants qw(OK AUTH_REQUIRED);
use strict;
sub handler {
my $r = shift;
# Get the client-supplied credentials.
my ($status, $password) = $r->get_basic_auth_pw;
return $status unless $status == OK;
# Perform some custom user/password validation.
return OK if authenticate_user($r->user, $password);
# Whoops, bad credentials.
$r->note_basic_auth_failure;
return AUTH_REQUIRED;
}
http://www.modperlcookbook.org/
125
package My::Authenticate;
use Apache::Constants qw(OK AUTH_REQUIRED);
use strict;
sub handler {
my $r = shift;
# Get the client-supplied credentials.
my ($status, $password) = $r->get_basic_auth_pw;
return $status unless $status == OK;
# Perform some custom user/password validation.
return OK if authenticate_user($r->user, $password);
# Whoops, bad credentials.
$r->note_basic_auth_failure;
return AUTH_REQUIRED;
}
http://www.modperlcookbook.org/
126
package My::Authenticate;
use Apache::Constants qw(OK AUTH_REQUIRED);
use strict;
sub handler {
my $r = shift;
# Get the client-supplied credentials.
my ($status, $password) = $r->get_basic_auth_pw;
return $status unless $status == OK;
# Perform some custom user/password validation.
return OK if authenticate_user($r->user, $password);
# Whoops, bad credentials.
$r->note_basic_auth_failure;
return AUTH_REQUIRED;
}
http://www.modperlcookbook.org/
127
package My::Authenticate;
use Apache::Constants qw(OK AUTH_REQUIRED);
use strict;
sub handler {
my $r = shift;
# Get the client-supplied credentials.
my ($status, $password) = $r->get_basic_auth_pw;
return $status unless $status == OK;
# Perform some custom user/password validation.
return OK if authenticate_user($r->user, $password);
# Whoops, bad credentials.
$r->note_basic_auth_failure;
return AUTH_REQUIRED;
}
http://www.modperlcookbook.org/
128
package My::Authenticate;
use Apache::Constants qw(OK AUTH_REQUIRED);
use strict;
sub handler {
my $r = shift;
# Get the client-supplied credentials.
my ($status, $password) = $r->get_basic_auth_pw;
return $status unless $status == OK;
# Perform some custom user/password validation.
return OK if authenticate_user($r->user, $password);
# Whoops, bad credentials.
$r->note_basic_auth_failure;
return AUTH_REQUIRED;
}
http://www.modperlcookbook.org/
129
package My::Authenticate;
use Apache::Constants qw(OK AUTH_REQUIRED);
use strict;
sub handler {
my $r = shift;
# Get the client-supplied credentials.
my ($status, $password) = $r->get_basic_auth_pw;
return $status unless $status == OK;
# Perform some custom user/password validation.
return OK if authenticate_user($r->user, $password);
# Whoops, bad credentials.
$r->note_basic_auth_failure;
return AUTH_REQUIRED;
}
http://www.modperlcookbook.org/
130
package My::Authenticate;
use Apache::Constants qw(OK AUTH_REQUIRED);
use strict;
sub handler {
my $r = shift;
# Get the client-supplied credentials.
my ($status, $password) = $r->get_basic_auth_pw;
return $status unless $status == OK;
# Perform some custom user/password validation.
return OK if authenticate_user($r->user, $password);
# Whoops, bad credentials.
$r->note_basic_auth_failure;
return AUTH_REQUIRED;
}
http://www.modperlcookbook.org/
131
package My::Authenticate;
use Apache::Constants qw(OK AUTH_REQUIRED);
use strict;
sub handler {
my $r = shift;
# Get the client-supplied credentials.
my ($status, $password) = $r->get_basic_auth_pw;
return $status unless $status == OK;
# Perform some custom user/password validation.
return OK if authenticate_user($r->user, $password);
# Whoops, bad credentials.
$r->note_basic_auth_failure;
return AUTH_REQUIRED;
}
http://www.modperlcookbook.org/
132
package My::Authenticate;
use Apache::Constants qw(OK AUTH_REQUIRED);
use strict;
sub handler {
my $r = shift;
# Get the client-supplied credentials.
my ($status, $password) = $r->get_basic_auth_pw;
return $status unless $status == OK;
# Perform some custom user/password validation.
return OK if authenticate_user($r->user, $password);
# Whoops, bad credentials.
$r->note_basic_auth_failure;
return AUTH_REQUIRED;
}
http://www.modperlcookbook.org/
133
Configuration
http://www.modperlcookbook.org/
134
Configuration
• change
AuthUserFile .htpasswd
AuthName "my site"
AuthType Basic
Require valid-user
http://www.modperlcookbook.org/
135
Configuration
• change
AuthUserFile .htpasswd
AuthName "my site"
AuthType Basic
Require valid-user
• to
PerlAuthenHandler My::Authenticate
AuthName "cookbook"
AuthType Basic
Require valid-user
http://www.modperlcookbook.org/
136
Configuration
• change
AuthUserFile .htpasswd
AuthName "my site"
AuthType Basic
Require valid-user
• to
PerlAuthenHandler My::Authenticate
AuthName "cookbook"
AuthType Basic
Require valid-user
http://www.modperlcookbook.org/
137
Authentication
client request
URI-based init
URI translation
file-based init
PerlAuthenHandler
http://www.modperlcookbook.org/
138
Authentication
client request
URI-based init
URI translation
file-based init
PerlAuthenHandler
HTTP/1.1 401 Authorization Required
http://www.modperlcookbook.org/
139
Authentication
client request
logging
URI-based init
URI translation
file-based init
PerlAuthenHandler
http://www.modperlcookbook.org/
140
The Choice is Yours
• How you decide to authenticate is now
up to you
http://www.modperlcookbook.org/
141
The Choice is Yours
• How you decide to authenticate is now
up to you
sub authenticate_user {
my ($user, $pass) = @_;
return $user eq $pass;
}
http://www.modperlcookbook.org/
142
The Choice is Yours
• How you decide to authenticate is now
up to you
sub authenticate_user {
my ($user, $pass) = @_;
return $user eq $pass;
}
• Are you seeing the possibilities yet?
http://www.modperlcookbook.org/
143
The Power of CPAN
• Over 25 Apache:: shrink-wrapped
modules on CPAN for authentication
– SecureID
– Radius
– SMB
– LDAP
– NTLM
http://www.modperlcookbook.org/
144
What else?
http://www.modperlcookbook.org/
145
Logging
• Apache's default is to use
mod_log_config in common format
http://www.modperlcookbook.org/
146
Logging
• Apache's default is to use
mod_log_config in common format
LogFormat "%h %l %u %t \"%r\" %>s %b" common
CustomLog logs/access_log common
http://www.modperlcookbook.org/
147
Logging
• Apache's default is to use
mod_log_config in common format
LogFormat "%h %l %u %t \"%r\" %>s %b" common
CustomLog logs/access_log common
• Most people tweak this to combined
http://www.modperlcookbook.org/
148
Logging
• Apache's default is to use
mod_log_config in common format
LogFormat "%h %l %u %t \"%r\" %>s %b" common
CustomLog logs/access_log common
• Most people tweak this to combined
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
http://www.modperlcookbook.org/
149
Logging to a Database
http://www.modperlcookbook.org/
150
Logging to a Database
• In general, people in marketing don't
know what they want when it comes
to reports
http://www.modperlcookbook.org/
151
Logging to a Database
• In general, people in marketing don't
know what they want when it comes
to reports
• Logging directly to a database makes
life easier if you have an application
for which you need lots of reports
http://www.modperlcookbook.org/
152
Logging to a Database
• In general, people in marketing don't
know what they want when it comes
to reports
• Logging directly to a database makes
life easier if you have an application
for which you need lots of reports
• Incurs very little overhead if you are
already using a database in your
application
http://www.modperlcookbook.org/
153
package Cookbook::SiteLog;
use Apache::Constants qw(OK);
use DBI;
use strict;
sub handler {
my $r = shift;
my $dbh = DBI->connect($r->dir_config('DBASE'),
{RaiseError => 1, AutoCommit => 1, PrintError => 1}) or die $DBI::errstr;
my %columns = ( status
bytes
language
);
=> $r->status,
=> $r->bytes_sent,
=> $r->headers_in->get('Accept-Language'),
my $fields = join "$_,", keys %columns;
my $values = join ', ', ('?') x values %columns;
my $sql = qq(
insert into www.sitelog (hit, servedate, $fields)
values (hitsequence.nextval, sysdate, $values)
);
my $sth = $dbh->prepare($sql);
$sth->execute(values %columns);
return OK;
}
1;
http://www.modperlcookbook.org/
154
package Cookbook::SiteLog;
use Apache::Constants qw(OK);
use DBI;
use strict;
sub handler {
my $r = shift;
my $dbh = DBI->connect($r->dir_config('DBASE'),
{RaiseError => 1, AutoCommit => 1, PrintError => 1}) or die $DBI::errstr;
my %columns = ( status
bytes
language
);
=> $r->status,
=> $r->bytes_sent,
=> $r->headers_in->get('Accept-Language'),
my $fields = join "$_,", keys %columns;
my $values = join ', ', ('?') x values %columns;
my $sql = qq(
insert into www.sitelog (hit, servedate, $fields)
values (hitsequence.nextval, sysdate, $values)
);
my $sth = $dbh->prepare($sql);
$sth->execute(values %columns);
return OK;
}
1;
http://www.modperlcookbook.org/
155
package Cookbook::SiteLog;
use Apache::Constants qw(OK);
use DBI;
use strict;
sub handler {
my $r = shift;
my $dbh = DBI->connect($r->dir_config('DBASE'),
{RaiseError => 1, AutoCommit => 1, PrintError => 1}) or die $DBI::errstr;
my %columns = ( status
bytes
language
);
=> $r->status,
=> $r->bytes_sent,
=> $r->headers_in->get('Accept-Language'),
my $fields = join "$_,", keys %columns;
my $values = join ', ', ('?') x values %columns;
my $sql = qq(
insert into www.sitelog (hit, servedate, $fields)
values (hitsequence.nextval, sysdate, $values)
);
my $sth = $dbh->prepare($sql);
$sth->execute(values %columns);
return OK;
}
1;
http://www.modperlcookbook.org/
156
package Cookbook::SiteLog;
use Apache::Constants qw(OK);
use DBI;
use strict;
sub handler {
my $r = shift;
my $dbh = DBI->connect($r->dir_config('DBASE'),
{RaiseError => 1, AutoCommit => 1, PrintError => 1}) or die $DBI::errstr;
my %columns = ( status
bytes
language
);
=> $r->status,
=> $r->bytes_sent,
=> $r->headers_in->get('Accept-Language'),
my $fields = join "$_,", keys %columns;
my $values = join ', ', ('?') x values %columns;
my $sql = qq(
insert into www.sitelog (hit, servedate, $fields)
values (hitsequence.nextval, sysdate, $values)
);
my $sth = $dbh->prepare($sql);
$sth->execute(values %columns);
return OK;
}
1;
http://www.modperlcookbook.org/
157
package Cookbook::SiteLog;
use Apache::Constants qw(OK);
use DBI;
use strict;
sub handler {
my $r = shift;
my $dbh = DBI->connect($r->dir_config('DBASE'),
{RaiseError => 1, AutoCommit => 1, PrintError => 1}) or die $DBI::errstr;
my %columns = ( status
bytes
language
);
=> $r->status,
=> $r->bytes_sent,
=> $r->headers_in->get('Accept-Language'),
my $fields = join "$_,", keys %columns;
my $values = join ', ', ('?') x values %columns;
my $sql = qq(
insert into www.sitelog (hit, servedate, $fields)
values (hitsequence.nextval, sysdate, $values)
);
my $sth = $dbh->prepare($sql);
$sth->execute(values %columns);
return OK;
}
1;
http://www.modperlcookbook.org/
158
package Cookbook::SiteLog;
use Apache::Constants qw(OK);
use DBI;
use strict;
sub handler {
my $r = shift;
my $dbh = DBI->connect($r->dir_config('DBASE'),
{RaiseError => 1, AutoCommit => 1, PrintError => 1}) or die $DBI::errstr;
my %columns = ( status
bytes
language
);
=> $r->status,
=> $r->bytes_sent,
=> $r->headers_in->get('Accept-Language'),
my $fields = join "$_,", keys %columns;
my $values = join ', ', ('?') x values %columns;
my $sql = qq(
insert into www.sitelog (hit, servedate, $fields)
values (hitsequence.nextval, sysdate, $values)
);
my $sth = $dbh->prepare($sql);
$sth->execute(values %columns);
return OK;
}
1;
http://www.modperlcookbook.org/
159
Logging
client request
PerlLogHandler
content
fixups
MIME setting
http://www.modperlcookbook.org/
URI-based init
URI translation
file-based init
resource control
160
Speaking of Databases
http://www.modperlcookbook.org/
161
Speedy DBI
• Apache::DBI rocks
http://www.modperlcookbook.org/
162
Speedy DBI
• Apache::DBI rocks
• Reduces connection overhead
http://www.modperlcookbook.org/
163
Speedy DBI
• Apache::DBI rocks
• Reduces connection overhead
• "Works like magic"
http://www.modperlcookbook.org/
164
Speedy DBI
• Apache::DBI rocks
• Reduces connection overhead
• "Works like magic"
PerlModule Apache::DBI
http://www.modperlcookbook.org/
165
Speedy DBI
• Apache::DBI rocks
• Reduces connection overhead
• "Works like magic"
(action-at-a-distance)
PerlModule Apache::DBI
http://www.modperlcookbook.org/
166
Speedy DBI
• Apache::DBI rocks
• Reduces connection overhead
• "Works like magic"
(action-at-a-distance)
PerlModule Apache::DBI
• Speeds up both legacy CGI and
mod_perl applications
http://www.modperlcookbook.org/
167
http://www.modperlcookbook.org/
168
Use what you have
http://www.modperlcookbook.org/
169
Use what you have
• Programming using the request cycle
represents an entirely different way of
looking at your web applications
http://www.modperlcookbook.org/
170
Use what you have
• Programming using the request cycle
represents an entirely different way of
looking at your web applications
• Apache provides a rich API for
interacting with the request
http://www.modperlcookbook.org/
171
Use what you have
• Programming using the request cycle
represents an entirely different way of
looking at your web applications
• Apache provides a rich API for
interacting with the request
• mod_perl passes the savings to you
http://www.modperlcookbook.org/
172
http://www.modperlcookbook.org/
173
Objects, smobjects
http://www.modperlcookbook.org/
174
Objects, smobjects
• Object-oriented programming has
many advantages
http://www.modperlcookbook.org/
175
Objects, smobjects
• Object-oriented programming has
many advantages
– subject of great debate
http://www.modperlcookbook.org/
176
Objects, smobjects
• Object-oriented programming has
many advantages
– subject of great debate
• Programming mod_perl in OO makes
all kinds of wizardy possible
http://www.modperlcookbook.org/
177
Objects, smobjects
• 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
http://www.modperlcookbook.org/
178
Objects, smobjects
• 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 do more using OOP
http://www.modperlcookbook.org/
179
Perl OO Primer
http://www.modperlcookbook.org/
180
Perl OO Primer
• Some basic object-oriented features
to understand
http://www.modperlcookbook.org/
181
Perl OO Primer
• Some basic object-oriented features
to understand
– classes
– methods
– objects
– inheritance
http://www.modperlcookbook.org/
182
Pay Homage
http://www.modperlcookbook.org/
183
Pay Homage
• The entire object-oriented Perl world
owes Damian Conway a huge debt of
gratitude
http://www.modperlcookbook.org/
184
Pay Homage
• The entire object-oriented Perl world
owes Damian Conway a huge debt of
gratitude
• The definitions that follow are
essentially his...
http://www.modperlcookbook.org/
185
Pay Homage
• The entire object-oriented Perl world
owes Damian Conway a huge debt of
gratitude
• The definitions that follow are
essentially his...
• Any mistakes are unquestionably mine
http://www.modperlcookbook.org/
186
Perl Classes
http://www.modperlcookbook.org/
187
Perl Classes
• "To create a class, build a package"
http://www.modperlcookbook.org/
188
Perl Classes
• "To create a class, build a package"
• Perl packages associate variables and
subroutines together under a common
namespace
http://www.modperlcookbook.org/
189
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;
http://www.modperlcookbook.org/
190
Perl Methods
http://www.modperlcookbook.org/
191
Perl Methods
• "To create a method, build a
subroutine"
http://www.modperlcookbook.org/
192
Perl Methods
• "To create a method, build a
subroutine"
• Perl subroutines can be called as
functional subroutines
http://www.modperlcookbook.org/
193
Perl Methods
• "To create a method, build a
subroutine"
• Perl subroutines can be called as
functional subroutines
print $fh 'print() is a function';
http://www.modperlcookbook.org/
194
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
http://www.modperlcookbook.org/
195
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');
http://www.modperlcookbook.org/
196
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()
http://www.modperlcookbook.org/
is a method');
197
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) = @_;
}
http://www.modperlcookbook.org/
198
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) = @_;
}
http://www.modperlcookbook.org/
199
Perl Objects
http://www.modperlcookbook.org/
200
Perl Objects
• "To create an object, bless a referent"
http://www.modperlcookbook.org/
201
Perl Objects
• "To create an object, bless a referent"
• Perl has a special function bless()
that associates a variable with a class
http://www.modperlcookbook.org/
202
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;
http://www.modperlcookbook.org/
203
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
http://www.modperlcookbook.org/
204
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
http://www.modperlcookbook.org/
205
Perl Inhertiance
http://www.modperlcookbook.org/
206
Perl Inhertiance
• To create a subclass, populate @ISA
http://www.modperlcookbook.org/
207
Perl Inheritance
• To create a subclass, populate @ISA
– I made that up for consistency
http://www.modperlcookbook.org/
208
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
http://www.modperlcookbook.org/
209
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
http://www.modperlcookbook.org/
210
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
our @ISA = qw(My::Dinghy);
http://www.modperlcookbook.org/
211
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
our @ISA = qw(My::Dinghy);
use vars qw(@ISA);
@ISA = qw(My::Dinghy);
http://www.modperlcookbook.org/
212
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
our @ISA = qw(My::Dinghy);
use vars qw(@ISA);
@ISA = qw(My::Dinghy);
@My::12Meter::ISA = qw(My::Dinghy);
http://www.modperlcookbook.org/
213
Guess What?
http://www.modperlcookbook.org/
214
Guess What?
• mod_perl has already introduced you
to most of Perl's OO semantics
http://www.modperlcookbook.org/
215
Guess What?
• mod_perl has already introduced you
to most of Perl's OO semantics
my $r = Apache->request;
http://www.modperlcookbook.org/
216
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');
http://www.modperlcookbook.org/
217
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
http://www.modperlcookbook.org/
218
Handlers as Classes
http://www.modperlcookbook.org/
219
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;
http://www.modperlcookbook.org/
220
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;
http://www.modperlcookbook.org/
221
OO mod_perl
• Programming using the mod_perl API
forces us to use most of Perls OO
tools already
http://www.modperlcookbook.org/
222
OO mod_perl
• Programming using the mod_perl API
forces us to use most of Perls OO
tools already
• We just need to fill in a few of the
gaps for phenomenal cosmic power...
http://www.modperlcookbook.org/
223
Step #1
http://www.modperlcookbook.org/
224
Step #1
• Change our existing handlers to
method handlers
http://www.modperlcookbook.org/
225
Step #1
• Change our existing handlers to
method handlers
• Method handlers are just normal
handlers called using OO syntax
http://www.modperlcookbook.org/
226
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
http://www.modperlcookbook.org/
227
Prototyping
• The classical way is to use Perl
prototypes
http://www.modperlcookbook.org/
228
Prototyping
• The classical way is to use Perl
prototypes
sub handler ($$) {
...
}
http://www.modperlcookbook.org/
229
Prototyping
• The classical way is to use Perl
prototypes
sub handler ($$) {
...
}
• Prototypes are deprecated in 2.0
http://www.modperlcookbook.org/
230
Attributes
• The new way is to use subroutine
attributes
http://www.modperlcookbook.org/
231
Attributes
• The new way is to use subroutine
attributes
sub handler : method {
...
}
http://www.modperlcookbook.org/
232
Attributes
• The new way is to use subroutine
attributes
sub handler : method {
...
}
• See the attributes manpage
http://www.modperlcookbook.org/
233
Step #2
http://www.modperlcookbook.org/
234
Step #2
• Change our handler() method to be
able to receive an OO call
http://www.modperlcookbook.org/
235
Step #2
• Change our handler() method to be
able to receive an OO call
sub handler {
my $r = shift;
}
http://www.modperlcookbook.org/
236
Step #2
• Change our handler() method to be
able to receive an OO call
sub handler : method {
my ($self, $r) = @_;
}
http://www.modperlcookbook.org/
237
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
http://www.modperlcookbook.org/
238
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
http://www.modperlcookbook.org/
239
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
object
http://www.modperlcookbook.org/
240
Step #3
http://www.modperlcookbook.org/
241
Step #3
• Call the handler using a method
syntax
http://www.modperlcookbook.org/
242
Step #3
• Call the handler using a method
syntax
PerlModule My::MethodHandler
http://www.modperlcookbook.org/
243
Step #3
• Call the handler using a method
syntax
PerlModule My::MethodHandler
PerlInitHandler My::MethodHandler->handler
http://www.modperlcookbook.org/
244
Step #3
• Call the handler using a method
syntax
PerlModule My::MethodHandler
PerlInitHandler My::MethodHandler->handler
http://www.modperlcookbook.org/
245
Step #3
• Call the handler using a method
syntax
PerlModule My::MethodHandler
PerlInitHandler My::MethodHandler->handler
• Pre-loading is required
http://www.modperlcookbook.org/
246
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
http://www.modperlcookbook.org/
247
So What?
http://www.modperlcookbook.org/
248
So What?
• Normal handlers and method handlers
are equivalent in nearly all areas...
http://www.modperlcookbook.org/
249
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
http://www.modperlcookbook.org/
250
For Example
http://www.modperlcookbook.org/
251
For Example
• Apache::SSI provides a Perl
implementation of Server Side
Includes
http://www.modperlcookbook.org/
252
For Example
• Apache::SSI provides a Perl
implementation of Server Side
Includes
<Files *.shtml>
SetHandler perl-script
PerlHandler Apache::SSI
</Files>
http://www.modperlcookbook.org/
253
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...
http://www.modperlcookbook.org/
254
Apache::SSI
• Integrates with Apache::Filter to
provide filtered content generation
http://www.modperlcookbook.org/
255
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>
http://www.modperlcookbook.org/
256
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>
http://www.modperlcookbook.org/
257
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>
http://www.modperlcookbook.org/
258
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>
http://www.modperlcookbook.org/
259
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
http://www.modperlcookbook.org/
260
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
http://www.modperlcookbook.org/
261
Drawbacks
http://www.modperlcookbook.org/
262
Drawbacks
• Apache::SSI is a huge win for people
who like to modularize processing
http://www.modperlcookbook.org/
263
Drawbacks
• Apache::SSI is a huge win for people
who like to modularize processing
• There is one rather limiting drawback
to the current implementation
http://www.modperlcookbook.org/
264
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
http://www.modperlcookbook.org/
265
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 Apache::Clean
http://www.modperlcookbook.org/
266
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
http://www.modperlcookbook.org/
267
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
http://www.modperlcookbook.org/
268
There is Hope
http://www.modperlcookbook.org/
269
There is Hope
• Fortunately, Apache::SSI is implemented
using method handlers
http://www.modperlcookbook.org/
270
There is Hope
• Fortunately, Apache::SSI is implemented
using method handlers
• We can subclass Apache::SSI and provide
our own exec and include implementations
that fix the problem
http://www.modperlcookbook.org/
271
There is Hope
• Fortunately, Apache::SSI is implemented
using method handlers
• We can subclass Apache::SSI and provide
our own exec and include implementations
that fix the problem
• We leave all the document parsing and
other tag implementations alone
http://www.modperlcookbook.org/
272
There is Hope
• Fortunately, Apache::SSI is implemented
using method handlers
• We can subclass Apache::SSI and provide
our own exec and include implementations
that fix the problem
• We leave all the document parsing and
other tag implementations alone
* Apache::SSI now includes Apache::FakeSSI which
accomplishes the same thing, but is a complete
implementation
http://www.modperlcookbook.org/
273
package Cookbook::SSI;
use
use
use
use
Apache::SSI;
HTTP::Request;
LWP::UserAgent;
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});
}
else {
my ($base) = $uri->path =~ m!(.*/)!;
# path is absolute
# 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;
http://www.modperlcookbook.org/
274
Setup
• Just use our module wherever we
used to use Apache::SSI
http://www.modperlcookbook.org/
275
Setup
• Just use our module wherever we
used to use Apache::SSI
PerlModule Apache::SSI
<Location /pipeline>
SetHandler perl-script
PerlHandler My::Content Apache::SSI Apache::Clean
PerlSetVar Filter On
</Location>
http://www.modperlcookbook.org/
276
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>
http://www.modperlcookbook.org/
277
http://www.modperlcookbook.org/
278
http://www.modperlcookbook.org/
279
http://www.modperlcookbook.org/
280
But wait, there's more...
http://www.modperlcookbook.org/
281
But wait, there's more...
• Method handlers are a nice thing to
have
http://www.modperlcookbook.org/
282
But wait, there's more...
• Method handlers are a nice thing to
have
• Not very interesting in themselves
http://www.modperlcookbook.org/
283
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
http://www.modperlcookbook.org/
284
The Apache Class
http://www.modperlcookbook.org/
285
The Apache Class
• The Apache class is at the heart of all
we do in mod_perl
http://www.modperlcookbook.org/
286
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
http://www.modperlcookbook.org/
287
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
overriding Apache
http://www.modperlcookbook.org/
288
Subclassing Apache
http://www.modperlcookbook.org/
289
Subclassing Apache
• Let's make $r->bytes_sent() return
KB instead of bytes
http://www.modperlcookbook.org/
290
Subclassing Apache
• Let's make $r->bytes_sent() return
KB instead of bytes
• How? Create a simple subclass that
does the calculation for us
http://www.modperlcookbook.org/
291
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;
http://www.modperlcookbook.org/
292
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;
http://www.modperlcookbook.org/
293
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;
http://www.modperlcookbook.org/
294
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;
http://www.modperlcookbook.org/
295
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;
http://www.modperlcookbook.org/
296
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;
http://www.modperlcookbook.org/
297
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;
http://www.modperlcookbook.org/
298
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;
http://www.modperlcookbook.org/
299
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;
http://www.modperlcookbook.org/
300
H'wa?
http://www.modperlcookbook.org/
301
H'wa?
• What's going on here?
our @ISA = qw(Apache);
return bless { r => $r }, $class;
http://www.modperlcookbook.org/
302
H'wa?
• What's going on here?
our @ISA = qw(Apache);
return bless { r => $r }, $class;
– ask Doug if you see him
http://www.modperlcookbook.org/
303
H'wa?
• What's going on here?
our @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
http://www.modperlcookbook.org/
304
H'wa?
• What's going on here?
our @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
http://www.modperlcookbook.org/
305
Sample Usage
http://www.modperlcookbook.org/
306
Sample Usage
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;
http://www.modperlcookbook.org/
307
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;
http://www.modperlcookbook.org/
308
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;
http://www.modperlcookbook.org/
309
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;
http://www.modperlcookbook.org/
310
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;
http://www.modperlcookbook.org/
311
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;
http://www.modperlcookbook.org/
312
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;
http://www.modperlcookbook.org/
313
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;
http://www.modperlcookbook.org/
314
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;
http://www.modperlcookbook.org/
315
[Wed Jun 12 21:19:35 2002] [error] 9 KB sent for /manual/index.html
[Wed Jun 12 21:19:35 2002] [error] 9268 bytes sent for /manual/index.html
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;
http://www.modperlcookbook.org/
316
Let's Simplify
http://www.modperlcookbook.org/
317
Let's Simplify
• We only used both $r and $c in this
example to show the difference
http://www.modperlcookbook.org/
318
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
http://www.modperlcookbook.org/
319
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 = shift;
my $c = Cookbook::Apache->new($r);
http://www.modperlcookbook.org/
320
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);
http://www.modperlcookbook.org/
321
Kick it up a notch
http://www.modperlcookbook.org/
322
Kick it up a notch
• Our sample Apache subclass isn't
terribly interesting or terribly useful
http://www.modperlcookbook.org/
323
Kick it up a notch
• Our sample Apache subclass isn't
terribly interesting or terribly useful
• Time to add a little heat
http://www.modperlcookbook.org/
324
Cross-Site Scripting
http://www.modperlcookbook.org/
325
Cross-Site Scripting
• As web developers, we should always check
end-user input before using it
http://www.modperlcookbook.org/
326
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
http://www.modperlcookbook.org/
327
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
http://www.modperlcookbook.org/
328
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
http://www.modperlcookbook.org/
329
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
http://www.modperlcookbook.org/
330
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()
http://www.modperlcookbook.org/
331
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()
http://www.modperlcookbook.org/
332
Lots of Overhead
http://www.modperlcookbook.org/
333
Lots of Overhead
• For CGI or mod_perl developers, that
means remembering lots of calls to
encode() or escape_html()
http://www.modperlcookbook.org/
334
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?
http://www.modperlcookbook.org/
335
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
http://www.modperlcookbook.org/
336
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
http://www.modperlcookbook.org/
337
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
http://www.modperlcookbook.org/
338
Background
http://www.modperlcookbook.org/
339
Background
• We need to add PerlTaintCheck On
to our httpd.conf to mimic the -T
switch
http://www.modperlcookbook.org/
340
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
http://www.modperlcookbook.org/
341
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 };
http://www.modperlcookbook.org/
342
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"
http://www.modperlcookbook.org/
343
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);
}
http://www.modperlcookbook.org/
344
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);
}
http://www.modperlcookbook.org/
345
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);
}
http://www.modperlcookbook.org/
346
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);
}
http://www.modperlcookbook.org/
347
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);
}
http://www.modperlcookbook.org/
348
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);
}
http://www.modperlcookbook.org/
349
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);
}
http://www.modperlcookbook.org/
350
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);
}
http://www.modperlcookbook.org/
351
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);
}
http://www.modperlcookbook.org/
352
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);
}
http://www.modperlcookbook.org/
353
What's missing?
http://www.modperlcookbook.org/
354
What's missing?
• So far all we have done is override
mod_perl's $r->print()
http://www.modperlcookbook.org/
355
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
http://www.modperlcookbook.org/
356
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>";
http://www.modperlcookbook.org/
357
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
http://www.modperlcookbook.org/
358
TIEHANDLE
• Perl provides the TIEHANDLE interface
as a way to override how filehandles
behave when written to or read from
http://www.modperlcookbook.org/
359
TIEHANDLE
• Perl provides the TIEHANDLE interface
as a way to override how filehandles
behave when written to or read from
print "foo";
http://www.modperlcookbook.org/
360
TIEHANDLE
• Perl provides the TIEHANDLE interface
as a way to override how filehandles
behave when written to or read from
print "foo";
print STDOUT "foo";
http://www.modperlcookbook.org/
361
TIEHANDLE
• 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
http://www.modperlcookbook.org/
362
More mod_perl Magic
http://www.modperlcookbook.org/
363
More mod_perl Magic
• $r->print() sends data to the client
http://www.modperlcookbook.org/
364
More mod_perl Magic
• $r->print() sends data to the client
– wrapper around Apache API calls that write data
over the wire
http://www.modperlcookbook.org/
365
More mod_perl Magic
• $r->print() sends data to the client
– wrapper around Apache API calls that write data
over the wire
• mod_perl ties standard streams to the
Apache class
http://www.modperlcookbook.org/
366
More mod_perl Magic
• $r->print() sends data to the client
– wrapper around Apache API calls that write data
over the wire
• mod_perl ties standard streams to the
Apache class
– writes to STDOUT use $r->print()
http://www.modperlcookbook.org/
367
More mod_perl Magic
• $r->print() sends data to the client
– wrapper around Apache API calls that write data
over the wire
• mod_perl ties standard streams to the
Apache class
– writes to STDOUT use $r->print()
• why Apache::Registry works
http://www.modperlcookbook.org/
368
More mod_perl Magic
• $r->print() sends data to the client
– wrapper around Apache API calls that write data
over 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
http://www.modperlcookbook.org/
369
More mod_perl Magic
• $r->print() sends data to the client
– wrapper around Apache API calls that write data
over 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
• We need to intercept both $r->print() and
print()s to STDOUT
http://www.modperlcookbook.org/
370
Apache's TIEHANDLE
http://www.modperlcookbook.org/
371
Apache's TIEHANDLE
• The Apache class provides a
TIEHANDLE interface
http://www.modperlcookbook.org/
372
Apache's TIEHANDLE
• The Apache class provides a
TIEHANDLE interface
• When subclassing the Apache class,
we can override the PRINT part of the
interface
http://www.modperlcookbook.org/
373
Apache's TIEHANDLE
• The Apache class 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
http://www.modperlcookbook.org/
374
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
tie *STDOUT, $class, $r;
return tied *STDOUT;
}
http://www.modperlcookbook.org/
375
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
tie *STDOUT, $class, $r;
return tied *STDOUT;
}
http://www.modperlcookbook.org/
376
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
tie *STDOUT, $class, $r;
return tied *STDOUT;
}
http://www.modperlcookbook.org/
377
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
tie *STDOUT, $class, $r;
return tied *STDOUT;
}
http://www.modperlcookbook.org/
378
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
tie *STDOUT, $class, $r;
return tied *STDOUT;
}
sub TIEHANDLE {
my ($class, $r) = @_;
return bless { r => $r }, $class;
}
sub PRINT {
shift->print(@_);
}
1;
http://www.modperlcookbook.org/
379
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
tie *STDOUT, $class, $r;
return tied *STDOUT;
}
sub TIEHANDLE {
my ($class, $r) = @_;
return bless { r => $r }, $class;
}
sub PRINT {
shift->print(@_);
}
1;
http://www.modperlcookbook.org/
380
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
tie *STDOUT, $class, $r;
return tied *STDOUT;
}
sub TIEHANDLE {
my ($class, $r) = @_;
return bless { r => $r }, $class;
}
sub PRINT {
shift->print(@_);
}
1;
http://www.modperlcookbook.org/
381
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
tie *STDOUT, $class, $r;
return tied *STDOUT;
}
sub TIEHANDLE {
my ($class, $r) = @_;
return bless { r => $r }, $class;
}
sub PRINT {
shift->print(@_);
}
1;
http://www.modperlcookbook.org/
382
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
tie *STDOUT, $class, $r;
return tied *STDOUT;
}
sub TIEHANDLE {
my ($class, $r) = @_;
return bless { r => $r }, $class;
}
sub PRINT {
shift->print(@_);
}
1;
http://www.modperlcookbook.org/
383
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
tie *STDOUT, $class, $r;
return tied *STDOUT;
}
sub TIEHANDLE {
my ($class, $r) = @_;
return bless { r => $r }, $class;
}
sub PRINT {
shift->print(@_);
}
1;
http://www.modperlcookbook.org/
384
Let's Try It Out
http://www.modperlcookbook.org/
385
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;
http://www.modperlcookbook.org/
386
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;
http://www.modperlcookbook.org/
387
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;
http://www.modperlcookbook.org/
388
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;
http://www.modperlcookbook.org/
389
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;
http://www.modperlcookbook.org/
390
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;
http://www.modperlcookbook.org/
391
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;
http://www.modperlcookbook.org/
392
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;
http://www.modperlcookbook.org/
393
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');
print "<html>You entered ", @data, "<br/></html>";
return OK;
}
1;
http://www.modperlcookbook.org/
394
/tainted?x=<script>alert("Hi!")</script>
http://www.modperlcookbook.org/
395
/tainted?x=<script>alert("Hi!")</script>
http://www.modperlcookbook.org/
396
/tainted?x=<script>alert("Hi!")</script>
http://www.modperlcookbook.org/
397
/tainted?x=<script>alert("override Hi!")</script>
http://www.modperlcookbook.org/
398
/tainted?x=<script>alert("override Hi!")</script>
http://www.modperlcookbook.org/
399
/tainted?x=<script>alert("override Hi!")</script>
http://www.modperlcookbook.org/
400
http://www.modperlcookbook.org/
401
Registry has issues...
http://www.modperlcookbook.org/
402
Registry has issues...
• Apache::Registry is incredibly cool
http://www.modperlcookbook.org/
403
Registry has issues...
• Apache::Registry is incredibly cool
• But it's not perfect
http://www.modperlcookbook.org/
404
Registry has issues...
• Apache::Registry is incredibly cool
• But it's not perfect
Apache::Registry - Run unaltered CGI scrips under mod_perl
http://www.modperlcookbook.org/
405
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
http://www.modperlcookbook.org/
406
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
http://www.modperlcookbook.org/
407
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
of the issues
http://www.modperlcookbook.org/
408
For instance...
http://www.modperlcookbook.org/
409
For instance...
• Mixing mod_perl with legacy CGI code
can be difficult
http://www.modperlcookbook.org/
410
For instance...
• Mixing mod_perl with legacy CGI code
can be difficult
– now you can isolate processing in phases
other than content-generation
http://www.modperlcookbook.org/
411
For instance...
• Mixing mod_perl with legacy CGI code
can be difficult
– now you can isolate processing in phases
other than content-generation
• What happens when you need POST
data in other phases and legacy
Apache::Registry code?
http://www.modperlcookbook.org/
412
For instance...
• Mixing mod_perl with legacy CGI code
can be difficult
– now you can isolate processing in phases
other 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
http://www.modperlcookbook.org/
413
Registry: The Next Generation
http://www.modperlcookbook.org/
414
Registry: The Next Generation
http://www.modperlcookbook.org/
415
Registry: The Next Generation
• Apache::Registry is pretty complex and
difficult to alter
http://www.modperlcookbook.org/
416
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
http://www.modperlcookbook.org/
417
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
http://www.modperlcookbook.org/
418
Do more!
• Let's do more by subclassing
Apache::RegistryNG
http://www.modperlcookbook.org/
419
Do more!
• Let's do more by subclassing
Apache::RegistryNG
• tie STDIN instead...
http://www.modperlcookbook.org/
420
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;
}http://www.modperlcookbook.org/
421
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;
}http://www.modperlcookbook.org/
422
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;
}http://www.modperlcookbook.org/
423
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;
}http://www.modperlcookbook.org/
424
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;
}http://www.modperlcookbook.org/
425
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;
}http://www.modperlcookbook.org/
426
Apache::Request->instance()
http://www.modperlcookbook.org/
427
Apache::Request->instance()
• Same as Apache::Request->new()
http://www.modperlcookbook.org/
428
Apache::Request->instance()
• Same as Apache::Request->new()
• Stores away an Apache::Request object
(with the POST data) and uses it for future
instantiations
http://www.modperlcookbook.org/
429
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;
}
http://www.modperlcookbook.org/
430
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;
}
http://www.modperlcookbook.org/
431
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;
}
http://www.modperlcookbook.org/
432
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;
}
http://www.modperlcookbook.org/
433
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;
}
http://www.modperlcookbook.org/
434
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;
}http://www.modperlcookbook.org/
435
sub READ {
my
my
my
my
$self = shift;
$buf = \($_[0]); shift;
$len = shift;
$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;
http://www.modperlcookbook.org/
436
sub READ {
my
my
my
my
$self = shift;
$buf = \($_[0]); shift;
$len = shift;
$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;
http://www.modperlcookbook.org/
437
sub READ {
my
my
my
my
$self = shift;
$buf = \($_[0]); shift;
$len = shift;
$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;
http://www.modperlcookbook.org/
438
sub READ {
my
my
my
my
$self = shift;
$buf = \($_[0]); shift;
$len = shift;
$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;
http://www.modperlcookbook.org/
439
sub READ {
my
my
my
my
$self = shift;
$buf = \($_[0]); shift;
$len = shift;
$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;
http://www.modperlcookbook.org/
440
sub READ {
my
my
my
my
$self = shift;
$buf = \($_[0]); shift;
$len = shift;
$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;
http://www.modperlcookbook.org/
441
sub READ {
my
my
my
my
$self = shift;
$buf = \($_[0]); shift;
$len = shift;
$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;
http://www.modperlcookbook.org/
442
sub READ {
my
my
my
my
$self = shift;
$buf = \($_[0]); shift;
$len = shift;
$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;
http://www.modperlcookbook.org/
443
sub READ {
my
my
my
my
$self = shift;
$buf = \($_[0]); shift;
$len = shift;
$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;
http://www.modperlcookbook.org/
444
It Works!
http://www.modperlcookbook.org/
445
It Works!
sub My::InitHandler {
my $r = Apache::Request->instance(shift);
my @post = $r->param;
...
return Apache::Constants::OK;
}
1;
http://www.modperlcookbook.org/
446
It Works!
sub My::InitHandler {
my $r = Apache::Request->instance(shift);
my @post = $r->param;
...
return Apache::Constants::OK;
}
1;
http://www.modperlcookbook.org/
447
It Works!
sub My::InitHandler {
my $r = Apache::Request->instance(shift);
my @post = $r->param;
...
return Apache::Constants::OK;
}
1;
http://www.modperlcookbook.org/
448
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;
http://www.modperlcookbook.org/
449
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;
http://www.modperlcookbook.org/
450
http://www.modperlcookbook.org/
451
XS Anyone?
http://www.modperlcookbook.org/
452
XS Anyone?
• Just for kicks, let's throw some XS into the
mix
http://www.modperlcookbook.org/
453
XS Anyone?
• Just for kicks, let's throw some XS into the
mix
• XS is the glue that ties Apache and Perl
together
http://www.modperlcookbook.org/
454
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
http://www.modperlcookbook.org/
455
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
http://www.modperlcookbook.org/
456
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...
http://www.modperlcookbook.org/
457
Assbackwards
http://www.modperlcookbook.org/
458
Assbackwards
• In Apache-speak, a request that is
assbackwards is an HTTP/0.9 request
http://www.modperlcookbook.org/
459
Assbackwards
• In Apache-speak, a request that is
assbackwards is an HTTP/0.9 request
• Apache still supports HTTP/0.9
http://www.modperlcookbook.org/
460
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
http://www.modperlcookbook.org/
461
Assbackwards
• In Apache-speak, a request that is
assbackward 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
http://www.modperlcookbook.org/
462
Assbackwards
• In Apache-speak, a request that is
assbackward 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
Hi
http://www.modperlcookbook.org/
463
The assbackwards Flag
http://www.modperlcookbook.org/
464
The assbackwards Flag
• Apache marks HTTP/0.9 requests with the
assbackwards flag in the request record
http://www.modperlcookbook.org/
465
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
http://www.modperlcookbook.org/
466
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
http://www.modperlcookbook.org/
467
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
http://www.modperlcookbook.org/
468
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');
http://www.modperlcookbook.org/
469
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();
http://www.modperlcookbook.org/
470
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);
http://www.modperlcookbook.org/
471
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!
http://www.modperlcookbook.org/
472
Approach
http://www.modperlcookbook.org/
473
Approach
• Accessing parts of the Apache API
that mod_perl does not natively
support requires XS
http://www.modperlcookbook.org/
474
Approach
• Accessing parts of the Apache API
that mod_perl does not natively
support requires XS
– Assbackwards.pm
http://www.modperlcookbook.org/
475
Approach
• Accessing parts of the Apache API
that mod_perl does not natively
support requires XS
– Assbackwards.pm
– Assbackwards.xs
http://www.modperlcookbook.org/
476
Approach
• Accessing parts of the Apache API
that mod_perl does not natively
support requires XS
– Assbackwards.pm
– Assbackwards.xs
– typemap
http://www.modperlcookbook.org/
477
Approach
• Accessing parts of the Apache API
that mod_perl does not natively
support requires XS
– Assbackwards.pm
– Assbackwards.xs
– typemap
– Makefile.PL
http://www.modperlcookbook.org/
478
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
http://www.modperlcookbook.org/
479
The Perl Part
http://www.modperlcookbook.org/
480
package Apache::Assbackwards;
use 5.006;
use strict;
use warnings;
use DynaLoader;
our @ISA = qw(DynaLoader Apache);
our $VERSION = '0.01';
__PACKAGE__->bootstrap($VERSION);
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
return bless { r => $r }, $class;
}
1;
http://www.modperlcookbook.org/
481
package Apache::Assbackwards;
use 5.006;
use strict;
use warnings;
use DynaLoader;
our @ISA = qw(DynaLoader Apache);
our $VERSION = '0.01';
__PACKAGE__->bootstrap($VERSION);
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
return bless { r => $r }, $class;
}
1;
http://www.modperlcookbook.org/
482
package Apache::Assbackwards;
use 5.006;
use strict;
use warnings;
use DynaLoader;
our @ISA = qw(DynaLoader Apache);
our $VERSION = '0.01';
__PACKAGE__->bootstrap($VERSION);
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
return bless { r => $r }, $class;
}
1;
http://www.modperlcookbook.org/
483
package Apache::Assbackwards;
use 5.006;
use strict;
use warnings;
use DynaLoader;
our @ISA = qw(DynaLoader Apache);
our $VERSION = '0.01';
__PACKAGE__->bootstrap($VERSION);
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
return bless { r => $r }, $class;
}
1;
http://www.modperlcookbook.org/
484
package Apache::Assbackwards;
use 5.006;
use strict;
use warnings;
use DynaLoader;
our @ISA = qw(DynaLoader Apache);
our $VERSION = '0.01';
__PACKAGE__->bootstrap($VERSION);
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
return bless { r => $r }, $class;
}
1;
http://www.modperlcookbook.org/
485
package Apache::Assbackwards;
use 5.006;
use strict;
use warnings;
use DynaLoader;
our @ISA = qw(DynaLoader Apache);
our $VERSION = '0.01';
__PACKAGE__->bootstrap($VERSION);
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
return bless { r => $r }, $class;
}
1;
http://www.modperlcookbook.org/
486
package Apache::Assbackwards;
use 5.006;
use strict;
use warnings;
use DynaLoader;
our @ISA = qw(DynaLoader Apache);
our $VERSION = '0.01';
__PACKAGE__->bootstrap($VERSION);
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
return bless { r => $r }, $class;
}
1;
http://www.modperlcookbook.org/
487
The XS Part
http://www.modperlcookbook.org/
488
#include
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"mod_perl.h"
"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
http://www.modperlcookbook.org/
489
#include
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"mod_perl.h"
"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
http://www.modperlcookbook.org/
490
#include
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"mod_perl.h"
"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
http://www.modperlcookbook.org/
491
#include
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"mod_perl.h"
"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
http://www.modperlcookbook.org/
492
#include
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"mod_perl.h"
"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
http://www.modperlcookbook.org/
493
#include
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"mod_perl.h"
"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
http://www.modperlcookbook.org/
494
#include
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"mod_perl.h"
"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
http://www.modperlcookbook.org/
495
#include
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"mod_perl.h"
"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
http://www.modperlcookbook.org/
496
#include
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"mod_perl.h"
"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
http://www.modperlcookbook.org/
497
The typemap Part
http://www.modperlcookbook.org/
498
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)
http://www.modperlcookbook.org/
499
The Makefile.PL Part
http://www.modperlcookbook.org/
500
The Makefile.PL Part
use Apache::src ();
WriteMakefile(
NAME
=> 'Apache::Assbackwards',
VERSION_FROM => 'Assbackwards.pm',
INC
=> Apache::src->new->inc,
}
http://www.modperlcookbook.org/
501
The Makefile.PL Part
use Apache::src ();
WriteMakefile(
NAME
=> 'Apache::Assbackwards',
VERSION_FROM => 'Assbackwards.pm',
INC
=> Apache::src->new->inc,
}
http://www.modperlcookbook.org/
502
The Makefile.PL Part
use Apache::src ();
WriteMakefile(
NAME
=> 'Apache::Assbackwards',
VERSION_FROM => 'Assbackwards.pm',
INC
=> Apache::src->new->inc,
}
http://www.modperlcookbook.org/
503
The Makefile.PL Part
use Apache::src ();
WriteMakefile(
NAME
VERSION_FROM
INC
TYPEMAPS
}
=>
=>
=>
=>
'Apache::Assbackwards',
'Assbackwards.pm',
Apache::src->new->inc,
Apache::src->new->typemaps,
http://www.modperlcookbook.org/
504
make
http://www.modperlcookbook.org/
505
make
• Just use the canonical
$ perl Makefile.PL
$ make
$ sudo make install
and you're good to go
http://www.modperlcookbook.org/
506
How do we use it?
http://www.modperlcookbook.org/
507
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;
http://www.modperlcookbook.org/
508
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;
http://www.modperlcookbook.org/
509
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;
http://www.modperlcookbook.org/
510
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;
http://www.modperlcookbook.org/
511
$ telnet localhost 80
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET /cgi-bin/sayhello.cgi HTTP/1.0
http://www.modperlcookbook.org/
512
$ 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
http://www.modperlcookbook.org/
513
$ 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
http://www.modperlcookbook.org/
514
$ 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
http://www.modperlcookbook.org/
515
That was fun, but...
• Ok, the assbackwards flag is amusing
but not all too practical
http://www.modperlcookbook.org/
516
That was fun, but...
• Ok, the assbackwards flag is amusing
but not all too practical
• How about something more
applicable?
http://www.modperlcookbook.org/
517
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
http://www.modperlcookbook.org/
518
The XS Part
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"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);
http://www.modperlcookbook.org/
519
The XS Part
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"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);
http://www.modperlcookbook.org/
520
The XS Part
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"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);
http://www.modperlcookbook.org/
521
The XS Part
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"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);
http://www.modperlcookbook.org/
522
The XS Part
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"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);
http://www.modperlcookbook.org/
523
The Perl Part
http://www.modperlcookbook.org/
524
...
The Perl Part
our $VERSION = '0.01';
our @ISA = qw(DynaLoader Apache);
__PACKAGE__->bootstrap($VERSION);
http://www.modperlcookbook.org/
525
...
The Perl Part
our $VERSION = '0.01';
our @ISA = qw(DynaLoader Apache);
__PACKAGE__->bootstrap($VERSION);
...
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
return bless { r => $r }, $class;
}
http://www.modperlcookbook.org/
526
The Perl Part
...
our $VERSION = '0.01';
our @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
}
http://www.modperlcookbook.org/
527
The Perl Part
...
our $VERSION = '0.01';
our @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
}
http://www.modperlcookbook.org/
528
More?
http://www.modperlcookbook.org/
529
More?
• Apache provides for something called
"registered cleanups"
http://www.modperlcookbook.org/
530
More?
• Apache provides for something called
"registered cleanups"
$r->register_cleanup(\&cleanup);
http://www.modperlcookbook.org/
531
More?
• Apache provides for something called
"registered cleanups"
$r->register_cleanup(\&cleanup);
PerlCleanupHandler My::Cleanup
http://www.modperlcookbook.org/
532
More?
• Apache provides for something called
"registered cleanups"
$r->register_cleanup(\&cleanup);
PerlCleanupHandler My::Cleanup
Apache->server->register_cleanup(\&cleanup);
http://www.modperlcookbook.org/
533
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
http://www.modperlcookbook.org/
534
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
http://www.modperlcookbook.org/
535
Keepalives
• HTTP/1.1 allows for more than one
request per connection
http://www.modperlcookbook.org/
536
Keepalives
• HTTP/1.1 allows for more than one
request per connection
Connection: Keep-Alive
http://www.modperlcookbook.org/
537
Keepalives
• HTTP/1.1 allows for more than one
request per connection
Connection: Keep-Alive
http://www.modperlcookbook.org/
538
Keepalives
• HTTP/1.1 allows for more than one
request per connection
Connection: Keep-Alive
• Connections are interfaces with the
Apache::Connection class
http://www.modperlcookbook.org/
539
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;
http://www.modperlcookbook.org/
540
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
http://www.modperlcookbook.org/
541
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
http://www.modperlcookbook.org/
542
Per-connection Cleanups
http://www.modperlcookbook.org/
543
Per-connection Cleanups
• Unfortunately, mod_perl wasn't
designed so you could subclass the
Apache::Connection class
http://www.modperlcookbook.org/
544
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
http://www.modperlcookbook.org/
545
package Apache::ConnectionCleanup;
use 5.006;
use strict;
use Apache;
use Apache::ConnectionCleanup::RegisterCleanup;
our @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;
http://www.modperlcookbook.org/
546
package Apache::ConnectionCleanup;
use 5.006;
use strict;
use Apache;
use Apache::ConnectionCleanup::RegisterCleanup;
our @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;
http://www.modperlcookbook.org/
547
package Apache::ConnectionCleanup;
use 5.006;
use strict;
use Apache;
use Apache::ConnectionCleanup::RegisterCleanup;
our @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;
http://www.modperlcookbook.org/
548
package Apache::ConnectionCleanup;
use 5.006;
use strict;
use Apache;
use Apache::ConnectionCleanup::RegisterCleanup;
our @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;
http://www.modperlcookbook.org/
549
package Apache::ConnectionCleanup;
use 5.006;
use strict;
use Apache;
use Apache::ConnectionCleanup::RegisterCleanup;
our @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;
http://www.modperlcookbook.org/
550
package Apache::ConnectionCleanup;
use 5.006;
use strict;
use Apache;
use Apache::ConnectionCleanup::RegisterCleanup;
our @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;
http://www.modperlcookbook.org/
551
package Apache::ConnectionCleanup;
use 5.006;
use strict;
use Apache;
use Apache::ConnectionCleanup::RegisterCleanup;
our @ISA = qw(Apache);
sub new {
my ($class, $r) = @_;
$r ||= Apache->request;
return bless { r => $r }, $class;
}
sub connection {
my $connection = $self->SUPER::connection;
return bless $connection,
'Apache::ConnectionCleanup::RegisterCleanup';
}
1;
http://www.modperlcookbook.org/
552
package Apache::ConnectionCleanup::RegisterCleanup;
use 5.006;
use strict;
use warnings;
use Apache::Connection;
use DynaLoader;
our @ISA = qw(DynaLoader Apache::Connection);
our $VERSION = '0.01';
__PACKAGE__->bootstrap($VERSION);
1;
http://www.modperlcookbook.org/
553
package Apache::ConnectionCleanup::RegisterCleanup;
use 5.006;
use strict;
use warnings;
use Apache::Connection;
use DynaLoader;
our @ISA = qw(DynaLoader Apache::Connection);
our $VERSION = '0.01';
__PACKAGE__->bootstrap($VERSION);
1;
http://www.modperlcookbook.org/
554
package Apache::ConnectionCleanup::RegisterCleanup;
use 5.006;
use strict;
use warnings;
use Apache::Connection;
use DynaLoader;
our @ISA = qw(DynaLoader Apache::Connection);
our $VERSION = '0.01';
__PACKAGE__->bootstrap($VERSION);
1;
http://www.modperlcookbook.org/
555
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"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);
http://www.modperlcookbook.org/
556
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"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);
http://www.modperlcookbook.org/
557
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"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);
http://www.modperlcookbook.org/
558
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"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);
http://www.modperlcookbook.org/
559
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"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);
http://www.modperlcookbook.org/
560
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"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);
http://www.modperlcookbook.org/
561
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"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);
http://www.modperlcookbook.org/
562
#include
#include
#include
#include
"EXTERN.h"
"perl.h"
"XSUB.h"
"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);
http://www.modperlcookbook.org/
563
http://www.modperlcookbook.org/
564
But wait, there's more!
http://www.modperlcookbook.org/
565
But wait, there's more!
• We mentioned that part of mod_perl
fun was overriding core Apache
behaviors with your own "devious
subsititutes"
http://www.modperlcookbook.org/
566
But wait, there's more!
• We mentioned that part of mod_perl
fun was overriding core Apache
behaviors with your own "devious
subsititutes"
• Let's do more devious things...
http://www.modperlcookbook.org/
567
Apache Directives
http://www.modperlcookbook.org/
568
Apache Directives
• If you have ever typo'd a directive in
httpd.conf you've seen something
like
Invalid command 'Foo', perhaps misspelled or defined by a module
not included in the server configuration
/usr/local/apache/bin/apachectl start: httpd could not be started
http://www.modperlcookbook.org/
569
Apache Directives
• If you have ever typo'd a directive in
httpd.conf you've seen something
like
Invalid command 'Foo', perhaps misspelled or defined by a module
not included in the server configuration
/usr/local/apache/bin/apachectl start: httpd could not be started
• How does Apache know that Foo isn't
a real directive?
http://www.modperlcookbook.org/
570
Core Apache is small
• Over 200 directives are supported by the
standard Apache distribution
http://www.modperlcookbook.org/
571
Core Apache is small
• Over 200 directives are supported by the
standard Apache distribution
• Less that 80 are from core Apache
http://www.modperlcookbook.org/
572
Core Apache is small
• Over 200 directives are supported by the
standard Apache distribution
• Less that 80 are from core Apache
• All the rest are from C extension modules
http://www.modperlcookbook.org/
573
Core Apache is small
• Over 200 directives are supported by the
standard Apache distribution
• Less that 80 are from core Apache
• All the rest are from C extension modules
Alias /perl-bin /usr/local/apache/perl-bin
– mod_alias
http://www.modperlcookbook.org/
574
Core Apache is small
• Over 200 directives are supported by the
standard Apache distribution
• Less that 80 are from core Apache
• All the rest are from C extension modules
Alias /perl-bin /usr/local/apache/perl-bin
– mod_alias
SetHandler perl-script
– mod_mime
http://www.modperlcookbook.org/
575
Core Apache is small
• Over 200 directives are supported by the
standard Apache distribution
• Less that 80 are from core Apache
• All the rest are from C extension modules
Alias /perl-bin /usr/local/apache/perl-bin
– mod_alias
SetHandler perl-script
– mod_mime
PerlHandler
– mod_perl
http://www.modperlcookbook.org/
576
How it works
http://www.modperlcookbook.org/
577
How it works
• For C modules the process is ordinary
http://www.modperlcookbook.org/
578
How it works
• For C modules the process is ordinary
– a module registers itself with Apache
http://www.modperlcookbook.org/
579
How it works
• For C modules the process is ordinary
– a module registers itself with Apache
– Apache parses httpd.conf
http://www.modperlcookbook.org/
580
How it works
• For C modules the process is ordinary
– a module registers itself with Apache
– Apache parses httpd.conf
– finds a directive
http://www.modperlcookbook.org/
581
How it works
• For C modules the process is ordinary
– a module registers itself with Apache
– Apache parses httpd.conf
– finds a directive
– looks for a module that agrees to handle
the directive
http://www.modperlcookbook.org/
582
How it works
• For C modules the process is ordinary
– a module registers itself with Apache
– Apache parses httpd.conf
– finds a directive
– looks for a module that agrees to handle
the directive
– defaults to http_core if no module
agrees
http://www.modperlcookbook.org/
583
Data Validation
http://www.modperlcookbook.org/
584
Data Validation
• If a module agrees to handle the
directive
http://www.modperlcookbook.org/
585
Data Validation
• If a module agrees to handle the
directive
– module tells Apache how the data should
be formatted
http://www.modperlcookbook.org/
586
Data Validation
• If a module agrees to handle the
directive
– module tells Apache how the data should
be formatted
– Apache validates the data format in
httpd.conf
http://www.modperlcookbook.org/
587
Data Validation
• If a module agrees to handle the
directive
– module tells Apache how the data should
be formatted
– Apache validates the data format in
httpd.conf
– Apache passes the config to the module
http://www.modperlcookbook.org/
588
Data Validation
• If a module agrees to handle the
directive
– module tells Apache how the data should
be formatted
– Apache validates the data format in
httpd.conf
– Apache passes the config to the module
– module is free to use the data
http://www.modperlcookbook.org/
589
Data Validation
• httpd.conf
XBitHack One Two, Buckle My Shoe
http://www.modperlcookbook.org/
590
Data Validation
• httpd.conf
XBitHack One Two, Buckle My Shoe
• Apache responds
Syntax error on line 19 of /usr/local/apache/conf/httpd.conf:
XBitHack takes one argument, Off, On, or Full
/usr/local/apache/bin/apachectl start: httpd could not be started
http://www.modperlcookbook.org/
591
Data Validation
• httpd.conf
XBitHack One Two, Buckle My Shoe
• Apache responds
Syntax error on line 19 of /usr/local/apache/conf/httpd.conf:
XBitHack takes one argument, Off, On, or Full
/usr/local/apache/bin/apachectl start: httpd could not be started
http://www.modperlcookbook.org/
592
Directive Handlers
http://www.modperlcookbook.org/
593
Directive Handlers
• As with all things, mod_perl provides
an API for creating our own Apache
directives
http://www.modperlcookbook.org/
594
Directive Handlers
• As with all things, mod_perl provides
an API for creating our own Apache
directives
• API is not all that intuitive
http://www.modperlcookbook.org/
595
Directive Handlers
• As with all things, mod_perl provides
an API for creating our own Apache
directives
• API is not all that intuitive
• Does make sense if you think of the
steps Apache has to go through
http://www.modperlcookbook.org/
596
http://www.modperlcookbook.org/
597
Our own XBitHack
http://www.modperlcookbook.org/
598
Our own XBitHack
• Let's re-implement XBitHack in our
own Perl module
http://www.modperlcookbook.org/
599
Our own XBitHack
• Let's re-implement XBitHack in our
own Perl module
• Make it usable in for Apache on Win32
http://www.modperlcookbook.org/
600
Our own XBitHack
• Let's re-implement XBitHack in our
own Perl module
• Make it usable in for Apache on Win32
– on Unix - default to mod_include
http://www.modperlcookbook.org/
601
Our own XBitHack
• Let's re-implement XBitHack in our
own Perl module
• Make it usable in for Apache on Win32
– on Unix - default to mod_include
– on Win32 - use our implementation
http://www.modperlcookbook.org/
602
Our own XBitHack
• Let's re-implement XBitHack in our
own Perl module
• Make it usable in for Apache on Win32
– on Unix - default to mod_include
– on Win32 - use our implementation
PerlModule Cookbook::WinBitHack
PerlFixupHandler Cookbook::WinBitHack
XBitHack On
http://www.modperlcookbook.org/
603
Step #1
• Define what happens when Apache
sees a good XBitHack directive
http://www.modperlcookbook.org/
604
sub XBitHack {
my ($cfg, $parms, $arg) = @_;
# Let mod_include do the Unix stuff - we only do Win32.
return DECLINE_CMD unless $^O =~ m/Win32/;
if ($arg =~ m/^(On|Off|Full)$/i) {
$cfg->{_state} = uc($arg);
}
else {
die "Invalid XBitHack $arg!";
}
}
http://www.modperlcookbook.org/
605
sub XBitHack {
my ($cfg, $parms, $arg) = @_;
# Let mod_include do the Unix stuff - we only do Win32.
return DECLINE_CMD unless $^O =~ m/Win32/;
if ($arg =~ m/^(On|Off|Full)$/i) {
$cfg->{_state} = uc($arg);
}
else {
die "Invalid XBitHack $arg!";
}
}
http://www.modperlcookbook.org/
606
sub XBitHack {
my ($cfg, $parms, $arg) = @_;
# Let mod_include do the Unix stuff - we only do Win32.
return DECLINE_CMD unless $^O =~ m/Win32/;
if ($arg =~ m/^(On|Off|Full)$/i) {
$cfg->{_state} = uc($arg);
}
else {
die "Invalid XBitHack $arg!";
}
}
http://www.modperlcookbook.org/
607
sub XBitHack {
my ($cfg, $parms, $arg) = @_;
# Let mod_include do the Unix stuff - we only do Win32.
return DECLINE_CMD unless $^O =~ m/Win32/;
if ($arg =~ m/^(On|Off|Full)$/i) {
$cfg->{_state} = uc($arg);
}
else {
die "Invalid XBitHack $arg!";
}
}
http://www.modperlcookbook.org/
608
sub XBitHack {
my ($cfg, $parms, $arg) = @_;
# Let mod_include do the Unix stuff - we only do Win32.
return DECLINE_CMD unless $^O =~ m/Win32/;
if ($arg =~ m/^(On|Off|Full)$/i) {
$cfg->{_state} = uc($arg);
}
else {
die "Invalid XBitHack $arg!";
}
}
http://www.modperlcookbook.org/
609
sub XBitHack {
my ($cfg, $parms, $arg) = @_;
# Let mod_include do the Unix stuff - we only do Win32.
return DECLINE_CMD unless $^O =~ m/Win32/;
if ($arg =~ m/^(On|Off|Full)$/i) {
$cfg->{_state} = uc($arg);
}
else {
die "Invalid XBitHack $arg!";
}
}
http://www.modperlcookbook.org/
610
sub XBitHack {
my ($cfg, $parms, $arg) = @_;
# Let mod_include do the Unix stuff - we only do Win32.
return DECLINE_CMD unless $^O =~ m/Win32/;
if ($arg =~ m/^(On|Off|Full)$/i) {
$cfg->{_state} = uc($arg);
}
else {
die "Invalid XBitHack $arg!";
}
}
http://www.modperlcookbook.org/
611
Step #2
• Insert our request time processing
http://www.modperlcookbook.org/
612
Step #2
• Insert our request time processing
PerlFixupHandler Cookbook::WinBitHack
http://www.modperlcookbook.org/
613
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
return DECLINED unless (
$^O =~ m/Win32/
-f $r->finfo
$r->content_type eq 'text/html'
$r->allow_options & OPT_INCLUDES
$cfg->{_state} ne 'OFF');
&&
&&
&&
&&
#
#
#
#
#
we're on Win32
the file exists
and is HTML
and we have Options +Includes
and XBitHack On or Full
# Gather the file attributes.
my $attr;
Win32::File::GetAttributes($r->filename, $attr);
# Return DECLINED if the file has the ARCHIVE attribute set,
# which is the usual case.
return DECLINED if $attr & ARCHIVE();
# Set the Last-Modified header unless the READONLY attribute is set.
if ($cfg->{_state} eq 'FULL') {
$r->set_last_modified((stat _)[9]) unless $attr & READONLY();
}
# Make sure mod_include picks it up.
$r->handler('server-parsed');
return OK;
}
http://www.modperlcookbook.org/
614
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
return DECLINED unless (
$^O =~ m/Win32/
-f $r->finfo
$r->content_type eq 'text/html'
$r->allow_options & OPT_INCLUDES
$cfg->{_state} ne 'OFF');
&&
&&
&&
&&
#
#
#
#
#
we're on Win32
the file exists
and is HTML
and we have Options +Includes
and XBitHack On or Full
# Gather the file attributes.
my $attr;
Win32::File::GetAttributes($r->filename, $attr);
# Return DECLINED if the file has the ARCHIVE attribute set,
# which is the usual case.
return DECLINED if $attr & ARCHIVE();
# Set the Last-Modified header unless the READONLY attribute is set.
if ($cfg->{_state} eq 'FULL') {
$r->set_last_modified((stat _)[9]) unless $attr & READONLY();
}
# Make sure mod_include picks it up.
$r->handler('server-parsed');
return OK;
}
http://www.modperlcookbook.org/
615
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
return DECLINED unless (
$^O =~ m/Win32/
-f $r->finfo
$r->content_type eq 'text/html'
$r->allow_options & OPT_INCLUDES
$cfg->{_state} ne 'OFF');
&&
&&
&&
&&
#
#
#
#
#
we're on Win32
the file exists
and is HTML
and we have Options +Includes
and XBitHack On or Full
# Gather the file attributes.
my $attr;
Win32::File::GetAttributes($r->filename, $attr);
# Return DECLINED if the file has the ARCHIVE attribute set,
# which is the usual case.
return DECLINED if $attr & ARCHIVE();
# Set the Last-Modified header unless the READONLY attribute is set.
if ($cfg->{_state} eq 'FULL') {
$r->set_last_modified((stat _)[9]) unless $attr & READONLY();
}
# Make sure mod_include picks it up.
$r->handler('server-parsed');
return OK;
}
http://www.modperlcookbook.org/
616
sub XBitHack ($$$) {
my ($cfg, $parms, $arg) = @_;
# Let mod_include do the Unix stuff - we only do Win32.
return DECLINE_CMD unless $^O =~ m/Win32/;
if ($arg =~ m/^(On|Off|Full)$/i) {
$cfg->{_state} = uc($arg);
}
else {
die "Invalid XBitHack $arg!";
}
}
http://www.modperlcookbook.org/
617
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
return DECLINED unless (
$^O =~ m/Win32/
-f $r->finfo
$r->content_type eq 'text/html'
$r->allow_options & OPT_INCLUDES
$cfg->{_state} ne 'OFF');
&&
&&
&&
&&
#
#
#
#
#
we're on Win32
the file exists
and is HTML
and we have Options +Includes
and XBitHack On or Full
# Gather the file attributes.
my $attr;
Win32::File::GetAttributes($r->filename, $attr);
# Return DECLINED if the file has the ARCHIVE attribute set,
# which is the usual case.
return DECLINED if $attr & ARCHIVE();
# Set the Last-Modified header unless the READONLY attribute is set.
if ($cfg->{_state} eq 'FULL') {
$r->set_last_modified((stat _)[9]) unless $attr & READONLY();
}
# Make sure mod_include picks it up.
$r->handler('server-parsed');
return OK;
}
http://www.modperlcookbook.org/
618
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
return DECLINED unless (
$^O =~ m/Win32/
-f $r->finfo
$r->content_type eq 'text/html'
$r->allow_options & OPT_INCLUDES
$cfg->{_state} ne 'OFF');
&&
&&
&&
&&
#
#
#
#
#
we're on Win32
the file exists
and is HTML
and we have Options +Includes
and XBitHack On or Full
# Gather the file attributes.
my $attr;
Win32::File::GetAttributes($r->filename, $attr);
# Return DECLINED if the file has the ARCHIVE attribute set,
# which is the usual case.
return DECLINED if $attr & ARCHIVE();
# Set the Last-Modified header unless the READONLY attribute is set.
if ($cfg->{_state} eq 'FULL') {
$r->set_last_modified((stat _)[9]) unless $attr & READONLY();
}
# Make sure mod_include picks it up.
$r->handler('server-parsed');
return OK;
}
http://www.modperlcookbook.org/
619
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
return DECLINED unless (
$^O =~ m/Win32/
-f $r->finfo
$r->content_type eq 'text/html'
$r->allow_options & OPT_INCLUDES
$cfg->{_state} ne 'OFF');
&&
&&
&&
&&
#
#
#
#
#
we're on Win32
the file exists
and is HTML
and we have Options +Includes
and XBitHack On or Full
# Gather the file attributes.
my $attr;
Win32::File::GetAttributes($r->filename, $attr);
# Return DECLINED if the file has the ARCHIVE attribute set,
# which is the usual case.
return DECLINED if $attr & ARCHIVE();
# Set the Last-Modified header unless the READONLY attribute is set.
if ($cfg->{_state} eq 'FULL') {
$r->set_last_modified((stat _)[9]) unless $attr & READONLY();
}
# Make sure mod_include picks it up.
$r->handler('server-parsed');
return OK;
}
http://www.modperlcookbook.org/
620
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
return DECLINED unless (
$^O =~ m/Win32/
-f $r->finfo
$r->content_type eq 'text/html'
$r->allow_options & OPT_INCLUDES
$cfg->{_state} ne 'OFF');
&&
&&
&&
&&
#
#
#
#
#
we're on Win32
the file exists
and is HTML
and we have Options +Includes
and XBitHack On or Full
# Gather the file attributes.
my $attr;
Win32::File::GetAttributes($r->filename, $attr);
# Return DECLINED if the file has the ARCHIVE attribute set,
# which is the usual case.
return DECLINED if $attr & ARCHIVE();
# Set the Last-Modified header unless the READONLY attribute is set.
if ($cfg->{_state} eq 'FULL') {
$r->set_last_modified((stat _)[9]) unless $attr & READONLY();
}
# Make sure mod_include picks it up.
$r->handler('server-parsed');
return OK;
}
http://www.modperlcookbook.org/
621
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
return DECLINED unless (
$^O =~ m/Win32/
-f $r->finfo
$r->content_type eq 'text/html'
$r->allow_options & OPT_INCLUDES
$cfg->{_state} ne 'OFF');
&&
&&
&&
&&
#
#
#
#
#
we're on Win32
the file exists
and is HTML
and we have Options +Includes
and XBitHack On or Full
# Gather the file attributes.
my $attr;
Win32::File::GetAttributes($r->filename, $attr);
# Return DECLINED if the file has the ARCHIVE attribute set,
# which is the usual case.
return DECLINED if $attr & ARCHIVE();
# Set the Last-Modified header unless the READONLY attribute is set.
if ($cfg->{_state} eq 'FULL') {
$r->set_last_modified((stat _)[9]) unless $attr & READONLY();
}
# Make sure mod_include picks it up.
$r->handler('server-parsed');
return OK;
}
http://www.modperlcookbook.org/
622
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
return DECLINED unless (
$^O =~ m/Win32/
-f $r->finfo
$r->content_type eq 'text/html'
$r->allow_options & OPT_INCLUDES
$cfg->{_state} ne 'OFF');
&&
&&
&&
&&
#
#
#
#
#
we're on Win32
the file exists
and is HTML
and we have Options +Includes
and XBitHack On or Full
# Gather the file attributes.
my $attr;
Win32::File::GetAttributes($r->filename, $attr);
# Return DECLINED if the file has the ARCHIVE attribute set,
# which is the usual case.
return DECLINED if $attr & ARCHIVE();
# Set the Last-Modified header unless the READONLY attribute is set.
if ($cfg->{_state} eq 'FULL') {
$r->set_last_modified((stat _)[9]) unless $attr & READONLY();
}
# Make sure mod_include picks it up.
$r->handler('server-parsed');
return OK;
}
http://www.modperlcookbook.org/
623
Win32 File Attributes
http://www.modperlcookbook.org/
624
Win32 File Attributes
http://www.modperlcookbook.org/
625
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
return DECLINED unless (
$^O =~ m/Win32/
-f $r->finfo
$r->content_type eq 'text/html'
$r->allow_options & OPT_INCLUDES
$cfg->{_state} ne 'OFF');
&&
&&
&&
&&
#
#
#
#
#
we're on Win32
the file exists
and is HTML
and we have Options +Includes
and XBitHack On or Full
# Gather the file attributes.
my $attr;
Win32::File::GetAttributes($r->filename, $attr);
# Return DECLINED if the file has the ARCHIVE attribute set,
# which is the usual case.
return DECLINED if $attr & ARCHIVE();
# Set the Last-Modified header unless the READONLY attribute is set.
if ($cfg->{_state} eq 'FULL') {
$r->set_last_modified((stat _)[9]) unless $attr & READONLY();
}
# Make sure mod_include picks it up.
$r->handler('server-parsed');
return OK;
}
http://www.modperlcookbook.org/
626
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
return DECLINED unless (
$^O =~ m/Win32/
-f $r->finfo
$r->content_type eq 'text/html'
$r->allow_options & OPT_INCLUDES
$cfg->{_state} ne 'OFF');
&&
&&
&&
&&
#
#
#
#
#
we're on Win32
the file exists
and is HTML
and we have Options +Includes
and XBitHack On or Full
# Gather the file attributes.
my $attr;
Win32::File::GetAttributes($r->filename, $attr);
# Return DECLINED if the file has the ARCHIVE attribute set,
# which is the usual case.
return DECLINED if $attr & ARCHIVE();
# Set the Last-Modified header unless the READONLY attribute is set.
if ($cfg->{_state} eq 'FULL') {
$r->set_last_modified((stat _)[9]) unless $attr & READONLY();
}
# Make sure mod_include picks it up.
$r->handler('server-parsed');
return OK;
}
http://www.modperlcookbook.org/
627
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
return DECLINED unless (
$^O =~ m/Win32/
-f $r->finfo
$r->content_type eq 'text/html'
$r->allow_options & OPT_INCLUDES
$cfg->{_state} ne 'OFF');
&&
&&
&&
&&
#
#
#
#
#
we're on Win32
the file exists
and is HTML
and we have Options +Includes
and XBitHack On or Full
# Gather the file attributes.
my $attr;
Win32::File::GetAttributes($r->filename, $attr);
# Return DECLINED if the file has the ARCHIVE attribute set,
# which is the usual case.
return DECLINED if $attr & ARCHIVE();
# Set the Last-Modified header unless the READONLY attribute is set.
if ($cfg->{_state} eq 'FULL') {
$r->set_last_modified((stat _)[9]) unless $attr & READONLY();
}
# Make sure mod_include picks it up.
$r->handler('server-parsed');
return OK;
}
http://www.modperlcookbook.org/
628
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
return DECLINED unless (
$^O =~ m/Win32/
-f $r->finfo
$r->content_type eq 'text/html'
$r->allow_options & OPT_INCLUDES
$cfg->{_state} ne 'OFF');
&&
&&
&&
&&
#
#
#
#
#
we're on Win32
the file exists
and is HTML
and we have Options +Includes
and XBitHack On or Full
# Gather the file attributes.
my $attr;
Win32::File::GetAttributes($r->filename, $attr);
# Return DECLINED if the file has the ARCHIVE attribute set,
# which is the usual case.
return DECLINED if $attr & ARCHIVE();
# Set the Last-Modified header unless the READONLY attribute is set.
if ($cfg->{_state} eq 'FULL') {
$r->set_last_modified((stat _)[9]) unless $attr & READONLY();
}
# Make sure mod_include picks it up.
$r->handler('server-parsed');
return OK;
}
http://www.modperlcookbook.org/
629
Step #3
• Let Apache know our module exists
http://www.modperlcookbook.org/
630
More than meets the eye
http://www.modperlcookbook.org/
631
More than meets the eye
• As Apache parses httpd.conf we
have to let it know to check our Perl
module when it encounters a directive
http://www.modperlcookbook.org/
632
More than meets the eye
• As Apache parses httpd.conf we
have to let it know to check our Perl
module when it encounters a directive
• The mod_perl API essentially makes
our Perl module into a C module using
XS
http://www.modperlcookbook.org/
633
More than meets the eye
• As Apache parses httpd.conf we
have to let it know to check our Perl
module when it encounters a directive
• The mod_perl API essentially makes
our Perl module into a C module using
XS
• Just a few simple steps in
Makefile.PL
http://www.modperlcookbook.org/
634
Makefile.PL
package Cookbook::WinBitHack;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
);
(
=>
=>
=>
=>
'XBitHack',
'Off, On, or Full',
'TAKE1',
'OR_OPTIONS', },
command_table(\@directives);
http://www.modperlcookbook.org/
635
Makefile.PL
package Cookbook::WinBitHack;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
);
(
=>
=>
=>
=>
'XBitHack',
'Off, On, or Full',
'TAKE1',
'OR_OPTIONS', },
command_table(\@directives);
http://www.modperlcookbook.org/
636
Makefile.PL
package Cookbook::WinBitHack;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
);
(
=>
=>
=>
=>
'XBitHack',
'Off, On, or Full',
'TAKE1',
'OR_OPTIONS', },
command_table(\@directives);
http://www.modperlcookbook.org/
637
Makefile.PL
package Cookbook::WinBitHack;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
);
(
=>
=>
=>
=>
'XBitHack',
'Off, On, or Full',
'TAKE1',
'OR_OPTIONS', },
command_table(\@directives);
http://www.modperlcookbook.org/
638
Makefile.PL
package Cookbook::WinBitHack;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives = (
{ name
errmsg
args_how
=> 'XBitHack',
=> 'Off, On, or Full',
=> 'TAKE1',
req_override => 'OR_OPTIONS',
},
);
command_table(\@directives);
http://www.modperlcookbook.org/
639
Makefile.PL
package Cookbook::WinBitHack;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
);
(
=>
=>
=>
=>
'XBitHack',
'Off, On, or Full',
'TAKE1',
'OR_OPTIONS', },
command_table(\@directives);
http://www.modperlcookbook.org/
640
Makefile.PL
package Cookbook::WinBitHack;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
);
(
=>
=>
=>
=>
'XBitHack',
'Off, On, or Full',
'TAKE1',
'OR_OPTIONS', },
command_table(\@directives);
http://www.modperlcookbook.org/
641
Makefile.PL
package Cookbook::WinBitHack;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
);
(
=>
=>
=>
=>
'XBitHack',
'Off, On, or Full',
'TAKE1',
'OR_OPTIONS', },
command_table(\@directives);
http://www.modperlcookbook.org/
642
Makefile.PL
package Cookbook::WinBitHack;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
);
(
=>
=>
=>
=>
'XBitHack',
'Off, On, or Full',
'TAKE1',
'OR_OPTIONS', },
command_table(\@directives);
http://www.modperlcookbook.org/
643
Makefile.PL
package Cookbook::WinBitHack;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
);
(
=>
=>
=>
=>
'XBitHack',
'Off, On, or Full',
'TAKE1',
'OR_OPTIONS', },
command_table(\@directives);
http://www.modperlcookbook.org/
644
Magic
http://www.modperlcookbook.org/
645
Magic
• Running perl Makefile.PL has
magically created WinBitHack.xs for
us
http://www.modperlcookbook.org/
646
Magic
• Running perl Makefile.PL has
magically created WinBitHack.xs for
us
static mod_perl_cmd_info cmd_info_XBitHack = {
"Cookbook::WinBitHack::XBitHack", "",
};
static command_rec mod_cmds[] = {
{ "XBitHack", perl_cmd_perl_TAKE1,
(void*)&cmd_info_XBitHack,
OR_OPTIONS, TAKE1, "Off, On, or Full" },
{ NULL }
};
http://www.modperlcookbook.org/
647
Magic
• Running perl Makefile.PL has
magically created WinBitHack.xs for
us
static mod_perl_cmd_info cmd_info_XBitHack = {
"Cookbook::WinBitHack::XBitHack", "",
};
static command_rec mod_cmds[] = {
{ "XBitHack", perl_cmd_perl_TAKE1,
(void*)&cmd_info_XBitHack,
OR_OPTIONS, TAKE1, "Off, On, or Full" },
{ NULL }
};
http://www.modperlcookbook.org/
648
Magic
• Running perl Makefile.PL has
magically created WinBitHack.xs for
us
static mod_perl_cmd_info cmd_info_XBitHack = {
"Cookbook::WinBitHack::XBitHack", "",
};
static command_rec mod_cmds[] = {
{ "XBitHack", perl_cmd_perl_TAKE1,
(void*)&cmd_info_XBitHack,
OR_OPTIONS, TAKE1, "Off, On, or Full" },
{ NULL }
};
http://www.modperlcookbook.org/
649
Magic
• Running perl Makefile.PL has
magically created WinBitHack.xs for
us
static mod_perl_cmd_info cmd_info_XBitHack = {
"Cookbook::WinBitHack::XBitHack", "",
};
static command_rec mod_cmds[] = {
{ "XBitHack", perl_cmd_perl_TAKE1,
(void*)&cmd_info_XBitHack,
OR_OPTIONS, TAKE1, "Off, On, or Full" },
{ NULL }
};
http://www.modperlcookbook.org/
650
Magic
• Running perl Makefile.PL has
magically created WinBitHack.xs for
us
static mod_perl_cmd_info cmd_info_XBitHack = {
"Cookbook::WinBitHack::XBitHack", "",
};
static command_rec mod_cmds[] = {
{ "XBitHack", perl_cmd_perl_TAKE1,
(void*)&cmd_info_XBitHack,
OR_OPTIONS, TAKE1, "Off, On, or Full" },
{ NULL }
};
http://www.modperlcookbook.org/
651
Magic
• Running perl Makefile.PL has
magically created WinBitHack.xs for
us
static mod_perl_cmd_info cmd_info_XBitHack = {
"Cookbook::WinBitHack::XBitHack", "",
};
static command_rec mod_cmds[] = {
{ "XBitHack", perl_cmd_perl_TAKE1,
(void*)&cmd_info_XBitHack,
OR_OPTIONS, TAKE1, "Off, On, or Full" },
{ NULL }
};
http://www.modperlcookbook.org/
652
Magic
• Running perl Makefile.PL has
magically created WinBitHack.xs for
us
static mod_perl_cmd_info cmd_info_XBitHack = {
"Cookbook::WinBitHack::XBitHack", "",
};
static command_rec mod_cmds[] = {
{ "XBitHack", perl_cmd_perl_TAKE1,
(void*)&cmd_info_XBitHack,
OR_OPTIONS, TAKE1, "Off, On, or Full" },
{ NULL }
};
http://www.modperlcookbook.org/
653
Magic
• Running perl Makefile.PL has
magically created WinBitHack.xs for
us
static mod_perl_cmd_info cmd_info_XBitHack = {
"Cookbook::WinBitHack::XBitHack", "",
};
static command_rec mod_cmds[] = {
{ "XBitHack", perl_cmd_perl_TAKE1,
(void*)&cmd_info_XBitHack,
OR_OPTIONS, TAKE1, "Off, On, or Full" },
{ NULL }
};
http://www.modperlcookbook.org/
654
mod_include.c
static command_rec mod_cmds[] = {
{ "XBitHack", perl_cmd_perl_TAKE1,
(void*)&cmd_info_XBitHack,
OR_OPTIONS, TAKE1, "Off, On, or Full" },
{ NULL }
};
static const command_rec includes_cmds[] =
{
{"XBitHack", set_xbithack, NULL, OR_OPTIONS, TAKE1,
"Off, On, or Full"},
{NULL}
};
http://www.modperlcookbook.org/
655
DynaLoader
package Cookbook::WinBitHack;
BEGIN {
eval{
require Win32::File;
Win32::File->import(qw(READONLY ARCHIVE));
};
}
use Apache::Constants qw(OK DECLINED OPT_INCLUDES DECLINE_CMD);
use Apache::File;
use Apache::ModuleConfig;
use DynaLoader;
use 5.006;
use strict;
our $VERSION = '0.01';
our @ISA = qw(DynaLoader);
__PACKAGE__->bootstrap($VERSION);
http://www.modperlcookbook.org/
656
DynaLoader
package Cookbook::WinBitHack;
BEGIN {
eval{
require Win32::File;
Win32::File->import(qw(READONLY ARCHIVE));
};
}
use Apache::Constants qw(OK DECLINED OPT_INCLUDES DECLINE_CMD);
use Apache::File;
use Apache::ModuleConfig;
use DynaLoader;
use 5.006;
use strict;
our $VERSION = '0.01';
our @ISA = qw(DynaLoader);
__PACKAGE__->bootstrap($VERSION);
http://www.modperlcookbook.org/
657
DynaLoader
package Cookbook::WinBitHack;
BEGIN {
eval{
require Win32::File;
Win32::File->import(qw(READONLY ARCHIVE));
};
}
use Apache::Constants qw(OK DECLINED OPT_INCLUDES DECLINE_CMD);
use Apache::File;
use Apache::ModuleConfig;
use DynaLoader;
use 5.006;
use strict;
our $VERSION = '0.01';
our @ISA = qw(DynaLoader);
__PACKAGE__->bootstrap($VERSION);
http://www.modperlcookbook.org/
658
DynaLoader
package Cookbook::WinBitHack;
BEGIN {
eval{
require Win32::File;
Win32::File->import(qw(READONLY ARCHIVE));
};
}
use Apache::Constants qw(OK DECLINED OPT_INCLUDES DECLINE_CMD);
use Apache::File;
use Apache::ModuleConfig;
use DynaLoader;
use 5.006;
use strict;
our $VERSION = '0.01';
our @ISA = qw(DynaLoader);
__PACKAGE__->bootstrap($VERSION);
http://www.modperlcookbook.org/
659
# apachectl start
http://www.modperlcookbook.org/
660
# apachectl start
PerlModule Cookbook::WinBitHack
http://www.modperlcookbook.org/
661
# apachectl start
PerlModule Cookbook::WinBitHack
__PACKAGE__->bootstrap($VERSION);
http://www.modperlcookbook.org/
662
# apachectl start
PerlModule Cookbook::WinBitHack
XBitHack Full
http://www.modperlcookbook.org/
663
# apachectl start
PerlModule Cookbook::WinBitHack
XBitHack Full
Cookbook::WinBitHack::XBitHack()
http://www.modperlcookbook.org/
664
# apachectl start
PerlModule Cookbook::WinBitHack
XBitHack Full
client request
http://www.modperlcookbook.org/
665
# apachectl start
PerlModule Cookbook::WinBitHack
XBitHack Full
client request
URI-based init
URI translation
PerlFixupHandler
MIME setting
http://www.modperlcookbook.org/
file-based init
resource control
666
# apachectl start
PerlModule Cookbook::WinBitHack
XBitHack Full
client request
URI-based init
URI translation
Cookbook::WinBitHack::handler()
PerlFixupHandler
MIME setting
http://www.modperlcookbook.org/
file-based init
resource control
667
# apachectl start
PerlModule Cookbook::WinBitHack
XBitHack Full
client request
URI-based init
content
fixups
MIME setting
http://www.modperlcookbook.org/
URI translation
file-based init
resource control
668
# apachectl start
PerlModule Cookbook::WinBitHack
XBitHack Full
client request
URI-based init
mod_include
content
fixups
MIME setting
http://www.modperlcookbook.org/
URI translation
file-based init
resource control
669
# apachectl start
PerlModule Cookbook::WinBitHack
XBitHack Full
client request
logging
content
fixups
MIME setting
http://www.modperlcookbook.org/
URI-based init
URI translation
file-based init
resource control
670
# apachectl start
PerlModule Cookbook::WinBitHack
XBitHack Full
client request
logging
content
fixups
MIME setting
http://www.modperlcookbook.org/
URI-based init
URI translation
file-based init
resource control
671
http://www.modperlcookbook.org/
672
Be Proud
• What we've just accomplished is
pretty amazing
http://www.modperlcookbook.org/
673
Be Proud
• What we've just accomplished is
pretty amazing
– made our Perl module look like an
Apache C extension module
http://www.modperlcookbook.org/
674
Be Proud
• What we've just accomplished is
pretty amazing
– made our Perl module look like an
Apache C extension module
– Altered the behavior of a standard
Apache directive to meet new, previously
unmet needs
http://www.modperlcookbook.org/
675
Be Proud
• What we've just accomplished is
pretty amazing
– made our Perl module look like an
Apache C extension module
– Altered the behavior of a standard
Apache directive to meet new, previously
unmet needs
– All with relatively little work
http://www.modperlcookbook.org/
676
Be Proud
• What we've just accomplished is
pretty amazing
– made our Perl module look like an
Apache C extension module
– Altered the behavior of a standard
Apache directive to meet new, previously
unmet needs
– All with relatively little work
• Now, we're doing more
http://www.modperlcookbook.org/
677
More?
• If we've gotten here you're all either
masochists or I went waaay too fast
http://www.modperlcookbook.org/
678
More?
• If we've gotten here you're all either
masochists or I went waaay too fast
• Let's do another example anyway
http://www.modperlcookbook.org/
679
AddHandler and mod_perl
http://www.modperlcookbook.org/
680
AddHandler and mod_perl
• The default AddHandler directive doesn't
suit the needs of mod_perl developers
http://www.modperlcookbook.org/
681
AddHandler and mod_perl
• The default AddHandler directive doesn't
suit the needs of mod_perl developers
AddHandler server-parsed .html
http://www.modperlcookbook.org/
682
AddHandler and mod_perl
• The default AddHandler directive doesn't
suit the needs of mod_perl developers
AddHandler server-parsed .html
• The problem is that mod_perl requires two
directives in order to handle content
http://www.modperlcookbook.org/
683
AddHandler and mod_perl
• The default AddHandler directive doesn't
suit the needs of mod_perl developers
AddHandler server-parsed .html
• The problem is that mod_perl requires two
directives in order to handle content
AddHandler perl-script .html
http://www.modperlcookbook.org/
684
AddHandler and mod_perl
• The default AddHandler directive doesn't
suit the needs of mod_perl developers
AddHandler server-parsed .html
• The problem is that mod_perl requires two
directives in order to handle content
AddHandler perl-script .html
PerlHandler Apache::SSI
http://www.modperlcookbook.org/
685
AddHandler and mod_perl
• The default AddHandler directive doesn't
suit the needs of mod_perl developers
AddHandler server-parsed .html
• The problem is that mod_perl requires two
directives in order to handle content
AddHandler perl-script .html
PerlHandler Apache::SSI
• Wouldn't it be nice to have
AddHandler Apache::SSI .html
http://www.modperlcookbook.org/
686
Let's do it ourselves
http://www.modperlcookbook.org/
687
Let's do it ourselves
• Some things we need to do...
http://www.modperlcookbook.org/
688
Let's do it ourselves
• Some things we need to do...
– override the default AddHandler directive
http://www.modperlcookbook.org/
689
Let's do it ourselves
• Some things we need to do...
– override the default AddHandler directive
– schedule various extensions to use
various Perl modules
http://www.modperlcookbook.org/
690
Let's do it ourselves
• Some things we need to do...
– override the default AddHandler directive
– schedule various extensions to use
various Perl modules
– figure out where SetHandler overrides
the file extension
http://www.modperlcookbook.org/
691
Makefile.PL
http://www.modperlcookbook.org/
692
package Cookbook::MIMEMapper;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
(
=>
=>
=>
=>
'AddHandler',
'stash AddHandler settings',
'ITERATE2',
'OR_FILEINFO', },
{ name
errmsg
args_how
req_override
=>
=>
=>
=>
'SetHandler',
'note SetHandler is active',
'TAKE1',
'OR_FILEINFO', },
);
command_table(\@directives);
http://www.modperlcookbook.org/
693
package Cookbook::MIMEMapper;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
(
=>
=>
=>
=>
'AddHandler',
'stash AddHandler settings',
'ITERATE2',
'OR_FILEINFO', },
{ name
errmsg
args_how
req_override
=>
=>
=>
=>
'SetHandler',
'note SetHandler is active',
'TAKE1',
'OR_FILEINFO', },
);
command_table(\@directives);
http://www.modperlcookbook.org/
694
package Cookbook::MIMEMapper;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
(
=>
=>
=>
=>
'AddHandler',
'stash AddHandler settings',
'ITERATE2',
'OR_FILEINFO', },
{ name
errmsg
args_how
req_override
=>
=>
=>
=>
'SetHandler',
'note SetHandler is active',
'TAKE1',
'OR_FILEINFO', },
);
command_table(\@directives);
http://www.modperlcookbook.org/
695
ITERATE2
http://www.modperlcookbook.org/
696
ITERATE2
AddHandler server-parsed .html .shtml
http://www.modperlcookbook.org/
697
ITERATE2
AddHandler server-parsed .html .shtml
http://www.modperlcookbook.org/
698
ITERATE2
AddHandler server-parsed .html .shtml
http://www.modperlcookbook.org/
699
package Cookbook::MIMEMapper;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
(
=>
=>
=>
=>
'AddHandler',
'stash AddHandler settings',
'ITERATE2',
'OR_FILEINFO', },
{ name
errmsg
args_how
req_override
=>
=>
=>
=>
'SetHandler',
'note SetHandler is active',
'TAKE1',
'OR_FILEINFO', },
);
command_table(\@directives);
http://www.modperlcookbook.org/
700
package Cookbook::MIMEMapper;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
(
=>
=>
=>
=>
'AddHandler',
'stash AddHandler settings',
'ITERATE2',
'OR_FILEINFO', },
{ name
errmsg
args_how
req_override
=>
=>
=>
=>
'SetHandler',
'note SetHandler is active',
'TAKE1',
'OR_FILEINFO', },
);
command_table(\@directives);
http://www.modperlcookbook.org/
701
package Cookbook::MIMEMapper;
use ExtUtils::MakeMaker;
use Apache::ExtUtils qw(command_table);
use Apache::src ();
use strict;
my @directives =
{ name
errmsg
args_how
req_override
(
=>
=>
=>
=>
'AddHandler',
'stash AddHandler settings',
'ITERATE2',
'OR_FILEINFO', },
{ name
errmsg
args_how
req_override
=>
=>
=>
=>
'SetHandler',
'note SetHandler is active',
'TAKE1',
'OR_FILEINFO', },
);
command_table(\@directives);
http://www.modperlcookbook.org/
702
The Perl Part
http://www.modperlcookbook.org/
703
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
704
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
705
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
706
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
707
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
708
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
709
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) { # AddHandler My::Handler .html
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
710
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
711
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
712
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
713
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
714
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
715
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
716
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_; # SetHandler perl-script
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
717
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
718
sub AddHandler {
my ($cfg, $parms, $handler, $type) = @_;
# Intercept the directive if it looks like a PerlHandler.
# This is not an ideal check, but sufficient
if ($handler =~ m/::/) {
push @{$cfg->{$type}}, $handler;
return OK;
}
# Otherwise let mod_mime handle it.
return DECLINE_CMD;
}
sub SetHandler {
my ($cfg, $parms, $handler) = @_;
$cfg->{_set_handler} = 1;
# We're just marking areas governed by SetHandler.
return DECLINE_CMD;
}
http://www.modperlcookbook.org/
719
Setup
PerlModule Apache::MIMEMapper
PerlFixupHandler Apache::MIMEMapper
AddHandler Apache::RegistryFilter .pl
AddHandler Apache::SSI .html .pl
Alias /perl-bin/ /usr/local/apache/perl-bin/
<Location /perl-bin/>
SetHandler perl-script
PerlHandler Apache::Registry
Options +ExecCGI
PerlSendHeader On
</Location>
http://www.modperlcookbook.org/
720
Setup
PerlModule Apache::MIMEMapper
PerlFixupHandler Apache::MIMEMapper
AddHandler Apache::RegistryFilter .pl
AddHandler Apache::SSI .html .pl
Alias /perl-bin/ /usr/local/apache/perl-bin/
<Location /perl-bin/>
SetHandler perl-script
PerlHandler Apache::Registry
Options +ExecCGI
PerlSendHeader On
</Location>
http://www.modperlcookbook.org/
721
Setup
PerlModule Apache::MIMEMapper
PerlFixupHandler Apache::MIMEMapper
AddHandler Apache::RegistryFilter .pl
AddHandler Apache::SSI .html .pl
Alias /perl-bin/ /usr/local/apache/perl-bin/
<Location /perl-bin/>
SetHandler perl-script
PerlHandler Apache::Registry
Options +ExecCGI
PerlSendHeader On
</Location>
http://www.modperlcookbook.org/
722
Setup
PerlModule Apache::MIMEMapper
PerlFixupHandler Apache::MIMEMapper
AddHandler Apache::RegistryFilter .pl
AddHandler Apache::SSI .html .pl
Alias /perl-bin/ /usr/local/apache/perl-bin/
<Location /perl-bin/>
SetHandler perl-script
PerlHandler Apache::Registry
Options +ExecCGI
PerlSendHeader On
</Location>
http://www.modperlcookbook.org/
723
Setup
PerlModule Apache::MIMEMapper
PerlFixupHandler Apache::MIMEMapper
AddHandler Apache::RegistryFilter .pl
AddHandler Apache::SSI .html .pl
Alias /perl-bin/ /usr/local/apache/perl-bin/
<Location /perl-bin/>
SetHandler perl-script
PerlHandler Apache::Registry
Options +ExecCGI
PerlSendHeader On
</Location>
http://www.modperlcookbook.org/
724
Setup
PerlModule Apache::MIMEMapper
PerlFixupHandler Apache::MIMEMapper
AddHandler Apache::RegistryFilter .pl
AddHandler Apache::SSI .html .pl
Alias /perl-bin/ /usr/local/apache/perl-bin/
<Location /perl-bin/>
SetHandler perl-script
PerlHandler Apache::Registry
Options +ExecCGI
PerlSendHeader On
</Location>
http://www.modperlcookbook.org/
725
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
# Also decline if a SetHandler directive is present.
# which ought to override any AddHandler settings.
return DECLINED if $cfg->{_set_handler};
my ($extension) = $r->filename =~ m!(\.[^.]+)$!;
# Set the PerlHandler stack if we have a mapping
if (my $handlers = $cfg->{$extension}) {
$r->handler('perl-script');
$r->set_handlers(PerlHandler => $handlers);
# Notify Apache::Filter if we have more than one
$r->dir_config->set(Filter => 'On') if @$handlers > 1;
}
return OK;
}
http://www.modperlcookbook.org/
726
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
# Also decline if a SetHandler directive is present.
# which ought to override any AddHandler settings.
return DECLINED if $cfg->{_set_handler};
my ($extension) = $r->filename =~ m!(\.[^.]+)$!;
# Set the PerlHandler stack if we have a mapping
if (my $handlers = $cfg->{$extension}) {
$r->handler('perl-script');
$r->set_handlers(PerlHandler => $handlers);
# Notify Apache::Filter if we have more than one
$r->dir_config->set(Filter => 'On') if @$handlers > 1;
}
return OK;
}
http://www.modperlcookbook.org/
727
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
# Also decline if a SetHandler directive is present.
# which ought to override any AddHandler settings.
return DECLINED if $cfg->{_set_handler};
my ($extension) = $r->filename =~ m!(\.[^.]+)$!;
# Set the PerlHandler stack if we have a mapping
if (my $handlers = $cfg->{$extension}) {
$r->handler('perl-script');
$r->set_handlers(PerlHandler => $handlers);
# Notify Apache::Filter if we have more than one
$r->dir_config->set(Filter => 'On') if @$handlers > 1;
}
return OK;
}
http://www.modperlcookbook.org/
728
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
# Also decline if a SetHandler directive is present.
# which ought to override any AddHandler settings.
return DECLINED if $cfg->{_set_handler};
my ($extension) = $r->filename =~ m!(\.[^.]+)$!;
# Set the PerlHandler stack if we have a mapping
if (my $handlers = $cfg->{$extension}) {
$r->handler('perl-script');
$r->set_handlers(PerlHandler => $handlers);
# Notify Apache::Filter if we have more than one
$r->dir_config->set(Filter => 'On') if @$handlers > 1;
}
return OK;
}
http://www.modperlcookbook.org/
729
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
# Also decline if a SetHandler directive is present.
# which ought to override any AddHandler settings.
return DECLINED if $cfg->{_set_handler};
my ($extension) = $r->filename =~ m!(\.[^.]+)$!;
# Set the PerlHandler stack if we have a mapping
if (my $handlers = $cfg->{$extension}) {
$r->handler('perl-script');
$r->set_handlers(PerlHandler => $handlers);
# Notify Apache::Filter if we have more than one
$r->dir_config->set(Filter => 'On') if @$handlers > 1;
}
return OK;
}
http://www.modperlcookbook.org/
730
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
# Also decline if a SetHandler directive is present.
# which ought to override any AddHandler settings.
return DECLINED if $cfg->{_set_handler};
my ($extension) = $r->filename =~ m!(\.[^.]+)$!;
# Set the PerlHandler stack if we have a mapping
if (my $handlers = $cfg->{$extension}) {
$r->handler('perl-script');
$r->set_handlers(PerlHandler => $handlers);
# Notify Apache::Filter if we have more than one
$r->dir_config->set(Filter => 'On') if @$handlers > 1;
}
return OK;
}
http://www.modperlcookbook.org/
731
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
# Also decline if a SetHandler directive is present.
# which ought to override any AddHandler settings.
return DECLINED if $cfg->{_set_handler};
my ($extension) = $r->filename =~ m!(\.[^.]+)$!;
# Set the PerlHandler stack if we have a mapping
if (my $handlers = $cfg->{$extension}) {
$r->handler('perl-script');
$r->set_handlers(PerlHandler => $handlers);
# Notify Apache::Filter if we have more than one
$r->dir_config->set(Filter => 'On') if @$handlers > 1;
}
return OK;
}
http://www.modperlcookbook.org/
732
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
# Also decline if a SetHandler directive is present.
# which ought to override any AddHandler settings.
return DECLINED if $cfg->{_set_handler};
my ($extension) = $r->filename =~ m!(\.[^.]+)$!;
# Set the PerlHandler stack if we have a mapping
if (my $handlers = $cfg->{$extension}) {
$r->handler('perl-script');
$r->set_handlers(PerlHandler => $handlers);
# Notify Apache::Filter if we have more than one
$r->dir_config->set(Filter => 'On') if @$handlers > 1;
}
return OK;
}
http://www.modperlcookbook.org/
733
sub handler {
my $r = shift;
my $cfg = Apache::ModuleConfig->get($r, __PACKAGE__);
# Also decline if a SetHandler directive is present.
# which ought to override any AddHandler settings.
return DECLINED if $cfg->{_set_handler};
my ($extension) = $r->filename =~ m!(\.[^.]+)$!;
# Set the PerlHandler stack if we have a mapping
if (my $handlers = $cfg->{$extension}) {
$r->handler('perl-script');
$r->set_handlers(PerlHandler => $handlers);
# Notify Apache::Filter if we have more than one
$r->dir_config->set(Filter => 'On') if @$handlers > 1;
}
return OK;
}
http://www.modperlcookbook.org/
734
http://www.modperlcookbook.org/
735
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/
http://www.modperlcookbook.org/
736
Materials
These slides
http://www.modperlcookbook.org/~geoff/slides/YAPC
My modules
http://www.modperlcookbook.org/~geoff/modules
http://www.modperlcookbook.org/
737
http://www.modperlcookbook.org/
738
# apachectl start
PerlModule Cookbook::WinBitHack
DIR_CREATE
SERVER_CREATE
XBitHack Full
DIR_MERGE
SERVER_MERGE
request cycle
http://www.modperlcookbook.org/
739