Newer
Older
#!/usr/bin/perl
use Socket;
use Carp;
#use strict;
sub spawn; # forward declaration
sub logmsg { #print "$0 $$: @_ at ", scalar localtime, "\n"
}
my $port = 8999; # just a default
do {
if($ARGV[0] eq "-v") {
$verbose=1;
}
elsif($ARGV[0] =~ /^(\d+)$/) {
$port = $1;
}
} while(shift @ARGV);
socket(Server, PF_INET, SOCK_STREAM, $proto)|| die "socket: $!";
setsockopt(Server, SOL_SOCKET, SO_REUSEADDR,
pack("l", 1)) || die "setsockopt: $!";
bind(Server, sockaddr_in($port, INADDR_ANY))|| die "bind: $!";
listen(Server,SOMAXCONN) || die "listen: $!";
if($verbose) {
print "HTTP server started on port $port\n";
}
open(PID, ">.http.pid");
my $waitedpid = 0;
my $paddr;
sub REAPER {
$waitedpid = wait;
$SIG{CHLD} = \&REAPER; # loathe sysV
logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
}
sub performcmd {
my @cmd = @_;
for(@cmd) {
if($_ =~ /^ *wait *(\d*)/) {
# instructed to sleep!
sleep($1);
}
}
}
$SIG{CHLD} = \&REAPER;
for ( $waitedpid = 0;
($paddr = accept(Client,Server)) || $waitedpid;
$waitedpid = 0, close Client)
{
next if $waitedpid and not $paddr;
my($port,$iaddr) = sockaddr_in($paddr);
my $name = gethostbyaddr($iaddr,AF_INET);
logmsg "connection from $name [", inet_ntoa($iaddr), "] at port $port";
# this code is forked and run
spawn sub {
Daniel Stenberg
committed
my ($request, $path, $ver, $left, $cl);
if($_ =~ /([A-Z]*) (.*) HTTP\/1.(\d)/) {
$request=$1;
$path=$2;
$ver=$3;
}
elsif($_ =~ /^Content-Length: (\d*)/) {
$cl=$1;
}
if($verbose) {
print STDERR "IN: $_";
}
push @headers, $_;
if($left > 0) {
$left -= length($_);
Daniel Stenberg
committed
if($left == 0) {
$left = -1; # just to force a loop break here
}
Daniel Stenberg
committed
# print STDERR "RCV ($left): $_";
Daniel Stenberg
committed
if(!$left &&
($_ eq "\r\n") or ($_ eq "")) {
elsif($request =~ /^CONNECT$/) {
if($verbose) {
print STDERR "We're emulating a SSL proxy!\n";
}
$left = -1;
}
else {
$left = -1; # force abort
}
}
if($left < 0) {
last;
}
}
if($request =~ /^CONNECT$/) {
# ssl proxy mode
print "HTTP/1.1 400 WE CANNOT ROOL NOW\r\n",
"Server: bahoooba\r\n\r\n";
exit;
}
elsif($path =~ /verifiedserver/) {
Daniel Stenberg
committed
# this is a hard-coded query-string for the test script
# to verify that this is the server actually running!
print "HTTP/1.1 999 WE ROOLZ: $PID\r\n";
Daniel Stenberg
committed
else {
Daniel Stenberg
committed
#
# we always start the path with a number, this is the
# test number that this server will use to know what
# contents to pass back to the client
#
Daniel Stenberg
committed
if($path =~ /.*\/(\d*)/) {
$testnum=$1;
}
else {
Daniel Stenberg
committed
}
open(INPUT, ">>log/server.input");
binmode(INPUT,":raw"); # this makes it work better on cygwin
Daniel Stenberg
committed
for(@headers) {
print INPUT $_;
}
close(INPUT);
if(0 == $testnum ) {
print "HTTP/1.1 200 OK\r\n",
"header: yes\r\n",
"\r\n",
"You must enter a test number to get good data back\r\n";
my $part="";
if($testnum > 10000) {
$part = $testnum % 10000;
$testnum = sprintf("%d", $testnum/10000);
}
if($verbose) {
print STDERR "OUT: sending reply $testnum (part $part)\n";
}
my @cmd = getpart("reply", "cmd");
performcmd(@cmd);
# flush data:
$| = 1;
if($verbose) {
print STDERR "OUT: $_";
}
my @postcmd = getpart("reply", "postcmd");
performcmd(@postcmd);
Daniel Stenberg
committed
}
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
}
# print "Hello there, $name, it's now ", scalar localtime, "\r\n";
};
}
sub spawn {
my $coderef = shift;
unless (@_ == 0 && $coderef && ref($coderef) eq 'CODE') {
confess "usage: spawn CODEREF";
}
my $pid;
if (!defined($pid = fork)) {
logmsg "cannot fork: $!";
return;
} elsif ($pid) {
logmsg "begat $pid";
return; # I'm the parent
}
# else I'm the child -- go spawn
open(STDIN, "<&Client") || die "can't dup client to stdin";
open(STDOUT, ">&Client") || die "can't dup client to stdout";
## open(STDERR, ">&STDOUT") || die "can't dup stdout to stderr";
exit &$coderef();
}