NAME
Apache2::PerlSections - write Apache configuration files in Perl
Synopsis
<Perl>
@PerlModule
=
qw(Mail::Send Devel::Peek)
;
#run the server as whoever starts it
$User
=
getpwuid
(>) || >;
$Group
=
getgrgid
()) || );
$ServerAdmin
=
$User
;
</Perl>
Description
With <Perl>
...</Perl>
sections, it is possible to configure your server entirely in Perl.
<Perl>
sections can contain any and as much Perl code as you wish. These sections are compiled into a special package whose symbol table mod_perl can then walk and grind the names and values of Perl variables/structures through the Apache core configuration gears.
Block sections such as <Location>
..</Location>
are represented in a %Location
hash, e.g.:
<Perl>
$Location
{
"/~dougm/"
} = {
AuthUserFile
=>
'/tmp/htpasswd'
,
AuthType
=>
'Basic'
,
AuthName
=>
'test'
,
DirectoryIndex
=> [
qw(index.html index.htm)
],
Limit
=> {
"GET POST"
=> {
require
=>
'user dougm'
,
}
},
};
</Perl>
If an Apache directive can take two or three arguments you may push strings (the lowest number of arguments will be shifted off the @list
) or use an array reference to handle any number greater than the minimum for that directive:
Other section counterparts include %VirtualHost
, %Directory
and %Files
.
To pass all environment variables to the children with a single configuration directive, rather than listing each one via PassEnv
or PerlPassEnv
, a <Perl>
section could read in a file and:
push
@PerlPassEnv
, [
$key
=>
$val
];
or
Apache2->httpd_conf(
"PerlPassEnv $key $val"
);
These are somewhat simple examples, but they should give you the basic idea. You can mix in any Perl code you desire. See eg/httpd.conf.pl and eg/perl_sections.txt in the mod_perl distribution for more examples.
Assume that you have a cluster of machines with similar configurations and only small distinctions between them: ideally you would want to maintain a single configuration file, but because the configurations aren't exactly the same (e.g. the ServerName
directive) it's not quite that simple.
<Perl>
sections come to rescue. Now you have a single configuration file and the full power of Perl to tweak the local configuration. For example to solve the problem of the ServerName
directive you might have this <Perl>
section:
<Perl>
$ServerName
= `hostname`;
</Perl>
For example if you want to allow personal directories on all machines except the ones whose names start with secure:
<Perl>
$ServerName
= `hostname`;
if
(
$ServerName
!~ /^secure/) {
$UserDir
=
"public.html"
;
}
else
{
$UserDir
=
"DISABLED"
;
}
</Perl>
API
Apache2::PerlSections
provides the following functions and/or methods:
server
Get the current server's object for the <Perl> section
<Perl>
$s
= Apache2::PerlSections->server();
</Perl>
- obj:
Apache2::PerlSections
(class name) - ret:
$s
(Apache2::ServerRec object
) - since: 2.0.03
@PerlConfig
and $PerlConfig
This array and scalar can be used to introduce literal configuration into the apache configuration. For example:
push
@PerlConfig
,
'Alias /foo /bar'
;
Or: $PerlConfig .= "Alias /foo /bar\n";
See also $r->add_config
Configuration Variables
There are a few variables that can be set to change the default behaviour of <Perl>
sections.
$Apache2::PerlSections::Save
Each <Perl>
section is evaluated in its unique namespace, by default residing in a sub-namespace of Apache2::ReadConfig::
, therefore any local variables will end up in that namespace. For example if a <Perl>
section happened to be in file /tmp/httpd.conf starting on line 20, the namespace: Apache2::ReadConfig::tmp::httpd_conf::line_20
will be used. Now if it had:
<Perl>
$foo
= 5;
my
$bar
= 6;
$My::tar
= 7;
</Perl>
The local global variable $foo
becomes $Apache2::ReadConfig::tmp::httpd_conf::line_20::foo
, the other variable remain where they are.
By default, the namespace in which <Perl>
sections are evaluated is cleared after each block closes. In our example nuking $Apache2::ReadConfig::tmp::httpd_conf::line_20::foo
, leaving the rest untouched.
By setting $Apache2::PerlSections::Save
to a true value, the content of those namespaces will be preserved and will be available for inspection by Apache2::Status
and Apache2::PerlSections->dump
In our example $Apache2::ReadConfig::tmp::httpd_conf::line_20::foo
will still be accessible from other perl code, after the <Perl>
section was parsed.
PerlSections Dumping
Apache2::PerlSections->dump
This method will dump out all the configuration variables mod_perl will be feeding to the apache config gears. The output is suitable to read back in via eval
.
my
$dump
= Apache2::PerlSections->
dump
;
- ret:
$dump
( string /undef
) -
A string dump of all the Perl code encountered in <Perl> blocks, suitable to be read back via
eval
For example:
<Perl>
$Apache2::PerlSections::Save
= 1;
$Listen
= 8529;
$Location
{
"/perl"
} = {
SetHandler
=>
"perl-script"
,
PerlHandler
=>
"ModPerl::Registry"
,
Options
=>
"ExecCGI"
,
};
@DirectoryIndex
=
qw(index.htm index.html)
;
$VirtualHost
{
"www.foo.com"
} = {
DocumentRoot
=>
"/tmp/docs"
,
ErrorLog
=>
"/dev/null"
,
Location
=> {
"/"
=> {
Allowoverride
=>
'All'
,
Order
=>
'deny,allow'
,
Deny
=>
'from all'
,
Allow
=>
'from foo.com'
,
},
},
};
</Perl>
<Perl>
Apache2::PerlSections->
dump
;
</Perl>
This will print something like this:
$Listen
= 8529;
@DirectoryIndex
= (
'index.htm'
,
'index.html'
);
$Location
{
'/perl'
} = (
PerlHandler
=>
'Apache2::Registry'
,
SetHandler
=>
'perl-script'
,
Options
=>
'ExecCGI'
);
$VirtualHost
{
'www.foo.com'
} = (
Location
=> {
'/'
=> {
Deny
=>
'from all'
,
Order
=>
'deny,allow'
,
Allow
=>
'from foo.com'
,
Allowoverride
=>
'All'
}
},
DocumentRoot
=>
'/tmp/docs'
,
ErrorLog
=>
'/dev/null'
);
1;
__END__
It is important to put the call to dump
in it's own <Perl>
section, otherwise the content of the current <Perl>
section will not be dumped.
Apache2::PerlSections->store
This method will call the dump
method, writing the output to a file, suitable to be pulled in via require
or do
.
Apache2::PerlSections->store(
$filename
);
Advanced API
mod_perl 2.0 now introduces the same general concept of handlers to <Perl>
sections. Apache2::PerlSections simply being the default handler for them.
To specify a different handler for a given perl section, an extra handler argument must be given to the section:
<Perl handler=
"My::PerlSection::Handler"
somearg=
"test1"
>
$foo
= 1;
$bar
= 2;
</Perl>
And in My/PerlSection/Handler.pm:
sub
My::Handler::handler : handler {
my
(
$self
,
$parms
,
$args
) =
@_
;
#do your thing!
}
So, when that given <Perl>
block in encountered, the code within will first be evaluated, then the handler routine will be invoked with 3 arguments:
- arg1:
$self
-
self-explanatory
- arg2:
$parms
(Apache2::CmdParms
) -
$parms
is specific for the current Container, for example, you might want to call$parms->server()
to get the current server. - arg3:
$args
(APR::Table object
) -
the table object of the section arguments. The 2 guaranteed ones will be:
$args
->{
'handler'
} =
'My::PerlSection::Handler'
;
$args
->{
'package'
} =
'Apache2::ReadConfig'
;
Other
name="value"
pairs given on the<Perl>
line will also be included.
At this point, it's up to the handler routing to inspect the namespace of the $args
->{'package'} and chooses what to do.
The most likely thing to do is to feed configuration data back into apache. To do that, use Apache2::Server->add_config("directive"), for example:
$parms
->server->add_config(
"Alias /foo /bar"
);
Would create a new alias. The source code of Apache2::PerlSections
is a good place to look for a practical example.
Verifying <Perl>
Sections
If the <Perl>
sections include no code requiring a running mod_perl, it is possible to check those from the command line. But the following trick should be used:
# file: httpd.conf
<Perl>
#!perl
# ... code here ...
__END__
</Perl>
Now you can run:
% perl -c httpd.conf
Bugs
<Perl> directive missing closing '>'
httpd-2.0.47 had a bug in the configuration parser which caused the startup failure with the following error:
Starting httpd:
Syntax error on line ... of /etc/httpd/conf/httpd.conf:
<Perl> directive missing closing
'>'
[FAILED]
This has been fixed in httpd-2.0.48. If you can't upgrade to this or a higher version, please add a space before the closing '>' of the opening tag as a workaround. So if you had:
<Perl>
# some code
</Perl>
change it to be:
<Perl >
# some code
</Perl>
<Perl>[...]> was not closed.
On encountering a one-line <Perl> block, httpd's configuration parser will cause a startup failure with an error similar to this one:
Starting httpd:
Syntax error on line ... of /etc/httpd/conf/httpd.conf:
<Perl>
use
> was not closed.
If you have written a simple one-line <Perl> section like this one :
change it to be:
This is caused by a limitation of httpd's configuration parser and is not likely to be changed to allow one-line block like the example above. Use multi-line blocks instead.
See Also
Copyright
mod_perl 2.0 and its core modules are copyrighted under The Apache Software License, Version 2.0.