René Nyffenegger's collection of things on the web with comments added by Charles Nicholas, for use in CMSC 331 |
|
|
René Nyffenegger on Oracle - Most wanted - Feedback
|
A webserver with Perl | ||
|
This is a very simple webserver written in Perl.
It consists of two parts: webserver.pl and http_handler.pl.
webserver.pl is the core, so to speak, that accepts new connections and creates a thread for each connection. http_handler.pl is the file that actually
defines what should be done at a request. Currently, http_handler.pl must expose two sub's: http_request_handler and
init_webserver_extension.
The port on which the webserver listens, should be set within init_webserver_extension by assigning the port number to the variable $port_listen.
webserver.pluse strict;
use warnings;
use Socket; # CKN so that we can work with TCP/IP sockets
use IO::Select; # CKN so that we can use the select system call
# CKN see man select for details
# CKN not much use of STDIN, but lots of I/O anyway
use threads;
use threads::shared;
$| = 1; # CKN tells perl to flush the output buffer automatically
# The following variables should be set within init_webserver_extension
# CKN the default port for a web server is 80, but requires privileges
# CKN other popular ports for web servers include 1080 and 8080
use vars qw/
$port_listen
/;
require "http_handler.pl";
init_webserver_extension();
local *S; # CKN this will be a socket pointer - yes, Perl has pointers, much syntax like C
# CKN local is like my, but makes a local copy of a global variable, use with care
# CKN open a socket and start listening
socket (S, PF_INET , SOCK_STREAM , getprotobyname('tcp')) or die "couldn't open socket: $!";
setsockopt (S, SOL_SOCKET, SO_REUSEADDR, 1);
bind (S, sockaddr_in($port_listen, INADDR_ANY));
listen (S, 5) or die "don't hear anything: $!";
my $ss = IO::Select->new();
$ss -> add (*S); # CKN lets us do some select ops on the newly opened socket
while(1) {
my @connections_pending = $ss->can_read(); # CKN once we have a connection request,
foreach (@connections_pending) {
my $fh;
my $remote = accept($fh, $_); # CKN accept the connection and open a file handler
my($port,$iaddr) = sockaddr_in($remote);
my $peeraddress = inet_ntoa($iaddr);
my $t = threads->create(\&new_connection, $fh); # CKN spawn off a sub-process
$t->detach();
}
}
sub extract_vars {
my $line = shift;
my %vars;
foreach my $part (split '&', $line) {
$part =~ /^(.*)=(.*)$/;
my $n = $1; # CKN get name and value of parameters
my $v = $2;
$n =~ s/%(..)/chr(hex($1))/eg;
$v =~ s/%(..)/chr(hex($1))/eg;
$vars{$n}=$v;
}
return \%vars;
}
sub new_connection {
my $fh = shift;
binmode $fh; # CKN this is useful for Unicode files too
my %req;
$req{HEADER}={};
my $request_line = <$fh>;
my $first_line = "";
while ($request_line ne "\r\n") {
unless ($request_line) {
close $fh;
}
chomp $request_line;
unless ($first_line) {
$first_line = $request_line;
my @parts = split(" ", $first_line);
if (@parts != 3) {
close $fh;
}
$req{METHOD} = $parts[0];
$req{OBJECT} = $parts[1];
}
else {
my ($name, $value) = split(": ", $request_line);
$name = lc $name;
$req{HEADER}{$name} = $value;
}
$request_line = <$fh>;
}
http_request_handler($fh, \%req);
close $fh;
}
http_handler.plsub http_request_handler {
my $fh = shift;
my $req_ = shift;
my %req = %$req_;
my %header = %{$req{HEADER}};
print $fh "HTTP/1.0 200 OK\r\n";
print $fh "Server: adp perl webserver\r\n";
#print $fh "content-length: ... \r\n";
print $fh "\r\n";
print $fh "<html><h1>hello</h1></html>";
print $fh "Method: $req{METHOD}<br>";
print $fh "Object: $req{OBJECT}<br>";
foreach my $r (keys %header) {
print $fh $r, " = ", $header{$r} , "<br>";
}
}
sub init_webserver_extension {
$port_listen = 8888;
}
1; # CKN this is the return value that will be sent back when thread ends
Thanks
Thanks to Rob Neild who found out that this server leaked memory without the
$t->detach(); after the creation of the thread.
Related Links |