summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Apache/Config/Preproc.pm51
-rw-r--r--lib/Apache/Config/Preproc/ifdefine.pm137
-rw-r--r--t/05ifdefine00.t46
-rw-r--r--t/05ifdefine01.t28
-rw-r--r--t/05ifdefine02.t28
-rw-r--r--t/99all00.t9
6 files changed, 282 insertions, 17 deletions
diff --git a/lib/Apache/Config/Preproc.pm b/lib/Apache/Config/Preproc.pm
index 76afac7..18f0be0 100644
--- a/lib/Apache/Config/Preproc.pm
+++ b/lib/Apache/Config/Preproc.pm
@@ -98,7 +98,7 @@ Apache::Config::Preproc - Preprocess Apache configuration files
use Apache::Config::Preproc;
$x = new Apache::Config::Preproc '/path/to/httpd.conf',
- -expand => [ qw(include compact macro ifmodule) ]
+ -expand => [ qw(include compact macro ifmodule ifdefine) ]
or die $Apache::Admin::Config::ERROR;
=head1 DESCRIPTION
@@ -108,7 +108,7 @@ file, expanding the syntactic constructs selected by the B<-expand> option.
In the simplest case, the argument to that option is a reference to the
list of names. Each name in the list identifies a module responsible for
processing specific Apache configuration keywords. For convenience, most
-modules are named after the keyword they process, so that B<include> is
+modules are named after the keyword they process, so that, e.g. B<include> is
responsible for inclusion of the files listed with B<Include> and
B<IncludeOptional> statements. The list of built-in module names follows:
@@ -127,25 +127,29 @@ with the content of the corresponding files.
Expands the B<E<lt>IfModuleE<gt>> statements.
+=item B<ifdefine>
+
+Expands the B<E<lt>IfDefineE<gt>> statements.
+
=item B<macro>
Expands the B<E<lt>MacroE<gt>> statements.
=back
-See the section B<PREPROCESSING> for a detailed description of these modules.
+See the section B<MODULES> for a detailed description of these modules.
New modules can be easily implemented by supplying a corresponding
-expansion module (see the section B<MODULES> below).
+expansion module (see the section B<MODULE INTERNALS> below).
If the B<-expand> argument is not supplied, the following default is
used:
[ 'include' ]
-Rest of module functionality is inherited from B<Apache::Admin::Config>.
+The rest of methods is inherited from B<Apache::Admin::Config>.
-=head1 METHODS
+=head1 CONSTRUCTOR
=head2 new
@@ -161,11 +165,11 @@ keywords are:
=item B<-expand> =E<gt> I<$arrayref>
-Define what expansions are to be performed. Argument is a reference to
-array of module names with optional parameters. To specify parameters,
-use either list reference where the first element is the module
+Define what expansions are to be performed. B<$arrayref> is a reference to
+array of module names with optional arguments. To supply arguments,
+use either a list reference where the first element is the module
name and rest of elements are arguments, or a hash reference with the name
-of the module as a key and a reference to the list of arguments as its value.
+of the module as key and a reference to the list of arguments as its value.
Consider, for example:
-expand => [ 'include', { ifmodule => { probe => 1 } } ]
@@ -226,6 +230,10 @@ Same as comment grouping but for blank lines.
=back
+=head1 METHODS
+
+All methods are inherited from B<Apache::Admin::Config>.
+
=head1 MODULES
The preprocessing phases to be performed on the parsed configuration text are
@@ -291,6 +299,17 @@ The option
is a shorthand for
probe => [qw(/usr/sbin/httpd /usr/sbin/apache2)]
+
+=back
+
+=head2 ifdefine
+
+Eliminates the B<Define> and B<UnDefine> statements and expands the
+B<E<lt>IfDefineE<gt>> statements in the Apache configuration parse
+tree. Optional arguments to the constructor are treated as the names
+of symbols to define (similar to the B<httpd> B<-D> options). Example:
+
+ -expand => [ { ifdefine => [ qw(SSL FOREGROUND) ] } ]
=head2 macro
@@ -335,12 +354,12 @@ expansion is to be stored.
=back
-The function returns true if if did process the I<$subtree>. In this case,
+The function returns true if it did process the I<$subtree>. In this case,
the subtree will be removed from the parse tree and the items from B<@$repl>
-will be inserted instead. Thus, to simply remove the I<$subtree> the B<expand>
-method must return true and not touch I<$repl>. For example, the following
-is the B<expand> method definition from the B<Apache::Config::Preproc::compact>
-module:
+will be inserted in its place. Thus, to simply remove the I<$subtree> the
+B<expand> method must return true and not touch I<$repl>. For example, the
+following is the B<expand> method definition from the
+B<Apache::Config::Preproc::compact> module:
sub expand {
my ($self, $d, $repl) = @_;
@@ -348,7 +367,7 @@ module:
}
Notice, that B<expand> does not need to recurse into section objects. This
-will be done by the caller.
+is taken care of by the caller.
=head1 EXAMPLE
diff --git a/lib/Apache/Config/Preproc/ifdefine.pm b/lib/Apache/Config/Preproc/ifdefine.pm
new file mode 100644
index 0000000..834d602
--- /dev/null
+++ b/lib/Apache/Config/Preproc/ifdefine.pm
@@ -0,0 +1,137 @@
+package Apache::Config::Preproc::ifdefine;
+use strict;
+use warnings;
+use Carp;
+
+sub new {
+ my $class = shift;
+ my $conf = shift;
+ my $self = bless {}, $class;
+ @{$self->{D}}{@_} = (1) x @_;
+ return $self;
+}
+
+sub find_define {
+ my ($self,$elt,$id) = @_;
+
+ while (my $p = $elt->parent) {
+ if (grep {
+ (split /\s+/, $_->value)[0] eq $id
+ } $p->directive('define')) {
+ return 1;
+ }
+ }
+ return;
+}
+
+sub _changed_in_section {
+ my ($self, $section, $id, $before) = @_;
+ foreach my $d (reverse $section->select) {
+ if ($before) {
+ if ($d == $before) {
+ $before = undef;
+ }
+ next;
+ }
+
+ if ($d->type eq 'directive') {
+ if ($d->name =~ m/^(un)?define$/i && $d->value eq $id) {
+ if ($1) {
+ $self->undefine($id);
+ } else {
+ $self->define($id);
+ }
+ return 1;
+ }
+ } elsif ($d->type eq 'section' && lc($d->name) eq 'virtualhost') {
+ # Need to descend into VirtualHost, because accorind to the
+ # Apache docs
+ # see (https://httpd.apache.org/docs/2.4/mod/core.html#define):
+ #
+ # While [the Define] directive is supported in virtual host
+ # context, the changes it makes are visible to any later
+ # configuration directives, beyond any enclosing virtual host.
+ #
+ # The same is said about the UnDefine directive.
+
+ return 1 if $self->_changed_in_section($d, $id);
+ }
+ }
+ return 0;
+}
+
+sub is_defined {
+ my ($self,$id,$d) = @_;
+
+ unless ($self->{D}{$id}) {
+ my $before = $d;
+ while ($d = $d->parent) {
+ last if $self->_changed_in_section($d, $id, $before);
+ $before = undef;
+ }
+ }
+ return $self->{D}{$id};
+}
+
+sub define {
+ my ($self,$id) = @_;
+ $self->{D}{$id} = 1;
+}
+
+sub undefine {
+ my ($self,$id) = @_;
+ delete $self->{D}{$id};
+}
+
+sub expand {
+ my ($self, $d, $repl) = @_;
+ if ($d->type eq 'section') {
+ if (lc($d->name) eq 'ifdefine') {
+ my $id = $d->value;
+ my $negate = $id =~ s/^!//;
+ my $res = $self->is_defined($id, $d);
+ $res = !$res if $negate;
+ if ($res) {
+ push @$repl, $d->select;
+ }
+ return 1;
+ }
+ }
+ if ($d->type eq 'directive') {
+ my $name = lc($d->name);
+ if ($name eq 'define') {
+ $self->define($d->value);
+ return 1;
+ } elsif ($name eq 'undefine') {
+ $self->undefine($d->value);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Apache::Config::Preproc::ifmodule - expand IfDefine sections
+
+=head1 SYNOPSIS
+
+ $x = new Apache::Config::Preproc '/path/to/httpd.conf',
+ -expand => [ qw(ifdefine) ];
+
+ $x = new Apache::Config::Preproc '/path/to/httpd.conf',
+ -expand => [
+ { ifdefine => [qw(SYM1 SYM2)] }
+ ];
+
+=head1 DESCRIPTION
+
+Eliminates the B<Define> and B<UnDefine> statements and expands the
+B<E<lt>IfDefineE<gt>> statements in the Apache configuration parse
+tree. Optional arguments to the constructor are treated as the names
+of symbols to define (similar to the B<httpd> B<-D> options).
+
+
diff --git a/t/05ifdefine00.t b/t/05ifdefine00.t
new file mode 100644
index 0000000..e488101
--- /dev/null
+++ b/t/05ifdefine00.t
@@ -0,0 +1,46 @@
+# -*- perl -*-
+use lib qw(t lib);
+use strict;
+use Test;
+plan test => 3;
+
+use TestPreproc;
+
+my $obj = new TestPreproc -expand => ['ifdefine'];
+ok($obj->dump_raw, $obj->dump_expect);
+
+my $obj = new TestPreproc -expand => [ { ifdefine => [qw(VAR)] } ];
+ok($obj->dump_raw, $obj->dump_expect);
+
+my $obj = new TestPreproc -expand => ['ifdefine'];
+ok($obj->dump_raw, $obj->dump_expect);
+
+__DATA__
+!>httpd.conf
+ServerAdmin foo
+<IfDefine VAR>
+ ServerName localhost
+</IfDefine>
+!=
+ServerAdmin foo
+!$
+__END__
+!>httpd.conf
+ServerAdmin foo
+<IfDefine VAR>
+ ServerName localhost
+</IfDefine>
+!=
+ServerAdmin foo
+ ServerName localhost
+!$
+__END__
+!>httpd.conf
+ServerAdmin foo
+<IfDefine !VAR>
+ ServerName localhost
+</IfDefine>
+!=
+ServerAdmin foo
+ ServerName localhost
+!$
diff --git a/t/05ifdefine01.t b/t/05ifdefine01.t
new file mode 100644
index 0000000..da2e5f9
--- /dev/null
+++ b/t/05ifdefine01.t
@@ -0,0 +1,28 @@
+# -*- perl -*-
+use lib qw(t lib);
+use strict;
+use Test;
+plan test => 1;
+
+use TestPreproc;
+
+my $obj = new TestPreproc -expand => ['ifdefine'];
+ok($obj->dump_raw, $obj->dump_expect);
+
+__DATA__
+!>httpd.conf
+Define FOO
+ServerName localhost
+<IfDefine FOO>
+ ServerAlias remote
+</IfDefine>
+UnDefine FOO
+DocumentRoot /var
+<IfDefine FOO>
+ Require all granted
+</IfDefine>
+!=
+ServerName localhost
+ ServerAlias remote
+DocumentRoot /var
+!$ \ No newline at end of file
diff --git a/t/05ifdefine02.t b/t/05ifdefine02.t
new file mode 100644
index 0000000..030ca7b
--- /dev/null
+++ b/t/05ifdefine02.t
@@ -0,0 +1,28 @@
+# -*- perl -*-
+use lib qw(t lib);
+use strict;
+use Test;
+plan test => 1;
+
+use TestPreproc;
+
+my $obj = new TestPreproc -expand => ['ifdefine'];
+ok($obj->dump_raw, $obj->dump_expect);
+
+__DATA__
+!>httpd.conf
+<VirtualHost bar>
+ ServerName localhost
+ ServerAdmin root
+ Define FOO
+</VirtualHost>
+<IfDefine FOO>
+ Alias /foo /bar
+</IfDefine>
+!=
+<VirtualHost bar>
+ ServerName localhost
+ ServerAdmin root
+</VirtualHost>
+ Alias /foo /bar
+!$
diff --git a/t/99all00.t b/t/99all00.t
index a70dd6a..cf79c27 100644
--- a/t/99all00.t
+++ b/t/99all00.t
@@ -6,7 +6,7 @@ plan test => 1;
use TestPreproc;
-my $obj = new TestPreproc -expand => [qw(compact include ifmodule macro)];
+my $obj = new TestPreproc -expand => [qw(compact include ifmodule macro ifdefine)];
ok($obj->dump_raw, $obj->dump_expect);
__DATA__
!>httpd.conf
@@ -19,6 +19,10 @@ Include conf.d/*.conf
Include mpm.conf
Include log.conf
Include vhost.conf
+Include def.conf
+<IfDefine FOO>
+ Listen 8080
+</IfDefine>
Timeout 300
!>conf.d/load.conf
# Load prefork mpm
@@ -39,6 +43,8 @@ LoadModule logio_module lib/httpd/modules/mod_logio.so
</VirtualHost>
</Macro>
+!>def.conf
+Define FOO
!>mpm.conf
<IfModule !mpm_netware_module>
PidFile "/var/run/httpd.pid"
@@ -124,5 +130,6 @@ LoadModule logio_module lib/httpd/modules/mod_logio.so
Require all granted
</Directory>
</VirtualHost>
+ Listen 8080
Timeout 300
!$

Return to:

Send suggestions and report system problems to the System administrator.