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;
Alexander Farber [ Fr, 22 Oktober 2010 17:19 ] [ ID #2049450 ]

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
torsten.foertsch [ Fr, 22 Oktober 2010 19:03 ] [ ID #2049451 ]

Re: Implementing a custom config directive (AP_INIT_TAKE1) inmod_perl 2

Wow, thank you - I'll try it out
Alexander Farber [ Fr, 22 Oktober 2010 20:26 ] [ ID #2049452 ]
Webserver » gmane.comp.apache.mod-perl » Implementing a custom config directive (AP_INIT_TAKE1) in mod_perl 2

Vorheriges Thema: mp2: apache virtual host configuration: error output written todefault error.log-file but virtual h
Nächstes Thema: Path to my module and APR::Socket::send() usage