#!/usr/bin/perl -w -T ###----------------------------------------### ### httpd server class ### ###----------------------------------------### package MyHTTPD; use vars qw(@ISA); use strict; ### what type of server is this - we could ### use multi type when we add command line ### parsing to this http server to allow ### for different configurations use Net::Server::PreFork; @ISA = qw(Net::Server::PreFork); ### run the server MyHTTPD->run(); exit; ### set up some server parameters sub configure_hook { my $self = shift; $self->{server}->{port} = ['*:80']; # port and addr to bind $self->{server}->{chdir} = '/'; # chdir to root $self->{server}->{user} = 'nobody'; # user to run as $self->{server}->{group} = 'nobody'; # group to run as $self->{server}->{setsid} = 1; # daemonize open(STDIN, '/dev/null') || die "Can't close STDOUT [$!]"; # open(STDERR,'>&STDOUT') || die "Can't close STDERR [$!]"; $self->{document_root} = "/home/httpd/www"; $self->{default_index} = [ qw(index.html index.htm main.htm) ]; $self->{mime_types} = { html => 'text/html', htm => 'text/html', gif => 'image/gif', jpg => 'image/jpeg', }; $self->{mime_default} = 'text/plain'; } ### process the request sub process_request { my $self = shift; local %ENV = (); ### read the first line of response my $line = ; $line =~ s/[\r\n]+$//; unless( $line =~ /^ (\w+) \ + (\S+) \ + (HTTP\/1.\d) $ /x ){ return error(400, "Bad request"); } my ($method,$req,$protocol) = ($1,$2,$3); ### read in other headers $self->read_headers || return error(400, "Strange headers"); ### do we support the type unless( $method =~ /GET|POST|HEAD/ ){ return error(400, "Unsupported Method"); } ### can we read that request unless( $req =~ m%^ (?:http://[^/]+)? (.*) $%x ){ return error(400, "Malformed URL"); } $ENV{REQUEST_URI} = $1; ### parse out the uri and query string my $uri = ''; $ENV{QUERY_STRING} = ''; if( $ENV{REQUEST_URI} =~ m%^ ([^\?]+) (?:\?(.+))? $%x ){ $ENV{QUERY_STRING} = defined($2) ? $2 : ''; $uri = $1; } ### clean up uri if( $uri=~/[\ \;]/ ){ return error(400, "Malformed URL"); } $uri =~ s/%(\w\w)/chr(hex($1))/eg; 1 while $uri =~ s|^\.\./+||; # can't go below doc root ### at this point the uri should be ready to use $uri = "$self->{document_root}$uri"; ### see if there's an index page if( -d $uri ){ foreach (@{ $self->{default_index} }){ if( -e "$uri/$_" ){ $uri = "$uri/$_"; last; } } } ### error 404 if( !-e $uri ){ return error(404, "file not found"); ### directory listing }elsif( -d $uri ){ ### need work on this print content_type('text/html'),"\r\n"; print "Directory listing not supported"; ### spit it out }elsif( open(FILE, "<$uri") ){ my ($type) = $uri =~ m/([^\.]+)$/; $type = exists($self->{mime_types}->{$type}) ? $self->{mime_types}->{$type} : $self->{mime_default}; print status(200), content_type( $type ), "\r\n"; print STDOUT $_ while (); close(FILE); }else{ return error(500, "Can't open file [$!]"); } } sub read_headers { my $self = shift; $self->{headers} = {}; while(){ s/[\r\n]+$//; last unless length $_; unless( /^([\w\-]+) :[\ \t]+ (.+) $/x ){ return 0; } my $key = "HTTP_" . uc($1); $key =~ tr/-/_/; $self->{headers}->{$key} = $2; } return 1; } sub content_type { my $type = shift; return "Content-type: $type\r\n"; } sub error{ print &status; print "\r\n"; #,shift(); } sub status { my $number = shift; my $msg = shift || ''; return "Status $number: $msg\r\n"; } 1;