--- loncom/lonhttpd 2002/10/29 20:21:32 1.1
+++ loncom/lonhttpd 2003/07/30 15:28:56 1.9
@@ -1,152 +1,600 @@
#!/usr/bin/perl
-# The LearningOnline Network with CAPA
-# lonhttpd server (port 8080)
-# based on
-# TinyHTTPD - a minimum-functional HTTP server written in -*- Perl -*-
-# -ot.0894
-# $Id: lonhttpd,v 1.1 2002/10/29 20:21:32 www Exp $
-
-# Currently supported: HTTP 1.0/1.1 GET and POST queries
-# File types of .html and .gif
-
-$ENV{'SERVER_SOFTWARE'}="TinyHTTPD $Revision: 1.1 $ -ot.0894 (LON-CAPA)";
-
-
-use POSIX;
-
-$pid=fork;
-exit if $pid;
-die "Could not fork: $!" unless defined($pid);
-POSIX::setsid() or die "Can't start new session: $!";
-open (PIDSAVE,">/home/httpd/perl/logs/lonhttpd.pid");
+# $Id: lonhttpd,v 1.9 2003/07/30 15:28:56 www Exp $
+
+$VERSION = "1.3.2 (Demonic/Linux/LON-CAPA Derivative $Revison$)";
+
+# HTTPi Hypertext Tiny Truncated Process Implementation
+# Copyright 1999-2001 Cameron Kaiser # All rights reserved
+# Please read LICENSE # Do not strip this copyright message.
+#
+# LON-CAPA: find httpi license and readme at CVS loncom/license
+#
+
+use lib '/home/httpd/lib/perl/';
+use LONCAPA::Configuration();
+%loncapavar=%{&LONCAPA::Configuration::read_conf('loncapa.conf')};
+$port_to_use=$loncapavar{'lonhttpdPort'};
+if (!defined($port_to_use)) {
+ $port_to_use='8080';
+}
+
+# The main server is running on 80, so exit in this case
+if ($port_to_use eq '80') { die('Apache is already on Port 80'); }
+
+%system_content_types =
+ ("html" => "text/html",
+ "htm" => "text/html",
+ "wml" => "text/vnd.wap.wml",
+ "wbmp" => "image/vnd.wap.wbmp",
+ "wbm" => "image/vnd.wap.wbmp",
+ "xbm" => "image/x-xbitmap",
+ "pdf" => "application/pdf",
+ "fdf" => "application/vnd.fdf",
+ "bin" => "application/octet-stream",
+ "class" => "application/octet-stream",
+ "jar" => "application/octet-stream",
+ "js" => "application/x-javascript",
+ "lnk" => "application/x-hyperlink",
+ "wav" => "audio/x-wav",
+ "mp3" => "audio/x-mpeg",
+ "tif" => "image/tiff",
+ "tiff" => "image/tiff",
+ "mid" => "audio/x-midi",
+ "txt" => "text/plain",
+ "gif" => "image/gif",
+ "sit" => "application/x-stuffit",
+ "zip" => "application/x-zip-compressed",
+ "lzh" => "application/octet-stream",
+ "lha" => "application/octet-stream",
+ "gz" => "application/x-gzip",
+ "mov" => "movie/quicktime",
+ "mpeg" => "video/mpeg",
+ "mpg" => "video/mpeg",
+ "jpeg" => "image/jpeg",
+ "jpg" => "image/jpeg");
+
+$logfile = "/home/httpd/perl/logs/lonhttpd.log";
+
+# Write out PID
+
+$pidfile="/home/httpd/perl/logs/lonhttpd.pid";
+
+if (-e $pidfile) {
+ open(LFH,"$pidfile");
+ my $pide=<$LFH>;
+ chomp($pide);
+ close(LFH);
+ if (kill 0 => $pide) { die "already running"; }
+}
+
+$path = "/home/httpd/html";
+$sockaddr = 'S n a4 x8';
+
+
+%content_types =
+ ("html" => "text/html",
+ "htm" => "text/html");
+%restrictions =
+ ("/" => "#.##", # deny everything
+ "/res/adm" => ".###", # allow /res/adm
+ "/adm" => ".###", # allow /adm
+ "/status" => ".####lonadm:oeRooOvb3HtpI");
+ # See documentation for interpreting this string.
+
+$headers = <<"EOF";
+Server: HTTPi/$VERSION
+MIME-Version: 1.0
+EOF
+
+%virtual_files =
+ (
+"/adm/lonLCDfont/0.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/0.gif" ] ,
+"/adm/lonLCDfont/1.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/1.gif" ] ,
+"/adm/lonLCDfont/2.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/2.gif" ] ,
+"/adm/lonLCDfont/3.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/3.gif" ] ,
+"/adm/lonLCDfont/4.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/4.gif" ] ,
+"/adm/lonLCDfont/5.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/5.gif" ] ,
+"/adm/lonLCDfont/6.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/6.gif" ] ,
+"/adm/lonLCDfont/7.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/7.gif" ] ,
+"/adm/lonLCDfont/8.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/8.gif" ] ,
+"/adm/lonLCDfont/9.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/9.gif" ] ,
+"/adm/lonLCDfont/a.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/a.gif" ] ,
+"/adm/lonLCDfont/b.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/b.gif" ] ,
+"/adm/lonLCDfont/c.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/c.gif" ] ,
+"/adm/lonLCDfont/d.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/d.gif" ] ,
+"/adm/lonLCDfont/e.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/e.gif" ] ,
+"/adm/lonLCDfont/f.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/f.gif" ] ,
+"/adm/lonLCDfont/g.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/g.gif" ] ,
+"/adm/lonLCDfont/h.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/h.gif" ] ,
+"/adm/lonLCDfont/i.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/i.gif" ] ,
+"/adm/lonLCDfont/j.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/j.gif" ] ,
+"/adm/lonLCDfont/k.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/k.gif" ] ,
+"/adm/lonLCDfont/l.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/l.gif" ] ,
+"/adm/lonLCDfont/m.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/m.gif" ] ,
+"/adm/lonLCDfont/n.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/n.gif" ] ,
+"/adm/lonLCDfont/o.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/o.gif" ] ,
+"/adm/lonLCDfont/p.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/p.gif" ] ,
+"/adm/lonLCDfont/q.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/q.gif" ] ,
+"/adm/lonLCDfont/r.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/r.gif" ] ,
+"/adm/lonLCDfont/s.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/s.gif" ] ,
+"/adm/lonLCDfont/t.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/t.gif" ] ,
+"/adm/lonLCDfont/u.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/u.gif" ] ,
+"/adm/lonLCDfont/v.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/v.gif" ] ,
+"/adm/lonLCDfont/w.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/w.gif" ] ,
+"/adm/lonLCDfont/x.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/x.gif" ] ,
+"/adm/lonLCDfont/y.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/y.gif" ] ,
+"/adm/lonLCDfont/z.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/z.gif" ] ,
+"/adm/lonLCDfont/colon.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/colon.gif" ] ,
+"/adm/lonLCDfont/slash.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/slash.gif" ] ,
+"/adm/lonLCDfont/hyphen.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/hyphen.gif" ] ,
+"/adm/lonLCDfont/space.gif" => [ "image/gif", "FILE",
+ "/home/httpd/html/adm/lonLCDfont/space.gif" ] ,
+ );
+
+%content_types = (%system_content_types, %content_types);
+undef %system_content_types;
+
+while (($file, $arrayref) = each(%virtual_files)) {
+ my ($mime, $type, $block) = (@{ $arrayref });
+ next if ($type ne 'FILE');
+ if(open(S, "$block")) {
+ $j = $/; undef $/; $virtual_files{$file}->[2] = scalar();
+ $/ = $j; close(S);
+ } else {
+ warn "while getting virtual file $file: $!\n";
+ map_delete(%virtual_files, $file);
+ }
+}
+if ($pid = fork()) { exit; }
+
+#
+# Store parent PID
+#
+
+open (PIDSAVE,">$pidfile");
print PIDSAVE "$$\n";
close(PIDSAVE);
-sub REAPER {
- 1 until (-1==waitpid(-1,WNOHANG));
- $SIG{CHLD}=\&REAPER;
-}
-
-$SIG{CHLD}=\&REAPER;
-
-## Configuration section
-$port=8080; # Port on which we listen
-$htmldir="/home/httpd/html/"; # Base directory for HTML files
-
-# the following substitutes "require 'sys/socket.ph';" on ultrix
-# Check if the definitions are correct with /usr/include/sys/socket.h
-$AF_INET=2; $PF_INET=$AF_INET; $SOCK_STREAM=1;
-
-# Messages
-%errors=
- (
- "403", "Forbidden",
- "404", "Not Found",
- "500", "Internal Error",
- "501", "Not Implemented",
- );
-%verrors=
- (
- "403", "Your client is not allowed to request this item",
- "404", "The requested item was not found on this server",
- "500", "An error occurred while trying to retrieve item",
- "501", "This server does not support the given request type",
- );
+$0 = "lonhttpd: (dhttpi) binding port ...";
+$bindthis = pack($sockaddr, 2, $port_to_use,
+ pack('l', chr(0).chr(0).chr(0).chr(0)));
+socket(S, 2, 1, 6);
+setsockopt(S, 1, 2, 1);
+bind(S, $bindthis) || die("$0: while binding port $port_to_use:\n\"$!\"\n");
+listen(S, 128);
+$0 = "lonhttpd: (dhttpi) connected and waiting ANY:$port_to_use";
+
+$statiosuptime = time();
+
+###############################################################
+# WHITE HATS ONLY BELOW THIS POINT -- SEE DOCUMENTATION FIRST #
+###############################################################
+
+sub sock_to_host {
+ local($sock) = getpeername(STDIN);
+
+ return (undef, undef, undef) if (!$sock);
+ local($AFC, $port, $thataddr, $zero) = unpack($sockaddr, $sock);
+ local($ip) = join('.', unpack("C4", $thataddr));
+ return ($ip, $port, $ip);
+}
+
+sub htsponse {
+ ($currentcode, $currentstring) = (@_);
+ return if (0+$httpver < 1);
+ local($what) = <<"EOF";
+HTTP/$httpver $currentcode $currentstring
+${headers}Date: $rfcdate
+EOF
+ $what =~ s/\n/\r\n/g;
+ print stdout $what;
+ &hthead("Connection: close") if (0+$httpver > 1);
+}
-(($>)&&($<==$>)&&($(==$))) || die "Don't run this program with privileges!\n";
+sub hthead {
+ local($header, $term) = (@_);
+ return if (0+$httpver < 1);
+ print stdout "$header\r\n" , ($term) ? "\r\n" : "";
+}
-# set up a server socket, redirect stderr to logfile
-$IPPROTO_TCP=6;
-$sockaddr = 'S n a4 x8';
-$this = pack($sockaddr, $AF_INET, $port, "\0\0\0\0");
-socket(S, $PF_INET, $SOCK_STREAM, $IPPROTO_TCP) || die "socket: $!";
-bind(S, $this) || die "bind: $!";
-listen(S, 5) || die "listen: $!";
-open(LOG,">>/home/httpd/perl/logs/lonhttpd.log");
-select(LOG); $|=1;
-open(STDERR, ">&LOG") || die "dup2 log->stderr";
+sub htcontent {
+ local($what, $ctype, $mode) = (@_);
+ ($contentlength) = $mode || length($what);
+ &hthead("Content-Length: $contentlength");
+ &hthead("Content-Type: $ctype", 1);
+ return if ($method eq 'HEAD' || $mode);
+ print stdout $what;
+}
+
+sub log {
+ if (open(J, ">>$logfile")) {
+ local $q = $address . (($variables) ? "?$variables" : "");
+ $contentlength += 0;
+ $contentlength = 0 if ($method eq 'HEAD');
+ local ($hostname, $port, $ip) = &sock_to_host();
+ $hostname = $hostname || "-";
+ $httpuser = $httpuser || "-";
+ print J <<"EOF";
+$hostname - $httpuser [$date] "$method $q HTTP/$httpver" $currentcode $contentlength "$httpref" "$httpua"
+EOF
+ close(J); }
+ }
+
+
+sub bye { exit; }
+
+sub goodbye { unlink($pidfile); exit; }
+
+sub dead {
+ &htsponse(500, "Server Error");
+ &hterror("Server Error", <<"EOF");
+While handling a request for resource $address, the server crashed. Please
+attempt to notify the administrators.
+
Useful(?) debugging information: +
+@_ ++EOF + &log; unlink($pidfile); exit; +} + +$SIG{'__DIE__'} = \&dead; +$SIG{'ALRM'} = \&bye; +$SIG{'TERM'} = $SIG{'INT'} = \&goodbye; + +sub master { + $0 = "lonhttpd: (dhttpi) handling request"; +# $sock = getpeername(STDIN); +$rfcdate = scalar gmtime; +($dow, $mon, $dt, $tm, $yr) = ($rfcdate =~ + m/(...) (...) (..) (..:..:..) (....)/); +$dt += 0; $yr += 0; +$rfcdate = "$dow, $dt $mon $yr $tm GMT"; +$date = scalar localtime; +($dow, $mon, $dt, $tm, $yr) = ($date =~ + m/(...) (...) (..) (..:..:..) (....)/); +$dt += 0; +$dt = substr("0$dt", length("0$dt") - 2, 2); +$date = "$dt/$mon/$yr:$tm +0000"; + +select(STDOUT); $|=1; $address = 0; +alarm 1; +while (
$VERSION
)
+Requests received: $statiosreq
+Average time between requests: ${rps}s
+
+Most recent requests: +
+@_[1]-