views:

143

answers:

2

Is it possible to have an apache mod_perl handler, which receives all incoming requests and decides based upon a set of rules if this request is something it wants to act upon, and if not, return control to apache which would serve the request as normal?

A use-case:

A legacy site which uses DirectoryIndex for serving index.html (or similar) and default handlers for perl scripts etc, is being given a freshened up url-scheme (django/catalyst-ish). A dispatcher will have a set of urls mapped to controllers that are dispatched based on the incoming url.

However, the tricky part is having this dispatcher within the same namespace on the same vhost as the old site. The thought is to rewrite the site piece by piece, as a "update all" migration gives no chance in testing site performance with the new system, nor is it feasible due to the sheer size of the site.

One of the many problems, is that the dispatcher now receives all URLs as expected, but DirectoryIndex and static content (which is mostly served by a different host, but not everything) is not served properly. The dispatcher returns an Apache::Const::DECLINED for non-matching urls, but Apache does not continue to serve the request as it normally would, but instead gives the default error page. Apache does not seem to try to look for /index.html etc.

How can this be solved? Do you need to use internal redirects? Change the handler stack in the dispatcher? Use some clever directives? All of the above? Not possible at all?

All suggestions are welcome!

A: 

Maybe you will have success using a mod_rewrite configuration which only does rewrite URLs to your dispatcher if a requested file does not exist in the file system. That way your new application acts as an overlay to the old application and can be replaced in successive steps by just removing old parts of the application during deployment of new parts.

This can be accomblished by a combination of RewriteCond and RewriteRule. Your new application needs to sit in a private "namespace" (location) not otherwise used in the old application.

I am not a mod_perl expert but with eg mod_php it could work like this:

RewriteEngine on

# do not rewrite requests into the new application(s) / namespaces
RewriteRule ^new_app/ - [L]

# do not rewrite requests to existing file system objects
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l

# do the actual rewrite here
RewriteRule ^(.*)$ new_app/dispatcher.php/$1
hurikhan77
I have been thinking about the solution you suggest, but I can't quuuite see how to solve it with rewrites. I was first thinking about having the dispatcher handle "all" requests, but I guess it's smarter for it to handle all "missing" requests, meaning, all requests not found either by DirectoryIndex or explicit file/mime-type handlers. That means that Apache must call the dispatcher as a last resort, at the time it would normally give a 404. Then, if even the dispatcher declines, a 404 is given.
myme
I added an example of the proposed rewrite configuration
hurikhan77
A: 

I have done a similar thing but a while back, so I might be a little vague:

  • I think you need to have the standard file handler (I believe this is done using the set-handler directive) as well as the perl handler in the stack
  • You might need to use PerlTransHandler or a similar one to hook into the filename/url mapping phase and make sure the next handler inline will pick the right file up off the filesystem.
Maxwell Troy Milton King
A quick update on this for those interested. I added a PerlTransHandler to point to MyClass::handler, in which I check all the URLs against $r->uri(). If there's a match, do: $r->handler('perl-script'); $r->set_handlers(PerlResponseHandler => sub { $self->dispatch(); }); Return value depends on desired behavior. If there's no match just return Apache2::Const::DECLINED.
myme