Geoffrey Young geoff@modperlcookbook.org mod_perl: do more) Geoffrey Young geoff@modperlcookbook.org http://www.modperlcookbook.org/
Just the facts OSCon theme this year is doing more with less If you ask Joe Developer what mod_perl is, he quacks "It's basically just faster CGI" That's not exactly right... http://www.modperlcookbook.org/
Request Phases Apache breaks down request processing into separate, logical parts called phases Each request is stepped through the phases in turn until... all processing is complete somebody throws an "error" http://www.modperlcookbook.org/
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, 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 mod_perl embeds a perl interpreter directly within the Apache runtime opens up the Apache API to Perl code offers an interface to each phase of the request cycle We like Perl http://www.modperlcookbook.org/
Registry is just a handler Apache::Registry is merely a set of (incredibly clever) Perl subroutines that interact with the request cycle Performance gains are made possible due to what mod_perl really is Let's take a peek inside... http://www.modperlcookbook.org/
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 (a la CGI) 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 within Apache the (compiled) package is already in memory when called http://www.modperlcookbook.org/
Do more with less? Most developer's haven't even scratched the surface of what's possible with mod_perl Almost 25% of Apache servers are running mod_perl Why do more with less? Do more with what you already have http://www.modperlcookbook.org/
Do more mod_perl allows you to interact with and directly alter server behavior Gives you the ability to "program within Apache's framework instead of around it" Allows you to intercept basic Apache functions and replace them with your own (sometimes devious) Perl substitutes Lets you do it all in Perl instead of C http://www.modperlcookbook.org/
For Instance... With mod_perl, it's easy to protect our name-based virtual hosts from HTTP/1.0 requests Apache can't handle http://www.modperlcookbook.org/
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/
Let's fix it Intercept every request prior to content-generation and return an error unless... there is a Host header the request is an absolute URI http://www.modperlcookbook.org/
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 add to httpd.conf that's it! ServerRoot/lib/perl/Cookbook/TrapNoHost.pm add to httpd.conf PerlModule Cookbook::TrapNoHost PerlTransHandler Cookbook::TrapNoHost that's it! 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/
Intercept the Request client request URI-based init PerlTransHandler HTTP/1.1 400 Bad Request Date: Tue, 04 Jun 2002 01:17:52 GMT Server: Apache/1.3.25-dev (Unix) mod_perl/1.27_01-dev Perl/v5.8.0 Connection: close Content-Type: text/html; charset=iso-8859-1 Oops! Did you mean to omit a Host header? http://www.modperlcookbook.org/
Intercept the Request client request logging URI-based init PerlTransHandler http://www.modperlcookbook.org/
Modularize Processing Parsing out the query string or POST data on each request is a pain For the most part, you know you need it for every request to a given <Location> Take advantage of the request cycle Modularize the parsing code http://www.modperlcookbook.org/
Apache::RequestNotes Apache::RequestNotes parses cookies and input parameters stores the data in pnotes() for later retrieval http://www.modperlcookbook.org/
Setup Alias /perl-bin /usr/local/apache/perl-bin <Location /perl-bin/> SetHandler perl-script PerlHandler Apache::Registry Options +ExecCGI PerlInitHandler Apache::RequestNotes </Location> http://www.modperlcookbook.org/
<Location> Processing client request URI-based init URI translation PerlInitHandler my $input = $r->pnotes('INPUT'); # Apache::Table reference my $uploads = $r->pnotes('UPLOADS'); # Apache::Upload array ref my $cookies = $r->pnotes('COOKIES'); # hash reference http://www.modperlcookbook.org/
User Authentication Some .htaccess file or httpd.conf AuthUserFile .htpasswd AuthName "my site" AuthType Basic Require valid-user http://www.modperlcookbook.org/
Who Uses Flat Files? flat files are limiting, hard to manage, difficult to integrate, and just plain boring we can do more and replace flat files with our own authentication mechanism http://www.modperlcookbook.org/
package My::Authenticate; use Apache::Constants qw(OK AUTH_REQUIRED); use strict; sub handler { my $r = shift; # Get the client-supplied credentials. my ($status, $password) = $r->get_basic_auth_pw; return $status unless $status == OK; # Perform some custom user/password validation. return OK if authenticate_user($r->user, $password); # Whoops, bad credentials. $r->note_basic_auth_failure; return AUTH_REQUIRED; } http://www.modperlcookbook.org/
Configuration change to AuthUserFile .htpasswd AuthName "my site" AuthType Basic Require valid-user to PerlAuthenHandler My::Authenticate AuthName "cookbook" http://www.modperlcookbook.org/
Authentication HTTP/1.1 401 Authorization Required client request URI-based init URI translation file-based init PerlAuthenHandler HTTP/1.1 401 Authorization Required http://www.modperlcookbook.org/
Authentication client request logging URI-based init URI translation file-based init PerlAuthenHandler 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/
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 to a Database In general, people in marketing don't know what they want when it comes to reports Logging directly to a database makes life easier if you have an application for which you need lots of reports Incurs very little overhead if you are already using a database in your application http://www.modperlcookbook.org/
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/
Logging client request PerlLogHandler URI-based init content URI translation fixups file-based init MIME setting resource control http://www.modperlcookbook.org/
Speedy DBI Apache::DBI rocks Reduces connection overhead "Works like magic" (action-at-a-distance) PerlModule Apache::DBI Speeds up both legacy CGI and mod_perl applications http://www.modperlcookbook.org/
Use what you have Programming using the request cycle represents an entirely different way of looking at your web applications Apache provides a rich API for interacting with the request mod_perl passes the savings to you http://www.modperlcookbook.org/
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/~geoff/slides/YAPC My modules http://www.modperlcookbook.org/~geoff/modules http://www.modperlcookbook.org/
http://www.modperlcookbook.org/