In the last article we looked at all the tools mod_perl gives us when using it. Now lets take a look at some of the things you can do with those tools. I will be demonstrating what use those tools can be in a real world app. The first thing to do is create our skeleton handler for the app. You can use the handler we put together in the previous article for this. Just replace the contents of the handler subroutine with the code we will be generating here. I'm using my bricklayer framework to demonstrate this but the lessons apply equally well to most other applications. The first thing we need to do is load any libraries we might need. In my case this is just the bricklayer module.

package mod_perl_wrapper; use strict; use warnings FATAL => 'all'; no warnings 'redefine'; use lib "/data/Jeremy/workspace/BrickLayer_Main"; #Apache2 Mod_Perl2 libraries use Apache2::RequestRec (); use Apache2::RequestIO (); use Apache2::Filter (); use Apache2::Const -compile => qw(DECLINED OK); #the apache2 constants we need # Bricklayer Library use BrickLayer (); #my bricklayer module sub handler { } 1;
There a several things to note about the code above. First is the use lib. mod_perl looks in the usual places for your libraries. You might think that just a simple . in the @INC array will make it look in the same location as your handler. However in a mod_perl environment ./ actually refers to the Apache root directory. Therefore it's always a good idea to explicitely tell it any nonstandard library locations in your handler. Also note the mod_perl2 libraries I loaded. These are the most common libraries your app will need so I included them here. Now lets get started building that app shall we? Our handler has several jobs to do.
  1. examine the URL string to see what page was requested
  2. examine and request variables and modify them appropriately
  3. retrieve any post information and send that to the appliaction or provide a way for that application to retrieve it
  4. run the application
To this end we need to know the path_info(), the args(), the contents of read() and be able to pass that information to our application. So lets take a look at accomplishing those tasks now. First we need to see what page was requested. We can get this information from the path_info method of our Apache2::RequestRec object. Once we have retrieved it we can parse out the needed information. In my case I want to look for *.txml files and turn those into a page request in the request string. This will allow me to hit my template files directly without anyone knowing or caring if I use a perl script to parse them first. It makes my URL's friendlier and helps in site tracking. To that end I need to take any .txml files requested and prepend or append them to my request string. Here is an example of just that.
#$[0] is our Apache2::RequestRec object my $pathinfo = ""; $pathinfo .= $[0]->path_info(); return Apache2::Const::DECLINED unless ($pathinfo =~ m/(.txml$)|(/$)/g) or ($pathinfo eq ""); $pathinfo =~ s/^///; $pathinfo =~ s///::/; $pathinfo =~ s/.txml//; #rewrite the request string; $[0]->args("Page=$pathinfo&".$[0]->args()) unless $pathinfo eq ""; #
First we retrieve the pathinfo string and test to make sure it contains a *.txml file at the end. We don't care for this example if there are any at the beginning so we will consider anything else to invalid for us to handle. If there is no .txml at the end then we decline to handle this request and let apache take over. by returning the Apache2::Const::DECLINED constant. If there was a *.txml file requested though then we want to capture that and modify it for use in the bricklayer app. I use a series of substitution expressions to rewrite the path string stripping off the beginning slash and changing all other slashes to "::" so that bricklayer can understand the template request. Once I have rewritten the string I prepend it to the argument list as a Page argument using the args() method. This method both retrieves and lets us set the argument string. One nifty thing about mod_perl environments is that you can freely choose to ignore whether or not you are processing a POST or GET request. This means you can post a form to a request string and still retrieve the request string variables. Something that would have been difficult to do in traditional CGI environment. It also means that when I translate this path request I don't have to worry about whether this was GET or POST request since my cgi wrapper can process both simultaneously. That's really all my handler needs to do now it just calls the bricklayer app and runs it with the new request string. We aren't finished yet though. The next article will cover how I created a CGI wrapper and rewrote CGI_Lite.pm to handle mod_perl requests.