Programming the Apache Lifecycle

Slides:



Advertisements
Similar presentations
Chapter 6 Server-side Programming: Java Servlets
Advertisements

HTTP and Apache Roy T. Fielding eBuilt, Inc. The Apache Software Foundation
Rensselaer Polytechnic Institute CSC-432 – Operating Systems David Goldschmidt, Ph.D.
DAT602 Database Application Development Lecture 15 Java Server Pages Part 1.
Mod_lua for beginners Eric Covener, IBM November 2011.
M. Taimoor Khan * Java Server Pages (JSP) is a server-side programming technology that enables the creation of dynamic,
1 HTML and CGI Scripting CSC8304 – Computing Environments for Bioinformatics - Lecture 10.
FTP (File Transfer Protocol) & Telnet
TCP/IP Protocol Suite 1 Chapter 22 Upon completion you will be able to: World Wide Web: HTTP Understand the components of a browser and a server Understand.
1 Apache. 2 Module - Apache ♦ Overview This module focuses on configuring and customizing Apache web server. Apache is a commonly used Hypertext Transfer.
Apache and... Virtual Hosts ---- aliases mod_rewrite ---- htaccess AFNOG 11 Kigali, Rwanda May 2010 Dorcas Muthoni Courtesy: Hervey Allen.
Web Server Design Week 8 Old Dominion University Department of Computer Science CS 495/595 Spring 2010 Martin Klein 3/3/10.
1 Apache and... Virtual Hosts ---- aliases mod_rewrite ---- htaccess AFNOG X Cairo, Egypt May 2009 Hervey Allen.
Web Server Design Assignment #2: Conditionals & Persistence Due: 02/24/2010 Old Dominion University Department of Computer Science CS 495/595 Spring 2010.
1 Programming the Apache Lifecycle Geoffrey Young
Apache Web Server Architecture Chaitanya Kulkarni MSCS rd April /23/20081Apache Web Server Architecture.
Overview of Servlets and JSP
Introduction to mod_perl Issac Goldstand Mirimar Networks
What’s Really Happening
Transitioning to mod_perl Handlers
Transitioning to mod_perl Handlers
Apache web server Quick overview.
Apache and... Virtual Hosts ---- aliases mod_rewrite ---- htaccess
HTTP – An overview.
(Brief) Introduction to mod_perl
Web Development Web Servers.
Geoffrey Young mod_perl: do more) Geoffrey Young
Web Server Design Week 10 Old Dominion University
Why mod_perl 2.0 Sucks Why mod_perl 2.0 Rocks
Web Server Design Week 4 Old Dominion University
HTTP Protocol Specification
Hypertext Transport Protocol
Transitioning to mod_perl Handlers
Introduction to Programming the WWW I
Debugging Your Website with Fiddler and Chrome Developer Tools
Processes The most important processes used in Web-based systems and their internal organization.
Web Server Design Assignment #2: Conditionals & Persistence
Web Server Design Week 8 Old Dominion University
Web Server Design Week 7 Old Dominion University
TCP/IP Networking An Example
HTTP Protocol.
Tutorial (4): HTTP Copyright © The McGraw-Hill Companies, Inc. Permission required for reproduction or display.
IS333D: MULTI-TIER APPLICATION DEVELOPMENT
HTTP Hypertext Transfer Protocol
Hypertext Transfer Protocol
HTTP Request Method URL Protocol Version GET /index.html HTTP/1.1
Hypertext Transfer Protocol
Web Server Design Week 5 Old Dominion University
Distributed Systems - Comp 655
Hypertext Transfer Protocol
Web Server Design Assignment #2: Conditionals & Persistence
Web Server Design Week 8 Old Dominion University
EE 122: HyperText Transfer Protocol (HTTP)
Web Server Design Week 8 Old Dominion University
Web Server Design Week 8 Old Dominion University
Lecture 5: Functions and Parameters
Hypertext Transfer Protocol
Kevin Harville Source: Webmaster in a Nutshell, O'Rielly Books
The HTTP Protocol COSC 2206 Internet Tools The HTTP Protocol
Requests and Server Response Codes
Web Server Design Week 5 Old Dominion University
HTTP Hypertext Transfer Protocol
Web Server Design Week 16 Old Dominion University
Hypertext Transfer Protocol
Web Server Design Week 6 Old Dominion University
CSCI-351 Data communication and Networks
Old Dominion University Department of Computer Science
Web Server Design Week 7 Old Dominion University
MSc Internet Computing
Web Server Design Week 7 Old Dominion University
Presentation transcript:

Programming the Apache Lifecycle Geoffrey Young geoff@modperlcookbook.org http://www.modperlcookbook.org/

Overview http://www.modperlcookbook.org/

Overview Apache and mod_perl 101 http://www.modperlcookbook.org/

Overview Apache and mod_perl 101 mod_perl Handler Basics http://www.modperlcookbook.org/

Overview Apache and mod_perl 101 mod_perl Handler Basics Using the Apache Framework http://www.modperlcookbook.org/

Overview Apache and mod_perl 101 mod_perl Handler Basics Using the Apache Framework Advanced mod_perl API Features http://www.modperlcookbook.org/

http://www.modperlcookbook.org/

Apache's Pre-fork Model http://www.modperlcookbook.org/

Apache's Pre-fork Model Apache parent process http://www.modperlcookbook.org/

Apache's Pre-fork Model Apache parent process httpd (parent) http://www.modperlcookbook.org/

Apache's Pre-fork Model Apache parent process forks multiple child processes httpd (parent) httpd (child) httpd (child) httpd (child) httpd (child) http://www.modperlcookbook.org/

Roles and Responsibilities http://www.modperlcookbook.org/

Roles and Responsibilities httpd parent processes no actual requests http://www.modperlcookbook.org/

Roles and Responsibilities httpd parent processes no actual requests all requests are served by the child processes http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

Children are Individuals httpd (parent) httpd (child) httpd (child) httpd (child) httpd (child) http://www.modperlcookbook.org/

Children are Individuals httpd (parent) httpd (child) httpd (child) httpd (child) httpd (child) http://www.modperlcookbook.org/

Children are Individuals httpd (parent) httpd (child) httpd (child) httpd (child) httpd (child) http://www.modperlcookbook.org/

Nice, Responsible Children http://www.modperlcookbook.org/

Nice, Responsible Children each httpd child processes one incoming request at a time http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

Request Phases http://www.modperlcookbook.org/

Request Phases Apache breaks down request processing into separate, logical parts called phases http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

Request Phases Apache breaks down request processing into separate, logical parts called phases each request is stepped through the phases until... http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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" http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

Apache Request Cycle client request http://www.modperlcookbook.org/

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: www.example.com User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 5.12 [en] http://www.modperlcookbook.org/

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: www.example.com User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 5.12 [en] http://www.modperlcookbook.org/

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: www.example.com User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 5.12 [en] http://www.modperlcookbook.org/

Apache Request Cycle client request URI-based init http://www.modperlcookbook.org/

Apache Request Cycle client request URI-based init URI translation http://www.modperlcookbook.org/

Apache Request Cycle client request URI-based init URI translation file-based init http://www.modperlcookbook.org/

Apache Request Cycle client request URI-based init URI translation file-based init resource control http://www.modperlcookbook.org/

Apache Request Cycle client request URI-based init URI translation file-based init MIME setting resource control http://www.modperlcookbook.org/

Apache Request Cycle client request URI-based init URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

Apache Request Cycle client request URI-based init content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

Apache Request Cycle client request URI-based init content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

Apache Request Cycle client request logging URI-based init content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

Apache Request Cycle client request logging URI-based init content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

So What? most Apache users don't worry about the request cycle too much... http://www.modperlcookbook.org/

So What? most Apache users don't worry about the request cycle too much... ...but they do use modules that plug into it http://www.modperlcookbook.org/

... for instance mod_rewrite: client request URI-based init mod_rewrite: RewriteRule /favicon.ico$ /images/favicon.ico URI translation http://www.modperlcookbook.org/

... for instance mod_auth: AuthUserFile .htpasswd client request URI-based init URI translation file-based init mod_auth: AuthUserFile .htpasswd resource control http://www.modperlcookbook.org/

... for instance mod_cgi: SetHandler cgi-script client request URI-based init content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

That's great breaking down the request into distinct phases has many benefits http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

That's great, but... breaking down the request into distinct phases has many benefits gives each processing point a role that can be easily managed and programmed makes Apache more like an application framework rather than a content engine but you have to code in C http://www.modperlcookbook.org/

Enter mod_perl http://www.modperlcookbook.org/

Enter mod_perl mod_perl offers an interface to each phase of the request cycle http://www.modperlcookbook.org/

Enter mod_perl mod_perl offers an interface to each phase of the request cycle opens up the Apache API to Perl code http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

Apache Request Cycle client request logging URI-based init content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

What is mod_perl? http://www.modperlcookbook.org/

What is mod_perl? mod_perl is the Perl interface to the Apache API http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

What's the Big Deal? http://www.modperlcookbook.org/

What's the Big Deal? mod_perl allows you to interact with and directly alter server behavior http://www.modperlcookbook.org/

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" http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

Registry is just a handler http://www.modperlcookbook.org/

Registry is just a handler Apache::Registry is merely an (incredibly clever and amazing) mod_perl handler http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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... http://www.modperlcookbook.org/

Apache::Registry http://www.modperlcookbook.org/

Apache::Registry Client side http://localhost/perl-bin/bar.pl http://www.modperlcookbook.org/

Apache::Registry Client side Server side http://localhost/perl-bin/bar.pl Server side http://www.modperlcookbook.org/

Apache::Registry Client side Server side http://localhost/perl-bin/bar.pl Server side mod_perl intercepts content generation http://www.modperlcookbook.org/

Apache::Registry Client side Server side http://localhost/perl-bin/bar.pl Server side mod_perl intercepts content generation searches @INC for Apache/Registry.pm http://www.modperlcookbook.org/

Apache::Registry Client side Server side http://localhost/perl-bin/bar.pl Server side mod_perl intercepts content generation searches @INC for Apache/Registry.pm calls Apache::Registry::handler(Apache->request) http://www.modperlcookbook.org/

Apache::Registry Client side Server side http://localhost/perl-bin/bar.pl Server side mod_perl intercepts content generation searches @INC for Apache/Registry.pm calls Apache::Registry::handler(Apache->request) inserts wizardry http://www.modperlcookbook.org/

Apache::Registry Client side Server side http://localhost/perl-bin/bar.pl Server side mod_perl intercepts content generation searches @INC for Apache/Registry.pm calls Apache::Registry::handler(Apache->request) inserts wizardry returns response to client http://www.modperlcookbook.org/

Wizardry, you say? http://www.modperlcookbook.org/

Wizardry, you say? the wizardry is basically just putting the CGI script into it's own package http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

http://www.modperlcookbook.org/

"The dream is always the same" http://www.modperlcookbook.org/

"The dream is always the same" http://www.modperlcookbook.org/

"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) http://www.modperlcookbook.org/

"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 http://www.modperlcookbook.org/

"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 http://www.modperlcookbook.org/

"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 http://www.modperlcookbook.org/

"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 http://www.modperlcookbook.org/

"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 http://www.modperlcookbook.org/

Apache Request Cycle client request logging URI-based init content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

Key Questions http://www.modperlcookbook.org/

Key Questions What is the Apache default behavior for the phase? http://www.modperlcookbook.org/

Key Questions What is the Apache default behavior for the phase? What is a typical mod_perl usage of the phase? http://www.modperlcookbook.org/

Key Questions What is the Apache default behavior for the phase? What is a typical mod_perl usage of the phase? What happens on success? http://www.modperlcookbook.org/

Key Questions What is the Apache default behavior for the phase? What is a typical mod_perl usage of the phase? What happens on success? What happens on error? http://www.modperlcookbook.org/

The Client Request client request http://www.modperlcookbook.org/

The Client Request 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: www.example.com User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 5.12 [en] http://www.modperlcookbook.org/

The Client Request 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: www.example.com User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 5.12 [en] http://www.modperlcookbook.org/

URI-based Initialization client request URI-based init http://www.modperlcookbook.org/

URI-based Initialization Request URI and headers are known http://www.modperlcookbook.org/

URI-based Initialization Request URI and headers are known Apache request record has been populated http://www.modperlcookbook.org/

URI-based Initialization Request URI and headers are known Apache request record has been populated The first place you can insert processing http://www.modperlcookbook.org/

URI-based Initialization Request URI and headers are known Apache request record has been populated The first place you can insert processing Apache has no default behavior http://www.modperlcookbook.org/

URI-based Initialization Request URI and headers are known Apache request record has been populated The first place you can insert processing Apache has no default behavior All configured handlers are run http://www.modperlcookbook.org/

URI-based Initialization client request URI-based init http://www.modperlcookbook.org/

URI-based Initialization client request PerlPostReadRequestHandler http://www.modperlcookbook.org/

URI-based Initialization client request PerlInitHandler http://www.modperlcookbook.org/

