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

use NetServer::Generic;

# minimal http server (HTTP/0.9):

sub url_to_file($) {
   # for a given URL, turn it into an absolute pathname
   my ($u) = shift ;    # incoming URL fragment from GET request
   my ($f) = "";        # file pathname to return
   my ($htbase) = "/home/httpd/html/";
   my ($htdefault) = "index.html";
   chomp $u;
   if ($u eq "/") {
       $f = $htbase . $htdefault;
       return $f;
   } else {
       if ($u =~ m|^/.+|) {
           $f = $htbase;  chop $f;
           $f .= $u;
       } elsif ($u =~ m|[^/]+|) {
           $f = $htbase . $u;
       }
       if ($u =~ m|.+/$|) {
           $f .= $htdefault;
       }
       if ($f =~ /\.\./) {
           my (@path) = split("/", $f);
           my ($buff, $acc) = "";
           shift @path;
           while ($buff = shift @path) {
               my ($tmp) = shift @path;
               if ($tmp ne '..') {
                   unshift @path, $tmp;
                   $acc .= "/$buff";
               }
           }
           $f = $acc;
       }
   }
   return $f;
}

my ($http) = sub {
    while (defined ($tmp = <STDIN>)) {
        chomp $tmp;
	print STDERR "Raw http request: $tmp\n";
	my ($req, $url, $proto) = split(/\s+/, $tmp);
	print STDERR "request: $req\nurl: $url\nprotocol: $proto\n\n";
        if ($req =~ /GET/) { 
            my ($getfile) = url_to_file($url);
            print STDERR "Sending $getfile\n";
	    if (! -r $getfile) {
                 print STDERR "could not read $getfile\n";
	    }
            my ($in) = new IO::File();
            if ($in->open("<$getfile") ) {
                $in->autoflush(1);
                my $httpd_hdr = "Content-type: text/html\n\n";
                print STDOUT $httpd_hdr;
		$NetServer::Debug && print STDERR $httpd_hdr;
                while (defined ($line = <$in>)) {
                    print STDOUT $line;
		    $NetServer::Debug && print STDERR $line;
                }
            } else {
	        my $httpd_err = "404: File not found\n\n";
                print STDOUT $httpd_err;
		$NetServer::Debug && print $httpd_err, "$!\n";
            }
        }
        return 0;
    }
};                           

my (%config) =  ("port" => 9000, 
                 "callback" => $http, 
                 "mode" => "prefork",
                 "start_servers" => 4,
                 "max_servers" => 10,
                 "min_spare_servers" => 2,
                );
my ($foo) = new NetServer::Generic(%config);

my ($allowed) = ['.*antipope\.org', 
                 '.*easynet\.co\.uk' ];

my ($forbidden) = [ '194\.205\.10\.2'];

$foo->allowed($allowed);
$foo->forbidden($forbidden);
print "Server started\n";
$foo->run();

__END__

=pod

=head1 shttpd -- a trivial HTTP server

This is not a real web server, although it might turn into one
eventually!

You will need to modify %config (specifically the hostname) before
it will do anything useful. You may also need to modify the
B<allowed> and B<forbidden> anonymous arrays; these are given to
provide an example of simple access control to a server.

B<shttpd> understands a single HTTP command:

  GET I<filename>

It looks for files in B<$htbase> (defined in B<url_to_file()>, the 
subroutine that maps HTTP requests to absolute pathnames). If a
trailing slash is encountered, it appends B<$htdefault> (currently
set to I<index.html>).

If the file is not found, it returns a 404: File not found response --
otherwise it assumes the file is HTML and sends it(!). This may not
be what you want to do if the file is I<not> HTML, so take care.

B<shttpd> doesn't understand CGI scripts, relative URLs, or just about
anything. However, it serves as a skeleton which can easily be
extended to add these features.