The details
If you can't start a discussion of 'my' vs 'local' in perl, better go home,
it could get boring here :-)
The Facts
The code of this site runs within mod_perl inside the Apache daemon. Mason executes
the code in the context of the package HTML::Mason::Commands.
The Setup
I have several name based virtual servers on my host, two of them dedicated to this site:
the production server that you see now and the develepment server that you should not see.
A library external to mason provides constants and common subroutines to both mason and
the external programs such as the search enginge and the events notifier. The library had
it's own package name.
The Mess
I started by simply copying the devel server over to the production
directory, editing only some constants and pathnames. I then soon
noticed that sometimes development stuff showed up in the production
server and vice versa.
The Reason
Different mod_perl applications share the same namespace. So if they're not explicitely
in different packages, the share the same variables. Even if you separate them, they still
should be able to read all the vars, which is a security nightmare. So don't try this in
the wild, kids.
Of course also the library used the same package name in both devel and production and so
I randomly got subroutines from devel and production.
The solution
Separation. Simple.
httpd.conf
Start up via an external handler and give each site an unique name (the domain, in this case).
PerlSetVar sitename pgz.eschle.com
PerlRequire conf/mason-handler.pl
SetHandler perl-script
PerlHandler Com::Eschle::Masonhandler
# output: print error in html, ok for debugging
# fatal: produce a standard html error, ok for production
PerlSetVar MasonErrorMode output
# PerlSetVar MasonErrorMode fatal
conf/mason-handler.pl
Run each instance in a separate packacke (the reverse domain, in this case).
So www.pgz.ch runs under package ch::pgz::www;
#
# A basic, functional Mason handler.pl.
#
use strict;
package Com::Eschle::Masonhandler;
# Bring in Mason with Apache support.
use HTML::Mason::ApacheHandler;
use strict;
# List of modules that you want to use within components.
{ package HTML::Mason::Commands;
use Data::Dumper;
}
# Create ApacheHandler object at startup.
my %ah;
foreach my $site (qw(pgz.eschle.com www.pgz.ch)){
my $package = join('::',reverse(split(/\./,$site)));
$ah{$site} =
HTML::Mason::ApacheHandler->new
(
in_package => $package,
apache_status_title => "$site",
comp_root => "/usr/local/www/$site/www/htdocs",
data_dir => "/usr/local/apache/mason/$site"
);
}
sub handler
{
my ($r) = @_;
my $site = $r->dir_config('sitename');
my $status = $ah{$site}->handle_request($r);
return $status;
}
1;
The library
In the library, set the package also to the reverse domain (and edit when copying).
Now the library routines become part of the applications name space and you can't use
a package name anymore (or you would also have to edit it when copying from devel to production).
To make things not so ugly, I changed all subroutine names in the library to sub lib...
Summary
- Watch your namespace, build a fence around your application. Well, in perl it's more like
a sign reading "please don't enter".
- Don't use mod_perl in a hostile environment where several unfriendliy applications would
share the same httpd and thus the same perl interpreter and thus the same variables.
- Same topic: I have no idea how you could stop mod_perl from accessing the whole server
(as in PHP which allows to limit the range of file operations).
Patrik Eschle, patrik@eschle.com 22. October 2002
and this is where I shop. Not likely to be close to you.
|