PerlPostReadRequestHandler http://www.modperlcookbook.org/

PerlPostReadRequestHandler Non-specific hook http://www.modperlcookbook.org/

PerlPostReadRequestHandler Non-specific hook Useful for adding processing that needs to occur on every request http://www.modperlcookbook.org/

PerlPostReadRequestHandler Non-specific hook Useful for adding processing that needs to occur on every request every request means every request http://www.modperlcookbook.org/

A sample... Object: to protect our name-based virtual hosts from HTTP/1.0 requests Apache can't handle http://www.modperlcookbook.org/

A sample... Object: to protect our name-based virtual hosts from HTTP/1.0 requests Apache can't handle http://www.modperlcookbook.org/

HTTP/1.0 and Host http://www.modperlcookbook.org/

HTTP/1.0 and Host HTTP/1.0 does not require a Host header http://www.modperlcookbook.org/

HTTP/1.0 and Host HTTP/1.0 does not require a Host header assumes a “one host per IP" configuration http://www.modperlcookbook.org/

HTTP/1.0 and Host HTTP/1.0 does not require a Host header assumes a “one host per IP" configuration this limitation "breaks" name-based virtual host servers for browsers that follow HTTP/1.0 to the letter http://www.modperlcookbook.org/

HTTP/1.0 and Host HTTP/1.0 does not require a Host header assumes a “one host per IP" configuration this limitation "breaks" name-based virtual host servers for browsers that follow HTTP/1.0 to the letter most send the Host header, so all is well http://www.modperlcookbook.org/

Connected to www.apache.org. Escape character is '^]'. $ telnet www.apache.org 80 Trying 63.251.56.142... Connected to www.apache.org. Escape character is '^]'. GET /foo.html HTTP/1.0 http://www.modperlcookbook.org/

Connected to www.apache.org. Escape character is '^]'. $ telnet www.apache.org 80 Trying 63.251.56.142... Connected to www.apache.org. Escape character is '^]'. GET /foo.html HTTP/1.0 http://www.modperlcookbook.org/

Connected to www.apache.org. Escape character is '^]'. $ telnet www.apache.org 80 Trying 63.251.56.142... Connected to www.apache.org. Escape character is '^]'. GET /foo.html HTTP/1.0 http://www.modperlcookbook.org/

Connected to www.apache.org. Escape character is '^]'. $ telnet www.apache.org 80 Trying 63.251.56.142... Connected to www.apache.org. Escape character is '^]'. GET /foo.html HTTP/1.0 HTTP/1.1 302 Found Date: Tue, 04 Jun 2002 00:52:55 GMT Server: Apache/2.0.37-dev (Unix) Location: http://httpd.apache.org/dev/ Content-Length: 289 Connection: close Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>302 Found</title> </head><body> <h1>Found</h1> <p>The document has moved <a href="http://httpd.apache.org/dev/">here</a>.</p> <hr /> <address>Apache/2.0.37-dev Server at dev.apache.org Port 80</address> </body></html> Connection closed by foreign host. http://www.modperlcookbook.org/

Connected to www.apache.org. Escape character is '^]'. $ telnet www.apache.org 80 Trying 63.251.56.142... Connected to www.apache.org. Escape character is '^]'. GET /foo.html HTTP/1.0 HTTP/1.1 302 Found Date: Tue, 04 Jun 2002 00:52:55 GMT Server: Apache/2.0.37-dev (Unix) Location: http://httpd.apache.org/dev/ Content-Length: 289 Connection: close Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>302 Found</title> </head><body> <h1>Found</h1> <p>The document has moved <a href="http://httpd.apache.org/dev/">here</a>.</p> <hr /> <address>Apache/2.0.37-dev Server at dev.apache.org Port 80</address> </body></html> Connection closed by foreign host. http://www.modperlcookbook.org/

Connected to www.apache.org. Escape character is '^]'. $ telnet www.apache.org 80 Trying 63.251.56.142... Connected to www.apache.org. Escape character is '^]'. GET /foo.html HTTP/1.0 Host: www.apache.org http://www.modperlcookbook.org/

Connected to www.apache.org. Escape character is '^]'. $ telnet www.apache.org 80 Trying 63.251.56.142... Connected to www.apache.org. Escape character is '^]'. GET /foo.html HTTP/1.0 Host: www.apache.org http://www.modperlcookbook.org/

Connected to www.apache.org. Escape character is '^]'. $ telnet www.apache.org 80 Trying 63.251.56.142... Connected to www.apache.org. Escape character is '^]'. GET /foo.html HTTP/1.0 Host: www.apache.org http://www.modperlcookbook.org/

Connected to www.apache.org. Escape character is '^]'. $ telnet www.apache.org 80 Trying 63.251.56.142... Connected to www.apache.org. Escape character is '^]'. GET /foo.html HTTP/1.0 Host: www.apache.org http://www.modperlcookbook.org/

Connected to www.apache.org. Escape character is '^]'. $ telnet www.apache.org 80 Trying 63.251.56.142... Connected to www.apache.org. Escape character is '^]'. GET /foo.html HTTP/1.0 Host: www.apache.org HTTP/1.1 404 Not Found Date: Tue, 04 Jun 2002 00:56:40 GMT Server: Apache/2.0.37-dev (Unix) Content-Length: 283 Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>404 Not Found</title> </head><body> <h1>Not Found</h1> <p>The requested URL /foo.html was not found on this server.</p> <hr /> <address>Apache/2.0.37-dev Server at www.apache.org Port 80</address> </body></html> http://www.modperlcookbook.org/

Connected to www.apache.org. Escape character is '^]'. $ telnet www.apache.org 80 Trying 63.251.56.142... Connected to www.apache.org. Escape character is '^]'. GET /foo.html HTTP/1.0 Host: www.apache.org HTTP/1.1 404 Not Found Date: Tue, 04 Jun 2002 00:56:40 GMT Server: Apache/2.0.37-dev (Unix) Content-Length: 283 Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>404 Not Found</title> </head><body> <h1>Not Found</h1> <p>The requested URL /foo.html was not found on this server.</p> <hr /> <address>Apache/2.0.37-dev Server at www.apache.org Port 80</address> </body></html> http://www.modperlcookbook.org/

A sample... Object: to protect our name-based virtual hosts from HTTP/1.0 requests Apache can't handle http://www.modperlcookbook.org/

A sample... Object: to protect our name-based virtual hosts from HTTP/1.0 requests Apache can't handle Method: intercept every request prior to content-generation and return an error unless... http://www.modperlcookbook.org/

A sample... Object: to protect our name-based virtual hosts from HTTP/1.0 requests Apache can't handle Method: intercept every request prior to content-generation and return an error unless... there is a Host header http://www.modperlcookbook.org/

A sample... Object: to protect our name-based virtual hosts from HTTP/1.0 requests Apache can't handle Method: intercept every request prior to content-generation and return an error unless... there is a Host header the request is an absolute URI http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

Setup add TrapNoHost.pm to @INC http://www.modperlcookbook.org/

Setup add TrapNoHost.pm to @INC ServerRoot/lib/perl/Cookbook/TrapNoHost.pm http://www.modperlcookbook.org/

Setup add TrapNoHost.pm to @INC add to httpd.conf ServerRoot/lib/perl/Cookbook/TrapNoHost.pm add to httpd.conf http://www.modperlcookbook.org/

Setup add TrapNoHost.pm to @INC add to httpd.conf ServerRoot/lib/perl/Cookbook/TrapNoHost.pm add to httpd.conf PerlModule Cookbook::TrapNoHost http://www.modperlcookbook.org/

Setup add TrapNoHost.pm to @INC add to httpd.conf ServerRoot/lib/perl/Cookbook/TrapNoHost.pm add to httpd.conf PerlModule Cookbook::TrapNoHost PerlInitHandler Cookbook::TrapNoHost http://www.modperlcookbook.org/

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 PerlInitHandler Cookbook::TrapNoHost that's it! http://www.modperlcookbook.org/

Apache Request Cycle client request logging URI-based init content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

PerlPostReadRequestHandler Intercept the Request client request PerlPostReadRequestHandler http://www.modperlcookbook.org/

PerlPostReadRequestHandler Intercept the Request client request PerlPostReadRequestHandler HTTP/1.1 400 Bad Request Date: Tue, 04 Jun 2002 01:17:52 GMT Server: Apache/1.3.25-dev (Unix) mod_perl/1.27_01-dev Perl/v5.8.0 Connection: close Content-Type: text/html; charset=iso-8859-1 Oops! Did you mean to omit a Host header? http://www.modperlcookbook.org/

PerlPostReadRequestHandler Intercept the Request client request PerlPostReadRequestHandler HTTP/1.1 400 Bad Request Date: Tue, 04 Jun 2002 01:17:52 GMT Server: Apache/1.3.25-dev (Unix) mod_perl/1.27_01-dev Perl/v5.8.0 Connection: close Content-Type: text/html; charset=iso-8859-1 Oops! Did you mean to omit a Host header? http://www.modperlcookbook.org/

PerlPostReadRequestHandler Intercept the Request client request logging PerlPostReadRequestHandler http://www.modperlcookbook.org/

http://www.modperlcookbook.org/

Key Concepts http://www.modperlcookbook.org/

Key Concepts The Apache request object, $r http://www.modperlcookbook.org/

Key Concepts The Apache request object, $r The Apache::Table class http://www.modperlcookbook.org/

Key Concepts The Apache request object, $r The Apache::Table class Return values and the Apache::Constants class http://www.modperlcookbook.org/

Key Concepts The Apache request object, $r The Apache::Table class Return values and the Apache::Constants class Stacked handlers http://www.modperlcookbook.org/

Apache Request Object http://www.modperlcookbook.org/

Apache Request Object passed to handlers or available via Apache->request() http://www.modperlcookbook.org/

Apache Request Object passed to handlers or available via Apache->request() $r = shift; # from @_ passed to handler() http://www.modperlcookbook.org/

Apache Request Object passed to handlers or available via Apache->request() $r = shift; # from @_ passed to handler() $r = Apache->request(); http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

Apache Request Object passed to handlers or available via Apache->request() $r = shift; # from @_ passed to handler() $r = Apache->request(); http://www.modperlcookbook.org/

Apache Request Object passed to handlers or available via Apache->request() $r = shift; # from @_ passed to handler() $r = Apache->request(); provides access to the Apache class, which provides access to request attributes http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

Apache Request Object passed to handlers or available via Apache->request() $r = shift; # from @_ passed to handler() $r = Apache->request(); provides access to the Apache class, which provides access to request attributes http://www.modperlcookbook.org/

Apache Request Object passed to handlers or available via Apache->request() $r = shift; # from @_ 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 http://www.modperlcookbook.org/

Apache::Table http://www.modperlcookbook.org/

Apache::Table the Apache::Table class provides the underlying API for the following request attributes... http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

Apache::Table to manipulate Apache::Table objects, you use the provided methods http://www.modperlcookbook.org/

Apache::Table to manipulate Apache::Table objects, you use the provided methods get() set() add() unset() do() merge() new() clear() http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

Apache Table Properties http://www.modperlcookbook.org/

Apache Table Properties Apache tables have some nice properties http://www.modperlcookbook.org/

Apache Table Properties Apache tables have some nice properties case insensitive http://www.modperlcookbook.org/

Apache Table Properties Apache tables have some nice properties case insensitive allow for multi-valued keys http://www.modperlcookbook.org/

Apache Table Properties Apache tables have some nice properties case insensitive allow for multi-valued keys they also have one important limitation http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

keeps the Net flowin'... http://www.modperlcookbook.org/

keeps the Net flowin'... both case-insensitivity and multiple values are key to manipulating headers http://www.modperlcookbook.org/

keeps the Net flowin'... both case-insensitivity and multiple values are key to manipulating headers $r->headers_out->set('Set-Cookie' => 'name=foo'); http://www.modperlcookbook.org/

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'); http://www.modperlcookbook.org/

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'); my @cookies = $r->headers_out->get('Set-cookie'); http://www.modperlcookbook.org/

Table Iteration http://www.modperlcookbook.org/

Table Iteration Apache::Table objects use a special idiom when you need to operate on every item in a table http://www.modperlcookbook.org/

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; }); http://www.modperlcookbook.org/

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; }); http://www.modperlcookbook.org/

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; }); http://www.modperlcookbook.org/

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; }); http://www.modperlcookbook.org/

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; }); http://www.modperlcookbook.org/

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; }); http://www.modperlcookbook.org/

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; }); http://www.modperlcookbook.org/

More Apache::Table Fun http://www.modperlcookbook.org/

More Apache::Table Fun Tired http://www.modperlcookbook.org/

More Apache::Table Fun Tired PerlSetVar Sails "jib" http://www.modperlcookbook.org/

More Apache::Table Fun Tired PerlSetVar Sails "jib" my $sail = $r->dir_config('Sails'); http://www.modperlcookbook.org/

More Apache::Table Fun Tired PerlSetVar Sails "jib" my $sail = $r->dir_config('Sails'); Wired PerlSetVar Sails "spinnaker" http://www.modperlcookbook.org/

