#!/usr/bin/perl -w

use IO::Socket;

$USAGE = "Usage: $0 host[:port] [-d] testfile1, testfile2, ...\n";
$USERAGENT = "mod_security regression test utility";

$debug = 0;

$count = 0;

sub perform_test {
    my $filename = shift(@_);

    if (!open(FILE, $filename)) {
        print("Could not open file $filename.\n");
        return;
    }

    $socket = IO::Socket::INET->new(Proto => 'tcp', PeerAddr => $server, PeerPort => $port, Timeout => 10);

    if(!$socket) {
        # this is treated as a serious problem and we
        # die if we cannot connect
        die("Could not connect to $server:$port");
    }

    $socket->autoflush(1);

    $mode = 1;
    $expected_status = 500;
    $test_name_found = 0;
    $test_name = '';

    $send_host_header = 1;
    $send_useragent_header = 1;
    $send_connection_header = 1;

    LINE: while(<FILE>) {

        $send_line = 1;
    
        if ($mode == 1) {

            # discard comments
            if (/^#/) {

                if ($test_name_found == 0) {
                    chomp;
                    $test_name = substr($_, 2);
                    $test_name_found = 1;

                    if ($test_name =~ /([0-9]{3})/) {
                        $expected_status = $1;
                    }

                    print "Test \"${test_name}\": ";
                    if ($debug) { print "\n"; }
                }
                next LINE;
            }

            $mode = 2;
    
            # execution flow continues as
            # mode is 2 now
        }        

        if ($mode == 2) {

            # check for the "Host" header
            if (/^(Host: )(.*)$/i) {
                $send_host_header = 0;
                if ($2 eq "-") {
                    $send_line = 0;
                }
            }

            # check for the "User-Agent" header
            if (/^(User-Agent: )(.*)$/i) {
                $send_useragent_header = 0;
                if ($2 eq "-") {
                    $send_line = 0;
                }
            }

            # check for the "Connection" header
            if (/^(Connection: )(.*)$/i) {
                $send_connection_header = 0;
                if ($2 eq "-") {
                    $send_line = 0;
                }
            }

            if (/^$/) {
                # empty line detected, the body follows
                $mode = 3;

                # send additional headers
                if ($send_host_header) {
                    print $socket "Host: $server:$port\n";
                    if ($debug) { print "> Host: $server:$port\n"; }
                }

                if ($send_useragent_header) {
                    print $socket "User-Agent: $USERAGENT\n";
                    if ($debug) { print "> User-Agent: $USERAGENT\n"; }
                }

                if  ($send_connection_header) {
                    print $socket "Connection: Close\n";
                    if ($debug) { print "> Connection: Close\n"; }
                }
            }

            if ($send_line) {
                print $socket $_;
                if ($debug) { print "> $_"; }
            }

            next LINE;
        }

        if ($mode == 3) {
            print $socket $_;
            if ($debug) { print "> $_"; }
        }   
    }

    close(FILE);

    $status = 0;
    while (<$socket>) {
        
        if (($status == 0) && (/^HTTP\/[0-9]\.[0-9] ([0-9]+).+$/)) {
            $status = $1;
        }

        if ($debug) { print "< $_"; }
    }

    if ($status == 0) {
        print "Failed (status not available)\n";
    }

    if ($status == $expected_status) {
        print "OK\n";
    } else {
        print "Failed (status = $status)\n";
    }

}


# -- main -------------------------------------------

if(!@ARGV) {
    print $USAGE;
    exit;
}

if ($#ARGV < 1) {
    print $USAGE;
    exit;
}

$_ = shift(@ARGV);

if (/(.+):(.+)/) {
    $server = $1;
    $port = $2;
} else {
    $server = $_;
    $port = 80;
}

foreach $filename (@ARGV) {
    if ($filename =~ /^-d$/) {
        $debug = 1;
    } else {
        perform_test($filename);
        $count++;
    }
}

if ($count == 0) {
    print $USAGE;
}

