Implementing a custom config directive (AP_INIT_TAKE1) in mod_perl 2

Implementing a custom config directive (AP_INIT_TAKE1) in mod_perl 2

am 22.10.2010 17:19:15 von Alexander Farber

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

MyPolicyString "blah"
PerlModule SocketPolicy
PerlProcessConnectionHandler SocketPolicy


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{
"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">



\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

am 22.10.2010 19:03:32 von torsten.foertsch

On Friday, October 22, 2010 17:19:15 Alexander Farber wrote:
> Hello,
>=20
> I have a simple protocol handler which writes a string to client
> socket (source code below).
>=20
> I would like to make that string configurable through httpd.conf, so
> that I could say there:
>=20
> Listen 843
>
> MyPolicyString "blah"
> PerlModule SocketPolicy
> PerlProcessConnectionHandler SocketPolicy
>

>=20
> 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?
>=20
> 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 @directives=3D
(
{
name =3D> 'SocketPolicyString',
req_override =3D> Apache2::Const::RSRC_CONF,
args_how =3D> Apache2::Const::TAKE1,
errmsg =3D> '...',
},
...
);
Apache2::Module::add(__PACKAGE__, \@directives);

sub SocketPolicyString {
my(undef, $parms, $arg)=3D@_;
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@_;
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@_;

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=20
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=20
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=
=20
so.

It is also possible to create container directives which is more convenient=
=20
for the user if the policy string may become longer. The user can then put =
it=20
as


blah blah


The corresponding @directives element would look like:
{
name =3D> ' func =3D> __PACKAGE__.'::SocketPolicyContainer',
req_override =3D> Apache2::Const::RSRC_CONF,
args_how =3D> Apache2::Const::RAW_ARGS,
errmsg =3D> <<'EOF',

...

EOF
},

and you'd have to implement a SocketPolicyContainer function and the=20
corresponding stuff in SERVER_CREATE/_MERGE as well.

sub SocketPolicyContainer {
my(undef, $parms, $rest)=3D@_;
$cf=3DApache2::Module::get_config(__PACKAGE__, $parms->server);

# $rest contains the stuff after " ">"
# the stuff between the opening and closing "" lines =
is
# read as $parms->directive->as_string
...
}

You can have both the simple string SocketPolicyString directive and the=20
container directive at once.

Torsten Förtsch

=2D-=20
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

am 22.10.2010 20:26:13 von Alexander Farber

Wow, thank you - I'll try it out