More Apache::Table Fun Tired PerlSetVar Sails "jib" my $sail = $r->dir_config('Sails'); Wired PerlSetVar Sails "spinnaker" PerlAddVar Sails "blooper" http://www.modperlcookbook.org/

More Apache::Table Fun Tired PerlSetVar Sails "jib" my $sail = $r->dir_config('Sails'); Wired PerlSetVar Sails "spinnaker" PerlAddVar Sails "blooper" my @sails = $r->dir_config->get('Sails'); http://www.modperlcookbook.org/

Trickery http://www.modperlcookbook.org/

Trickery really understanding the Apache::Table class will make you a better mod_perl programmer http://www.modperlcookbook.org/

Trickery really understanding the Apache::Table class will make you a better mod_perl programmer every table can be set http://www.modperlcookbook.org/

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() http://www.modperlcookbook.org/

Trickery handle "what if?" cases http://www.modperlcookbook.org/

Trickery handle "what if?" cases $r->headers_in->set('Set-Cookie' => 'name=foo'); my $sub = $r->lookup_uri('/scripts/foo.html'); http://www.modperlcookbook.org/

Trickery handle "what if?" cases $r->headers_in->set('Set-Cookie' => 'name=foo'); my $sub = $r->lookup_uri('/scripts/foo.html'); http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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'); http://www.modperlcookbook.org/

Apache::Constants http://www.modperlcookbook.org/

Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST); http://www.modperlcookbook.org/

Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST); the most common are: http://www.modperlcookbook.org/

Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST); the most common are: OK http://www.modperlcookbook.org/

Apache::Constants Apache::Constants class provides over 90 runtime constants use Apache::Constants qw(DECLINED BAD_REQUEST); the most common are: OK SERVER_ERROR http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

Return Values handlers are expected to return a value http://www.modperlcookbook.org/

Return Values handlers are expected to return a value the return value of the handler defines the status of the request http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

