Implementing a custom config directive (AP_INIT_TAKE1) in mod_perl 2
Hello,
I have a simple protocol handler which writes a string to client
socket (source code below).
I would like to make that string configurable through httpd.conf, so
that I could say there:
Listen 843
<VirtualHost _default_:843>
MyPolicyString "<xml>blah</xml>"
PerlModule SocketPolicy
PerlProcessConnectionHandler SocketPolicy
</VirtualHost>
I keep reading http://perl.apache.org/docs/2.0/user/ and other docs,
but just can't find how to do it. Do you use PerlPostConfigHandler for
that and how would I get that string in my
PerlProcessConnectionHandler?
I've noticed, that I could use a Apache2::Directive or a
$r->dir_config("MyPerlVar") but those seem to be slower and are
mod_perl-ish. I would like to use the mod_perl method corresponding to
the command_rec structure in C, where you would use an AP_INIT_TAKE1
(I guess... I'm not an expert here).
Thanks
Alex
package SocketPolicy;
use strict;
use warnings FATAL => 'all';
use APR::Const(-compile => 'SO_NONBLOCK');
use APR::Socket();
use Apache2::ServerRec();
use Apache2::Connection();
use Apache2::Const(-compile => qw(OK DECLINED));
use constant POLICY =>
qq{<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*" to-ports="8080"/>
</cross-domain-policy>
\0};
sub handler {
my $conn = shift;
my $socket = $conn->client_socket();
my $offset = 0;
# set the socket to the blocking mode
$socket->opt_set(APR::Const::SO_NONBLOCK => 0);
# XXX use the policy string coming from httpd.conf XXX
do {
my $nbytes = $socket->send(substr(POLICY, $offset),
length(POLICY) - $offset);
# client connection closed or interrupted
return Apache2::Const::DECLINED unless $nbytes;
$offset += $nbytes;
} while ($offset < length(POLICY));
my $slog = $conn->base_server()->log();
$slog->warn('served socket policy to: ', $conn->remote_ip());
return Apache2::Const::OK;
}
1;
Re: Implementing a custom config directive (AP_INIT_TAKE1) in mod_perl 2
On Friday, October 22, 2010 17:19:15 Alexander Farber wrote:
> Hello,
>
> I have a simple protocol handler which writes a string to client
> socket (source code below).
>
> I would like to make that string configurable through httpd.conf, so
> that I could say there:
>
> Listen 843
> <VirtualHost _default_:843>
> MyPolicyString "<xml>blah</xml>"
> PerlModule SocketPolicy
> PerlProcessConnectionHandler SocketPolicy
> </VirtualHost>
>
> I keep reading http://perl.apache.org/docs/2.0/user/ and other docs,
> but just can't find how to do it. Do you use PerlPostConfigHandler for
> that and how would I get that string in my
> PerlProcessConnectionHandler?
>
> I've noticed, that I could use a Apache2::Directive or a
> $r->dir_config("MyPerlVar") but those seem to be slower and are
> mod_perl-ish. I would like to use the mod_perl method corresponding to
> the command_rec structure in C, where you would use an AP_INIT_TAKE1
> (I guess... I'm not an expert here).
use Apache2::CmdParms ();
use Apache2::Directive ();
use Apache2::Module ();
my [at] directives=3D
(
{
name =3D> 'SocketPolicyString',
req_override =3D> Apache2::Const::RSRC_CONF,
args_how =3D> Apache2::Const::TAKE1,
errmsg =3D> '...',
},
...
);
Apache2::Module::add(__PACKAGE__, \ [at] directives);
sub SocketPolicyString {
my(undef, $parms, $arg)=3D [at] _;
my $cf=3DApache2::Module::get_config(__PACKAGE__, $parms->server);
$cf->{policystring}=3D$arg;
}
# merge merges the configurations of the vhost and the base server to build
# the final config for the vhost. that means here a vhost inherits from the
# base server.
sub SERVER_MERGE {
my ($base, $add)=3D [at] _;
my %merged;
if( exists $add->{policystring} ) {
$merged{policystring}=3D$add->{policystring};
} else {
$merged{policystring}=3D$base->{policystring};
}
return bless \%merged, ref($base);
}
# This is called only if there is at least one directive for the module in =
the
# httpd.conf for the server
sub SERVER_CREATE {
my ($class, $parms)=3D [at] _;
return bless {
policystring=3D>'defaultpolicy',
} =3D> $class;
}
Put something like that outside any function in your module.
In the httpd.conf you need to use PerlLoadModule instead of PerlModule to l=
oad
the module. After that you should be able to use
SocketPolicyString "hugo"
That is a short outline compiled from my memory. I may have missed somethin=
g
here very well.
Then at runtime (in your handler):
$cf=3DApache2::Module::get_config( __PACKAGE__, $conn->base_server );
There is more documentation on this on the site. Search for SERVER_MERGE or=
so.
It is also possible to create container directives which is more convenient=
for the user if the policy string may become longer. The user can then put =
it
as
<SocketPolicyString some parameters>
blah blah
</SocketPolicyString>
The corresponding [at] directives element would look like:
{
name =3D> '<SocketPolicyString',
func =3D> __PACKAGE__.'::SocketPolicyContainer',
req_override =3D> Apache2::Const::RSRC_CONF,
args_how =3D> Apache2::Const::RAW_ARGS,
errmsg =3D> <<'EOF',
<SocketPolicyString ...>
...
</SocketPolicyString>
EOF
},
and you'd have to implement a SocketPolicyContainer function and the
corresponding stuff in SERVER_CREATE/_MERGE as well.
sub SocketPolicyContainer {
my(undef, $parms, $rest)=3D [at] _;
$cf=3DApache2::Module::get_config(__PACKAGE__, $parms->server);
# $rest contains the stuff after "<SocketPolicyString" up to the closing =
">"
# the stuff between the opening and closing "<SocketPolicyString>" lines =
is
# read as $parms->directive->as_string
...
}
You can have both the simple string SocketPolicyString directive and the
container directive at once.
Torsten Förtsch
=2D-
Need professional modperl support? Hire me! (http://foertsch.name)
Like fantasy? http://kabatinte.net
Re: Implementing a custom config directive (AP_INIT_TAKE1) inmod_perl 2
Wow, thank you - I'll try it out