Download presentation
Presentation is loading. Please wait.
1
Transitioning to mod_perl Handlers
Geoffrey Young
2
Overview
3
Overview Apache and mod_perl 101
4
Overview Apache and mod_perl 101 mod_perl Handler Basics
5
Overview Apache and mod_perl 101 mod_perl Handler Basics
mod_perl Handler API Basics
6
Overview Apache and mod_perl 101 mod_perl Handler Basics
mod_perl Handler API Basics Using the Apache Framework
7
Overview Apache and mod_perl 101 mod_perl Handler Basics
mod_perl Handler API Basics Using the Apache Framework Advanced mod_perl API Features
8
Overview Apache and mod_perl 101 mod_perl Handler Basics
mod_perl Handler API Basics Using the Apache Framework Advanced mod_perl API Features Transition Strategies
10
Apache's Pre-fork Model
11
Apache's Pre-fork Model
Apache parent process
12
Apache's Pre-fork Model
Apache parent process httpd (parent)
13
Apache's Pre-fork Model
Apache parent process forks multiple child processes httpd (parent) httpd (child) httpd (child) httpd (child) httpd (child)
14
Roles and Responsibilities
15
Roles and Responsibilities
httpd parent processes no actual requests
16
Roles and Responsibilities
httpd parent processes no actual requests all requests are served by the child processes
17
Roles and Responsibilities
httpd parent processes no actual requests all requests are served by the child processes requests are handled by any available child process, not necessarily the one that handled the previous request
18
Roles and Responsibilities
httpd parent processes no actual requests all requests are served by the child processes requests are handled by any available child process, not necessarily the one that handled the previous request remember, the HTTP is stateless by default
19
Children are Individuals
httpd (parent) httpd (child) httpd (child) httpd (child) httpd (child)
20
Children are Individuals
httpd (parent) httpd (child) httpd (child) httpd (child) httpd (child)
21
Children are Individuals
httpd (parent) httpd (child) httpd (child) httpd (child) httpd (child)
22
Nice, Responsible Children
23
Nice, Responsible Children
each httpd child processes one incoming request at a time
24
Nice, Responsible Children
each httpd child processes one incoming request at a time only when the request is over is the child free to serve the next request
25
Nice, Responsible Children
each httpd child processes one incoming request at a time only when the request is over is the child free to serve the next request over time httpd child processes are terminated and replaced with fresh children
26
Request Phases
27
Request Phases Apache breaks down request processing into separate, logical parts called phases
28
Request Phases Apache breaks down request processing into separate, logical parts called phases client request logging URI-based init content URI translation fixups file-based init MIME setting resource control
29
Request Phases Apache breaks down request processing into separate, logical parts called phases each request is stepped through the phases until...
30
Request Phases Apache breaks down request processing into separate, logical parts called phases each request is stepped through the phases until... all processing is complete
31
Request Phases Apache breaks down request processing into separate, logical parts called phases each request is stepped through the phases until... all processing is complete somebody throws an "error"
32
Request Phases Apache breaks down request processing into separate, logical parts called phases each request is stepped through the phases until... all processing is complete somebody throws an "error" developers are given the chance to hook into each phase to add custom processing
33
Apache Request Cycle client request
34
Apache Request Cycle client request GET /perl-status HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Cache-Control: no-cache Connection: Keep-Alive, TE Host: User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera [en]
35
Apache Request Cycle client request GET /perl-status HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Cache-Control: no-cache Connection: Keep-Alive, TE Host: User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera [en]
36
Apache Request Cycle client request GET /perl-status HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Cache-Control: no-cache Connection: Keep-Alive, TE Host: User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera [en]
37
Apache Request Cycle client request URI-based init
38
Apache Request Cycle client request URI-based init URI translation
39
Apache Request Cycle client request URI-based init URI translation
file-based init
40
Apache Request Cycle client request URI-based init URI translation
file-based init resource control
41
Apache Request Cycle client request URI-based init URI translation
file-based init MIME setting resource control
42
Apache Request Cycle client request URI-based init URI translation
fixups file-based init MIME setting resource control
43
Apache Request Cycle client request URI-based init content
URI translation fixups file-based init MIME setting resource control
44
Apache Request Cycle content HTTP/1.1 200 OK
Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html
45
Apache Request Cycle content HTTP/1.1 200 OK
Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html
46
Apache Request Cycle content HTTP/1.1 200 OK
Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html
47
Apache Request Cycle client request URI-based init content
URI translation fixups file-based init MIME setting resource control
48
Apache Request Cycle client request logging URI-based init content
URI translation fixups file-based init MIME setting resource control
49
Apache Request Cycle client request logging URI-based init content
URI translation fixups file-based init MIME setting resource control
50
So What? most Apache users don't worry about the request cycle too much...
51
So What? most Apache users don't worry about the request cycle too much... ...but they do use modules that plug into it
52
... for instance mod_rewrite:
client request URI-based init mod_rewrite: RewriteRule /favicon.ico$ /images/favicon.ico URI translation
53
... for instance mod_auth: AuthUserFile .htpasswd client request
URI-based init URI translation file-based init mod_auth: AuthUserFile .htpasswd resource control
54
... for instance mod_cgi: SetHandler cgi-script client request
URI-based init content URI translation fixups file-based init MIME setting resource control
55
That's great breaking down the request into distinct phases has many benefits
56
That's great breaking down the request into distinct phases has many benefits gives each processing point a role that can be easily managed and programmed
57
That's great 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
58
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
59
Enter mod_perl
60
Enter mod_perl mod_perl offers an interface to each phase of the request cycle
61
Enter mod_perl mod_perl offers an interface to each phase of the request cycle opens up the Apache API to Perl code
62
Enter mod_perl mod_perl offers an interface to each phase of the request cycle opens up the Apache API to Perl code allows you to program targeted parts of the request cycle using Perl
63
Enter mod_perl mod_perl offers an interface to each phase of the request cycle opens up the Apache API to Perl code allows you to program targeted parts of the request cycle using Perl we like Perl
64
Apache Request Cycle client request logging URI-based init content
URI translation fixups file-based init MIME setting resource control
65
mod_perl Interface client request PerlCleanupHandler PerlLogHandler
PerlPostReadRequestHandler logging URI-based init PerlHandler PerlTransHandler content URI translation PerlFixupHandler PerlHeaderParserHandler fixups file-based init PerlAccessHandler PerlAuthenHandler PerlAuthzHandler PerlTypeHandler MIME setting resource control
66
mod_perl Interface world's ugliest slide client request
PerlCleanupHandler PerlLogHandler PerlPostReadRequestHandler world's ugliest slide logging URI-based init PerlHandler PerlTransHandler content URI translation PerlFixupHandler PerlHeaderParserHandler fixups file-based init PerlAccessHandler PerlAuthenHandler PerlAuthzHandler PerlTypeHandler MIME setting resource control
67
mod_perl Interface client request PerlCleanupHandler PerlLogHandler
PerlPostReadRequestHandler logging URI-based init PerlHandler PerlTransHandler content URI translation PerlFixupHandler PerlHeaderParserHandler fixups file-based init PerlAccessHandler PerlAuthenHandler PerlAuthzHandler PerlTypeHandler MIME setting resource control
68
How?
69
How? mod_perl embeds an entire perl interpreter into Apache
70
Why?
71
Why? create a persistent perl environment
72
Why? create a persistent perl environment increase performance
73
Why? create a persistent perl environment
increase performance * (for the dynamic parts)
74
Why? create a persistent perl environment open up the Apache API
increase performance * (for the dynamic parts) open up the Apache API
75
Why? create a persistent perl environment open up the Apache API
increase performance * (for the dynamic parts) open up the Apache API increase developer options
76
Why? create a persistent perl environment open up the Apache API
increase performance * (for the dynamic parts) open up the Apache API increase developer options because it's cool
77
What is mod_perl?
78
What is mod_perl? to the masses, mod_perl is just faster CGI a la Apache::Registry
79
What is mod_perl? to the masses, mod_perl is just faster CGI a la Apache::Registry leads to comparisons to FastCGI, PerlEx, and other CGI enhancement engines
80
What is mod_perl? to the masses, mod_perl is just faster CGI a la Apache::Registry leads to comparisons to FastCGI, PerlEx, and other CGI enhancement engines not an accurate description of mod_perl, so comparisons aren't really valid
81
What is mod_perl?
82
What is mod_perl? mod_perl is the Perl interface to the Apache API
83
What is mod_perl? mod_perl is the Perl interface to the Apache API
a C extension module, just like mod_cgi or mod_rewrite
84
What is mod_perl? mod_perl is the Perl interface to the Apache API
a C extension module, just like mod_cgi or mod_rewrite creates a persistent perl environment embedded within Apache
85
What's the Big Deal?
86
What's the Big Deal? mod_perl allows you to interact with and directly alter server behavior
87
What's the Big Deal? 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"
88
What's the Big Deal? 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" let's you do it in Perl instead of C
89
What's the Big Deal? 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" let's you do it in Perl instead of C allows you to intercept basic Apache functions and replace them with your own (sometimes devious) Perl substitutes
90
Ok, so what's a handler?
91
Ok, so what's a handler? the term handler refers to processing that occurs during any of the Apache runtime phases
92
Ok, so what's a handler? the term handler refers to processing that occurs during any of the Apache runtime phases this includes the request-time phases as well as the other parts of the Apache runtime, such as restarts
93
Ok, so what's a handler? the term handler refers to processing that occurs during any of the Apache runtime phases this includes the request-time phases as well as the other parts of the Apache runtime, such as restarts the use of "handler" for all processing hooks is mod_perl specific
94
Why use handlers?
95
Why use handlers? gives each processing point a role that can be easily managed and programmed
96
Why use handlers? gives each processing point a role that can be easily managed and programmed process request at the proper phase meaningful access to the Apache API break up processing into smaller parts modularize and encapsulate processing
97
Why use handlers? gives each processing point a role that can be easily managed and programmed process request at the proper phase meaningful access to the Apache API break up processing into smaller parts modularize and encapsulate processing makes Apache more like an application framework rather than a content engine
98
Why use handlers? gives each processing point a role that can be easily managed and programmed process request at the proper phase meaningful access to the Apache API break up processing into smaller parts modularize and encapsulate processing makes Apache more like an application framework rather than a content engine CPAN
100
Registry is just a handler
101
Registry is just a handler
Apache::Registry is merely an (incredibly clever and amazing) mod_perl handler
102
Registry is just a handler
Apache::Registry is merely an (incredibly clever and amazing) mod_perl handler its performance gains are made possible due to what mod_perl really is
103
Registry is just a handler
Apache::Registry is merely an (incredibly clever and amazing) mod_perl handler its performance gains are made possible due to what mod_perl really is let's take a peek inside...
104
Apache::Registry
105
Apache::Registry Client side http://localhost/perl-bin/bar.pl
106
Apache::Registry Client side Server side
Server side
107
Apache::Registry Client side Server side
Server side mod_perl intercepts content generation
108
Apache::Registry Client side Server side
Server side mod_perl intercepts content generation for Apache/Registry.pm
109
Apache::Registry Client side Server side
Server side mod_perl intercepts content generation for Apache/Registry.pm calls Apache::Registry::handler(Apache->request)
110
Apache::Registry Client side Server side
Server side mod_perl intercepts content generation for Apache/Registry.pm calls Apache::Registry::handler(Apache->request) inserts wizardry
111
Apache::Registry Client side Server side
Server side mod_perl intercepts content generation for Apache/Registry.pm calls Apache::Registry::handler(Apache->request) inserts wizardry returns response to client
112
Wizardry, you say?
113
Wizardry, you say? the wizardry is basically just putting the CGI script into it's own package
114
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; }; ... your script here... } 1;
115
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; }; ... your script here... } 1;
116
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; }; ... your script here... } 1;
117
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; }; ... your script here... } 1; because the perl interpreter is persistent the (compiled) package is already in memory when called
118
"The dream is always the same"
119
"The dream is always the same"
120
"The dream is always the same"
the basic process for mod_perl is the same for the other request phases as for content generation (eg, Registry)
121
"The dream is always the same"
the basic process for mod_perl is the same for the other request phases as for content generation (eg, Registry) Apache passes control to mod_perl
122
"The dream is always the same"
the basic process for mod_perl is the same for the other request phases as for content generation (eg, Registry) Apache passes control to mod_perl mod_perl passes control to your Perl handler
123
"The dream is always the same"
the basic process for mod_perl is the same for the other request phases as for content generation (eg, Registry) Apache passes control to mod_perl mod_perl passes control to your Perl handler your Perl subroutine defines the status
124
"The dream is always the same"
the basic process for mod_perl is the same for the other request phases as for content generation (eg, Registry) Apache passes control to mod_perl mod_perl passes control to your Perl handler your Perl subroutine defines the status mod_perl passes status back to Apache
125
"The dream is always the same"
the basic process for mod_perl is the same for the other request phases as for content generation (eg, Registry) Apache passes control to mod_perl mod_perl passes control to your Perl handler your Perl subroutine defines the status mod_perl passes status back to Apache Apache continues along
126
Anatomy of a Handler
127
Anatomy of a Handler a mod_perl handler is just an ordinary Perl module
128
Anatomy of a Handler a mod_perl handler is just an ordinary Perl module visible
129
Anatomy of a Handler a mod_perl handler is just an ordinary Perl module visible including mod_perl extra paths
130
Anatomy of a Handler a mod_perl handler is just an ordinary Perl module visible including mod_perl extra paths contains a package declaration
131
Anatomy of a Handler a mod_perl handler is just an ordinary Perl module visible including mod_perl extra paths contains a package declaration has at least one subroutine
132
Anatomy of a Handler a mod_perl handler is just an ordinary Perl module visible including mod_perl extra paths contains a package declaration has at least one subroutine typically the handler() subroutine
133
Let's create a handler...
134
Let's create a handler... Object: to protect our name-based virtual hosts from proper but bad HTTP/1.0 requests
135
Let's create a handler... Object: to protect our name-based virtual hosts from unacceptable HTTP/1.0 requests
136
HTTP/1.0 and Host
137
HTTP/1.0 and Host HTTP/1.0 does not require a Host header
138
HTTP/1.0 and Host HTTP/1.0 does not require a Host header
assumes a “one host per IP" configuration
139
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
140
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
141
Connected to www.apache.org. Escape character is '^]'.
$ telnet 80 Trying Connected to Escape character is '^]'. GET /foo.html HTTP/1.0 HTTP/ Found Date: Tue, 04 Jun :52:55 GMT Server: Apache/ dev (Unix) Location: Content-Length: 289 Connection: close Content-Type: text/html; charset=iso <!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=" <hr /> <address>Apache/ dev Server at dev.apache.org Port 80</address> </body></html> Connection closed by foreign host.
142
Connected to www.apache.org. Escape character is '^]'.
$ telnet 80 Trying Connected to Escape character is '^]'. GET /foo.html HTTP/1.0 HTTP/ Found Date: Tue, 04 Jun :52:55 GMT Server: Apache/ dev (Unix) Location: Content-Length: 289 Connection: close Content-Type: text/html; charset=iso <!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=" /> <address>Apache/ dev Server at dev.apache.org Port 80</address> </body></html> Connection closed by foreign host.
143
Connected to www.apache.org. Escape character is '^]'.
$ telnet 80 Trying Connected to Escape character is '^]'. GET /foo.html HTTP/1.0 HTTP/ Found Date: Tue, 04 Jun :52:55 GMT Server: Apache/ dev (Unix) Location: Content-Length: 289 Connection: close Content-Type: text/html; charset=iso <!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=" <hr /> <address>Apache/ dev Server at dev.apache.org Port 80</address> </body></html> Connection closed by foreign host.
144
Connected to www.apache.org. Escape character is '^]'.
$ telnet 80 Trying Connected to Escape character is '^]'. GET /foo.html HTTP/1.0 Host: HTTP/ Not Found Date: Tue, 04 Jun :56:40 GMT Server: Apache/ dev (Unix) Content-Length: 283 Content-Type: text/html; charset=iso <!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/ dev Server at Port 80</address> </body></html>
145
Connected to www.apache.org. Escape character is '^]'.
$ telnet 80 Trying Connected to Escape character is '^]'. GET /foo.html HTTP/1.0 Host: HTTP/ Not Found Date: Tue, 04 Jun :56:40 GMT Server: Apache/ dev (Unix) Content-Length: 283 Content-Type: text/html; charset=iso <!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/ dev Server at Port 80</address> </body></html>
146
Connected to www.apache.org. Escape character is '^]'.
$ telnet 80 Trying Connected to Escape character is '^]'. GET /foo.html HTTP/1.0 Host: HTTP/ Not Found Date: Tue, 04 Jun :56:40 GMT Server: Apache/ dev (Unix) Content-Length: 283 Content-Type: text/html; charset=iso <!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/ dev Server at Port 80</address> </body></html>
147
Let's create a handler... Object: to protect our name-based virtual hosts from unacceptable HTTP/1.0 requests
148
Let's create a handler... Object: to protect our name-based virtual hosts from unacceptable HTTP/1.0 requests Method: intercept the request prior to content-generation and return an error unless...
149
Let's create a handler... Object: to protect our name-based virtual hosts from unacceptable HTTP/1.0 requests Method: intercept the request prior to content-generation and return an error unless... there is a Host header
150
Let's create a handler... Object: to protect our name-based virtual hosts from unacceptable HTTP/1.0 requests Method: intercept the request prior to content-generation and return an error unless... there is a Host header the request is an absolute URI
151
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;
152
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;
153
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;
154
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;
155
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;
156
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;
157
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;
158
package Cookbook::TrapNoHost;
use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = Apache->request; # 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;
159
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;
160
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;
161
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;
162
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;
163
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;
164
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;
165
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;
166
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;
167
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;
168
Setup add TrapNoHost.pm
169
Setup add TrapNoHost.pm to @INC
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm
170
Setup add TrapNoHost.pm to @INC add to httpd.conf
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm add to httpd.conf
171
Setup add TrapNoHost.pm to @INC add to httpd.conf
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm add to httpd.conf PerlModule Cookbook::TrapNoHost PerlTransHandler Cookbook::TrapNoHost
172
Setup add TrapNoHost.pm to @INC add to httpd.conf
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm add to httpd.conf PerlModule Cookbook::TrapNoHost PerlTransHandler Cookbook::TrapNoHost
173
Setup add TrapNoHost.pm to @INC add to httpd.conf
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm add to httpd.conf PerlModule Cookbook::TrapNoHost PerlTransHandler Cookbook::TrapNoHost
174
Setup add TrapNoHost.pm to @INC add to httpd.conf that's it!
ServerRoot/lib/perl/Cookbook/TrapNoHost.pm add to httpd.conf PerlModule Cookbook::TrapNoHost PerlTransHandler Cookbook::TrapNoHost that's it!
175
Apache Request Cycle client request client request logging
URI-based init content URI translation fixups file-based init MIME setting resource control
176
Intercept the Request client request URI-based init URI translation
177
Intercept the Request client request URI-based init URI translation
HTTP/ Bad Request Date: Tue, 04 Jun :17:52 GMT Server: Apache/ dev (Unix) mod_perl/1.27_01-dev Perl/v5.8.0 Connection: close Content-Type: text/html; charset=iso Oops! Did you mean to omit a Host header?
178
Intercept the Request client request URI-based init URI translation
HTTP/ Bad Request Date: Tue, 04 Jun :17:52 GMT Server: Apache/ dev (Unix) mod_perl/1.27_01-dev Perl/v5.8.0 Connection: close Content-Type: text/html; charset=iso Oops! Did you mean to omit a Host header?
179
Intercept the Request client request logging URI-based init
URI translation
181
Key Concepts
182
Key Concepts the Apache request object, $r
183
Key Concepts the Apache request object, $r the Apache::Table class
184
Key Concepts the Apache request object, $r the Apache::Table class
the Apache::URI class
185
Key Concepts the Apache request object, $r the Apache::Table class
the Apache::URI class return values and the Apache::Constants class
186
Key Concepts the Apache request object, $r the Apache::Table class
the Apache::URI class return values and the Apache::Constants class error responses and $r‑>custom_response()
187
Apache Request Object
188
Apache Request Object passed to handlers or available via Apache->request()
189
Apache Request Object passed to handlers or available via Apache->request() $r = shift; # passed to handler()
190
Apache Request Object passed to handlers or available via Apache->request() $r = shift; # passed to handler() $r = Apache->request();
191
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;
192
Apache Request Object passed to handlers or available via Apache->request() $r = shift; # passed to handler() $r = Apache->request();
193
Apache Request Object passed to handlers or available via Apache->request() $r = shift; # passed to handler() $r = Apache->request(); provides access to the Apache class, which provides access to request attributes
194
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;
195
Apache Request Object passed to handlers or available via Apache->request() $r = shift; # passed to handler() $r = Apache->request(); provides access to the Apache class, which provides access to request attributes
196
Apache Request Object passed to handlers or available via Apache->request() $r = shift; # passed to handler() $r = Apache->request(); provides access to the Apache class, which provides access to request attributes singleton-like constructor, always returning the same object
197
Apache::Table
198
Apache::Table the Apache::Table class provides the underlying API for the following request attributes...
199
Apache::Table the Apache::Table class provides the underlying API for the following request attributes... $r->headers_in() $r->headers_out() $r->err_headers_out() $r->dir_config() $r->subprocess_env() $r->notes() Apache::Request::param() Apache::Request::parms() in old releases
200
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;
201
Apache::Table to manipulate Apache::Table objects, you use the provided methods
202
Apache::Table to manipulate Apache::Table objects, you use the provided methods get() set() add() unset() do() merge() new() clear()
203
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;
204
Apache Table Properties
205
Apache Table Properties
Apache tables have some nice properties
206
Apache Table Properties
Apache tables have some nice properties case insensitive
207
Apache Table Properties
Apache tables have some nice properties case insensitive allow for multi-valued keys
208
Apache Table Properties
Apache tables have some nice properties case insensitive allow for multi-valued keys they also have one important limitation
209
Apache Table Properties
Apache tables have some nice properties case insensitive allow for multi-valued keys they also have one important limitation can contain only simple strings
210
Apache Table Properties
Apache tables have some nice properties case insensitive allow for multi-valued keys they also have one important limitation can contain only simple strings use pnotes() for Perl scalars
211
keeps the Net flowin'...
212
keeps the Net flowin'... both case-insensitivity and multiple values are key to manipulating headers
213
keeps the Net flowin'... both case-insensitivity and multiple values are key to manipulating headers $r->headers_out->set('Set-Cookie' => 'name=foo');
214
keeps the Net flowin'... both case-insensitivity and multiple values are key to manipulating headers $r->headers_out->set('Set-Cookie' => 'name=foo'); $r->headers_out->add('set-cookie' => 'name=bar');
215
keeps the Net flowin'... both case-insensitivity and multiple values are key to manipulating headers $r->headers_out->set('Set-Cookie' => 'name=foo'); $r->headers_out->add('set-cookie' => 'name=bar'); = $r->headers_out->get('Set-cookie');
216
Table Iteration
217
Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table
218
Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table my $input = $apr->param; # Apache::Table object $input->do(sub { my ($key, $value) $log->info("input: name = $key, value = $value"); 1; });
219
Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table my $input = $apr->param; # Apache::Table object $input->do(sub { my ($key, $value) $log->info("input: name = $key, value = $value"); 1; });
220
Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table my $input = $apr->param; # Apache::Table object $input->do(sub { my ($key, $value) $log->info("input: name = $key, value = $value"); 1; });
221
Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table my $input = $apr->param; # Apache::Table object $input->do(sub { my ($key, $value) $log->info("input: name = $key, value = $value"); 1; });
222
Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table my $input = $apr->param; # Apache::Table object $input->do(sub { my ($key, $value) $log->info("input: name = $key, value = $value"); 1; });
223
Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table my $input = $apr->param; # Apache::Table object $input->do(sub { my ($key, $value) $log->info("input: name = $key, value = $value"); 1; });
224
Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table my $input = $apr->param; # Apache::Table object $input->do(sub { my ($key, $value) $log->info("input: name = $key, value = $value"); 1; });
225
More Apache::Table Fun
226
More Apache::Table Fun
Tired
227
More Apache::Table Fun
Tired PerlSetVar MyVar "um, ok"
228
More Apache::Table Fun
Tired PerlSetVar MyVar "um, ok" my $ok = $r->dir_config('MyVar');
229
More Apache::Table Fun
Tired PerlSetVar MyVar "um, ok" my $ok = $r->dir_config('MyVar'); Wired
230
More Apache::Table Fun
Tired PerlSetVar MyVar "um, ok" my $ok = $r->dir_config('MyVar'); Wired PerlAddVar MyVar "cool"
231
More Apache::Table Fun
Tired PerlSetVar MyVar "um, ok" my $ok = $r->dir_config('MyVar'); Wired PerlAddVar MyVar "cool" = $r->dir_config->get('MyVar');
232
Trickery
233
Trickery really understanding the Apache::Table class will make you a better mod_perl programmer
234
Trickery really understanding the Apache::Table class will make you a better mod_perl programmer every table can be set
235
Trickery really understanding the Apache::Table class will make you a better mod_perl programmer every table can be set $r->headers_in() $r->headers_out() $r->err_headers_out() $r->dir_config() $r->subprocess_env() $r->notes() Apache::Request::param()
236
Trickery handle "what if?" cases
237
Trickery handle "what if?" cases
$r->headers_in->set('Set-Cookie' => 'name=foo'); my $sub = $r->lookup_uri('/scripts/foo.html');
238
Trickery handle "what if?" cases gratuitous exploitation
$r->headers_in->set('Set-Cookie' => 'name=foo'); my $sub = $r->lookup_uri('/scripts/foo.html'); gratuitous exploitation
239
Trickery handle "what if?" cases gratuitous exploitation
$r->headers_in->set('Set-Cookie' => 'name=foo'); my $sub = $r->lookup_uri('/scripts/foo.html'); gratuitous exploitation # configure "PerlSetVar Filter On" on-the-fly $r->dir_config->set(Filter => 'On');
240
All About URIs
241
All About URIs when Apache parses the incoming request, it puts parts of the URI into the request record
242
All About URIs when Apache parses the incoming request, it puts parts of the URI into the request record for just digging out the request URI you typically want the request attribute $r->uri()
243
All About URIs when Apache parses the incoming request, it puts parts of the URI into the request record for just digging out the request URI you typically want the request attribute $r->uri() my $uri = $r->uri; # $uri is "/index.html"
244
All About URIs when Apache parses the incoming request, it puts parts of the URI into the request record for just digging out the request URI you typically want the request attribute $r->uri() my $uri = $r->uri; # $uri is "/index.html" sometimes you need all the URI parts, like the scheme or port
245
Apache::URI
246
Apache::URI mod_perl provides the Apache::URI utility class for handling URIs
247
Apache::URI mod_perl provides the Apache::URI utility class for handling URIs allows for manipulating the current URI as well as constructing a new URI
248
Apache::URI mod_perl provides the Apache::URI utility class for handling URIs allows for manipulating the current URI as well as constructing a new URI unfortunately, it has two distinct interfaces that contain very subtle differences
249
Apache::URI mod_perl provides the Apache::URI utility class for handling URIs allows for manipulating the current URI as well as constructing a new URI unfortunately, it has two distinct interfaces that contain very subtle differences our code uses those differences to our advantage
250
Manipulating URIs
251
Manipulating URIs Apache::URI offers the parse() method as a constructor
252
Manipulating URIs Apache::URI offers the parse() method as a constructor my $uri = Apache::URI->parse($r);
253
Manipulating URIs Apache::URI offers the parse() method as a constructor my $uri = Apache::URI->parse($r); you can also grab an Apache::URI object from the request itself my $uri = $r->parsed_uri;
254
Manipulating URIs Apache::URI offers the parse() method as a constructor my $uri = Apache::URI->parse($r); you can also grab an Apache::URI object from the request itself my $uri = $r->parsed_uri; to get the URI string back, call the unparse() method
255
Manipulating URIs Apache::URI offers the parse() method as a constructor my $uri = Apache::URI->parse($r); you can also grab an Apache::URI object from the request itself my $uri = $r->parsed_uri; to get the URI string back, call the unparse() method $uri->path('/new/location'); $r->headers_out->set(Location => $uri->unparse);
256
Apache::URI methods
257
Apache::URI methods once you have an Apache::URI object, you can peek at or modify any part of the URI using its accessor methods
258
Apache::URI methods once you have an Apache::URI object, you can peek at or modify any part of the URI using its accessor methods - password() - port() - scheme() - path() - query() - more...
259
Apache::URI methods once you have an Apache::URI object, you can peek at or modify any part of the URI using its accessor methods - password() - port() - scheme() - path() - query() - more... unfortunately, although the objects have the same methods, they don't always behave the same...
260
parsed_uri()
261
parsed_uri() parsed_uri() returns an object populated based on $r->uri() and other parts of the request record
262
parsed_uri() parsed_uri() returns an object populated based on $r->uri() and other parts of the request record since the URI has undergone translation, the path_info() method will return useful information
263
parsed_uri() parsed_uri() returns an object populated based on $r->uri() and other parts of the request record since the URI has undergone translation, the path_info() method will return useful information Given: <Location /foo>
264
parsed_uri() parsed_uri() returns an object populated based on $r->uri() and other parts of the request record since the URI has undergone translation, the path_info() method will return useful information Given: <Location /foo> my $path = $r->parsed_uri->path; # "/foo" my $info = $r->parsed_uri->path_info; # "/bar"
265
Apache::URI->parse($r)
266
Apache::URI->parse($r)
Apache::URI->parse($r) only looks at the incoming URI and makes no assumptions about the underlying filesystem
267
Apache::URI->parse($r)
Apache::URI->parse($r) only looks at the incoming URI and makes no assumptions about the underlying filesystem Given: <Location /foo>
268
Apache::URI->parse($r)
Apache::URI->parse($r) only looks at the incoming URI and makes no assumptions about the underlying filesystem Given: <Location /foo> my $path = Apache::URI->parse($r)->path; # "/foo/bar" my $info = Apache::URI->parse($r)->path_info; # undef
269
parsed_uri()
270
parsed_uri() unless the request is an absolute URI the scheme, host, and port fields will be absent
271
parsed_uri() unless the request is an absolute URI the scheme, host, and port fields will be absent proxy requests are absolute URIs
272
parsed_uri() unless the request is an absolute URI the scheme, host, and port fields will be absent proxy requests are absolute URIs Given:
273
Apache::URI->parse($r)
274
Apache::URI->parse($r)
Apache::URI->parse($r) uses other bits of information to construct a self-referential URI
275
Apache::URI->parse($r)
Apache::URI->parse($r) uses other bits of information to construct a self-referential URI Given:
276
Apache::URI->parse($r)
Apache::URI->parse($r) uses other bits of information to construct a self-referential URI Given: my $scheme = Apache::URI->parse($r)->scheme; # "http" my $host = Apache::URI->parse($r)->hostname; "
277
it all boils down to...
278
it all boils down to... the differences between Apache::URI->parse($r) and $r->parsed_uri() are very confusing
279
it all boils down to... the differences between Apache::URI->parse($r) and $r->parsed_uri() are very confusing use Apache::URI->parse($r) for creating a self-referential URI that needs to point to the same server
280
it all boils down to... the differences between Apache::URI->parse($r) and $r->parsed_uri() are very confusing use Apache::URI->parse($r) for creating a self-referential URI that needs to point to the same server use $r->parsed_uri() for accessing request attributes
281
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;
282
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;
283
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;
284
Apache::Constants
285
Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST);
286
Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST); the most common are:
287
Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST); the most common are: OK
288
Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST); the most common are: OK SERVER_ERROR
289
Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST); the most common are: OK SERVER_ERROR REDIRECT
290
Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST); the most common are: OK SERVER_ERROR REDIRECT DECLINED
291
Return Values handlers are expected to return a value
292
Return Values handlers are expected to return a value
the return value of the handler defines the status of the request
293
Return Values handlers are expected to return a value
the return value of the handler defines the status of the request Apache defines three "good" return values
294
Return Values handlers are expected to return a value
the return value of the handler defines the status of the request Apache defines three "good" return values OK – all is well
295
Return Values handlers are expected to return a value
the return value of the handler defines the status of the request Apache defines three "good" return values OK – all is well DECLINED – forget about me
296
Return Values handlers are expected to return a value
the return value of the handler defines the status of the request Apache defines three "good" return values OK – all is well DECLINED – forget about me DONE – we're finished, start to log
297
Return Values handlers are expected to return a value
the return value of the handler defines the status of the request Apache defines three "good" return values OK – all is well DECLINED – forget about me DONE – we're finished, start to log All other values are "errors" and trigger the ErrorDocument cycle
298
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;
299
When handlers turn bad...
300
When handlers turn bad... "error" return codes are not always errors
301
When handlers turn bad... "error" return codes are not always errors
instead, they indicate a new route for the request
302
package My::Redirect; use Apache::Constants qw(REDIRECT);
sub handler { my $r = shift; $r->headers_out->set(Location => '/foo'); return REDIRECT; }; 1;
303
package My::Redirect; use Apache::Constants qw(REDIRECT);
sub handler { my $r = shift; $r->headers_out->set(Location => '/foo'); return REDIRECT; }; 1;
304
package My::Redirect; use Apache::Constants qw(REDIRECT);
sub handler { my $r = shift; $r->headers_out->set(Location => '/foo'); return REDIRECT; }; 1;
305
package My::Redirect; use Apache::Constants qw(REDIRECT);
sub handler { my $r = shift; $r->headers_out->set(Location => '/foo'); return REDIRECT; }; 1; <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <HTML><HEAD> <TITLE>302 Found</TITLE> </HEAD><BODY> <H1>Found</H1> The document has moved <A HREF="/foo">here</A>.<P> <HR> <ADDRESS>Apache/ dev Server at mainsheet.laserlink.com Port 80</ADDRESS> </BODY></HTML>
306
package My::Redirect; use Apache::Constants qw(REDIRECT);
sub handler { my $r = shift; $r->headers_out->set(Location => '/foo'); return REDIRECT; }; 1; <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <HTML><HEAD> <TITLE>302 Found</TITLE> </HEAD><BODY> <H1>Found</H1> The document has moved <A HREF="/foo">here</A>.<P> <HR> <ADDRESS>Apache/ dev Server at mainsheet.laserlink.com Port 80</ADDRESS> </BODY></HTML>
307
Custom Responses
308
Custom Responses Apache has default responses for most of the possible errors
309
Custom Responses Apache has default responses for most of the possible errors it also provides the ErrorDocument directive for fine-tuning server behavior
310
Custom Responses Apache has default responses for most of the possible errors it also provides the ErrorDocument directive for fine-tuning server behavior you can specify error behavior on-the-fly with custom_response()
311
custom_response()
312
custom_response() the custom_response() method has several interfaces...
313
custom_response() the custom_response() method has several interfaces... # set the response for 500 $r->custom_response(SERVER_ERROR, '/error.html')
314
custom_response() the custom_response() method has several interfaces... # set the response for 500 $r->custom_response(SERVER_ERROR, '/error.html') # capture the current 500 setting my $errordoc = $r->custom_response(SERVER_ERROR)
315
custom_response() the custom_response() method has several interfaces... # set the response for 500 $r->custom_response(SERVER_ERROR, '/error.html') # capture the current 500 setting my $errordoc = $r->custom_response(SERVER_ERROR) # reset 500 back to the Apache default $r->custom_response(SERVER_ERROR, undef);
316
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;
317
Key Concepts the Apache request object, $r the Apache::Table class
the Apache::URI class return values and the Apache::Constants class error responses and $r‑>custom_response()
319
Just the Beginning
320
Just the Beginning almost every part of Apache's default behavior can be replaced, rewritten, or extended using mod_perl
321
Just the Beginning almost every part of Apache's default behavior can be replaced, rewritten, or extended using mod_perl in many cases you can do much more than you can with Apache and C due to Perl's ability to fold, spindle, and mutilate everyday items
322
User Authentication
323
User Authentication Apache default authentication mechanism is mod_auth
324
User Authentication Apache default authentication mechanism is mod_auth uses a password file generated using Apache's htpasswd utility
325
User Authentication Apache default authentication mechanism is mod_auth uses a password file generated using Apache's htpasswd utility geoff:zzpEyL0tbgwwk
326
User Authentication configuration placed in .htaccess file or httpd.conf
327
User Authentication configuration placed in .htaccess file or httpd.conf AuthUserFile .htpasswd AuthName "my site" AuthType Basic Require valid-user
328
User Authentication configuration placed in .htaccess file or httpd.conf AuthUserFile .htpasswd AuthName "my site" AuthType Basic Require valid-user
329
Who Uses Flat Files?
330
Who Uses Flat Files? flat files are limiting, hard to manage, difficult to integrate, and just plain boring
331
Who Uses Flat Files? flat files are limiting, hard to manage, difficult to integrate, and just plain boring we can use the Apache API and Perl to replace flat files with our own authentication mechanism
332
How Authentication Works
client requests a document
333
How Authentication Works
client requests a document GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US)
334
How Authentication Works
client requests a document GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server denies request
335
How Authentication Works
client requests a document GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server denies request HTTP/ Authorization Required WWW-Authenticate: Basic realm="my site" Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html; charset=iso
336
How Authentication Works
client requests a document GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server denies request HTTP/ Authorization Required WWW-Authenticate: Basic realm="my site" Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html; charset=iso
337
How Authentication Works
client request client request logging URI-based init content URI translation fixups file-based init MIME setting resource control
338
How Authentication Works
client request client request URI-based init URI translation file-based init resource control resource control
339
How Authentication Works
client request client request URI-based init URI translation file-based init resource control resource control HTTP/ Authorization Required
340
How Authentication Works
client request client request logging URI-based init URI translation file-based init resource control resource control
341
How Authentication Works
client sends a new request
342
How Authentication Works
client sends a new request GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Authorization: Basic Z2VvZmY6YWZha2VwYXNzd29yZA== Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US)
343
How Authentication Works
client sends a new request GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Authorization: Basic Z2VvZmY6YWZha2VwYXNzd29yZA== Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US)
344
How Authentication Works
client sends a new request GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Authorization: Basic Z2VvZmY6YWZha2VwYXNzd29yZA== Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server sends document
345
How Authentication Works
client sends a new request GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Authorization: Basic Z2VvZmY6YWZha2VwYXNzd29yZA== Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server sends document HTTP/ OK Keep-Alive: timeout=15, max=99 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html
346
Do it in Perl since mod_perl gives us the ability to intercept the request cycle before Apache, we can authenticate using Perl instead
347
Do it in Perl since mod_perl gives us the ability to intercept the request cycle before Apache, we can authenticate using Perl instead Apache provides an API, making the job easy
348
Do it in Perl since mod_perl gives us the ability to intercept the request cycle before Apache, we can authenticate using Perl instead Apache provides an API, making the job easy mod_perl provides access to the Apache API
349
package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # 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; }
350
package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # 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; }
351
package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # 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; }
352
package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # 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; }
353
package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # 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; }
354
package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # 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; }
355
package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # 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; }
356
package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # 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; }
357
No Authorization Header
client requests a document GET /perl-status HTTP/1.1 Accept: text/xml, image/png, image/jpeg, image/gif, text/plain Accept-Charset: ISO , utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server denies request HTTP/ Authorization Required WWW-Authenticate: Basic realm="my site" Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html; charset=iso
358
package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # 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; }
359
package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # 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; }
360
package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # 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; }
361
package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # 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; }
362
package My::Authenticate;
use Apache::Constants qw(OK DECLINED AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Let subrequests pass. return DECLINED unless $r->is_initial_req; # 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; }
363
Configuration
364
Configuration change AuthUserFile .htpasswd AuthName "my site"
AuthType Basic Require valid-user
365
Configuration change to AuthUserFile .htpasswd AuthName "my site"
AuthType Basic Require valid-user to PerlAuthenHandler My::Authenticate
366
Configuration change to AuthUserFile .htpasswd AuthName "my site"
AuthType Basic Require valid-user to PerlAuthenHandler My::Authenticate
367
The Choice is Yours how you decide to authenticate is now up to you
368
The Choice is Yours how you decide to authenticate is now up to you
sub authenticate_user { my ($user, $pass) return $user eq $pass; }
369
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?
370
The Power of CPAN over 25 Apache:: shrink-wrapped modules on CPAN for authentication SecureID Radius SMB LDAP NTLM
371
To Infinity and Beyond!
372
To Infinity and Beyond!
373
To Infinity and Beyond! this example only covered Basic authentication via popup box
374
To Infinity and Beyond! this example only covered Basic authentication via popup box the same techniques can be used to authenticate via a login form plus cookies, munged URLs, or hidden fields
375
To Infinity and Beyond! this example only covered Basic authentication via popup box the same techniques can be used to authenticate via a login form plus cookies, munged URLs, or hidden fields extended to use Digest authentication as well
377
Content Generation client request logging URI-based init content
URI translation fixups file-based init MIME setting resource control
378
Sample PerlHandler create a handler that uses CPAN module HTML::Clean to "clean" outgoing documents
379
Sample PerlHandler create a handler that uses CPAN module HTML::Clean to "clean" outgoing documents alter the handler to take advantage of more advanced mod_perl features
380
use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;
381
use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;
382
use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;
383
use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;
384
use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;
385
use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;
386
use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;
387
use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;
388
use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;
389
use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;
390
use Apache::Constants qw(OK DECLINED); use Apache::File;
package TPC::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;
391
Configuration add directives to httpd.conf to mirror DocumentRoot
Alias /clean /usr/local/apache/htdocs <Location /clean> SetHandler perl-script PerlHandler TPC::Clean </Location>
392
Results original: 202 bytes <html> <body>
<form method="GET" action="/foo"> Text: <input type="text" name="foo"><br> <input type="submit"> </form> <strong>hi there </strong> </body> </html>
393
Results original: 202 bytes clean: 145 bytes <html> <body>
<form method="GET" action="/foo"> Text: <input type="text" name="foo"><br> <input type="submit"> </form> <strong>hi there </strong> </body> </html> clean: 145 bytes <html><body><form method="GET" action="/foo"> Text: <input type="text" name="foo"><br><input type="submit"></form><b>hi there </b></body></html>
394
Results original: 202 bytes clean: 145 bytes <html> <body>
<form method="GET" action="/foo"> Text: <input type="text" name="foo"><br> <input type="submit"> </form> <strong>hi there </strong> </body> </html> clean: 145 bytes <html><body><form method="GET" action="/foo"> Text: <input type="text" name="foo"><br><input type="submit"></form><b>hi there </b></body></html>
395
Key Concepts
396
Key Concepts Apache::File class
397
Key Concepts Apache::File class $r->filename
398
Key Concepts Apache::File class $r->filename local $/
399
Apache::File
400
Apache::File Apache::File is similar to IO::File
401
Apache::File Apache::File is similar to IO::File
my $fh = Apache::File->new($r->filename); while (my $line = <$fh>) { ... }
402
Apache::File Apache::File is similar to IO::File
my $fh = Apache::File->new($r->filename); while (my $line = <$fh>) { ... } it also adds a number of methods to the Apache class for use when manipulating files over HTTP
403
$r->filename()
404
$r->filename() contains the result of URI-to-filename translation
405
$r->filename() contains the result of URI-to-filename translation
if you just want to stat() the requested file, use $r->finfo and the special filehandle _
406
$r->filename() contains the result of URI-to-filename translation
if you just want to stat() the requested file, use $r->finfo and the special filehandle _ if (-f $r->finfo && -M _ < $timeout) { ... }
407
local $/;
408
local $/; typical Perl idiom
409
local $/; typical Perl idiom local $/; my $file = <$fh>; #slurp
410
local $/; typical Perl idiom local $/; my $file = <$fh>; #slurp
my $file = do {local $/; <$fh>};
411
local $/; typical Perl idiom bad under mod_perl local $/;
my $file = <$fh>; #slurp my $file = do {local $/; <$fh>}; bad under mod_perl
412
local $/; typical Perl idiom bad under mod_perl
my $file = <$fh>; #slurp my $file = do {local $/; <$fh>}; bad under mod_perl but we do it anyway with justification
413
The Choice is Yours!
414
The Choice is Yours! Content filtering with Apache::Filter?
415
The Choice is Yours! Content filtering with Apache::Filter?
Using proper cache-friendly headers?
416
Magic
417
Magic filtered content generation impossible with Apache 1.3
418
Magic filtered content generation impossible with Apache 1.3
can't send CGI output through mod_ssi
419
Magic filtered content generation impossible with Apache 1.3
can't send CGI output through mod_ssi reason for output filters in Apache 2.0
420
Magic filtered content generation impossible with Apache 1.3
can't send CGI output through mod_ssi reason for output filters in Apache 2.0 mod_perl has had output filtering for years
421
Magic filtered content generation impossible with Apache 1.3
can't send CGI output through mod_ssi reason for output filters in Apache 2.0 mod_perl has had output filtering for years possible due to Perl's TIEHANDLE interface
422
TIEHANDLE in mod_perl
423
TIEHANDLE in mod_perl mod_perl tie()s STDOUT to the Apache class prior to the content generation phase
424
TIEHANDLE in mod_perl mod_perl tie()s STDOUT to the Apache class prior to the content generation phase you can tie() STDOUT as well and override mod_perl's default behavior
425
TIEHANDLE in mod_perl mod_perl tie()s STDOUT to the Apache class prior to the content generation phase you can tie() STDOUT as well and override mod_perl's default behavior very useful with stacked handlers
426
Stacked Handlers
427
Stacked Handlers for each phase of the request, mod_perl will run any registered Perl handlers for that phase
428
Stacked Handlers for each phase of the request, mod_perl will run any registered Perl handlers for that phase you can register more than one Perl handler per phase
429
Stacked Handlers for each phase of the request, mod_perl will run any registered Perl handlers for that phase you can register more than one Perl handler per phase whether all handlers are called depends on the syntax of the phase itself in Apache
430
Stacked Handlers some phase run until the handler list is exhausted
431
Stacked Handlers some phase run until the handler list is exhausted
PerlLogHandler My::DBLogger PerlLogHandler My::FileLogger
432
Stacked Handlers some phase run until the handler list is exhausted
PerlLogHandler My::DBLogger PerlLogHandler My::FileLogger some phases run until one handler returns OK
433
Stacked Handlers some phase run until the handler list is exhausted
PerlLogHandler My::DBLogger PerlLogHandler My::FileLogger some phases run until one handler returns OK PerlTransHandler My::TranslateHTML PerlTransHandler My::TranslateText
434
Stacked Handlers some phase run until the handler list is exhausted
PerlLogHandler My::DBLogger PerlLogHandler My::FileLogger some phases run until one handler returns OK PerlTransHandler My::TranslateHTML PerlTransHandler My::TranslateText all phases terminate on "error"
435
Stacked Content Handlers
436
Stacked Content Handlers
for the content generation phase, running multiple Perl handlers can be incredibly powerful
437
Stacked Content Handlers
for the content generation phase, running multiple Perl handlers can be incredibly powerful Apache::Filter implements a simple interface for pipelining content handlers
438
Stacked Content Handlers
for the content generation phase, running multiple Perl handlers can be incredibly powerful Apache::Filter implements a simple interface for pipelining content handlers uses TIEHANDLE in the background
439
Now for the Fun Part
440
Now for the Fun Part modify our handler to work either standalone or as part of a handler chain
441
Now for the Fun Part modify our handler to work either standalone or as part of a handler chain easy using Apache::Filter
442
Apache::Filter Changes
443
Apache::Filter Changes
my $fh = Apache::File->new($r->filename) or return DECLINED;
444
Apache::Filter Changes
my $fh = Apache::File->new($r->filename) or return DECLINED; to: my $fh = undef; if (lc $r->dir_config('Filter') eq 'on') { $r = $r->filter_register; ($fh, my $status) = $r->filter_input; return $status unless $status == OK } else { $fh = Apache::File->new($r->filename) or return NOT_FOUND;
445
Apache::Filter Changes
my $fh = Apache::File->new($r->filename) or return DECLINED; to: my $fh = undef; if (lc $r->dir_config('Filter') eq 'on') { $r = $r->filter_register; ($fh, my $status) = $r->filter_input; return $status unless $status == OK } else { $fh = Apache::File->new($r->filename) or return NOT_FOUND;
446
Apache::Filter Changes
my $fh = Apache::File->new($r->filename) or return DECLINED; to: my $fh = undef; if (lc $r->dir_config('Filter') eq 'on') { $r = $r->filter_register; ($fh, my $status) = $r->filter_input; return $status unless $status == OK } else { $fh = Apache::File->new($r->filename) or return NOT_FOUND;
447
Apache::Filter Changes
my $fh = Apache::File->new($r->filename) or return DECLINED; to: my $fh = undef; if (lc $r->dir_config('Filter') eq 'on') { $r = $r->filter_register; ($fh, my $status) = $r->filter_input; return $status unless $status == OK } else { $fh = Apache::File->new($r->filename) or return NOT_FOUND;
448
Apache::Filter Changes
my $fh = Apache::File->new($r->filename) or return DECLINED; to: my $fh = undef; if (lc $r->dir_config('Filter') eq 'on') { $r = $r->filter_register; ($fh, my $status) = $r->filter_input; return $status unless $status == OK } else { $fh = Apache::File->new($r->filename) or return NOT_FOUND;
449
Apache::Filter Changes
my $fh = Apache::File->new($r->filename) or return DECLINED; to: my $fh = undef; if (lc $r->dir_config('Filter') eq 'on') { $r = $r->filter_register; ($fh, my $status) = $r->filter_input; return $status unless $status == OK } else { $fh = Apache::File->new($r->filename) or return NOT_FOUND;
450
Configuration
451
Configuration change Alias /clean /usr/local/apache/htdocs
<Location /clean> SetHandler perl-script PerlHandler My::Clean </Location>
452
Configuration change to Alias /clean /usr/local/apache/htdocs
<Location /clean> SetHandler perl-script PerlHandler My::Clean </Location> to PerlModule Apache::Filter PerlSetVar Filter On
453
Configuration change to Alias /clean /usr/local/apache/htdocs
<Location /clean> SetHandler perl-script PerlHandler My::Clean </Location> to PerlModule Apache::Filter PerlSetVar Filter On
454
Key Concepts Apache::Filter API
455
Apache::Filter
456
Apache::Filter Apache::Filter adds methods to the Apache class
457
Apache::Filter Apache::Filter adds methods to the Apache class
do not have to use Apache::Filter;
458
Apache::Filter Apache::Filter adds methods to the Apache class
do not have to use Apache::Filter; do have to PerlModule Apache::Filter
459
Apache::Filter Apache::Filter adds methods to the Apache class
do not have to use Apache::Filter; do have to PerlModule Apache::Filter because filtering content is tricky, the interface is quirky
460
Apache::Filter Apache::Filter adds methods to the Apache class
do not have to use Apache::Filter; do have to PerlModule Apache::Filter because filtering content is tricky, the interface is quirky $r = $r->filter_register;
461
Apache::Filter to get at filtered input, call $r->filter_input()
462
Apache::Filter to get at filtered input, call $r->filter_input()
returns an open filehandle on the input stream
463
Apache::Filter to get at filtered input, call $r->filter_input()
returns an open filehandle on the input stream if the first filter, the filehandle is for $r->filename()
464
Apache::Filter to get at filtered input, call $r->filter_input()
returns an open filehandle on the input stream if the first filter, the filehandle is for $r->filename() all filters use the same API, regardless of their position in the chain
465
So What?
466
So What? new Apache::Filter aware code works the same as the standalone module
467
So What? new Apache::Filter aware code works the same as the standalone module can be used as part of a PerlHandler chain
468
So What? new Apache::Filter aware code works the same as the standalone module can be used as part of a PerlHandler chain can be any part of the chain
469
Compressing Output
470
Compressing Output use Apache::Compress
471
Compressing Output use Apache::Compress available from CPAN
472
Compressing Output use Apache::Compress available from CPAN
uses Compress::Zlib to compress output
473
Compressing Output use Apache::Compress available from CPAN
uses Compress::Zlib to compress output Apache::Filter aware
474
Configuration
475
Configuration change Alias /clean /usr/local/apache/htdocs
<Location /clean> SetHandler perl-script PerlHandler My::Clean PerlSetVar Filter On </Location>
476
Configuration change to Alias /clean /usr/local/apache/htdocs
<Location /clean> SetHandler perl-script PerlHandler My::Clean PerlSetVar Filter On </Location> to PerlHandler My::Clean Apache::Compress
477
Configuration change to Alias /clean /usr/local/apache/htdocs
<Location /clean> SetHandler perl-script PerlHandler My::Clean PerlSetVar Filter On </Location> to PerlHandler My::Clean Apache::Compress
478
Stacked Power http://perl.apache.org/index.html straight HTML
35668 bytes My::Clean 28162 bytes (79%) Apache::Compress 8177 bytes (23%) My::Clean + Apache::Compress 7458 bytes (21%)
479
Caveats
480
Caveats using Apache::Filter is actually a bit more complex than this...
481
Caveats using Apache::Filter is actually a bit more complex than this... see the recent version of Apache::Clean to get an idea
482
Cache Headers
483
Cache Headers we often think of dynamic content as "could be different on any given access"
484
Cache Headers we often think of dynamic content as "could be different on any given access" "dynamic" content can also be static with clearly defined factors that can change its meaning
485
Cache Headers we often think of dynamic content as "could be different on any given access" "dynamic" content can also be static with clearly defined factors that can change its meaning by properly managing HTTP/1.1 cache headers, we can reduce strain on our servers
486
Conditional GET Request
487
Conditional GET Request
HTTP/1.1 allows for a conditional GET request
488
Conditional GET Request
HTTP/1.1 allows for a conditional GET request clients are allowed to use cached content based on information about the resource
489
Conditional GET Request
HTTP/1.1 allows for a conditional GET request clients are allowed to use cached content based on information about the resource information is provided by both the client and the server
490
GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 01 Nov :35:27 GMT ETag: "4c be179cf" Accept-Ranges: bytes Content-Length: 9268 Connection: close Content-Type: text/html
491
GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 01 Nov :35:27 GMT ETag: "4c be179cf" Accept-Ranges: bytes Content-Length: 9268 Connection: close Content-Type: text/html
492
GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 01 Nov :35:27 GMT ETag: "4c be179cf" Accept-Ranges: bytes Content-Length: 9268 Connection: close Content-Type: text/html
493
GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ Not Modified Last-Modified: Thu, 01 Nov :35:27 GMT ETag: "4c be179cf" Accept-Ranges: bytes Connection: close
494
GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ Not Modified Last-Modified: Thu, 01 Nov :35:27 GMT ETag: "4c be179cf" Accept-Ranges: bytes Connection: close
495
GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ Not Modified Last-Modified: Thu, 01 Nov :35:27 GMT ETag: "4c be179cf" Accept-Ranges: bytes Connection: close
496
GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ Not Modified Last-Modified: Thu, 01 Nov :35:27 GMT ETag: "4c be179cf" Accept-Ranges: bytes Connection: close
497
GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 06 Jun :51:11 GMT ETag: "4c cff4caf" Accept-Ranges: bytes Content-Length: 9268 Connection: close
498
GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 06 Jun :51:11 GMT ETag: "4c cff4caf" Accept-Ranges: bytes Content-Length: 9268 Connection: close
499
GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 06 Jun :51:11 GMT ETag: "4c cff4caf" Accept-Ranges: bytes Content-Length: 9268 Connection: close
500
GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 06 Jun :51:11 GMT ETag: "4c cff4caf" Accept-Ranges: bytes Content-Length: 9268 Connection: close
501
GET /manual/index.html HTTP/1.1
Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */* Accept-Charset: windows-1252;q=1.0, utf-8;q=1.0, utf-16;q=1.0, iso ;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Accept-Language: en Connection: Keep-Alive, TE Host: mainsheet.laserlink.net If-Modified-Since: Thu, 01 Nov :35:27 GMT If-None-Match: "4c be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera [en] HTTP/ OK Last-Modified: Thu, 06 Jun :51:11 GMT ETag: "4c cff4caf" Accept-Ranges: bytes Content-Length: 9268 Connection: close
502
Conditional GET Request
for static documents, Apache takes care of making our response cache-friendly
503
Conditional GET Request
for static documents, Apache takes care of making our response cache-friendly since the file is on disk, Apache can determine when the file was last changed
504
Conditional GET Request
for static documents, Apache takes care of making our response cache-friendly since the file is on disk, Apache can determine when the file was last changed with static files, local modification is the only factor
505
Conditional GET Request
for static documents, Apache takes care of making our response cache-friendly since the file is on disk, Apache can determine when the file was last changed with static files, local modification is the only factor still too many rules to keep straight
506
Conditional GET Request
for static documents, Apache takes care of making our response cache-friendly since the file is on disk, Apache can determine when the file was last changed with static files, local modification is the only factor still too many rules to keep straight Apache provides an API to use so we don't have to think too much
507
Now for the Fun Part
508
Now for the Fun Part modify our handler to be "cache friendly"
509
Now for the Fun Part modify our handler to be "cache friendly"
send 304 when the document hasn't changed
510
Now for the Fun Part modify our handler to be "cache friendly"
send 304 when the document hasn't changed properly handle If-* header comparisons
511
How do you define change?
512
How do you define change?
513
How do you define change?
when dynamically altering static documents there are a number of factors to consider
514
How do you define change?
when dynamically altering static documents there are a number of factors to consider when the file changes on disk
515
How do you define change?
when dynamically altering static documents there are a number of factors to consider when the file changes on disk when the code changes
516
How do you define change?
when dynamically altering static documents there are a number of factors to consider when the file changes on disk when the code changes when the options to the code changes
517
How do you define change?
when dynamically altering static documents there are a number of factors to consider when the file changes on disk when the code changes when the options to the code changes all of these affect the "freshness" of the document
518
Code Changes
519
Code Changes in order to determine when the code itself changes, we need to mark the modification time of the package
520
Code Changes in order to determine when the code itself changes, we need to mark the modification time of the package at request time, we call an API to compare the package modification to the If-Modified-Since header
521
Code Changes in order to determine when the code itself changes, we need to mark the modification time of the package at request time, we call an API to compare the package modification to the If-Modified-Since header on reloads, we regenerate the package modification time
522
use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; } 1;
523
use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9];
524
use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9];
525
Configuration Changes
526
Configuration Changes
in order to determine when the options to the code change, we need to mark the modification time of httpd.conf
527
Configuration Changes
in order to determine when the options to the code change, we need to mark the modification time of httpd.conf at request time, we call an API to compare the configuration modification to the If-Modified-Since header
528
Configuration Changes
in order to determine when the options to the code change, we need to mark the modification time of httpd.conf at request time, we call an API to compare the configuration modification to the If-Modified-Since header on restarts, we regenerate the configuration modification time
529
use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9];
530
use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9]; # ...and when httpd.conf was last modified my $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; # When the server is restarted we need to # make sure we recognize config file changes and propigate # them to the client to clear the client cache if necessary. Apache->server->register_cleanup(sub { $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; });
531
use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9]; # ...and when httpd.conf was last modified my $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; # When the server is restarted we need to # make sure we recognize config file changes and propigate # them to the client to clear the client cache if necessary. Apache->server->register_cleanup(sub { $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; });
532
use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9]; # ...and when httpd.conf was last modified my $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; # When the server is restarted we need to # make sure we recognize config file changes and propigate # them to the client to clear the client cache if necessary. Apache->server->register_cleanup(sub { $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; });
533
Resource Changes
534
Resource Changes in order to determine when the resources changes, we need to mark the modification time of $r->filename
535
Resource Changes in order to determine when the resources changes, we need to mark the modification time of $r->filename at request time, we call an API to compare the resource modification to the If-Modified-Since header
536
Resource Changes in order to determine when the resources changes, we need to mark the modification time of $r->filename at request time, we call an API to compare the resource modification to the If-Modified-Since header resource modification is checked on each request
537
use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9]; # ...and when httpd.conf was last modified my $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; # When the server is restarted we need to # make sure we recognize config file changes and propigate # them to the client to clear the client cache if necessary. Apache->server->register_cleanup(sub { $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; });
538
use Apache::Constants qw(OK DECLINED); use Apache::File;
package My::Clean; use Apache::Constants qw(OK DECLINED); use Apache::File; use HTML::Clean; use strict; # Get the package modification time... (my $package = __PACKAGE__) =~ s!::!/!g; my $package_mtime = (stat $INC{"$package.pm"})[9]; # ...and when httpd.conf was last modified my $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; # When the server is restarted we need to # make sure we recognize config file changes and propigate # them to the client to clear the client cache if necessary. Apache->server->register_cleanup(sub { $conf_mtime = (stat Apache->server_root_relative('conf/httpd.conf'))[9]; }); sub handler { ... } 1;
539
my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->send_http_header('text/html'); print ${$h->data}; return OK; }
540
my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;
541
my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;
542
my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;
543
my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;
544
my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;
545
my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;
546
my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;
547
my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;
548
my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;
549
my $fh = Apache::File->new($r->filename) or return DECLINED;
sub handler { my $r = shift; my $fh = Apache::File->new($r->filename) or return DECLINED; my $dirty = do {local $/; <$fh>}; my $h = HTML::Clean->new(\$dirty); $h->level(3); $h->strip; $r->update_mtime($package_mtime); $r->update_mtime((stat $r->finfo)[9]); $r->update_mtime($conf_mtime); $r->set_last_modified; $r->set_etag; $r->set_content_length(length ${$h->data}); # only send the file if it meets cache criteria if ((my $status = $r->meets_conditions) == OK) { $r->send_http_header('text/html'); } else { return $status; print ${$h->data}; return OK;
550
Key Concepts
551
Key Concepts Apache::File
552
Key Concepts Apache::File update_mtime() and time comparisons
553
Key Concepts Apache::File update_mtime() and time comparisons
headers to never modify directly
554
Key Concepts Apache::File update_mtime() and time comparisons
headers to never modify directly meets_conditions() for header comparison
555
Apache::File
556
Apache::File when you use Apache::File; methods are added to the Apache class
557
Apache::File when you use Apache::File; methods are added to the Apache class update_mtime() set_content_length() set_last_modified() set_etag() meets_conditions() set_byterange() each_byterange()
558
update_mtime()
559
update_mtime() used to update the apparent modification time of the resource
560
update_mtime() used to update the apparent modification time of the resource compares the current resource mtime to the set attempt and keeps the most recent
561
update_mtime() used to update the apparent modification time of the resource compares the current resource mtime to the set attempt and keeps the most recent just pile calls to update_mtime() up and let Apache do the work
562
Special Headers
563
Special Headers some headers you don't want to manipulate with headers_out()
564
Special Headers some headers you don't want to manipulate with headers_out() Apache provides a special set of APIs for these
565
Special Headers some headers you don't want to manipulate with headers_out() Apache provides a special set of APIs for these the ones added by Apache::File
566
set_last_modified()
567
set_last_modified() sets the Last-Modified header
568
set_last_modified() sets the Last-Modified header
uses mtime slot in the request record by default
569
set_last_modified() sets the Last-Modified header
uses mtime slot in the request record by default can pass it a properly formatted time
570
set_etag()
571
set_etag() sets the ETag header
572
set_etag() sets the ETag header
ETag is supposed to be unique for every version of a resource that ever existed
573
set_etag() sets the ETag header
ETag is supposed to be unique for every version of a resource that ever existed use only with static resources
574
set_content_length()
575
set_content_length()
sets the Content-Length header
576
set_content_length()
sets the Content-Length header ...
577
meets_conditions()
578
meets_conditions() does all the nasty comparisons between the client and server headers
579
meets_conditions() does all the nasty comparisons between the client and server headers returns OK or HTTP_NOT_MODIFIED
580
meets_conditions() does all the nasty comparisons between the client and server headers returns OK or HTTP_NOT_MODIFIED sets the headers_out() as appropriate
581
meets_conditions() does all the nasty comparisons between the client and server headers returns OK or HTTP_NOT_MODIFIED sets the headers_out() as appropriate you need to set all your outgoing headers before calling meets_conditions()
583
Fine Manuals Writing Apache Modules with Perl and C
mod_perl Developer's Cookbook mod_perl Pocket Reference mod_perl Guide mod_perl at the ASF
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.