use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestRequest; use Apache::TestUtil qw(t_write_file t_start_error_log_watch t_finish_error_log_watch t_cmp); use File::Spec; use Time::HiRes qw(usleep); # test ap_expr Apache::TestRequest::user_agent(keep_alive => 1); # The left-hand values are written into the config file as-is, i.e. # necessary quoting for the config file parser needs to be included # explicitly. my @test_cases = ( [ 'foo' => 'foo' ], [ '%{req:SomeHeader}' => 'SomeValue' ], [ '%{' => undef ], [ '%' => '%' ], [ '}' => '}' ], [ q{\"} => q{"} ], [ q{\'} => q{'} ], [ q{"\%{req:SomeHeader}"} => '%{req:SomeHeader}' ], [ '%{tolower:IDENT}' => 'ident' ], [ '%{tolower:%{REQUEST_METHOD}}' => 'get' ], ); if (have_min_apache_version("2.5")) { my $SAN_one = "email:<redacted1>, email:<redacted2>, " . "IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1, " . "IP Address:192.168.169.170"; my $SAN_tuple = "'email:<redacted1>', 'email:<redacted2>', " . "'IP Address:127.0.0.1', 'IP Address:0:0:0:0:0:0:0:1', " . "'IP Address:192.168.169.170'"; my $SAN_list_one = "{ '$SAN_one' }"; my $SAN_list_tuple = "{ $SAN_tuple }"; push(@test_cases, ( [ qq["%{tolower:%{:toupper(%{REQUEST_METHOD}):}}"] => "get" ], [ qq["%{: join $SAN_list_one :}"] => "$SAN_one" ], [ qq["%{: join($SAN_list_tuple, ', ') :}"] => "$SAN_one" ], [ qq['%{tolower:"IDENT"}'] => '"ident"' ], [ qq["%{: 'IP Address:%{REMOTE_ADDR}' -in split/, /, join $SAN_list_one :}"] => "true" ], )); } my $successful_expected = scalar(grep { defined $_->[1] } @test_cases); plan tests => scalar(@test_cases) * 2 + $successful_expected, need need_lwp, need_module('mod_log_debug'); foreach my $t (@test_cases) { my ($expr, $expect) = @{$t}; write_htaccess($expr); t_start_error_log_watch(); my $response = GET('/apache/expr/index.html', 'SomeHeader' => 'SomeValue', 'User-Agent' => 'SomeAgent', 'Referer' => 'SomeReferer'); ### Sleep here, attempt to avoid intermittent failures. usleep(250000); my @loglines = t_finish_error_log_watch(); my @evalerrors = grep {/(?:internal evaluation error|flex scanner jammed)/i } @loglines; my $num_errors = scalar @evalerrors; print "Error log should not have 'Internal evaluation error' or " . "'flex scanner jammed' entries, found $num_errors:\n@evalerrors\n" if $num_errors; ok($num_errors == 0); my $rc = $response->code; if (!defined $expect) { print qq{Should get parse error (500) for "$expr", got $rc\n}; ok($rc == 500); } else { print qq{Expected return code 200, got $rc for '$expr'\n}; ok($rc == 200); my @msg = grep { /log_debug:info/ } @loglines; if (scalar @msg != 1) { print "expected 1 message, got " . scalar @msg . ":\n@msg\n"; ok(0); } elsif ($msg[0] =~ m{^(?:\[ # opening '[' [^\]]+ # anything but a ']' \] # closing ']' [ ] # trailing space ){4} # repeat 4 times (timestamp, level, pid, client IP) (.*?) # The actual message logged by LogMessage (,[ ]referer # either trailing referer (LogLevel info) | # or [ ]\(log_transaction) # trailing hook info (LogLevel debug and higher) }x ) { my $result = $1; ok t_cmp($result, $expect, "log message @msg didn't match"); } else { print "Can't extract expr result from log message:\n@msg\n"; ok(0); } } } exit 0; ### sub routines sub write_htaccess { my $expr = shift; my $file = File::Spec->catfile(Apache::Test::vars('serverroot'), 'htdocs', 'apache', 'expr', '.htaccess'); t_write_file($file, << "EOF" ); LogMessage $expr EOF }