# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # package Apache2::PerlSections; use strict; use warnings FATAL => 'all'; our $VERSION = '2.00'; use Apache2::CmdParms (); use Apache2::Directive (); use APR::Table (); use Apache2::ServerRec (); use Apache2::ServerUtil (); use Apache2::Const -compile => qw(OK); use constant SPECIAL_NAME => 'PerlConfig'; use constant SPECIAL_PACKAGE => 'Apache2::ReadConfig'; sub new { my ($package, @args) = @_; return bless { @args }, ref($package) || $package; } sub parms { return shift->{'parms'} } sub directives { return shift->{'directives'} ||= [] } sub package { return shift->{'args'}->{'package'} } my @saved; sub save { return $Apache2::PerlSections::Save } sub server { return $Apache2::PerlSections::Server } sub saved { return @saved } sub handler : method { my ($self, $parms, $args) = @_; unless (ref $self) { $self = $self->new('parms' => $parms, 'args' => $args); } if ($self->save) { push @saved, $self->package; } my $special = $self->SPECIAL_NAME; for my $entry ($self->symdump()) { if ($entry->[0] !~ /$special/) { $self->dump_any(@$entry); } } { no strict 'refs'; foreach my $package ($self->package) { my @config = map { split /\n/ } grep { defined } (@{"${package}::$special"}, ${"${package}::$special"}); $self->dump_special(@config); } } $self->post_config(); Apache2::Const::OK; } my %directives_seen_hack; sub symdump { my ($self) = @_; unless ($self->{symbols}) { no strict; $self->{symbols} = []; #XXX: Here would be a good place to warn about NOT using # Apache2::ReadConfig:: directly in sections foreach my $pack ($self->package, $self->SPECIAL_PACKAGE) { #XXX: Shamelessly borrowed from Devel::Symdump; while (my ($key, $val) = each(%{ *{"$pack\::"} })) { #We don't want to pick up stashes... next if ($key =~ /::$/); local (*ENTRY) = $val; if (defined $val && defined *ENTRY{SCALAR} && defined $ENTRY) { push @{$self->{symbols}}, [$key, $ENTRY]; } if (defined $val && defined *ENTRY{ARRAY}) { unless (exists $directives_seen_hack{"$key$val"}) { $directives_seen_hack{"$key$val"} = 1; push @{$self->{symbols}}, [$key, \@ENTRY]; } } if (defined $val && defined *ENTRY{HASH} && $key !~ /::/) { push @{$self->{symbols}}, [$key, \%ENTRY]; } } } } return @{$self->{symbols}}; } sub dump_special { my ($self, @data) = @_; $self->add_config(@data); } sub dump_any { my ($self, $name, $entry) = @_; my $type = ref $entry; if ($type eq 'ARRAY') { $self->dump_array($name, $entry); } elsif ($type eq 'HASH') { $self->dump_hash($name, $entry); } else { $self->dump_entry($name, $entry); } } sub dump_hash { my ($self, $name, $hash) = @_; for my $entry (keys %{ $hash || {} }) { my $item = $hash->{$entry}; my $type = ref($item); if ($type eq 'HASH') { $self->dump_section($name, $entry, $item); } elsif ($type eq 'ARRAY') { for my $e (@$item) { $self->dump_section($name, $entry, $e); } } } } sub dump_section { my ($self, $name, $loc, $hash) = @_; $self->add_config("<$name $loc>\n"); for my $entry (keys %{ $hash || {} }) { $self->dump_entry($entry, $hash->{$entry}); } $self->add_config("\n"); } sub dump_array { my ($self, $name, $entries) = @_; for my $entry (@$entries) { $self->dump_entry($name, $entry); } } sub dump_entry { my ($self, $name, $entry) = @_; my $type = ref $entry; if ($type eq 'SCALAR') { $self->add_config("$name $$entry\n"); } elsif ($type eq 'ARRAY') { if (grep {ref} @$entry) { $self->dump_entry($name, $_) for @$entry; } else { $self->add_config("$name @$entry\n"); } } elsif ($type eq 'HASH') { $self->dump_hash($name, $entry); } elsif ($type) { #XXX: Could do $type->can('httpd_config') here on objects ??? die "Unknown type '$type' for directive $name"; } elsif (defined $entry) { $self->add_config("$name $entry\n"); } } sub add_config { my ($self, @config) = @_; foreach my $config (@config) { return unless defined $config; chomp($config); push @{ $self->directives }, $config; } } sub post_config { my ($self) = @_; my $errmsg = $self->parms->add_config($self->directives); die $errmsg if $errmsg; } sub dump { my $class = shift; require Apache2::PerlSections::Dump; return Apache2::PerlSections::Dump->dump(@_); } sub store { my $class = shift; require Apache2::PerlSections::Dump; return Apache2::PerlSections::Dump->store(@_); } 1; __END__