Search notes:

A (simple) webserver with Perl

This is a very simple webserver written in Perl.
It consists of two parts (files): 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.pl

#!/usr/bin/perl
use warnings;
use strict;


use strict;
use warnings;

use Socket;
use IO::Select;

use threads;
use threads::shared;


$|  = 1;

# The following variables should be set within init_webserver_extension
use vars qw/
 $port_listen
/;


require "http_handler.pl";
init_webserver_extension();

local *S;

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);


while(1) {
  my @connections_pending = $ss->can_read();
  foreach (@connections_pending) {
    my $fh;
    my $remote = accept($fh, $_);

    my($port,$iaddr) = sockaddr_in($remote);
    my $peeraddress = inet_ntoa($iaddr);

    my $t = threads->create(\&new_connection, $fh);
    $t->detach();
  }
}

sub extract_vars {
  my $line = shift;
  my %vars;

  foreach my $part (split '&', $line) {
    $part =~ /^(.*)=(.*)$/;

    my $n = $1;
    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;

  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;
}
Github repository perl-webserver, path: /adp-gmbh/webserver.pl

http_handler.pl

sub 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;
Github repository perl-webserver, path: /adp-gmbh/http_handler.pl
These scripts were originally hosted on my old web site (http://www.adp-gmbh.ch/perl/webserver/).
They can also be found on github.

Thanks

Thanks to Rob Neild who informed me that this server leaked memory without the $t->detach(); after the creation of the thread.

See also

Another simple Webserver using the Perl module HTTP::Server::Simple::CGI.
The Perl module HTTP::Daemon
webserver
Perl

Index