File Coverage

blib/lib/Apache/ConfigParser.pm
Criterion Covered Total %
statement 242 312 77.5
branch 108 150 72.0
condition 37 65 56.9
subroutine 21 22 95.4
pod 8 9 88.8
total 416 558 74.5


line stmt bran cond sub pod time code
1             # Apache::ConfigParser: Load Apache configuration file.
2             #
3             # Copyright (C) 2001-2005 Blair Zajac. All rights reserved.
4              
5             package Apache::ConfigParser;
6              
7             require 5.004_05;
8              
9 1     1   24328 use strict;
  1         1  
  1         58  
10              
11             =head1 NAME
12              
13             Apache::ConfigParser - Load Apache configuration files
14              
15             =head1 SYNOPSIS
16              
17             use Apache::ConfigParser;
18              
19             # Create a new empty parser.
20             my $c1 = Apache::ConfigParser->new;
21              
22             # Load an Apache configuration file.
23             my $rc = $c1->parse_file('/etc/httpd/conf/httpd.conf');
24              
25             # If there is an error in parsing the configuration file, then $rc
26             # will be false and an error string will be available.
27             if (not $rc) {
28             print $c1->errstr, "\n";
29             }
30              
31             # Get the root of a tree that represents the configuration file.
32             # This is an Apache::ConfigParser::Directive object.
33             my $root = $c1->root;
34              
35             # Get all of the directives and starting of context's.
36             my @directives = $root->daughters;
37              
38             # Get the first directive's name.
39             my $d_name = $directives[0]->name;
40              
41             # This directive appeared in this file, which may be in an Include'd
42             # or IncludeOptional'd file.
43             my $d_filename = $directives[0]->filename;
44              
45             # And it begins on this line number.
46             my $d_line_number = $directives[0]->line_number;
47              
48             # Find all the CustomLog entries, regardless of context.
49             my @custom_logs = $c1->find_down_directive_names('CustomLog');
50              
51             # Get the first CustomLog.
52             my $custom_log = $custom_logs[0];
53              
54             # Get the value in string form.
55             $custom_log_args = $custom_log->value;
56              
57             # Get the value in array form already split.
58             my @custom_log_args = $custom_log->get_value_array;
59              
60             # Get the same array but a reference to it.
61             my $customer_log_args = $custom_log->value_array_ref;
62              
63             # The first value in a CustomLog is the filename of the log.
64             my $custom_log_file = $custom_log_args->[0];
65              
66             # Get the original value before the path has been made absolute.
67             @custom_log_args = $custom_log->get_orig_value_array;
68             $customer_log_file = $custom_log_args[0];
69              
70             # Here is a more complete example to load an httpd.conf file and add
71             # a new VirtualHost directive to it.
72             #
73             # The Apache::ConfigParser object contains a reference to a
74             # Apache::ConfigParser::Directive object, which can be obtained by
75             # using Apache::ConfigParser->root. The root node is a
76             # Apache::ConfigParser::Directive which ISA Tree::DAG_Node (that is
77             # Apache::ConfigParser::Directive's @ISA contains Tree::DAG_Node).
78             # So to get the root node and add a new directive to it, it could be
79             # done like this:
80              
81             my $c = Apache::ConfigParser->new;
82             my $rc = $c->parse_file('/etc/httpd.conf');
83             my $root = $c->root;
84             my $new_virtual_host = $root->new_daughter;
85             $new_virtual_host->name('VirtualHost');
86             $new_virtual_host->value('*');
87              
88             # The VirtualHost is called a "context" that contains other
89             # Apache::ConfigParser::Directive's:
90              
91             my $server_name = $new_virtual_host->new_daughter;
92             $server_name->name('ServerName');
93             $server_name->value('my.hostname.com');
94              
95             =head1 DESCRIPTION
96              
97             The C module is used to load an Apache
98             configuration file to allow programs to determine Apache's
99             configuration directives and contexts. The resulting object contains
100             a tree based structure using the C
101             class, which is a subclass of C, so all of the methods
102             that enable tree based searches and modifications from
103             C are also available. The tree structure is used to
104             represent the ability to nest sections, such as ,
105             , etc.
106              
107             Apache does a great job of checking Apache configuration files for
108             errors and this modules leaves most of that to Apache. This module
109             does minimal configuration file checking. The module currently checks
110             for:
111              
112             =over 4
113              
114             =item Start and end context names match
115              
116             The module checks if the start and end context names match. If the
117             end context name does not match the start context name, then it is
118             ignored. The module does not even check if the configuration contexts
119             have valid names.
120              
121             =back
122              
123             =head1 PARSING
124              
125             Notes regarding parsing of configuration files.
126              
127             Line continuation is treated exactly as Apache 1.3.20. Line
128             continuation occurs only when the line ends in [^\\]\\\r?\n. If the
129             line ends in two \'s, then it will replace the two \'s with one \ and
130             not continue the line.
131              
132             =cut
133              
134 1     1   5 use Exporter;
  1         1  
  1         39  
135 1     1   4 use Carp;
  1         1  
  1         61  
136 1     1   484 use Symbol;
  1         697  
  1         76  
