The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl

# This test will start up a real httpd server with mod_perl loaded in
# it, and make several requests on that server.

# You shouldn't have to change any of these, but you can if you want:
$ACONF = "/dev/null";
$CONF  = "t/httpd.conf";
$SRM   = "/dev/null";
$LOCK  = "t/httpd.lock";
$PID   = "t/httpd.pid";
$ELOG  = "t/error_log";

######################################################################
################ Don't change anything below here ####################
######################################################################

#line 25 real.t

use vars qw(
     $ACONF   $CONF   $SRM   $LOCK   $PID   $ELOG
   $D_ACONF $D_CONF $D_SRM $D_LOCK $D_PID $D_ELOG
);
my $DIR = `pwd`;
chomp $DIR;
&dirify(qw(ACONF CONF SRM LOCK PID ELOG));
&read_httpd_loc();

use strict;
use vars qw($TEST_NUM $BAD %CONF);
use LWP::UserAgent;
use Carp;

my %requests = 
  (
   3  => 'index.html',

   # Should fail with 'no_cookie'
   4  => 'protected/get_me.html',

   # Should succeed (redirect)
   5  => {uri=>'LOGIN',
	  method=>'POST',
	  content=>'destination=/protected/get_me.html&credential_0=programmer&credential_1=Hero',
	 },

   # Should succeed
   6  => {uri=>'protected/get_me.html',
	  method=>'GET',
	  headers=>{Cookie=>'Sample::AuthCookieHandler_WhatEver=programmer:Hero;'},
	 },

   # Should fail with 'no_cookie'
   7  => {uri=>'protected/get_me.html',
	  method=>'GET',
	  content=>'destination=/protected/get_me.html&credential_0=programmer&credential_1=Heroo',
	 },

   8  => 'logout.pl',

   9  => {uri=>'echo_cookie.pl',
	  method=>'GET',
	  headers=>{Cookie=>'Sample::AuthCookieHandler_WhatEver=programmer:Hero;'},
	 },

   # Should fail
   10 => {uri=>'protected/get_me.html',
	  method=>'GET',
	  headers=>{Cookie=>'Sample::AuthCookieHandler_WhatEver=some-user:duck;'},
	 },

   # Should redirect to /protected/get_me.html
   11 => {uri=>'LOGIN',
	  method=>'POST',
	  content=>'destination=/protected/get_me.html&credential_0=programmer&credential_1=Heroo',
	 },

   # Should fail with 'bad_cookie'
   12 => {uri=>'protected/get_me.html',
	  method=>'GET',
	  headers=>{Cookie=>'Sample::AuthCookieHandler_WhatEver=programmer:Heroo'},
	 },

  );

my %special_tests = 
  (
   5  => sub {print "code: ", $_[0]->code(), "\n"; $_[0]->code() == 302},
   8  => sub {$_[0]->header('Set-Cookie') 
		eq 'Sample::AuthCookieHandler_WhatEver=; path=/; expires=Mon, 21-May-1971 00:00:00 GMT'},
   10 => sub {print "code: ", $_[0]->code(), "\n"; $_[0]->code() == 403},
   11 => sub 
     {
       my $r = shift;
       print("Location: ", $r->header('Location'), "\n",
	     "Set-Cookie: ", $r->header('Set-Cookie'), "\n", 
	     "Code: ", $r->code(), "\n");

       my $ok = 1;
       $ok = 0 unless $r->header('Location')   eq '/protected/get_me.html';
       $ok = 0 unless $r->header('Set-Cookie') eq 'Sample::AuthCookieHandler_WhatEver=programmer:Heroo; path=/';
       $ok = 0 unless $r->code() == 302;
       return $ok;
     }
   

  );

print "1.." . (2 + keys %requests) . "\n";

&report( &create_conf() );
my $result = &start_httpd;
&report( $result );

if ($result) {
  local $SIG{'__DIE__'} = \&kill_httpd;
  
  foreach my $testnum (sort {$a<=>$b} keys %requests) {
    my $ua = new LWP::UserAgent;
    my ($meth, $uri, $content, $headers);

    if (ref $requests{$testnum}) {
      # Allow customization of request
      ($meth, $uri, $content) = @{$requests{$testnum}}{'method','uri','content'};
      $headers = $requests{$testnum}{headers};
      $headers->{Content_Type} = 'application/x-www-form-urlencoded'
	if (!$headers and $requests{$testnum}{method} eq 'POST');
      $headers = new HTTP::Headers(%$headers);
    } else {
      ($meth, $uri, $content, $headers) = ('GET', $requests{$testnum}, '', undef);
    }

    my $req = new HTTP::Request($meth, "http://localhost:$CONF{port}/$uri", $headers, $content);
    my $response = $ua->request($req);
    
    &test_outcome($response, $testnum);
  }
  
  &kill_httpd();
  warn "\nSee $ELOG for failure details\n" if $BAD;
} else {
  warn "Aborting real.t";
}

