File Coverage

blib/lib/Apache/ConfigParser.pm
Criterion Covered Total %
statement 242 312 77.5
branch 108 150 72.0
condition 34 62 54.8
subroutine 21 22 95.4
pod 8 9 88.8
total 413 555 74.4


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