You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by John Hallam <jo...@mmmi.sdu.dk> on 2008/03/24 15:44:43 UTC

Problem with EXEC_ON_READ, custom block content

 	I'm trying to create a custom block directive, following the 
documentation in the ModPerl2 book (or the on-line documentation).  The 
minimal code for the problem I am seeing is below.  I have the following 
block in apache2.conf for the new block <StdVHost ...> and the module is 
in the /root/apache2 tree as required.

---
PerlSwitches -wT -Mlib=/root/apache2
PerlLoadModule MyApache::StdVHost;

<StdVHost test arguments>

<Directory /var/www >
 	Order deny,allow
 	Deny from all
</Directory>
</StdVHost>
---

 	I see two behaviours:  if EXEC_ON_READ is set, by removing the 
string ', #' in the code below, the handler is never invoked -- at least 
die "..." is not visibly executed;  if EXEC_ON_READ is unset, the handler 
is invoked but $cont is just the first line <Directory /var/www> and not 
the whole block.  Neither is what I wanted :-((.

 	The problem seems to have been reported back in 2005, with similar 
code, and an implication that it was to be fixed.  So what am I doing 
wrong?

Thanks in advance,

 	John Hallam

---
# PERL module for automating a standard virtual host configuration for Apache

package MyApache::StdVHost;

use strict;
use warnings FATAL => 'all';

use Apache2::Const -compile => qw(RSRC_CONF RAW_ARGS EXEC_ON_READ);

use Apache2::CmdParms ();
use Apache2::Module ();
use Apache2::Directive ();

use Apache2::ServerUtil ();

my @directives
    = (
       # Definition of a StdVHost container
       #
       # Note that EXEC_ON_READ is necessary, according to the
       # mod_perl2 book, but in fact breaks things if included
       # by stopping the handler from being called.

       {
 	  name		=> '<StdVHost',
 	  func		=> __PACKAGE__ . '::StdVHost',
 	  errmsg	=> 'StdVHost minimal test package',
 	  args_how	=> Apache2::Const::RAW_ARGS,
 	  req_override	=> Apache2::Const::RSRC_CONF, #| Apache2::Const::EXEC_ON_READ,
       },
      );

Apache2::Module::add( __PACKAGE__, \@directives );

# Handler for the config directive.
#
# It is unclear how to get the content of the <StdVHost> directive
# container:  maybe it has not been read when this routine is called?
# With RAW_ARGS, the first line of the content is available as
# $parms->directive->as_string but how do you get the rest??

sub StdVHost {
     my ($self,$parms,$arg) = @_;
     my $cont = $parms->directive->as_string();

     die "StdVHost arg='$arg' cont='$cont'";
}

1;

Re: Problem with EXEC_ON_READ, custom block content

Posted by Frederic Paillart <Fr...@gemalto.com>.
Hi John,

I've written such custom container few weeks ago,
and meet the same problems as you.

First, don't use the EXEC_ON_READ option.
Indeed, it doesn't work. Unfortunately, I don't know why.
But it doesn't care, you can perform your job  without using it.

I've written a small perl function to solve the as_string issue.

# Unfortunately, directive->as_string doesn't expand
# the content of all embeded sub-containers.
# Because directive->as_string seems to be buggy
# We load the content of the custom container
# by recursing into the directive tree
sub loadContent {
    my ($directive, $contentRef) = @_;

    my @newContent;
    for (my $currentDirective = $directive->first_child; 
$currentDirective; $currentDirective = $currentDirective->next) {
        if ($currentDirective->first_child) {
            my ($containerName) = $currentDirective->directive =~ 
m/<\s*(.+)$/;

            die "Container directive expected instead of " . 
$currentDirective->directive unless ($containerName);

            my $containerBegin = $currentDirective->directive . " " . 
$currentDirective->args;
            push(@newContent, $containerBegin);
            loadContent($currentDirective, \@newContent);
            my $containerEnd = "</" . $containerName . ">";
            push(@newContent, $containerEnd);
        } else {
            my $line = $currentDirective->directive . " " . 
$currentDirective->args;
            push(@newContent, $line);
        }
    }

    push(@$contentRef, @newContent);
}

Finally, you can write your custom container using this function :

use strict;
use warnings FATAL => 'all';
use Apache2::Const -compile => qw(NO_ARGS OR_ALL RAW_ARGS);

use Apache2::CmdParms ();
use Apache2::Module ();
use Apache2::Directive ();
use Apache2::ServerUtil ();

my @directives = (
        {
        name         => '<StdVHost',
        func         => __PACKAGE__ . '::StdVHost',
        req_override => Apache2::Const::OR_ALL,
        args_how     => Apache2::Const::RAW_ARGS,
        errmsg       => 'Std vhosts container',
        },
        {
        name         => '</StdVHost>',
        func         => __PACKAGE__ . "::StdVHost_END",
        errmsg       => 'end of StdVHost without beginning?',
        args_how     => Apache2::Const::NO_ARGS,
        req_override => Apache2::Const::OR_ALL,
        },
        );
Apache2::Module::add(__PACKAGE__, \@directives);

sub StdVHost {
    my ($self, $parms, $arg) = @_;

    # Load the container configuration content
    my $directive = $parms->directive;
    my @content;
    loadContent($directive, \@content);

    # ... Do your custom job
    # For example dynamically add apache configuration directives read 
inside the custom container :
    Apache2::ServerUtil->server->add_config(\@content);
}


sub StdVHost_END {
    die "</StdVHost> outside a <StdVHost> container\n";
}


Hope this example can help you.

Best regards

Fred


Le 23.12.-28158 20:59, John Hallam a �crit :
>
>     I'm trying to create a custom block directive, following the 
> documentation in the ModPerl2 book (or the on-line documentation).  
> The minimal code for the problem I am seeing is below.  I have the 
> following block in apache2.conf for the new block <StdVHost ...> and 
> the module is in the /root/apache2 tree as required.
>
> ---
> PerlSwitches -wT -Mlib=/root/apache2
> PerlLoadModule MyApache::StdVHost;
>
> <StdVHost test arguments>
>
> <Directory /var/www >
>     Order deny,allow
>     Deny from all
> </Directory>
> </StdVHost>
> ---
>
>     I see two behaviours:  if EXEC_ON_READ is set, by removing the 
> string ', #' in the code below, the handler is never invoked -- at 
> least die "..." is not visibly executed;  if EXEC_ON_READ is unset, 
> the handler is invoked but $cont is just the first line <Directory 
> /var/www> and not the whole block.  Neither is what I wanted :-((.
>
>     The problem seems to have been reported back in 2005, with similar 
> code, and an implication that it was to be fixed.  So what am I doing 
> wrong?
>
> Thanks in advance,
>
>     John Hallam
>
> ---
> # PERL module for automating a standard virtual host configuration for 
> Apache
>
> package MyApache::StdVHost;
>
> use strict;
> use warnings FATAL => 'all';
>
> use Apache2::Const -compile => qw(RSRC_CONF RAW_ARGS EXEC_ON_READ);
>
> use Apache2::CmdParms ();
> use Apache2::Module ();
> use Apache2::Directive ();
>
> use Apache2::ServerUtil ();
>
> my @directives
>    = (
>       # Definition of a StdVHost container
>       #
>       # Note that EXEC_ON_READ is necessary, according to the
>       # mod_perl2 book, but in fact breaks things if included
>       # by stopping the handler from being called.
>
>       {
>       name        => '<StdVHost',
>       func        => __PACKAGE__ . '::StdVHost',
>       errmsg    => 'StdVHost minimal test package',
>       args_how    => Apache2::Const::RAW_ARGS,
>       req_override    => Apache2::Const::RSRC_CONF, #| 
> Apache2::Const::EXEC_ON_READ,
>       },
>      );
>
> Apache2::Module::add( __PACKAGE__, \@directives );
>
> # Handler for the config directive.
> #
> # It is unclear how to get the content of the <StdVHost> directive
> # container:  maybe it has not been read when this routine is called?
> # With RAW_ARGS, the first line of the content is available as
> # $parms->directive->as_string but how do you get the rest??
>
> sub StdVHost {
>     my ($self,$parms,$arg) = @_;
>     my $cont = $parms->directive->as_string();
>
>     die "StdVHost arg='$arg' cont='$cont'";
> }
>
> 1;
>