137 1     1   397 use File::FnMatch 0.01 qw(fnmatch);
  1         627  
  1         85  
138 1     1   6 use File::Spec 0.82;
  1         20  
  1         25  
139 1         192 use Apache::ConfigParser::Directive qw(DEV_NULL
140 1     1   454 %directive_value_path_element_pos);
  1         2  
141              
142 1     1   4 use vars qw(@ISA $VERSION);
  1         2  
  1         87  
143             @ISA = qw(Exporter);
144             $VERSION = '1.02';
145              
146             # This constant is used throughout the module.
147             my $INCORRECT_NUMBER_OF_ARGS = "passed incorrect number of arguments.\n";
148              
149             # Determine if the filenames are case sensitive.
150 1     1   5 use constant CASE_SENSITIVE_PATH => (! File::Spec->case_tolerant);
  1         2  
  1         2851  
151              
152             =head1 METHODS
153              
154             The following methods are available:
155              
156             =over 4
157              
158             =item $c = Apache::ConfigParser->new
159              
160             =item $c = Apache::ConfigParser->new({options})
161              
162             Create a new C object that stores the content of
163             an Apache configuration file. The first optional argument is a
164             reference to a hash that contains options to new.
165              
166             The currently recognized options are:
167              
168             =over 4
169              
170             =item pre_transform_path_sub => sub { }
171              
172             =item pre_transform_path_sub => [sub { }, @args]
173              
174             This allows the file or directory name for any directive that takes
175             either a filename or directory name to be transformed by an arbitrary
176             subroutine before it is made absolute with ServerRoot. This
177             transformation is applied to any of the directives that appear in
178             C<%Apache::ConfigParser::Directive::directive_value_takes_path> that
179             have a filename or directory value instead of a pipe or syslog value,
180             i.e. "| cronolog" or "syslog:warning".
181              
182             If the second form of C is used with an array
183             reference, then the first element of the array reference must be a
184             subroutine reference followed by zero or more arbitrary arguments.
185             Any array elements following the subroutine reference are passed to
186             the specified subroutine.
187              
188             The subroutine is passed the following arguments:
189              
190             Apache::ConfigParser object
191             lowercase string of the configuration directive
192             the file or directory name to transform
193             @args
194              
195             NOTE: Be careful, because this subroutine will be applied to
196             ServerRoot and DocumentRoot, among other directives. See
197             L for the complete list of directives
198             that C is applied to. If you do not want the
199             transformation applied to any specific directives, make sure to check
200             the directive name and if you do not want to modify the filename,
201             return the subroutine's third argument.
202              
203             If the subroutine returns an undefined value or a value with 0 length,
204             then it is replaced with C<< File::Spec->devnull >> which is the
205             appropriate 0 length file for the operating system. This is done to
206             keep a value in the directive name since otherwise the directive may
207             not work properly. For example, with the input
208              
209             CustomLog logs/access_log combined
210              
211             and if C were to replace 'logs/access_log'
212             with '', then
213              
214             CustomLog combined
215              
216             would no longer be a valid directive. Instead,
217              
218             CustomLog Cdevnull> combined
219              
220             would be appropriate for all systems.
221              
222             =item post_transform_path_sub => sub { }
223              
224             =item post_transform_path_sub => [sub { }, @args]
225              
226             This allows the file or directory name for any directive that takes
227             either a filename or directory name to be transformed by this
228             subroutine after it is made absolute with ServerRoot. This
229             transformation is applied to any of the directives that appear in
230             C<%Apache::ConfigParser::Directive::directive_value_takes_path> that
231             have a filename or directory value instead of a pipe or syslog value,
232             i.e. "| cronolog" or "syslog:warning".
233              
234             If the second form of C is used with an array
235             reference, then the first element of the array reference must be a
236             subroutine reference followed by zero or more arbitrary arguments.
237             Any array elements following the subroutine reference are passed to
238             the specified subroutine.
239              
240             The subroutine is passed the following arguments:
241              
242             Apache::ConfigParser object
243             lowercase version of the configuration directive
244             the file or directory name to transform
245             @args
246              
247             NOTE: Be careful, because this subroutine will be applied to
248             ServerRoot and DocumentRoot, among other directives. See
249             L for the complete list of directives
250             that C is applied to. If you do not want the
251             transformation applied to any specific directives, make sure to check
252             the directive name and if you do not want to modify the filename,
253             return the subroutine's third argument.
254              
255             If the subroutine returns an undefined value or a value with 0 length,
256             then it is replaced with C<< File::Spec->devnull >> which is the
257             appropriate 0 length file for the operating system. This is done to
258             keep a value in the directive name since otherwise the directive may
259             not work properly. For example, with the input
260              
261             CustomLog logs/access_log combined
262              
263             and if C were to replace 'logs/access_log'
264             with '', then
265              
266             CustomLog combined
267              
268             would no longer be a valid directive. Instead,
269              
270             CustomLog Cdevnull> combined
271              
272             would be appropriate for all systems.
273              
274             =back
275              
276             One example of where the transformations is useful is when the Apache
277             configuration directory on one host is NFS exported to another host
278             and the remote host parses the configuration file using
279             C and the paths to the access logs must be
280             transformed so that the remote host can properly find them.
281              
282             =cut
283              
284             sub new {
285 9 50   9 1 19430 unless (@_ < 3) {
286 0         0 confess "$0: Apache::ConfigParser::new $INCORRECT_NUMBER_OF_ARGS";
287             }
288              
289 9         23 my $class = shift;
290 9   33     61 $class = ref($class) || $class;
291              
292             # This is the root of the tree that holds all of the directives and
293             # contexts in the Apache configuration file. Also keep track of the
294             # current node in the tree so that when options are parsed the code
295             # knows the context to insert them.
296 9         85 my $root = Apache::ConfigParser::Directive->new;
297 9         52 $root->name('root');
298              
299 9         69 my $self = bless {
300             current_node => $root,
301             root => $root,
302             server_root => '',
303             post_transform_path_sub => '',
304             pre_transform_path_sub => '',
305             errstr => '',
306             }, $class;
307              
308 9 100       30 return $self unless @_;
309              
310 2         6 my $options = shift;
311 2 50 33     19 unless (defined $options and UNIVERSAL::isa($options, 'HASH')) {
312 0         0 confess "$0: Apache::ConfigParser::new not passed a HASH reference as ",
313             "its first argument.\n";
314             }
315              
316 2         7 foreach my $opt_name (qw(pre_transform_path_sub post_transform_path_sub)) {
317 4 100       15 if (my $opt_value = $options->{$opt_name}) {
318 2 100       15 if (UNIVERSAL::isa($opt_value, 'CODE')) {
    50          
319 1         5 $self->{$opt_name} = [$opt_value];
320             } elsif (UNIVERSAL::isa($opt_value, 'ARRAY')) {
321 1 50 33     15 if (@$opt_value and UNIVERSAL::isa($opt_value->[0], 'CODE')) {
322 1         5 $self->{$opt_name} = $opt_value;
323             } else {
324 0         0 confess "$0: Apache::ConfigParser::new passed an ARRAY reference ",
325             "whose first element is not a CODE ref for '$opt_name'.\n";
326             }
327             } else {
328 0         0 warn "$0: Apache::ConfigParser::new not passed an ARRAY or CODE ",
329             "reference for '$opt_name'.\n";
330             }
331             }
332             }
333              
334 2         8 return $self;
335             }
336              
337             =item $c->DESTROY
338              
339             There is an explicit DESTROY method for this class to destroy the
340             tree, since it has cyclical references.
341              
342             =cut
343              
344             sub DESTROY {
345 9     9   346287 $_[0]->{root}->delete_tree;
346             }
347              
348             # Apache 1.3.27 and 2.0.41 check if the AccessConfig, Include or
349             # ResourceConfig directives' value contains a glob. Duplicate the
350             # exact same check here.
351             sub path_has_apache_style_glob {
352 19 50   19 0 50 unless (@_ == 1) {
353 0         0 confess "$0: Apache::ConfigParser::path_has_apache_style_glob ",
354             $INCORRECT_NUMBER_OF_ARGS;
355             }
356              
357 19         23 my $path = shift;
358              
359             # Apache 2.0.53 skips any \ protected characters in the path and
360             # then tests if the path is a glob by looking for ? or * characters
361             # or a [ ] pair.
362 19         38 $path =~ s/\\.//g;
363              
364 19   66     126 return $path =~ /[?*]/ || $path =~ /\[.*\]/;
365             }
366              
367             # Handle the AccessConfig, Include, IncludeOptional or ResourceConfig
368             # directives. Support the Apache 1.3.13 behavior where if the path is
369             # a directory then Apache will recursively load all of the files in
370             # that directory. Support the Apache 1.3.27 and 2.0.41 behavior where
371             # if the path contains any glob characters, then load the files and
372             # directories recursively that match the glob.
373             sub _handle_include_directive {
374 15 50   15   36 unless (@_ == 5) {
375 0         0 confess "$0: Apache::ConfigParser::_handle_include_directive ",
376             $INCORRECT_NUMBER_OF_ARGS;
377             }
378              
379 15         31 my ($self, $file_or_dir_name, $line_number, $directive, $path) = @_;
380              
381             # Apache 2.0.53 tests if the path is a glob and does a glob search
382             # if it is. Otherwise, it treats the path as a file or directory
383             # and opens it directly.
384 15         15 my @paths;
385 15 100       37 if (path_has_apache_style_glob($path)) {
386             # Apache splits the path into the dirname and basename portions
387             # and then checks that the dirname is not a glob and the basename
388             # is. It then matches the files in the dirname against the glob
389             # in the basename and generates a list from that. Duplicate this
390             # code here.
391 2         12 my ($dirname,
392             $separator,
393             $basename) = $path =~ m#(.*)([/\\])+([^\2]*)$#;
394 2 50 33     13 unless (defined $separator and length $separator) {
395 0         0 $self->{errstr} = "'$file_or_dir_name' line $line_number " .
396             "'$directive $path': cannot split path into " .
397             "dirname and basename";
398 0         0 return;
399             }
400 2 50       3 if (path_has_apache_style_glob($dirname)) {
401 0         0 $self->{errstr} = "'$file_or_dir_name' line $line_number " .
402             "'$directive $path': dirname '$dirname' is a glob";
403 0         0 return;
404             }
405 2 50       3 unless (path_has_apache_style_glob($basename)) {
406 0         0 $self->{errstr} = "'$file_or_dir_name' line $line_number " .
407             "'$directive $path': basename '$basename' is " .
408             "not a glob";
409 0         0 return;
410             }
411 2 100       39 unless (opendir(DIR, $dirname)) {
412 1         17 $self->{errstr} = "'$file_or_dir_name' line $line_number " .
413             "'$directive $path': opendir '$dirname' " .
414             "failed: $!";
415             # Check if missing file or directory errors should be ignored.
416             # This checks an undocumented object variable which is normally
417             # only used by the test suite to test the normal aspects of all
418             # the directives without worrying about a missing file or
419             # directory halting the tests early.
420 1 50       4 if ($self->{_include_file_ignore_missing_file}) {
421             # If the directory cannot be opened, then there are no
422             # configuration files that could be opened for the directive,
423             # so leave the method now, but with a successful return code.
424 1         3 return 1;
425             } else {
426 0         0 return;
427             }
428             }
429              
430             # The glob code Apache uses is fnmatch(3).
431 1         10 foreach my $n (sort readdir(DIR)) {
432 3 100       6 next if $n eq '.';
433 2 100       4 next if $n eq '..';
434 1 50       16 if (fnmatch($basename, $n)) {
435 1         5 push(@paths, "$dirname/$n");
436             }
437             }
438 1 50       9 unless (closedir(DIR)) {
439 0         0 $self->{errstr} = "'$file_or_dir_name' line $line_number " .
440             "'$directive $path': closedir '$dirname' " .
441             "failed: $!";
442 0         0 return;
443             }
444             } else {
445 13         24 @paths = ($path);
446             }
447              
448 14         29 foreach my $p (@paths) {
449 14         230 my @stat = stat($p);
450 14 100       42 unless (@stat) {
451 6         84 $self->{errstr} = "'$file_or_dir_name' line $line_number " .
452             "'$directive $path': stat of '$path' failed: $!";
453             # Check if missing file or directory errors should be ignored.
454             # This checks an undocumented object variable which is normally
455             # only used by the test suite to test the normal aspects of all
456             # the directives without worrying about a missing file or
457             # directory halting the tests early.
458 6 50       20 if ($self->{_include_file_ignore_missing_file}) {
459 6         21 next;
460             } else {
461 0         0 return;
462             }
463             }
464              
465             # Parse this if it is a directory or points to a file.
466 8 50 66     37 if (-d _ or -f _) {
467 8 50       36 unless ($self->parse_file($p)) {
468 0         0 return;
469             }
470             } else {
471 0         0 $self->{errstr} = "'$file_or_dir_name' line $line_number " .
472             "'$directive $path': cannot open non-file and " .
473             "non-directory '$p'";
474 0         0 return;
475             }
476             }
477              
478 14         60 return 1;
479             }
480              
481             =item $c->parse_file($filename)
482              
483             This method takes a filename and adds it to the already loaded
484             configuration file inside the object. If a previous Apache
485             configuration file was loaded either with new or parse_file and the
486             configuration file did not close all of its contexts, such as
487             , then the new configuration directives and contexts in
488             C<$filename> will be added to the existing context.
489              
490             If there is a failure in parsing any portion of the configuration
491             file, then this method returns undef and C<< $c->errstr >> will contain a
492             string explaining the error.
493              
494             =cut
495              
496             sub parse_file {
497 23 50   23 1 4391 unless (@_ == 2) {
498 0         0 confess "$0: Apache::ConfigParser::parse_file $INCORRECT_NUMBER_OF_ARGS";
499             }
500              
501 23         42 my ($self, $file_or_dir_name) = @_;
502              
503 23         377 my @stat = stat($file_or_dir_name);
504 23 100       60 unless (@stat) {
505 1         13 $self->{errstr} = "cannot stat '$file_or_dir_name': $!";
506 1         44 return;
507             }
508              
509             # If this is a real directory, than descend into it now.
510 22 100       65 if (-d _) {
511 4 50       82 unless (opendir(DIR, $file_or_dir_name)) {
512 0         0 $self->{errstr} = "cannot opendir '$file_or_dir_name': $!";
513 0         0 return;
514             }
515 4         44 my @entries = sort grep { $_ !~ /^\.{1,2}$/ } readdir(DIR);
  14         52  
516 4 50       37 unless (closedir(DIR)) {
517 0         0 $self->{errstr} = "closedir '$file_or_dir_name' failed: $!";
518 0         0 return;
519             }
520              
521 4         7 my $ok = 1;
522 4         10 foreach my $entry (@entries) {
523 6   33     66 $ok = $self->parse_file("$file_or_dir_name/$entry") && $ok;
524 6         19 next;
525             }
526              
527 4 50       10 if ($ok) {
528 4         35 return $self;
529             } else {
530 0         0 return;
531             }
532             }
533              
534             # Create a new file handle to open this file and open it.
535 18         67 my $fd = gensym;
536 18 50       758 unless (open($fd, $file_or_dir_name)) {
537 0         0 $self->{errstr} = "cannot open '$file_or_dir_name' for reading: $!";
538 0         0 return;
539             }
540              
541             # Change the mode to binary to mode to handle the line continuation
542             # match [^\\]\\[\r]\n. Since binary files may be copied from
543             # Windows to Unix, look for this exact match instead of relying upon
544             # the operating system to convert \r\n to \n.
545 18         57 binmode($fd);
546              
547             # This holds the contents of any previous lines that are continued
548             # using \ at the end of the line. Also keep track of the line
549             # number starting a continued line for warnings.
550 18         36 my $continued_line = '';
551 18         23 my $line_number = undef;
552              
553             # Scan the configuration file. Use the file format specified at
554             #
555             # http://httpd.apache.org/docs/configuring.html#syntax
556             #
557             # In addition, use the semantics from the function ap_cfg_getline
558             # in util.c
559             # 1) Leading whitespace is first skipped.
560             # 2) Configuration files are then parsed for line continuation. The
561             # line continuation is [^\\]\\[\r]\n.
562             # 3) If a line continues onto the next line then the line is not
563             # scanned for comments, the comment becomes part of the
564             # continuation.
565             # 4) Leading and trailing whitespace is compressed to a single
566             # space, but internal space is preserved.
567 18         3588 while (<$fd>) {
568             # Apache is not consistent in removing leading whitespace
569             # depending upon the particular method in getting characters from
570             # the configuration file. Remove all leading whitespace.
571 5278         10499 s/^\s+//;
572              
573 5278 100       9603 next unless length $_;
574              
575             # Handle line continuation. In the case where there is only one \
576             # character followed by the end of line character(s), then the \
577             # needs to be removed. In the case where there are two \
578             # characters followed by the end of line character(s), then the
579             # two \'s need to be replaced by one.
580 4700 100       8390 if (s#(\\)?\\\r?\n$##) {
581 72 100       145 if ($1) {
582 8         12 $_ .= $1;
583             } else {
584             # The line is being continued. If this is the first line to
585             # be continued, then note the starting line number.
586 64 100       106 unless (length $continued_line) {
587 17         28 $line_number = $.;
588             }
589 64         70 $continued_line .= $_;
590 64         153 next;
591             }
592             } else {
593             # Remove the end of line characters.
594 4628         14852 s#\r?\n$##;
595             }
596              
597             # Concatenate the continuation lines with this line. Only update
598             # the line number if the lines are not continued.
599 4636 100       6904 if (length $continued_line) {
600 17         42 $_ = "$continued_line $_";
601 17         19 $continued_line = '';
602             } else {
603 4619         6342 $line_number = $.;
604             }
605              
606             # Collapse any ending whitespace to a single space.
607 4636         9448 s#\s+$# #;
608              
609             # If the line begins with a #, then skip the line.
610 4636 100       9418 if (substr($_, 0, 1) eq '#') {
611 3223         8695 next;
612             }
613              
614             # If there is nothing on the line, then skip it.
615 1413 50       2387 next unless length $_;
616              
617             # If the line begins with
618 1413 100       4449 if (my ($context) = $_ =~ m#^<\s*/\s*([^\s>]+)\s*>\s*$#) {
619             # Check if an end context was seen with no start context in the
620             # configuration file.
621 180         793 my $mother = $self->{current_node}->mother;
622 180 50       1212 unless (defined $mother) {
623 0         0 $self->{errstr} = "'$file_or_dir_name' line $line_number closes " .
624             "context '$context' which was never started";
625 0         0 return;
626             }
627              
628             # Check that the start and end contexts have the same name.
629 180         271 $context = lc($context);
630 180         528 my $start_context_name = $self->{current_node}->name;
631 180 50       374 unless ($start_context_name eq $context) {
632 0         0 $self->{errstr} = "'$file_or_dir_name' line $line_number closes " .
633             "context '$context' that should close context " .
634             "'$start_context_name'";
635 0         0 return;
636             }
637              
638             # Move the current node up to the mother node.
639 180         265 $self->{current_node} = $mother;
640              
641 180         825 next;
642             }
643              
644             # At this point a new directive or context node will be created.
645 1233         4702 my $new_node = $self->{current_node}->new_daughter;
646 1233         10512 $new_node->filename($file_or_dir_name);
647 1233         2503 $new_node->line_number($line_number);
648              
649             # If the line begins with <, then it is starting a context.
650 1233 100       4224 if (my ($context, $value) = $_ =~ m#^<\s*(\S+)\s+(.*)>\s*$#) {
651 180         310 $context = lc($context);
652              
653             # Remove any trailing whitespace in the context's value as the
654             # above regular expression will match all after the context's
655             # name to the >. Do not modify any internal whitespace.
656 180         318 $value =~ s/\s+$//;
657              
658 180         464 $new_node->name($context);
659 180         396 $new_node->value($value);
660 180         447 $new_node->orig_value($value);
661              
662             # Set the current node to the new context.
663 180         304 $self->{current_node} = $new_node;
664              
665 180         903 next;
666             }
667              
668             # Anything else at this point is a normal directive. Split the
669             # line into the directive name and a value. Make sure not to
670             # collapse any whitespace in the value.
671 1053         6275 my ($directive, $value) = $_ =~ /^(\S+)(?:\s+(.*))?$/;
672 1053         1814 $directive = lc($directive);
673              
674 1053         3027 $new_node->name($directive);
675 1053         2312 $new_node->value($value);
676 1053         2446 $new_node->orig_value($value);
677              
678             # If there is no value for the directive, then move on.
679 1053 100 66     4006 unless (defined $value and length $value) {
680 4         20 next;
681             }
682              
683 1049         2646 my @values = $new_node->get_value_array;
684              
685             # Go through all of the value array elements for those elements
686             # that are paths that need to be optionally pre-transformed, then
687             # made absolute using ServerRoot and then optionally
688             # post-transformed.
689 1049         1844 my $value_path_index = $directive_value_path_element_pos{$directive};
690 1049         1081 my @value_path_indexes;
691 1049 100 66     3215 if (defined $value_path_index and $value_path_index =~ /^-?\d+$/) {
692 263 100       598 if (substr($value_path_index, 0, 1) eq '-') {
693 1         8 @value_path_indexes = (abs($value_path_index) .. $#values);
694             } else {
695 262         454 @value_path_indexes = ($value_path_index);
696             }
697             }
698              
699 1049         1711 for my $i (@value_path_indexes) {
700             # If this directive takes a path argument, then make sure the path
701             # is absolute.
702 265 100       723 if ($new_node->value_is_path($i)) {
703             # If the path needs to be pre transformed, then do that now.
704 260 50       617 if (my $pre_transform_path_sub = $self->{pre_transform_path_sub}) {
705 0         0 my ($sub, @args) = @$pre_transform_path_sub;
706 0         0 my $new_path = &$sub($self, $directive, $values[$i], @args);
707 0 0 0     0 if (defined $new_path and length $new_path) {
708 0         0 $values[$i] = $new_path;
709             } else {
710 0         0 $values[$i] = DEV_NULL;
711             }
712 0         0 $new_node->set_value_array(@values);
713             }
714              
715             # Determine if the file or directory path needs to have the
716             # ServerRoot prepended to it. First check if the ServerRoot
717             # has been set then check if the file or directory path is
718             # relative for this operating system.
719 260         339 my $server_root = $self->{server_root};
720 260 100 66     1428 if (defined $server_root and
      100        
721             length $server_root and
722             $new_node->value_is_rel_path) {
723 200         591 $values[$i] = "$server_root/$values[$i]";
724 200         512 $new_node->set_value_array(@values);
725             }
726              
727             # If the path needs to be post transformed, then do that now.
728 260 100       1107 if (my $post_transform_path_sub = $self->{post_transform_path_sub}) {
729 49         96 my ($sub, @args) = @$post_transform_path_sub;
730 49         254 my $new_path = &$sub($self, $directive, $values[$i], @args);
731 49 50 33     27589 if (defined $new_path and length $new_path) {
732 49         91 $values[$i] = $new_path;
733             } else {
734 0         0 $values[$i] = DEV_NULL;
735             }
736 49         165 $new_node->set_value_array(@values);
737             }
738             }
739             }
740              
741             # Always set the string value using the value array. This will
742             # normalize all string values by collapsing any whitespace,
743             # protect \'s, etc.
744 1049         2470 $new_node->set_value_array(@values);
745              
746             # If this directive is ServerRoot and node is the parent node,
747             # then record it now because it is used to make other relative
748             # pathnames absolute.
749 1049 100 66     2455 if ($directive eq 'serverroot' and !$self->{current_node}->mother) {
750 5         45 $self->{server_root} = $values[0];
751 5         32 next;
752             }
753              
754             # If this directive is AccessConfig, Include, IncludeOptional or
755             # ResourceConfig, then include the indicated file(s) given by the
756             # path.
757 1044 100 100     7470 if ($directive eq 'accessconfig' or
      100        
      100        
758             $directive eq 'include' or
759             $directive eq 'includeoptional' or
760             $directive eq 'resourceconfig') {
761 15 50       42 unless ($new_node->value_is_path) {
762 0         0 next;
763             }
764 15 50       69 unless ($self->_handle_include_directive($file_or_dir_name,
765             $line_number,
766             $directive,
767             $values[0])) {
768 0         0 return;
769             }
770             }
771              
772 1044         5947 next;
773             }
774              
775 18 50       348 unless (close($fd)) {
776 0         0 $self->{errstr} = "cannot close '$file_or_dir_name' for reading: $!";
777 0         0 return;
778             }
779              
780 18         222 return $self;
781              
782             # At this point check if all of the context have been closed. The
783             # filename that started the context may not be the current file, so
784             # get the filename from the context.
785 0         0 my $root = $self->{root};
786 0         0 while ($self->{current_node} != $root) {
787 0         0 my $context_name = $self->{current_node}->name;
788 0         0 my $attrs = $self->{current_node}->attributes;
789 0         0 my $context_filename = $attrs->{filename};
790 0         0 my $line_number = $attrs->{line_number};
791 0         0 warn "$0: '$context_filename' line $line_number context '$context_name' ",
792             "was never closed.\n";
793 0         0 $self->{current_node} = $self->{current_node}->mother;
794             }
795              
796 0         0 $self;
797             }
798              
799             =item $c->root
800              
801             Returns the root of the tree that represents the Apache configuration
802             file. Each object here is a C.
803              
804             =cut
805              
806             sub root {
807 8     8 1 37 $_[0]->{root}
808             }
809              
810             =item $c->find_down_directive_names('directive', ...)
811              
812             =item $c->find_down_directive_names($node, 'directive', ...)
813              
814             In list context, returns the list all of C<$c>'s directives that match
815             the directive names in C<$node> and C<$node>'s children. In scalar
816             context, returns the number of such directives. The level here is in
817             a tree sense, not in the sense that some directives appear before or
818             after C<$node> in the configuration file. If C<$node> is given, then
819             the search searches C<$node> and C<$node>'s children. If C<$node> is
820             not passed as an argument, then the search starts at the top of the
821             tree and searches the whole configuration file.
822              
823             The search for matching directive names is done without regards to
824             case.
825              
826             This is useful if you want to find all of the CustomLog's in the
827             configuration file:
828              
829             my @logs = $c->find_down_directive_names('CustomLog');
830              
831             =cut
832              
833             sub find_down_directive_names {
834 8 50   8 1 31 unless (@_ > 1) {
835 0         0 confess "$0: Apache::ConfigParser::find_down_directive_names ",
836             $INCORRECT_NUMBER_OF_ARGS;
837             }
838              
839 8         17 my $self = shift;
840              
841 8         10 my $start;
842 8 50 33     66 if (@_ and $_[0] and ref $_[0]) {
      33        
843 0         0 $start = shift;
844             } else {
845 8         19 $start = $self->{root};
846             }
847              
848 8 50       18 return () unless @_;
849              
850 8         11 my @found;
851 8         19 my %names = map { (lc($_), 1) } @_;
  8         46  
852              
853             my $callback = sub {
854 1241     1241   24799 my $node = shift;
855 1241 100       2550 push(@found, $node) if $names{$node->name};
856 1241         2185 return 1;
857 8         53 };
858              
859 8         48 $start->walk_down({callback => $callback});
860              
861 8         265 @found;
862             }
863              
864             =item $c->find_siblings_directive_names('directive', ...)
865              
866             =item $c->find_siblings_directive_names($node, 'directive', ...)
867              
868             In list context, returns the list of all C<$c>'s directives that match
869             the directive names at the same level of C<$node>, that is siblings of
870             C<$node>. In scalar context, returns the number of such directives.
871             The level here is in a tree sense, not in the sense that some
872             directives appear above or below C<$node> in the configuration file.
873             If C<$node> is passed to the method and it is equal to C<$c-Etree>
874             or if C<$node> is not given, then the method will search through
875             root's children.
876              
877             This method will return C<$node> as one of the matches if C<$node>'s
878             directive name is one of the directive names passed to the method.
879              
880             The search for matching directive names is done without regards to
881             case.
882              
883             =cut
884              
885             sub find_siblings_directive_names {
886 16 50   16 1 141 unless (@_ > 1) {
887 0         0 confess "$0: Apache::ConfigParser::find_siblings_directive_names ",
888             $INCORRECT_NUMBER_OF_ARGS;
889             }
890              
891 16         24 my $self = shift;
892              
893 16         19 my $start;
894 16 100 33     124 if (@_ and $_[0] and ref $_[0]) {
      66        
895 7         13 $start = shift;
896             } else {
897 9         23 $start = $self->{root};
898             }
899              
900 16 50       34 return () unless @_;
901              
902             # Special case for the root node. If the root node is given, then
903             # search its children.
904 16         18 my @siblings;
905 16 100       59 if ($start == $self->{root}) {
906 9         55 @siblings = $start->daughters;
907             } else {
908 7         34 @siblings = $start->mother->daughters;
909             }
910              
911 16 100       412 return @siblings unless @siblings;
912              
913 14         24 my %names = map { (lc($_), 1) } @_;
  14         76  
914              
915 14         27 grep { $names{$_->name} } @siblings;
  1126         2153  
916             }
917              
918             =item $c->find_siblings_and_up_directive_names($node, 'directive', ...)
919              
920             In list context, returns the list of all C<$c>'s directives that match
921             the directive names at the same level of C<$node>, that is siblings of
922             C<$node> and above C<$node>. In scalar context, returns the number of
923             such directives. The level here is in a tree sense, not in the sense
924             that some directives appear before or after C<$node> in the
925             configuration file. In this method C<$node> is a required argument
926             because it does not make sense to check the root node. If C<$node>
927             does not have a parent node, then no siblings will be found. This
928             method will return C<$node> as one of the matches if C<$node>'s
929             directive name is one of the directive names passed to the method.
930              
931             The search for matching directive names is done without regards to
932             case.
933              
934             This is useful when you find an directive and you want to find an
935             associated directive. For example, find all of the CustomLog's and
936             find the associated ServerName.
937              
938             foreach my $log_node ($c->find_down_directive_names('CustomLog')) {
939             my $log_filename = $log_node->name;
940             my @server_names = $c->find_siblings_and_up_directive_names($log_node);
941             my $server_name = $server_names[0];
942             print "ServerName for $log_filename is $server_name\n";
943             }
944              
945             =cut
946              
947             sub find_siblings_and_up_directive_names {
948 0 0   0 1 0 unless (@_ > 1) {
949 0         0 confess "$0: Apache::ConfigParser::find_siblings_and_up_directive_names ",
950             $INCORRECT_NUMBER_OF_ARGS;
951             }
952              
953 0         0 my $self = shift;
954 0         0 my $node = shift;
955              
956 0 0       0 return @_ unless @_;
957              
958 0         0 my %names = map { (lc($_), 1) } @_;
  0         0  
959              
960 0         0 my @found;
961              
962             # Recursively go through this node's siblings and all of the
963             # siblings of this node's parents.
964 0         0 while (my $mother = $node->mother) {
965 0         0 push(@found, grep { $names{$_->name} } $mother->daughters);
  0         0  
966 0         0 $node = $mother;
967             }
968              
969 0         0 @found;
970             }
971              
972             =item $c->errstr
973              
974             Return the error string associated with the last failure of any
975             C method. The string returned is not emptied
976             when any method calls succeed, so a non-zero length string returned
977             does not necessarily mean that the last method call failed.
978              
979             =cut
980              
981             sub errstr {
982 1 50   1 1 214 unless (@_ == 1) {
983 0         0 confess "$0: Apache::ConfigParser::errstr $INCORRECT_NUMBER_OF_ARGS";
984             }
985              
986 1         2 my $self = shift;
987 1         19 return $self->{errstr};
988             }
989              
990             =item $c->dump
991              
992             Return an array of lines that represents the internal state of the
993             tree.
994              
995             =cut
996              
997             my @dump_ref_count_stack;
998             sub dump {
999 8     8 1 25 @dump_ref_count_stack = (0);
1000 8         30 _dump(shift);
1001             }
1002              
1003             sub _dump {
1004 18277     18277   19423 my ($object, $seen_ref, $depth) = @_;
1005              
1006 18277   100     24906 $seen_ref ||= {};
1007 18277 100       20330 if (defined $depth) {
1008 18269         13696 ++$depth;
1009             } else {
1010 8         13 $depth = 0;
1011             }
1012              
1013 18277         17840 my $spaces = ' ' x $depth;
1014              
1015 18277 100       25847 unless (ref $object) {
1016 10827 100       11257 if (defined $object) {
1017 10803         26952 return ("$spaces '$object'");
1018             } else {
1019 24         57 return ("$spaces UNDEFINED");
1020             }
1021             }
1022              
1023 7450 100       15773 if (my $r = $seen_ref->{$object}) {
1024 1241         2955 return ("$spaces SEEN $r");
1025             }
1026              
1027 6209         7734 my $type = "$object";
1028 6209         21171 $type =~ s/\(\w+\)$//;
1029 6209         15676 my $comment = "reference " .
1030             join('-', @dump_ref_count_stack) .
1031             " $type";
1032 6209         5537 $spaces .= $comment;
1033 6209         12743 $seen_ref->{$object} = $comment;
1034 6209         5373 $dump_ref_count_stack[-1] += 1;
1035              
1036 6209 50       21911 if (UNIVERSAL::isa($object, 'SCALAR')) {
    100          
    100          
    50          
1037 0         0 return ("$spaces $$object");
1038             } elsif (UNIVERSAL::isa($object, 'ARRAY')) {
1039 3717         3772 push(@dump_ref_count_stack, 0);
1040 3717         8203 my @result = ("$spaces with " . scalar @$object . " elements");
1041 3717         7088 for (my $i=0; $i<@$object; ++$i) {
1042 5811         11170 push(@result, "$spaces index $i",
1043             _dump($object->[$i], $seen_ref, $depth));
1044             }
1045 3717         2813 pop(@dump_ref_count_stack);
1046 3717         26642 return @result;
1047             } elsif (UNIVERSAL::isa($object, 'HASH')) {
1048 2490         2426 push(@dump_ref_count_stack, 0);
1049 2490         7918 my @result = ("$spaces with " . scalar keys(%$object) . " keys");
1050 2490         8561 foreach my $key (sort keys %$object) {
1051 12458         25659 push(@result, "$spaces key '$key'",
1052             _dump($object->{$key}, $seen_ref, $depth));
1053             }
1054 2490         3054 pop(@dump_ref_count_stack);
1055 2490         35169 return @result;
1056             } elsif (UNIVERSAL::isa($object, 'CODE')) {
1057 2         7 return ($spaces);
1058             } else {
1059 0           die "$0: internal error: object of type ", ref($object), " not handled.\n";
1060             }
1061             }
1062              
1063             1;
1064              
1065             =back
1066              
1067             =head1 SEE ALSO
1068              
1069             L and L.
1070              
1071             =head1 AUTHOR
1072              
1073             Blair Zajac .
1074              
1075             =head1 COPYRIGHT
1076              
1077             Copyright (C) 2001-2005 Blair Zajac. All rights reserved. This
1078             program is free software; you can redistribute it and/or modify it
1079             under the same terms as Perl itself.