package Cookbook::TrapNoHost; use Apache::Constants qw(DECLINED BAD_REQUEST); use Apache::URI; use strict; sub handler { my $r = shift; # Valid requests for name based virtual hosting are: # requests with a Host header, or # requests that are absolute URIs. unless ($r->headers_in->get('Host') || $r->parsed_uri->hostname) { $r->custom_response(BAD_REQUEST, "Oops! Did you mean to omit a Host header?\n"); return BAD_REQUEST; } return DECLINED; 1; http://www.modperlcookbook.org/

When handlers turn bad... http://www.modperlcookbook.org/

When handlers turn bad... "error" return codes are not always errors http://www.modperlcookbook.org/

When handlers turn bad... "error" return codes are not always errors instead, they indicate a new route for the request http://www.modperlcookbook.org/

When handlers turn bad... "error" return codes are not always errors instead, they indicate a new route for the request errors codes take effect immediately http://www.modperlcookbook.org/

When handlers turn bad... "error" return codes are not always errors instead, they indicate a new route for the request errors codes take effect immediately other scheduled handlers are not run http://www.modperlcookbook.org/

package My::Redirect; use Apache::Constants qw(REDIRECT); sub handler { my $r = shift; $r->headers_out->set(Location => '/foo'); return REDIRECT; }; 1; http://www.modperlcookbook.org/

package My::Redirect; use Apache::Constants qw(REDIRECT); sub handler { my $r = shift; $r->headers_out->set(Location => '/foo'); return REDIRECT; }; 1; http://www.modperlcookbook.org/

package My::Redirect; use Apache::Constants qw(REDIRECT); sub handler { my $r = shift; $r->headers_out->set(Location => '/foo'); return REDIRECT; }; 1; http://www.modperlcookbook.org/

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/1.3.25-dev Server at mainsheet.laserlink.com Port 80</ADDRESS> </BODY></HTML> http://www.modperlcookbook.org/

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/1.3.25-dev Server at mainsheet.laserlink.com Port 80</ADDRESS> </BODY></HTML> http://www.modperlcookbook.org/

Stacked Handlers http://www.modperlcookbook.org/

Stacked Handlers Apache allows for more than one module to handle each phase http://www.modperlcookbook.org/

Stacked Handlers Apache allows for more than one module to handle each phase except content-generation http://www.modperlcookbook.org/

Stacked Handlers Apache allows for more than one module to handle each phase except content-generation (in 1.3) http://www.modperlcookbook.org/

Stacked Handlers Apache allows for more than one module to handle each phase except content-generation (in 1.3) For example, both mod_rewrite and mod_alias schedule fixup processing http://www.modperlcookbook.org/

Stacked Handlers Apache allows for more than one module to handle each phase except content-generation (in 1.3) For example, both mod_rewrite and mod_alias schedule fixup processing mod_perl is just another Apache module http://www.modperlcookbook.org/

Stacked Handlers Apache allows for more than one module to handle each phase except content-generation (in 1.3) For example, both mod_rewrite and mod_alias schedule fixup processing mod_perl is just another Apache module happens to schedule processing for every phase http://www.modperlcookbook.org/

Perl Stacked Handlers http://www.modperlcookbook.org/

Perl Stacked Handlers for each phase of the request, mod_perl will run any registered Perl handlers for that phase http://www.modperlcookbook.org/

Perl 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 http://www.modperlcookbook.org/

Perl 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 http://www.modperlcookbook.org/

Perl Stacked Handlers some phases run until the handler list is exhausted http://www.modperlcookbook.org/

Perl Stacked Handlers some phases run until the handler list is exhausted PerlInitHandler Cookbook::TrapNoHost PerlInitHandler Apache::Reload http://www.modperlcookbook.org/

Perl Stacked Handlers some phases run until the handler list is exhausted PerlInitHandler Cookbook::TrapNoHost PerlInitHandler Apache::Reload some phases run until one handler returns OK http://www.modperlcookbook.org/

Perl Stacked Handlers some phases run until the handler list is exhausted PerlInitHandler Cookbook::TrapNoHost PerlInitHandler Apache::Reload some phases run until one handler returns OK PerlTransHandler My::TranslateHTML PerlTransHandler My::TranslateText http://www.modperlcookbook.org/

Perl Stacked Handlers some phases run until the handler list is exhausted PerlInitHandler Cookbook::TrapNoHost PerlInitHandler Apache::Reload some phases run until one handler returns OK PerlTransHandler My::TranslateHTML PerlTransHandler My::TranslateText all phases terminate on "error" http://www.modperlcookbook.org/

Key Concepts The Apache request object, $r The Apache::Table class Return values and the Apache::Constants class Stacked handlers http://www.modperlcookbook.org/

http://www.modperlcookbook.org/

URI Translation client request URI-based init URI translation http://www.modperlcookbook.org/

URI Translation Apache needs to map the URI to a physical file on disk http://www.modperlcookbook.org/

URI Translation Apache needs to map the URI to a physical file on disk Default is to prepend DocumentRoot to the URI DocumentRoot /usr/local/apache/htdocs http://www.modperlcookbook.org/

URI Translation Directives like Alias override the default http://www.modperlcookbook.org/

URI Translation Directives like Alias override the default DocumentRoot /usr/local/apache/htdocs Alias /manual/ /usr/local/apache/manual/" <Directory /usr/local/apache/manual> ... http://www.modperlcookbook.org/

URI Translation Directives like Alias override the default DocumentRoot /usr/local/apache/htdocs Alias /manual/ /usr/local/apache/manual/ <Directory /usr/local/apache/manual> ... Some URIs have no associated file, but Apache tries anyway http://www.modperlcookbook.org/

URI Translation Directives like Alias override the default DocumentRoot /usr/local/apache/htdocs Alias /manual/ /usr/local/apache/manual/ <Directory /usr/local/apache/manual> ... Some URIs have no associated file, but Apache tries anyway <Location server-status> http://www.modperlcookbook.org/

URI Translation client request URI-based init URI translation http://www.modperlcookbook.org/

URI Translation client request URI-based init PerlTransHandler http://www.modperlcookbook.org/

PerlTransHandler http://www.modperlcookbook.org/

PerlTransHandler Useful for overriding the Apache default http://www.modperlcookbook.org/

PerlTransHandler Useful for overriding the Apache default Allows you to be extremely devious http://www.modperlcookbook.org/

PerlTransHandler Useful for overriding the Apache default Allows you to be extremely devious There are a few pitfalls of which to be aware http://www.modperlcookbook.org/

Simple PerlTransHandler http://www.modperlcookbook.org/

Simple PerlTransHandler Object: be rid of those silly favicon.ico requests that end up 404 http://www.modperlcookbook.org/

Simple PerlTransHandler Object: be rid of those silly favicon.ico requests that end up 404 Method: translate the incoming URI to a common place if it matches favicon.ico http://www.modperlcookbook.org/

package Cookbook::Favicon; use Apache::Constants qw(DECLINED); use strict; sub handler { my $r = shift; $r->uri("/images/favicon.ico") if $r->uri =~ m!/favicon\.ico$!; return DECLINED; } 1; http://www.modperlcookbook.org/

package Cookbook::Favicon; use Apache::Constants qw(DECLINED); use strict; sub handler { my $r = shift; $r->uri("/images/favicon.ico") if $r->uri =~ m!/favicon\.ico$!; return DECLINED; } 1; http://www.modperlcookbook.org/

package Cookbook::Favicon; use Apache::Constants qw(DECLINED); use strict; sub handler { my $r = shift; $r->uri("/images/favicon.ico") if $r->uri =~ m!/favicon\.ico$!; return DECLINED; } 1; http://www.modperlcookbook.org/

Setup http://www.modperlcookbook.org/

Setup add Favicon.pm to @INC http://www.modperlcookbook.org/

Setup add Favicon.pm to @INC ServerRoot/lib/perl/Cookbook/Favicon.pm http://www.modperlcookbook.org/

Setup add Favicon.pm to @INC add to httpd.conf ServerRoot/lib/perl/Cookbook/Favicon.pm add to httpd.conf http://www.modperlcookbook.org/

Setup add Favicon.pm to @INC add to httpd.conf ServerRoot/lib/perl/Cookbook/Favicon.pm add to httpd.conf PerlModule Cookbook::Favicon http://www.modperlcookbook.org/

Setup add Favicon.pm to @INC add to httpd.conf ServerRoot/lib/perl/Cookbook/Favicon.pm add to httpd.conf PerlModule Cookbook::Favicon PerlTransHandler Cookbook::Favicon http://www.modperlcookbook.org/

Setup add Favicon.pm to @INC add to httpd.conf that's it! ServerRoot/lib/perl/Cookbook/Favicon.pm add to httpd.conf PerlModule Cookbook::Favicon PerlTransHandler Cookbook::Favicon that's it! http://www.modperlcookbook.org/

Why Not Use mod_rewrite? http://www.modperlcookbook.org/

Why Not Use mod_rewrite? our Cookbook::Favicon is pretty much the same as RewriteRule /favicon.ico$ /images/favicon.ico http://www.modperlcookbook.org/

Why Not Use mod_rewrite? our Cookbook::Favicon is pretty much the same as RewriteRule /favicon.ico$ /images/favicon.ico Let's look at a more clever example... http://www.modperlcookbook.org/

Mischievous Behavior http://www.modperlcookbook.org/

Mischievous Behavior Simple URI re-mapping is only the beginning http://www.modperlcookbook.org/

Mischievous Behavior Simple URI re-mapping is only the beginning Apache has this neat, built-in functionality called proxying http://www.modperlcookbook.org/

Mischievous Behavior Simple URI re-mapping is only the beginning Apache has this neat, built-in functionality called proxying provided you have mod_proxy installed http://www.modperlcookbook.org/

Mischievous Behavior Simple URI re-mapping is only the beginning Apache has this neat, built-in functionality called proxying provided you have mod_proxy installed With mod_perl and mod_proxy you can proxy just about anything... http://www.modperlcookbook.org/

Advanced PerlTransHandler Object: create a proxy that uses our local Apache documentation instead of ASF servers http://www.modperlcookbook.org/

Advanced PerlTransHandler Object: create a proxy that uses our local Apache documentation instead of ASF servers Method: intercept proxy requests and silently replace calls to http://httpd.apache.org/docs with /usr/local/apache/htdocs/manual http://www.modperlcookbook.org/

Client Setup http://www.modperlcookbook.org/

package My::ManualProxy; use Apache::Constants qw(OK DECLINED); use strict; sub handler { my $r = shift; return DECLINED unless $r->proxyreq; my (undef, $file) = $r->uri =~ m!^http://(www|httpd).apache.org/(.*)!; if ($file =~ m!^docs/!) { $file =~ s!^docs/!manual/!; $file = join "/", ($r->document_root, $file); if (-f $file) { $r->filename($file); # use local disk $r->proxyreq(0); # fool mod_mime return OK; } return DECLINED; 1; http://www.modperlcookbook.org/

package My::ManualProxy; use Apache::Constants qw(OK DECLINED); use strict; sub handler { my $r = shift; return DECLINED unless $r->proxyreq; my (undef, $file) = $r->uri =~ m!^http://(www|httpd).apache.org/(.*)!; if ($file =~ m!^docs/!) { $file =~ s!^docs/!manual/!; $file = join "/", ($r->document_root, $file); if (-f $file) { $r->filename($file); # use local disk $r->proxyreq(0); # fool mod_mime return OK; } return DECLINED; 1; http://www.modperlcookbook.org/

package My::ManualProxy; use Apache::Constants qw(OK DECLINED); use strict; sub handler { my $r = shift; return DECLINED unless $r->proxyreq; my (undef, $file) = $r->uri =~ m!^http://(www|httpd).apache.org/(.*)!; if ($file =~ m!^docs/!) { $file =~ s!^docs/!manual/!; $file = join "/", ($r->document_root, $file); if (-f $file) { $r->filename($file); # use local disk $r->proxyreq(0); # fool mod_mime return OK; } return DECLINED; 1; http://www.modperlcookbook.org/

package My::ManualProxy; use Apache::Constants qw(OK DECLINED); use strict; sub handler { my $r = shift; return DECLINED unless $r->proxyreq; my (undef, $file) = $r->uri =~ m!^http://(www|httpd).apache.org/(.*)!; if ($file =~ m!^docs/!) { $file =~ s!^docs/!manual/!; $file = join "/", ($r->document_root, $file); if (-f $file) { $r->filename($file); # use local disk $r->proxyreq(0); # fool mod_mime return OK; } return DECLINED; 1; http://www.modperlcookbook.org/

package My::ManualProxy; use Apache::Constants qw(OK DECLINED); use strict; sub handler { my $r = shift; return DECLINED unless $r->proxyreq; my (undef, $file) = $r->uri =~ m!^http://(www|httpd).apache.org/(.*)!; if ($file =~ m!^docs/!) { $file =~ s!^docs/!manual/!; $file = join "/", ($r->document_root, $file); if (-f $file) { $r->filename($file); # use local disk $r->proxyreq(0); # fool mod_mime return OK; } return DECLINED; 1; http://www.modperlcookbook.org/

package My::ManualProxy; use Apache::Constants qw(OK DECLINED); use strict; sub handler { my $r = shift; return DECLINED unless $r->proxyreq; my (undef, $file) = $r->uri =~ m!^http://(www|httpd).apache.org/(.*)!; if ($file =~ m!^docs/!) { $file =~ s!^docs/!manual/!; $file = join "/", ($r->document_root, $file); if (-f $file) { $r->filename($file); # use local disk $r->proxyreq(0); # fool mod_mime return OK; } return DECLINED; 1; http://www.modperlcookbook.org/

package My::ManualProxy; use Apache::Constants qw(OK DECLINED); use strict; sub handler { my $r = shift; return DECLINED unless $r->proxyreq; my (undef, $file) = $r->uri =~ m!^http://(www|httpd).apache.org/(.*)!; if ($file =~ m!^docs/!) { $file =~ s!^docs/!manual/!; $file = join "/", ($r->document_root, $file); if (-f $file) { $r->filename($file); # use local disk $r->proxyreq(0); # fool mod_mime return OK; } return DECLINED; 1; http://www.modperlcookbook.org/

package My::ManualProxy; use Apache::Constants qw(OK DECLINED); use strict; sub handler { my $r = shift; return DECLINED unless $r->proxyreq; my (undef, $file) = $r->uri =~ m!^http://(www|httpd).apache.org/(.*)!; if ($file =~ m!^docs/!) { $file =~ s!^docs/!manual/!; $file = join "/", ($r->document_root, $file); if (-f $file) { $r->filename($file); # use local disk $r->proxyreq(0); # fool mod_mime return OK; } return DECLINED; 1; http://www.modperlcookbook.org/

package My::ManualProxy; use Apache::Constants qw(OK DECLINED); use strict; sub handler { my $r = shift; return DECLINED unless $r->proxyreq; my (undef, $file) = $r->uri =~ m!^http://(www|httpd).apache.org/(.*)!; if ($file =~ m!^docs/!) { $file =~ s!^docs/!manual/!; $file = join "/", ($r->document_root, $file); if (-f $file) { $r->filename($file); # use local disk $r->proxyreq(0); # fool mod_mime return OK; } return DECLINED; 1; http://www.modperlcookbook.org/

package My::ManualProxy; use Apache::Constants qw(OK DECLINED); use strict; sub handler { my $r = shift; return DECLINED unless $r->proxyreq; my (undef, $file) = $r->uri =~ m!^http://(www|httpd).apache.org/(.*)!; if ($file =~ m!^docs/!) { $file =~ s!^docs/!manual/!; $file = join "/", ($r->document_root, $file); if (-f $file) { $r->filename($file); # use local disk $r->proxyreq(0); # fool mod_mime return OK; } return DECLINED; 1; http://www.modperlcookbook.org/

Proxy in Action GET http://httpd.apache.org/docs/mod/directives.html 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 Connection: Keep-Alive, TE Host: httpd.apache.org User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 5.12 [en] HTTP/1.1 200 OK Last-Modified: Sat, 25 May 2002 22:15:27 GMT ETag: "240c0-3360-3cf00cff" Accept-Ranges: bytes Content-Length: 13152 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/html http://www.modperlcookbook.org/

Proxy in Action GET http://httpd.apache.org/docs/mod/directives.html 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 Connection: Keep-Alive, TE Host: httpd.apache.org User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 5.12 [en] HTTP/1.1 200 OK Last-Modified: Sat, 25 May 2002 22:15:27 GMT ETag: "240c0-3360-3cf00cff" Accept-Ranges: bytes Content-Length: 13152 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/html http://www.modperlcookbook.org/

Winner Takes All http://www.modperlcookbook.org/

Winner Takes All http://www.modperlcookbook.org/

Winner Takes All The first URI translation handler to return OK ends the phase http://www.modperlcookbook.org/

Winner Takes All The first URI translation handler to return OK ends the phase for both mod_perl and Apache! http://www.modperlcookbook.org/

Winner Takes All The first URI translation handler to return OK ends the phase for both mod_perl and Apache! Return OK only when you map the file to disk yourself http://www.modperlcookbook.org/

Winner Takes All The first URI translation handler to return OK ends the phase for both mod_perl and Apache! Return OK only when you map the file to disk yourself Return DECLINED all other times http://www.modperlcookbook.org/

File-based Initialization client request URI-based init URI translation file-based init http://www.modperlcookbook.org/

File-based Initialization URI has been mapped to a file $r->filename is now known http://www.modperlcookbook.org/

File-based Initialization URI has been mapped to a file $r->filename is now known We also know to which <Location> the request belongs http://www.modperlcookbook.org/

File-based Initialization URI has been mapped to a file $r->filename is now known We also know to which <Location> the request belongs Apache has no default behavior http://www.modperlcookbook.org/

File-based Initialization URI has been mapped to a file $r->filename is now known We also know to which <Location> the request belongs Apache has no default behavior All configured handlers are run http://www.modperlcookbook.org/

File-based Initialization client request URI-based init URI translation file-based init http://www.modperlcookbook.org/

File-based Initialization client request URI-based init URI translation PerlHeaderParserHandler http://www.modperlcookbook.org/

File-based Initialization client request URI-based init URI translation PerlInitHandler http://www.modperlcookbook.org/

PerlHeaderParserHandler http://www.modperlcookbook.org/

PerlHeaderParserHandler Non-specific hook http://www.modperlcookbook.org/

PerlHeaderParserHandler Non-specific hook Useful for adding processing that needs to occur on every request to a given URI http://www.modperlcookbook.org/

Sample Usage... http://www.modperlcookbook.org/

Sample Usage... Parsing out the query string or POST data on each request is a pain http://www.modperlcookbook.org/

Sample Usage... Parsing out the query string or POST data on each request is a pain For the most part, you know you need it to every request to a given <Location> http://www.modperlcookbook.org/

Sample Usage... Parsing out the query string or POST data on each request is a pain For the most part, you know you need it to every request to a given <Location> Modularize the parsing code http://www.modperlcookbook.org/

Apache::RequestNotes http://www.modperlcookbook.org/

Apache::RequestNotes Apache::RequestNotes parses cookies and input parameters http://www.modperlcookbook.org/

Apache::RequestNotes Apache::RequestNotes parses cookies and input parameters stores the data in pnotes() for later retrieval http://www.modperlcookbook.org/

Interface http://www.modperlcookbook.org/

Interface in httpd.conf http://www.modperlcookbook.org/

Interface in httpd.conf Alias /perl-bin /usr/local/apache/perl-bin <Location /perl-bin/> SetHandler perl-script PerlHandler Apache::Registry Options +ExecCGI PerlInitHandler Apache::RequestNotes </Location> http://www.modperlcookbook.org/

Interface in httpd.conf Alias /perl-bin /usr/local/apache/perl-bin <Location /perl-bin/> SetHandler perl-script PerlHandler Apache::Registry Options +ExecCGI PerlInitHandler Apache::RequestNotes </Location> http://www.modperlcookbook.org/

Interface in httpd.conf in handler Alias /perl-bin /usr/local/apache/perl-bin <Location /perl-bin/> SetHandler perl-script PerlHandler Apache::Registry Options +ExecCGI PerlInitHandler Apache::RequestNotes </Location> in handler http://www.modperlcookbook.org/

Interface in httpd.conf in handler Alias /perl-bin /usr/local/apache/perl-bin <Location /perl-bin/> SetHandler perl-script PerlHandler Apache::Registry Options +ExecCGI PerlInitHandler Apache::RequestNotes </Location> in handler my $input = $r->pnotes('INPUT'); # Apache::Table reference my $uploads = $r->pnotes('UPLOADS'); # Apache::Upload array ref my $cookies = $r->pnotes('COOKIES'); # hash reference http://www.modperlcookbook.org/

Resource Control client request URI-based init URI translation file-based init resource control http://www.modperlcookbook.org/

Resource Control http://www.modperlcookbook.org/

Resource Control Request is inside a particular <Location> container http://www.modperlcookbook.org/

Resource Control Request is inside a particular <Location> container Apache provides three different layers of control to determine who gets access to the resource http://www.modperlcookbook.org/

Resource Control Request is inside a particular <Location> container Apache provides three different layers of control to determine who gets access to the resource Client access checker http://www.modperlcookbook.org/

Resource Control Request is inside a particular <Location> container Apache provides three different layers of control to determine who gets access to the resource Client access checker User ID checker http://www.modperlcookbook.org/

Resource Control Request is inside a particular <Location> container Apache provides three different layers of control to determine who gets access to the resource Client access checker User ID checker User authorization checker http://www.modperlcookbook.org/

Resource Control client request URI-based init URI translation file-based init resource control http://www.modperlcookbook.org/

Resource Control client request URI-based init URI translation file-based init Client Access User ID User Authorization http://www.modperlcookbook.org/

Resource Control client request URI-based init URI translation file-based init PerlAccessHandler PerlAuthenHandler PerlAuthzHandler http://www.modperlcookbook.org/

User Access http://www.modperlcookbook.org/

User Access Used to make access decisions based on Client information http://www.modperlcookbook.org/

User Access Used to make access decisions based on Client information Client IP http://www.modperlcookbook.org/

User Access Used to make access decisions based on Client information Client IP Client User-Agent http://www.modperlcookbook.org/

User Access Used to make access decisions based on Client information Client IP Client User-Agent Request URI http://www.modperlcookbook.org/

User Access Used to make access decisions based on Client information Client IP Client User-Agent Request URI mod_access controls Apache's default http://www.modperlcookbook.org/

User Access Used to make access decisions based on Client information Client IP Client User-Agent Request URI mod_access controls Apache's default Allow from localhost http://www.modperlcookbook.org/

User Access Used to make access decisions based on Client information Client IP Client User-Agent Request URI mod_access controls Apache's default Allow from localhost All configured handlers run http://www.modperlcookbook.org/

PerlAccessHandler http://www.modperlcookbook.org/

PerlAccessHandler Useful for making same decisions as mod_auth http://www.modperlcookbook.org/

PerlAccessHandler Useful for making same decisions as mod_auth do it in Perl http://www.modperlcookbook.org/

Simple PerlAccessHandler http://www.modperlcookbook.org/

Simple PerlAccessHandler Object: get debugging telnet sessions past Basic authentication http://www.modperlcookbook.org/

Simple PerlAccessHandler Object: get debugging telnet sessions past Basic authentication Method: set the Authorization header to a known user if coming from localhost http://www.modperlcookbook.org/

package My::DefaultLogin; use Apache::Constants qw(OK); use MIME::Base64 (); use Socket qw(sockaddr_in inet_ntoa); use strict; sub handler { my $r = shift; my $c = $r->connection; my $local_ip = inet_ntoa((sockaddr_in($c->local_addr))[1]); if ($c->remote_ip eq $local_ip) { my $user = 'bug'; my $passwd = 'squashing'; # Join user and password and set the incoming header. my $credentials = MIME::Base64::encode(join(':', $user, $passwd)); $r->headers_in->set(Authorization => "Basic $credentials"); } return OK; 1; http://www.modperlcookbook.org/

package My::DefaultLogin; use Apache::Constants qw(OK); use MIME::Base64 (); use Socket qw(sockaddr_in inet_ntoa); use strict; sub handler { my $r = shift; my $c = $r->connection; my $local_ip = inet_ntoa((sockaddr_in($c->local_addr))[1]); if ($c->remote_ip eq $local_ip) { my $user = 'bug'; my $passwd = 'squashing'; # Join user and password and set the incoming header. my $credentials = MIME::Base64::encode(join(':', $user, $passwd)); $r->headers_in->set(Authorization => "Basic $credentials"); } return OK; 1; http://www.modperlcookbook.org/

package My::DefaultLogin; use Apache::Constants qw(OK); use MIME::Base64 (); use Socket qw(sockaddr_in inet_ntoa); use strict; sub handler { my $r = shift; my $c = $r->connection; my $local_ip = inet_ntoa((sockaddr_in($c->local_addr))[1]); if ($c->remote_ip eq $local_ip) { my $user = 'bug'; my $passwd = 'squashing'; # Join user and password and set the incoming header. my $credentials = MIME::Base64::encode(join(':', $user, $passwd)); $r->headers_in->set(Authorization => "Basic $credentials"); } return OK; 1; http://www.modperlcookbook.org/

package My::DefaultLogin; use Apache::Constants qw(OK); use MIME::Base64 (); use Socket qw(sockaddr_in inet_ntoa); use strict; sub handler { my $r = shift; my $c = $r->connection; my $local_ip = inet_ntoa((sockaddr_in($c->local_addr))[1]); if ($c->remote_ip eq $local_ip) { my $user = 'bug'; my $passwd = 'squashing'; # Join user and password and set the incoming header. my $credentials = MIME::Base64::encode(join(':', $user, $passwd)); $r->headers_in->set(Authorization => "Basic $credentials"); } return OK; 1; http://www.modperlcookbook.org/

package My::DefaultLogin; use Apache::Constants qw(OK); use MIME::Base64 (); use Socket qw(sockaddr_in inet_ntoa); use strict; sub handler { my $r = shift; my $c = $r->connection; my $local_ip = inet_ntoa((sockaddr_in($c->local_addr))[1]); if ($c->remote_ip eq $local_ip) { my $user = 'bug'; my $passwd = 'squashing'; # Join user and password and set the incoming header. my $credentials = MIME::Base64::encode(join(':', $user, $passwd)); $r->headers_in->set(Authorization => "Basic $credentials"); } return OK; 1; http://www.modperlcookbook.org/

package My::DefaultLogin; use Apache::Constants qw(OK); use MIME::Base64 (); use Socket qw(sockaddr_in inet_ntoa); use strict; sub handler { my $r = shift; my $c = $r->connection; my $local_ip = inet_ntoa((sockaddr_in($c->local_addr))[1]); if ($c->remote_ip eq $local_ip) { my $user = 'bug'; my $passwd = 'squashing'; # Join user and password and set the incoming header. my $credentials = MIME::Base64::encode(join(':', $user, $passwd)); $r->headers_in->set(Authorization => "Basic $credentials"); } return OK; 1; http://www.modperlcookbook.org/

package My::DefaultLogin; use Apache::Constants qw(OK); use MIME::Base64 (); use Socket qw(sockaddr_in inet_ntoa); use strict; sub handler { my $r = shift; my $c = $r->connection; my $local_ip = inet_ntoa((sockaddr_in($c->local_addr))[1]); if ($c->remote_ip eq $local_ip) { my $user = 'bug'; my $passwd = 'squashing'; # Join user and password and set the incoming header. my $credentials = MIME::Base64::encode(join(':', $user, $passwd)); $r->headers_in->set(Authorization => "Basic $credentials"); } return OK; 1; http://www.modperlcookbook.org/

package My::DefaultLogin; use Apache::Constants qw(OK); use MIME::Base64 (); use Socket qw(sockaddr_in inet_ntoa); use strict; sub handler { my $r = shift; my $c = $r->connection; my $local_ip = inet_ntoa((sockaddr_in($c->local_addr))[1]); if ($c->remote_ip eq $local_ip) { my $user = 'bug'; my $passwd = 'squashing'; # Join user and password and set the incoming header. my $credentials = MIME::Base64::encode(join(':', $user, $passwd)); $r->headers_in->set(Authorization => "Basic $credentials"); } return OK; 1; http://www.modperlcookbook.org/

package My::DefaultLogin; use Apache::Constants qw(OK); use MIME::Base64 (); use Socket qw(sockaddr_in inet_ntoa); use strict; sub handler { my $r = shift; my $c = $r->connection; my $local_ip = inet_ntoa((sockaddr_in($c->local_addr))[1]); if ($c->remote_ip eq $local_ip) { my $user = 'bug'; my $passwd = 'squashing'; # Join user and password and set the incoming header. my $credentials = MIME::Base64::encode(join(':', $user, $passwd)); $r->headers_in->set(Authorization => "Basic $credentials"); } return OK; 1; http://www.modperlcookbook.org/

Setup add DefaultLogin.pm to @INC add to httpd.conf that's it! ServerRoot/lib/perl/My/DefaultLogin.pm add to httpd.conf PerlModule My::DefaultLogin PerlAccessHandler My::DefaultLogin that's it! http://www.modperlcookbook.org/

How to Deny Access http://www.modperlcookbook.org/

How to Deny Access Each access handler returns OK if the client meets its conditions http://www.modperlcookbook.org/

How to Deny Access Each access handler returns OK if the client meets its conditions Access handlers return FORBIDDEN to decline access http://www.modperlcookbook.org/

Reality... In the real world, you could accomplish the same thing with the core Satisfy directive http://www.modperlcookbook.org/

Reality... In the real world, you could accomplish the same thing with the core Satisfy directive AuthType Basic AuthName "cookbook" AuthUserFile .htpasswd Require valid-user PerlAccessHandler My::DefaultLogin http://www.modperlcookbook.org/

Reality... In the real world, you could accomplish the same thing with the core Satisfy directive AuthType Basic AuthName "cookbook" AuthUserFile .htpasswd Require valid-user Allow from localhost Satisfy any http://www.modperlcookbook.org/

Resource Control client request URI-based init URI translation file-based init Client Access User ID http://www.modperlcookbook.org/

User Authentication http://www.modperlcookbook.org/

User Authentication Apache default authentication mechanism is mod_auth http://www.modperlcookbook.org/

User Authentication Apache default authentication mechanism is mod_auth Winner takes all http://www.modperlcookbook.org/

User Authentication Apache default authentication mechanism is mod_auth Winner takes all uses a password file generated using Apache's htpasswd utility http://www.modperlcookbook.org/

User Authentication Apache default authentication mechanism is mod_auth Winner takes all uses a password file generated using Apache's htpasswd utility geoff:zzpEyL0tbgwwk http://www.modperlcookbook.org/

User Authentication configuration placed in .htaccess file or httpd.conf http://www.modperlcookbook.org/

User Authentication configuration placed in .htaccess file or httpd.conf AuthUserFile .htpasswd AuthName "cookbook" AuthType Basic Require valid-user http://www.modperlcookbook.org/

User Authentication configuration placed in .htaccess file or httpd.conf AuthUserFile .htpasswd AuthName "cookbook" AuthType Basic Require valid-user http://www.modperlcookbook.org/

How Authentication Works client requests a document http://www.modperlcookbook.org/

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-8859-1, utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: www.example.com Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) http://www.modperlcookbook.org/

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-8859-1, utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: www.example.com Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server denies request http://www.modperlcookbook.org/

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-8859-1, utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: www.example.com Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server denies request HTTP/1.1 401 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-8859-1 http://www.modperlcookbook.org/

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-8859-1, utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: www.example.com Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server denies request HTTP/1.1 401 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-8859-1 http://www.modperlcookbook.org/

How Authentication Works client request client request URI-based init URI translation file-based init Client Access User ID http://www.modperlcookbook.org/

How Authentication Works client request client request URI-based init URI translation file-based init Client Access User ID HTTP/1.1 401 Authorization Required http://www.modperlcookbook.org/

How Authentication Works client request client request logging URI-based init URI translation file-based init Client Access User ID http://www.modperlcookbook.org/

How Authentication Works client sends a new request http://www.modperlcookbook.org/

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-8859-1, 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: www.example.com Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) http://www.modperlcookbook.org/

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-8859-1, 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: www.example.com Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) http://www.modperlcookbook.org/

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-8859-1, 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: www.example.com Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server sends document http://www.modperlcookbook.org/

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-8859-1, 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: www.example.com Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server sends document HTTP/1.1 200 OK Keep-Alive: timeout=15, max=99 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html http://www.modperlcookbook.org/

Resource Control client request URI-based init URI translation file-based init Client Access User ID http://www.modperlcookbook.org/

Resource Control client request URI-based init URI translation file-based init Client Access PerlAuthenHandler http://www.modperlcookbook.org/

Who Uses Flat Files? http://www.modperlcookbook.org/

Who Uses Flat Files? flat files are limiting, hard to manage, difficult to integrate, and just plain boring http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

Do it in Perl since mod_perl gives us the ability to intercept the request cycle before Apache, we can authenticate using Perl instead http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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; } http://www.modperlcookbook.org/

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; } http://www.modperlcookbook.org/

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; } http://www.modperlcookbook.org/

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; } http://www.modperlcookbook.org/

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; } http://www.modperlcookbook.org/

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; } http://www.modperlcookbook.org/

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; } http://www.modperlcookbook.org/

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; } http://www.modperlcookbook.org/

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-8859-1, utf-8;q=0.66, *;q=0.66 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Language: en-us Connection: keep-alive Host: www.example.com Keep-Alive: 300 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) server denies request HTTP/1.1 401 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-8859-1 http://www.modperlcookbook.org/

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; } http://www.modperlcookbook.org/

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; } http://www.modperlcookbook.org/

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; } http://www.modperlcookbook.org/

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; } http://www.modperlcookbook.org/

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; } http://www.modperlcookbook.org/

Configuration http://www.modperlcookbook.org/

Configuration change AuthUserFile .htpasswd AuthName "cookbook" AuthType Basic Require valid-user http://www.modperlcookbook.org/

Configuration change to AuthUserFile .htpasswd AuthName "cookbook" AuthType Basic Require valid-user to PerlAuthenHandler My::Authenticate http://www.modperlcookbook.org/

Configuration change to AuthUserFile .htpasswd AuthName "cookbook" AuthType Basic Require valid-user to PerlAuthenHandler My::Authenticate http://www.modperlcookbook.org/

The Choice is Yours how you decide to authenticate is now up to you http://www.modperlcookbook.org/

The Choice is Yours how you decide to authenticate is now up to you sub authenticate_user { my ($user, $pass) = @_; return $user eq $pass; } http://www.modperlcookbook.org/

The Choice is Yours how you decide to authenticate is now up to you sub authenticate_user { my ($user, $pass) = @_; return $user eq $pass; } are you seeing the possibilities yet? http://www.modperlcookbook.org/

The Power of CPAN over 25 Apache:: shrink-wrapped modules on CPAN for authentication SecureID Radius SMB LDAP NTLM http://www.modperlcookbook.org/

To Infinity and Beyond! http://www.modperlcookbook.org/

To Infinity and Beyond! http://www.modperlcookbook.org/

To Infinity and Beyond! this example only covered Basic authentication via popup box http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

http://www.modperlcookbook.org/

User Authorization client request URI-based init URI translation file-based init Client Access User ID User Authorization http://www.modperlcookbook.org/

User Authorization We now know the user has supplied a valid password http://www.modperlcookbook.org/

User Authorization We now know the user has supplied a valid password now it's up to us to decide if we want the user to have access http://www.modperlcookbook.org/

User Authorization http://www.modperlcookbook.org/

User Authorization Apache's default behavior varies, depending on the syntax of Require Require valid-user Require user foo Require group bar http://www.modperlcookbook.org/

User Authorization Apache's default behavior varies, depending on the syntax of Require Require valid-user Require user foo Require group bar Require file-owner Require file-group http://www.modperlcookbook.org/

User Authorization Apache's default behavior varies, depending on the syntax of Require Require valid-user Require user foo Require group bar Require file-owner Require file-group Winner takes all http://www.modperlcookbook.org/

User Authorization client request URI-based init URI translation file-based init Client Access User ID User Authorization http://www.modperlcookbook.org/

User Authorization client request URI-based init URI translation file-based init Client Access User ID PerlAuthzHandler http://www.modperlcookbook.org/

PerlAuthzHandler http://www.modperlcookbook.org/

PerlAuthzHandler Key is the requires() method http://www.modperlcookbook.org/

PerlAuthzHandler Key is the requires() method $r->requires() returns an array of hashes representing all Require directives http://www.modperlcookbook.org/

PerlAuthzHandler Key is the requires() method $r->requires() returns an array of hashes representing all Require directives Require user grier ryan Require group admiral http://www.modperlcookbook.org/

PerlAuthzHandler Key is the requires() method $r->requires() returns an array of hashes representing all Require directives Require user grier ryan Require group admiral [ { requirement => `user grier ryan', method => -1}, { requirement => `group admiral', ]; http://www.modperlcookbook.org/

PerlAuthzHandler Once you get the Require directive back, you can decide which users meet the authorization requirement http://www.modperlcookbook.org/

PerlAuthzHandler Once you get the Require directive back, you can decide which users meet the authorization requirement foreach my $requires (@{$r->requires}) { my ($directive, @list) = split " ", $requires->{requirement}; # We're ok if only valid-user was required. return OK if lc($directive) eq 'valid-user'; # Likewise if the user requirement was specified and # we match based on what we already know. return OK if lc($directive) eq 'user' && grep { $_ eq $r->user } @list; } http://www.modperlcookbook.org/

PerlAuthzHandler Once you get the Require directive back, you can decide which users meet the authorization requirement foreach my $requires (@{$r->requires}) { my ($directive, @list) = split " ", $requires->{requirement}; # We're ok if only valid-user was required. return OK if lc($directive) eq 'valid-user'; # Likewise if the user requirement was specified and # we match based on what we already know. return OK if lc($directive) eq 'user' && grep { $_ eq $r->user } @list; } http://www.modperlcookbook.org/

PerlAuthzHandler Once you get the Require directive back, you can decide which users meet the authorization requirement foreach my $requires (@{$r->requires}) { my ($directive, @list) = split " ", $requires->{requirement}; # We're ok if only valid-user was required. return OK if lc($directive) eq 'valid-user'; # Likewise if the user requirement was specified and # we match based on what we already know. return OK if lc($directive) eq 'user' && grep { $_ eq $r->user } @list; } [ { requirement => `user grier ryan', method => -1} ] http://www.modperlcookbook.org/

PerlAuthzHandler Once you get the Require directive back, you can decide which users meet the authorization requirement foreach my $requires (@{$r->requires}) { my ($directive, @list) = split " ", $requires->{requirement}; # We're ok if only valid-user was required. return OK if lc($directive) eq 'valid-user'; # Likewise if the user requirement was specified and # we match based on what we already know. return OK if lc($directive) eq 'user' && grep { $_ eq $r->user } @list; } [ { requirement => `user grier ryan', method => -1} ] http://www.modperlcookbook.org/

PerlAuthzHandler Once you get the Require directive back, you can decide which users meet the authorization requirement foreach my $requires (@{$r->requires}) { my ($directive, @list) = split " ", $requires->{requirement}; # We're ok if only valid-user was required. return OK if lc($directive) eq 'valid-user'; # Likewise if the user requirement was specified and # we match based on what we already know. return OK if lc($directive) eq 'user' && grep { $_ eq $r->user } @list; } [ { requirement => `user grier ryan', method => -1} ] http://www.modperlcookbook.org/

PerlAuthzHandler Once you get the Require directive back, you can decide which users meet the authorization requirement foreach my $requires (@{$r->requires}) { my ($directive, @list) = split " ", $requires->{requirement}; # We're ok if only valid-user was required. return OK if lc($directive) eq 'valid-user'; # Likewise if the user requirement was specified and # we match based on what we already know. return OK if lc($directive) eq 'user' && grep { $_ eq $r->user } @list; } [ { requirement => `user grier ryan', method => -1} ] http://www.modperlcookbook.org/

MIME-type Checking client request URI-based init URI translation file-based init MIME setting resource control http://www.modperlcookbook.org/

MIME-type Checking We now have the physical resource and have decided the user can see it http://www.modperlcookbook.org/

MIME-type Checking We now have the physical resource and have decided the user can see it time to set the Content-Type header http://www.modperlcookbook.org/

MIME-type Checking We now have the physical resource and have decided the user can see it time to set the Content-Type header Apache's default is mod_mime, which examines the file extension http://www.modperlcookbook.org/

MIME-type Checking We now have the physical resource and have decided the user can see it time to set the Content-Type header Apache's default is mod_mime, which examines the file extension mod_mime also decides which content handler will run http://www.modperlcookbook.org/

MIME-type Checking We now have the physical resource and have decided the user can see it time to set the Content-Type header Apache's default is mod_mime, which examines the file extension mod_mime also decides which content handler will run AddHandler server-parsed http://www.modperlcookbook.org/

MIME-type Checking We now have the physical resource and have decided the user can see it time to set the Content-Type header Apache's default is mod_mime, which examines the file extension mod_mime also decides which content handler will run AddHandler server-parsed Winner takes all http://www.modperlcookbook.org/

MIME-type Checking client request URI-based init URI translation file-based init MIME setting resource control http://www.modperlcookbook.org/

MIME-type Checking client request URI-based init URI translation file-based init PerlTypeHandler resource control http://www.modperlcookbook.org/

PerlTypeHandler http://www.modperlcookbook.org/

PerlTypeHandler mod_mime has a stranglehold on the request http://www.modperlcookbook.org/

PerlTypeHandler mod_mime has a stranglehold on the request http://www.modperlcookbook.org/

PerlTypeHandler mod_mime has a stranglehold on the request if you set the Content-Type and return OK, mod_mime won't set the content handler http://www.modperlcookbook.org/

PerlTypeHandler mod_mime has a stranglehold on the request if you set the Content-Type and return OK, mod_mime won't set the content handler if you set the Content-Type and return DECLINED, mod_mime will clobber the Content-Type http://www.modperlcookbook.org/

PerlTypeHandler mod_mime has a stranglehold on the request if you set the Content-Type and return OK, mod_mime won't set the content handler if you set the Content-Type and return DECLINED, mod_mime will clobber the Content-Type Best to just forget about the PerlTypeHandler http://www.modperlcookbook.org/

Fixups client request URI-based init URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

Fixups The final chance to fiddle with the request before content is written to the client http://www.modperlcookbook.org/

Fixups The final chance to fiddle with the request before content is written to the client non-specific phase http://www.modperlcookbook.org/

Fixups The final chance to fiddle with the request before content is written to the client non-specific phase Apache has no default behavior http://www.modperlcookbook.org/

Fixups The final chance to fiddle with the request before content is written to the client non-specific phase Apache has no default behavior All configured handlers will be run http://www.modperlcookbook.org/

Fixups client request URI-based init URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

Fixups client request URI-based init URI translation PerlFixupHandler file-based init MIME setting resource control http://www.modperlcookbook.org/

PerlFixupHandler http://www.modperlcookbook.org/

PerlFixupHandler Good place to do anything you might have wanted to do in the PerlTypeHandler http://www.modperlcookbook.org/

PerlFixupHandler Good place to do anything you might have wanted to do in the PerlTypeHandler especially setting $r->handler() http://www.modperlcookbook.org/

Sample Fixup Object: re-implement XBitHack in Perl Method: after some basic checks, turn the request over to mod_include using $r->handler() http://www.modperlcookbook.org/

package Cookbook::XBitHack; use Apache::Constants qw(OK DECLINED OPT_INCLUDES); use Apache::File; use Fcntl qw(S_IXUSR S_IXGRP); use strict; sub handler { my $r = shift; return DECLINED unless (-f $r->finfo && # the file exists $r->content_type eq 'text/html' && # and is HTML $r->allow_options & OPT_INCLUDES); # and we have Options +Includes # Find out the user and group execution status. my $mode = (stat _)[2]; # We have to be user executable specifically. return DECLINED unless ($mode & S_IXUSR); # Set the Last-Modified header if group executable. $r->set_last_modified((stat _)[9]) if ($mode & S_IXGRP); # Make sure mod_include picks it up. $r->handler('server-parsed'); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::XBitHack; use Apache::Constants qw(OK DECLINED OPT_INCLUDES); use Apache::File; use Fcntl qw(S_IXUSR S_IXGRP); use strict; sub handler { my $r = shift; return DECLINED unless (-f $r->finfo && # the file exists $r->content_type eq 'text/html' && # and is HTML $r->allow_options & OPT_INCLUDES); # and we have Options +Includes # Find out the user and group execution status. my $mode = (stat _)[2]; # We have to be user executable specifically. return DECLINED unless ($mode & S_IXUSR); # Set the Last-Modified header if group executable. $r->set_last_modified((stat _)[9]) if ($mode & S_IXGRP); # Make sure mod_include picks it up. $r->handler('server-parsed'); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::XBitHack; use Apache::Constants qw(OK DECLINED OPT_INCLUDES); use Apache::File; use Fcntl qw(S_IXUSR S_IXGRP); use strict; sub handler { my $r = shift; return DECLINED unless (-f $r->finfo && # the file exists $r->content_type eq 'text/html' && # and is HTML $r->allow_options & OPT_INCLUDES); # and we have Options +Includes # Find out the user and group execution status. my $mode = (stat _)[2]; # We have to be user executable specifically. return DECLINED unless ($mode & S_IXUSR); # Set the Last-Modified header if group executable. $r->set_last_modified((stat _)[9]) if ($mode & S_IXGRP); # Make sure mod_include picks it up. $r->handler('server-parsed'); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::XBitHack; use Apache::Constants qw(OK DECLINED OPT_INCLUDES); use Apache::File; use Fcntl qw(S_IXUSR S_IXGRP); use strict; sub handler { my $r = shift; return DECLINED unless (-f $r->finfo && # the file exists $r->content_type eq 'text/html' && # and is HTML $r->allow_options & OPT_INCLUDES); # and we have Options +Includes # Find out the user and group execution status. my $mode = (stat _)[2]; # We have to be user executable specifically. return DECLINED unless ($mode & S_IXUSR); # Set the Last-Modified header if group executable. $r->set_last_modified((stat _)[9]) if ($mode & S_IXGRP); # Make sure mod_include picks it up. $r->handler('server-parsed'); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::XBitHack; use Apache::Constants qw(OK DECLINED OPT_INCLUDES); use Apache::File; use Fcntl qw(S_IXUSR S_IXGRP); use strict; sub handler { my $r = shift; return DECLINED unless (-f $r->finfo && # the file exists $r->content_type eq 'text/html' && # and is HTML $r->allow_options & OPT_INCLUDES); # and we have Options +Includes # Find out the user and group execution status. my $mode = (stat _)[2]; # We have to be user executable specifically. return DECLINED unless ($mode & S_IXUSR); # Set the Last-Modified header if group executable. $r->set_last_modified((stat _)[9]) if ($mode & S_IXGRP); # Make sure mod_include picks it up. $r->handler('server-parsed'); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::XBitHack; use Apache::Constants qw(OK DECLINED OPT_INCLUDES); use Apache::File; use Fcntl qw(S_IXUSR S_IXGRP); use strict; sub handler { my $r = shift; return DECLINED unless (-f $r->finfo && # the file exists $r->content_type eq 'text/html' && # and is HTML $r->allow_options & OPT_INCLUDES); # and we have Options +Includes # Find out the user and group execution status. my $mode = (stat _)[2]; # We have to be user executable specifically. return DECLINED unless ($mode & S_IXUSR); # Set the Last-Modified header if group executable. $r->set_last_modified((stat _)[9]) if ($mode & S_IXGRP); # Make sure mod_include picks it up. $r->handler('server-parsed'); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::XBitHack; use Apache::Constants qw(OK DECLINED OPT_INCLUDES); use Apache::File; use Fcntl qw(S_IXUSR S_IXGRP); use strict; sub handler { my $r = shift; return DECLINED unless (-f $r->finfo && # the file exists $r->content_type eq 'text/html' && # and is HTML $r->allow_options & OPT_INCLUDES); # and we have Options +Includes # Find out the user and group execution status. my $mode = (stat _)[2]; # We have to be user executable specifically. return DECLINED unless ($mode & S_IXUSR); # Set the Last-Modified header if group executable. $r->set_last_modified((stat _)[9]) if ($mode & S_IXGRP); # Make sure mod_include picks it up. $r->handler('server-parsed'); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::XBitHack; use Apache::Constants qw(OK DECLINED OPT_INCLUDES); use Apache::File; use Fcntl qw(S_IXUSR S_IXGRP); use strict; sub handler { my $r = shift; return DECLINED unless (-f $r->finfo && # the file exists $r->content_type eq 'text/html' && # and is HTML $r->allow_options & OPT_INCLUDES); # and we have Options +Includes # Find out the user and group execution status. my $mode = (stat _)[2]; # We have to be user executable specifically. return DECLINED unless ($mode & S_IXUSR); # Set the Last-Modified header if group executable. $r->set_last_modified((stat _)[9]) if ($mode & S_IXGRP); # Make sure mod_include picks it up. $r->handler('server-parsed'); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::XBitHack; use Apache::Constants qw(OK DECLINED OPT_INCLUDES); use Apache::File; use Fcntl qw(S_IXUSR S_IXGRP); use strict; sub handler { my $r = shift; return DECLINED unless (-f $r->finfo && # the file exists $r->content_type eq 'text/html' && # and is HTML $r->allow_options & OPT_INCLUDES); # and we have Options +Includes # Find out the user and group execution status. my $mode = (stat _)[2]; # We have to be user executable specifically. return DECLINED unless ($mode & S_IXUSR); # Set the Last-Modified header if group executable. $r->set_last_modified((stat _)[9]) if ($mode & S_IXGRP); # Make sure mod_include picks it up. $r->handler('server-parsed'); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::XBitHack; use Apache::Constants qw(OK DECLINED OPT_INCLUDES); use Apache::File; use Fcntl qw(S_IXUSR S_IXGRP); use strict; sub handler { my $r = shift; return DECLINED unless (-f $r->finfo && # the file exists $r->content_type eq 'text/html' && # and is HTML $r->allow_options & OPT_INCLUDES); # and we have Options +Includes # Find out the user and group execution status. my $mode = (stat _)[2]; # We have to be user executable specifically. return DECLINED unless ($mode & S_IXUSR); # Set the Last-Modified header if group executable. $r->set_last_modified((stat _)[9]) if ($mode & S_IXGRP); # Make sure mod_include picks it up. $r->handler('server-parsed'); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::XBitHack; use Apache::Constants qw(OK DECLINED OPT_INCLUDES); use Apache::File; use Fcntl qw(S_IXUSR S_IXGRP); use strict; sub handler { my $r = shift; return DECLINED unless (-f $r->finfo && # the file exists $r->content_type eq 'text/html' && # and is HTML $r->allow_options & OPT_INCLUDES); # and we have Options +Includes # Find out the user and group execution status. my $mode = (stat _)[2]; # We have to be user executable specifically. return DECLINED unless ($mode & S_IXUSR); # Set the Last-Modified header if group executable. $r->set_last_modified((stat _)[9]) if ($mode & S_IXGRP); # Make sure mod_include picks it up. $r->handler('server-parsed'); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::XBitHack; use Apache::Constants qw(OK DECLINED OPT_INCLUDES); use Apache::File; use Fcntl qw(S_IXUSR S_IXGRP); use strict; sub handler { my $r = shift; return DECLINED unless (-f $r->finfo && # the file exists $r->content_type eq 'text/html' && # and is HTML $r->allow_options & OPT_INCLUDES); # and we have Options +Includes # Find out the user and group execution status. my $mode = (stat _)[2]; # We have to be user executable specifically. return DECLINED unless ($mode & S_IXUSR); # Set the Last-Modified header if group executable. $r->set_last_modified((stat _)[9]) if ($mode & S_IXGRP); # Make sure mod_include picks it up. $r->handler('server-parsed'); return OK; } 1; http://www.modperlcookbook.org/

Content Generation client request URI-based init content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

Content Generation Apache's default content handler is default-handler, which takes care of all HTTP/1.1 events http://www.modperlcookbook.org/

Content Generation Apache's default content handler is default-handler, which takes care of all HTTP/1.1 events byteserving http://www.modperlcookbook.org/

Content Generation Apache's default content handler is default-handler, which takes care of all HTTP/1.1 events byteserving cache headers http://www.modperlcookbook.org/

Content Generation Apache's default content handler is default-handler, which takes care of all HTTP/1.1 events byteserving cache headers one and only one C module gets to handle content-generation http://www.modperlcookbook.org/

Content Generation Apache's default content handler is default-handler, which takes care of all HTTP/1.1 events byteserving cache headers one and only one C module gets to handle content-generation mod_cgi mod_perl mod_include http://www.modperlcookbook.org/

Content Generation client request URI-based init content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

Content Generation client request URI-based init PerlHandler URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

Sample PerlHandler http://www.modperlcookbook.org/

Sample PerlHandler Object: save bandwidth universally http://www.modperlcookbook.org/

Sample PerlHandler Object: save bandwidth universally Method: module HTML::Clean to "clean" outgoing documents http://www.modperlcookbook.org/

Sample PerlHandler Object: save bandwidth universally Method: module HTML::Clean to "clean" outgoing documents Afterward: alter the handler to take advantage of more advanced mod_perl features http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

Configuration http://www.modperlcookbook.org/

Configuration add directives to httpd.conf to mirror DocumentRoot http://www.modperlcookbook.org/

Configuration add directives to httpd.conf to mirror DocumentRoot Alias /clean /usr/local/apache/htdocs <Location /clean> SetHandler perl-script PerlHandler My::Clean </Location> http://www.modperlcookbook.org/

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> http://www.modperlcookbook.org/

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> http://www.modperlcookbook.org/

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> http://www.modperlcookbook.org/

Dynamic or Static? http://www.modperlcookbook.org/

Dynamic or Static? we often think of dynamic content as "could be different on any given access" http://www.modperlcookbook.org/

Dynamic or Static? 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 http://www.modperlcookbook.org/

Dynamic or Static? 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 http://www.modperlcookbook.org/

Conditional GET Request http://www.modperlcookbook.org/

Conditional GET Request HTTP/1.1 allows for a conditional GET request http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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-8859-1;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 6.03 [en] http://www.modperlcookbook.org/

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-8859-1;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 6.03 [en] http://www.modperlcookbook.org/

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-8859-1;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 6.03 [en] HTTP/1.1 200 OK Last-Modified: Thu, 01 Nov 2001 16:35:27 GMT ETag: "4c949-2434-3be179cf" Accept-Ranges: bytes Content-Length: 9268 Connection: close Content-Type: text/html http://www.modperlcookbook.org/

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-8859-1;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 6.03 [en] HTTP/1.1 200 OK Last-Modified: Thu, 01 Nov 2001 16:35:27 GMT ETag: "4c949-2434-3be179cf" Accept-Ranges: bytes Content-Length: 9268 Connection: close Content-Type: text/html http://www.modperlcookbook.org/

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-8859-1;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 6.03 [en] HTTP/1.1 200 OK Last-Modified: Thu, 01 Nov 2001 16:35:27 GMT ETag: "4c949-2434-3be179cf" Accept-Ranges: bytes Content-Length: 9268 Connection: close Content-Type: text/html http://www.modperlcookbook.org/

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-8859-1;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 2001 16:35:27 GMT If-None-Match: "4c949-2434-3be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.03 [en] http://www.modperlcookbook.org/

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-8859-1;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 2001 16:35:27 GMT If-None-Match: "4c949-2434-3be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.03 [en] http://www.modperlcookbook.org/

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-8859-1;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 2001 16:35:27 GMT If-None-Match: "4c949-2434-3be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.03 [en] http://www.modperlcookbook.org/

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-8859-1;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 2001 16:35:27 GMT If-None-Match: "4c949-2434-3be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.03 [en] http://www.modperlcookbook.org/

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-8859-1;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 2001 16:35:27 GMT If-None-Match: "4c949-2434-3be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.03 [en] HTTP/1.1 304 Not Modified Last-Modified: Thu, 01 Nov 2001 16:35:27 GMT ETag: "4c949-2434-3be179cf" Accept-Ranges: bytes Connection: close http://www.modperlcookbook.org/

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-8859-1;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 2001 16:35:27 GMT If-None-Match: "4c949-2434-3be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.03 [en] HTTP/1.1 304 Not Modified Last-Modified: Thu, 01 Nov 2001 16:35:27 GMT ETag: "4c949-2434-3be179cf" Accept-Ranges: bytes Connection: close http://www.modperlcookbook.org/

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-8859-1;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 2001 16:35:27 GMT If-None-Match: "4c949-2434-3be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.03 [en] HTTP/1.1 304 Not Modified Last-Modified: Thu, 01 Nov 2001 16:35:27 GMT ETag: "4c949-2434-3be179cf" Accept-Ranges: bytes Connection: close http://www.modperlcookbook.org/

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-8859-1;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 2001 16:35:27 GMT If-None-Match: "4c949-2434-3be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.03 [en] http://www.modperlcookbook.org/

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-8859-1;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 2001 16:35:27 GMT If-None-Match: "4c949-2434-3be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.03 [en] HTTP/1.1 200 OK Last-Modified: Thu, 06 Jun 2002 11:51:11 GMT ETag: "4c949-2434-3cff4caf" Accept-Ranges: bytes Content-Length: 9268 Connection: close http://www.modperlcookbook.org/

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-8859-1;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 2001 16:35:27 GMT If-None-Match: "4c949-2434-3be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.03 [en] HTTP/1.1 200 OK Last-Modified: Thu, 06 Jun 2002 11:51:11 GMT ETag: "4c949-2434-3cff4caf" Accept-Ranges: bytes Content-Length: 9268 Connection: close http://www.modperlcookbook.org/

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-8859-1;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 2001 16:35:27 GMT If-None-Match: "4c949-2434-3be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.03 [en] HTTP/1.1 200 OK Last-Modified: Thu, 06 Jun 2002 11:51:11 GMT ETag: "4c949-2434-3cff4caf" Accept-Ranges: bytes Content-Length: 9268 Connection: close http://www.modperlcookbook.org/

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-8859-1;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 2001 16:35:27 GMT If-None-Match: "4c949-2434-3be179cf TE: deflate, gzip, chunked, identity, trailers User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.03 [en] HTTP/1.1 200 OK Last-Modified: Thu, 06 Jun 2002 11:51:11 GMT ETag: "4c949-2434-3cff4caf" Accept-Ranges: bytes Content-Length: 9268 Connection: close http://www.modperlcookbook.org/

Conditional GET Request for static documents, Apache takes care of making our response cache-friendly http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

Now for the Fun Part http://www.modperlcookbook.org/

Now for the Fun Part modify our PerlHandler to be "cache friendly" http://www.modperlcookbook.org/

Now for the Fun Part modify our PerlHandler to be "cache friendly" send 304 when the document hasn't changed http://www.modperlcookbook.org/

Now for the Fun Part modify our PerlHandler to be "cache friendly" send 304 when the document hasn't changed properly handle If-* header comparisons http://www.modperlcookbook.org/

How do you define change? http://www.modperlcookbook.org/

How do you define change? http://www.modperlcookbook.org/

How do you define change? when dynamically altering static documents there are a number of factors to consider http://www.modperlcookbook.org/

How do you define change? when dynamically altering static documents there are a number of factors to consider when the file changes on disk http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 change http://www.modperlcookbook.org/

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 change all of these affect the "freshness" of the document http://www.modperlcookbook.org/

Code Changes http://www.modperlcookbook.org/

Code Changes in order to determine when the code itself changes, we need to mark the modification time of the package http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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]; http://www.modperlcookbook.org/

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]; http://www.modperlcookbook.org/

Configuration Changes http://www.modperlcookbook.org/

Configuration Changes in order to determine when the options to the code change, we need to mark the modification time of httpd.conf http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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]; http://www.modperlcookbook.org/

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]; }); http://www.modperlcookbook.org/

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]; }); http://www.modperlcookbook.org/

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]; }); http://www.modperlcookbook.org/

Resource Changes http://www.modperlcookbook.org/

Resource Changes in order to determine when the resources changes, we need to mark the modification time of $r->filename http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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 http://www.modperlcookbook.org/

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]; }); http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; } http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

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; http://www.modperlcookbook.org/

http://www.modperlcookbook.org/

Logging client request logging URI-based init content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

Logging Apache's default is to use mod_log_config in common format http://www.modperlcookbook.org/

Logging Apache's default is to use mod_log_config in common format LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog logs/access_log common http://www.modperlcookbook.org/

Logging Apache's default is to use mod_log_config in common format LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog logs/access_log common Most people tweak this to combined http://www.modperlcookbook.org/

Logging Apache's default is to use mod_log_config in common format LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog logs/access_log common Most people tweak this to combined LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined http://www.modperlcookbook.org/

Logging Apache's default is to use mod_log_config in common format LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog logs/access_log common Most people tweak this to combined LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined The connection to the client is still open! http://www.modperlcookbook.org/

Logging Apache's default is to use mod_log_config in common format LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog logs/access_log common Most people tweak this to combined LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined The connection to the client is still open! All configured handlers run http://www.modperlcookbook.org/

Logging client request logging URI-based init content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

Logging client request PerlLogHandler URI-based init content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

PerlLogHandler http://www.modperlcookbook.org/

PerlLogHandler Useful for logging using interfaces in which Perl shines http://www.modperlcookbook.org/

PerlLogHandler Useful for logging using interfaces in which Perl shines like databases http://www.modperlcookbook.org/

Logging to a Database http://www.modperlcookbook.org/

Logging to a Database Logging directly to a database makes life easier if you have an application for which you need lots of reports http://www.modperlcookbook.org/

Logging to a Database Logging directly to a database makes life easier if you have an application for which you need lots of reports DBI rules http://www.modperlcookbook.org/

package Cookbook::SiteLog; use Apache::Constants qw(OK); use DBI; use strict; sub handler { my $r = shift; my $dbh = DBI->connect($r->dir_config('DBASE'), {RaiseError => 1, AutoCommit => 1, PrintError => 1}) or die $DBI::errstr; my %columns = ( status => $r->status, bytes => $r->bytes_sent, language => $r->headers_in->get('Accept-Language'), ); my $fields = join "$_,", keys %columns; my $values = join ', ', ('?') x values %columns; my $sql = qq( insert into www.sitelog (hit, servedate, $fields) values (hitsequence.nextval, sysdate, $values) my $sth = $dbh->prepare($sql); $sth->execute(values %columns); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::SiteLog; use Apache::Constants qw(OK); use DBI; use strict; sub handler { my $r = shift; my $dbh = DBI->connect($r->dir_config('DBASE'), {RaiseError => 1, AutoCommit => 1, PrintError => 1}) or die $DBI::errstr; my %columns = ( status => $r->status, bytes => $r->bytes_sent, language => $r->headers_in->get('Accept-Language'), ); my $fields = join "$_,", keys %columns; my $values = join ', ', ('?') x values %columns; my $sql = qq( insert into www.sitelog (hit, servedate, $fields) values (hitsequence.nextval, sysdate, $values) my $sth = $dbh->prepare($sql); $sth->execute(values %columns); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::SiteLog; use Apache::Constants qw(OK); use DBI; use strict; sub handler { my $r = shift; my $dbh = DBI->connect($r->dir_config('DBASE'), {RaiseError => 1, AutoCommit => 1, PrintError => 1}) or die $DBI::errstr; my %columns = ( status => $r->status, bytes => $r->bytes_sent, language => $r->headers_in->get('Accept-Language'), ); my $fields = join "$_,", keys %columns; my $values = join ', ', ('?') x values %columns; my $sql = qq( insert into www.sitelog (hit, servedate, $fields) values (hitsequence.nextval, sysdate, $values) my $sth = $dbh->prepare($sql); $sth->execute(values %columns); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::SiteLog; use Apache::Constants qw(OK); use DBI; use strict; sub handler { my $r = shift; my $dbh = DBI->connect($r->dir_config('DBASE'), {RaiseError => 1, AutoCommit => 1, PrintError => 1}) or die $DBI::errstr; my %columns = ( status => $r->status, bytes => $r->bytes_sent, language => $r->headers_in->get('Accept-Language'), ); my $fields = join "$_,", keys %columns; my $values = join ', ', ('?') x values %columns; my $sql = qq( insert into www.sitelog (hit, servedate, $fields) values (hitsequence.nextval, sysdate, $values) my $sth = $dbh->prepare($sql); $sth->execute(values %columns); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::SiteLog; use Apache::Constants qw(OK); use DBI; use strict; sub handler { my $r = shift; my $dbh = DBI->connect($r->dir_config('DBASE'), {RaiseError => 1, AutoCommit => 1, PrintError => 1}) or die $DBI::errstr; my %columns = ( status => $r->status, bytes => $r->bytes_sent, language => $r->headers_in->get('Accept-Language'), ); my $fields = join "$_,", keys %columns; my $values = join ', ', ('?') x values %columns; my $sql = qq( insert into www.sitelog (hit, servedate, $fields) values (hitsequence.nextval, sysdate, $values) my $sth = $dbh->prepare($sql); $sth->execute(values %columns); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::SiteLog; use Apache::Constants qw(OK); use DBI; use strict; sub handler { my $r = shift; my $dbh = DBI->connect($r->dir_config('DBASE'), {RaiseError => 1, AutoCommit => 1, PrintError => 1}) or die $DBI::errstr; my %columns = ( status => $r->status, bytes => $r->bytes_sent, language => $r->headers_in->get('Accept-Language'), ); my $fields = join "$_,", keys %columns; my $values = join ', ', ('?') x values %columns; my $sql = qq( insert into www.sitelog (hit, servedate, $fields) values (hitsequence.nextval, sysdate, $values) my $sth = $dbh->prepare($sql); $sth->execute(values %columns); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::SiteLog; use Apache::Constants qw(OK); use DBI; use strict; sub handler { my $r = shift; my $dbh = DBI->connect($r->dir_config('DBASE'), {RaiseError => 1, AutoCommit => 1, PrintError => 1}) or die $DBI::errstr; my %columns = ( status => $r->status, bytes => $r->bytes_sent, language => $r->headers_in->get('Accept-Language'), ); my $fields = join "$_,", keys %columns; my $values = join ', ', ('?') x values %columns; my $sql = qq( insert into www.sitelog (hit, servedate, $fields) values (hitsequence.nextval, sysdate, $values) my $sth = $dbh->prepare($sql); $sth->execute(values %columns); return OK; } 1; http://www.modperlcookbook.org/

Cleanups client request cleanups URI-based init logging content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

Cleanups Apache doesn't really have a cleanup phase http://www.modperlcookbook.org/

Cleanups Apache doesn't really have a cleanup phase It calls a function when the request memory pool is destroyed http://www.modperlcookbook.org/

Cleanups Apache doesn't really have a cleanup phase It calls a function when the request memory pool is destroyed The connection to the client is closed http://www.modperlcookbook.org/

Cleanups client request cleanups URI-based init logging content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

Cleanups client request PerlCleanupHandler URI-based init logging content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/

PerlCleanupHandler http://www.modperlcookbook.org/

PerlCleanupHandler Generally used to do any end of request cleanups http://www.modperlcookbook.org/

PerlCleanupHandler Generally used to do any end of request cleanups Apache::File::tmpfile() removes its temporary file here http://www.modperlcookbook.org/

PerlCleanupHandler Generally used to do any end of request cleanups Apache::File::tmpfile() removes its temporary file here Also good for logging http://www.modperlcookbook.org/

PerlCleanupHandler Generally used to do any end of request cleanups Apache::File::tmpfile() removes its temporary file here Also good for logging no active browsers http://www.modperlcookbook.org/

Debugging http://www.modperlcookbook.org/

Debugging Let's examine a very conceptual debugging cleanup handler http://www.modperlcookbook.org/

Debugging Let's examine a very conceptual debugging cleanup handler I actually did use it for a while http://www.modperlcookbook.org/

package Cookbook::TraceError; use Apache::Constants qw(OK SERVER_ERROR DECLINED); use Apache::Log; use strict; sub handler { my $r = shift; # Don't do anything unless the main process errors. return DECLINED unless $r->is_initial_req && $r->status == SERVER_ERROR; my $old_loglevel = $r->server->loglevel(Apache::Log::DEBUG); my $old_trace = DBI->trace(2); # Start the debuggging request. my $sub = $r->lookup_uri($r->uri); # run() would ordinarily send content to the client, but # since we're in cleanup, the connection is already closed. $sub->run; # Reset things back to their original state - # loglevel(N) will persist for the lifetime of the child process. DBI->trace($old_trace); $r->server->loglevel($old_loglevel); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::TraceError; use Apache::Constants qw(OK SERVER_ERROR DECLINED); use Apache::Log; use strict; sub handler { my $r = shift; # Don't do anything unless the main process errors. return DECLINED unless $r->is_initial_req && $r->status == SERVER_ERROR; my $old_loglevel = $r->server->loglevel(Apache::Log::DEBUG); my $old_trace = DBI->trace(2); # Start the debuggging request. my $sub = $r->lookup_uri($r->uri); # run() would ordinarily send content to the client, but # since we're in cleanup, the connection is already closed. $sub->run; # Reset things back to their original state - # loglevel(N) will persist for the lifetime of the child process. DBI->trace($old_trace); $r->server->loglevel($old_loglevel); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::TraceError; use Apache::Constants qw(OK SERVER_ERROR DECLINED); use Apache::Log; use strict; sub handler { my $r = shift; # Don't do anything unless the main process errors. return DECLINED unless $r->is_initial_req && $r->status == SERVER_ERROR; my $old_loglevel = $r->server->loglevel(Apache::Log::DEBUG); my $old_trace = DBI->trace(2); # Start the debuggging request. my $sub = $r->lookup_uri($r->uri); # run() would ordinarily send content to the client, but # since we're in cleanup, the connection is already closed. $sub->run; # Reset things back to their original state - # loglevel(N) will persist for the lifetime of the child process. DBI->trace($old_trace); $r->server->loglevel($old_loglevel); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::TraceError; use Apache::Constants qw(OK SERVER_ERROR DECLINED); use Apache::Log; use strict; sub handler { my $r = shift; # Don't do anything unless the main process errors. return DECLINED unless $r->is_initial_req && $r->status == SERVER_ERROR; my $old_loglevel = $r->server->loglevel(Apache::Log::DEBUG); my $old_trace = DBI->trace(2); # Start the debuggging request. my $sub = $r->lookup_uri($r->uri); # run() would ordinarily send content to the client, but # since we're in cleanup, the connection is already closed. $sub->run; # Reset things back to their original state - # loglevel(N) will persist for the lifetime of the child process. DBI->trace($old_trace); $r->server->loglevel($old_loglevel); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::TraceError; use Apache::Constants qw(OK SERVER_ERROR DECLINED); use Apache::Log; use strict; sub handler { my $r = shift; # Don't do anything unless the main process errors. return DECLINED unless $r->is_initial_req && $r->status == SERVER_ERROR; my $old_loglevel = $r->server->loglevel(Apache::Log::DEBUG); my $old_trace = DBI->trace(2); # Start the debuggging request. my $sub = $r->lookup_uri($r->uri); # run() would ordinarily send content to the client, but # since we're in cleanup, the connection is already closed. $sub->run; # Reset things back to their original state - # loglevel(N) will persist for the lifetime of the child process. DBI->trace($old_trace); $r->server->loglevel($old_loglevel); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::TraceError; use Apache::Constants qw(OK SERVER_ERROR DECLINED); use Apache::Log; use strict; sub handler { my $r = shift; # Don't do anything unless the main process errors. return DECLINED unless $r->is_initial_req && $r->status == SERVER_ERROR; my $old_loglevel = $r->server->loglevel(Apache::Log::DEBUG); my $old_trace = DBI->trace(2); # Start the debuggging request. my $sub = $r->lookup_uri($r->uri); # run() would ordinarily send content to the client, but # since we're in cleanup, the connection is already closed. $sub->run; # Reset things back to their original state - # loglevel(N) will persist for the lifetime of the child process. DBI->trace($old_trace); $r->server->loglevel($old_loglevel); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::TraceError; use Apache::Constants qw(OK SERVER_ERROR DECLINED); use Apache::Log; use strict; sub handler { my $r = shift; # Don't do anything unless the main process errors. return DECLINED unless $r->is_initial_req && $r->status == SERVER_ERROR; my $old_loglevel = $r->server->loglevel(Apache::Log::DEBUG); my $old_trace = DBI->trace(2); # Start the debuggging request. my $sub = $r->lookup_uri($r->uri); # run() would ordinarily send content to the client, but # since we're in cleanup, the connection is already closed. $sub->run; # Reset things back to their original state - # loglevel(N) will persist for the lifetime of the child process. DBI->trace($old_trace); $r->server->loglevel($old_loglevel); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::TraceError; use Apache::Constants qw(OK SERVER_ERROR DECLINED); use Apache::Log; use strict; sub handler { my $r = shift; # Don't do anything unless the main process errors. return DECLINED unless $r->is_initial_req && $r->status == SERVER_ERROR; my $old_loglevel = $r->server->loglevel(Apache::Log::DEBUG); my $old_trace = DBI->trace(2); # Start the debuggging request. my $sub = $r->lookup_uri($r->uri); # run() would ordinarily send content to the client, but # since we're in cleanup, the connection is already closed. $sub->run; # Reset things back to their original state - # loglevel(N) will persist for the lifetime of the child process. DBI->trace($old_trace); $r->server->loglevel($old_loglevel); return OK; } 1; http://www.modperlcookbook.org/

package Cookbook::TraceError; use Apache::Constants qw(OK SERVER_ERROR DECLINED); use Apache::Log; use strict; sub handler { my $r = shift; # Don't do anything unless the main process errors. return DECLINED unless $r->is_initial_req && $r->status == SERVER_ERROR; my $old_loglevel = $r->server->loglevel(Apache::Log::DEBUG); my $old_trace = DBI->trace(2); # Start the debuggging request. my $sub = $r->lookup_uri($r->uri); # run() would ordinarily send content to the client, but # since we're in cleanup, the connection is already closed. $sub->run; # Reset things back to their original state - # loglevel(N) will persist for the lifetime of the child process. DBI->trace($old_trace); $r->server->loglevel($old_loglevel); return OK; } 1; http://www.modperlcookbook.org/

http://www.modperlcookbook.org/

Fine Manuals Writing Apache Modules with Perl and C http://www.modperl.com/ mod_perl Developer's Cookbook http://www.modperlcookbook.org/ mod_perl Pocket Reference http://www.refcards.com/ mod_perl Guide http://perl.apache.org/guide/ http://www.modperlbook.org/ mod_perl at the ASF http://perl.apache.org/ http://www.modperlcookbook.org/

Materials These slides My modules http://www.modperlcookbook.org/~gyoung/slides/ My modules http://www.modperlcookbook.org/~gyoung/modules/ http://www.modperlcookbook.org/

http://www.modperlcookbook.org/