&cleanup();

sub index_ok { $_[0] =~ /index of/i };

#############################

sub read_httpd_loc {
  open LOC, "t/httpd.loc" or die "t/httpd.loc: $!";
  while (<LOC>) {
    $CONF{$1} = $2 if /^(\w+)=(.*)/;
  }
}

sub start_httpd {
  print STDERR "Starting http server... ";
  unless (-x $CONF{httpd}) {
    warn("$CONF{httpd} doesn't exist or isn't executable.\n");
    return;
  }
  &do_system("cp /dev/null $ELOG");
  &do_system("$CONF{httpd} -f $D_CONF") == 0
    or die "Can't start httpd: $!";
  print STDERR "ready. ";
  return 1;
}

sub kill_httpd {
  &do_system("kill -TERM `cat $PID`");
  &do_eval("unlink '$ELOG'") unless $BAD;
  return 1;
}

sub cleanup {
  &do_eval("unlink '$CONF'");
  return 1;
}

sub test_outcome {
  my $response = shift;
  my $i = shift;
  
  my ($text, $expected);
  my $ok = ($special_tests{$i} ?
	    $special_tests{$i}->($response) :
	    (($text = $response->content) eq ($expected = `cat t/check/$i`)) );
  &report($ok);
  my $headers = $response->headers_as_string();
  print "Result: $headers\n$text\nExpected: $expected\n" if ($ENV{TEST_VERBOSE} and not $ok);
}

sub report {
  my $ok = shift;
  $TEST_NUM++;
  print "not "x(!$ok), "ok $TEST_NUM\n";
  $BAD++ unless $ok;
}

sub do_system {
  my $cmd = shift;
  print "$cmd\n";
  return system $cmd;
}

sub do_eval {
  my $code = shift;
  print "$code\n";
  my $result = eval $code;
  if ($@ or !$result) { carp "WARNING: $@" }
  return $result;
}

sub dirify {
  no strict('refs');
  foreach (@_) {
    # Turn $VAR into $D_VAR, which has an absolute path
    ${"D_$_"} = (${$_} =~ m,^/, ? ${$_} : "$DIR/${$_}");
  }
}

sub create_conf {
  my $file = $CONF;
  open (CONF, ">$file") or die "Can't create $file: $!" && return;
  print CONF <<EOF;

#This file is created by the $0 script.

Port $CONF{port}
User $CONF{user}
Group $CONF{group}
ServerName localhost
DocumentRoot $DIR/t/eg

ErrorLog $D_ELOG
PidFile $D_PID
AccessConfig $D_ACONF
ResourceConfig $D_SRM
LockFile $D_LOCK
TypesConfig /dev/null
TransferLog /dev/null
ScoreBoardFile /dev/null

AddType text/html .html

# Look in ./blib/lib
PerlModule ExtUtils::testlib
PerlRequire $DIR/t/Sample/AuthCookieHandler.pm

PerlSetVar WhatEverPath /
PerlSetVar WhatEverLoginScript /login.pl
PerlSetVar AuthCookieDebug 3

# These documents require user to be logged in.
<Location /protected>
 AuthType Sample::AuthCookieHandler
 AuthName WhatEver
 PerlAuthenHandler Sample::AuthCookieHandler->authenticate
 PerlAuthzHandler Sample::AuthCookieHandler->authorize
 require user programmer
</Location>

# These documents don't require logging in, but allow it.
<FilesMatch "\.cgi$">
 AuthType Sample::AuthCookieHandler
 AuthName WhatEver
 PerlFixupHandler Sample::AuthCookieHandler->recognize_user
</FilesMatch>

<FilesMatch "\.pl">
 AuthType Sample::AuthCookieHandler
 AuthName WhatEver
 SetHandler perl-script
 PerlHandler Apache::Registry
 Options +ExecCGI
</FilesMatch>

# This is the action of the login.pl script above.
<Files LOGIN>
 AuthType Sample::AuthCookieHandler
 AuthName WhatEver
 SetHandler perl-script
 PerlHandler Sample::AuthCookieHandler->login
</Files>

<Location /perl-status>
 SetHandler perl-script
 PerlHandler Apache::Status
</Location>

EOF
	
  close CONF;
  
  chmod 0644, $file or warn "Couldn't 'chmod 0644 $file': $!";
  return 1;
}