pp2@nereida:~/src/perl/NET_SERVER$ cat -n httpd
1 #!/usr/bin/perl
2 use strict;
3 use warnings;
4 use base qw(Net::Server::PreFork);
5 use MIME::Types;
6 use HTTP::Status;
7 use HTTP::Request;
8
9 ### run the server
10 __PACKAGE__->run;
11 exit;
12
13 ###----------------------------------------------------------------###
14
15 #my $LOG;
16
17 ### set up some server parameters
18 sub configure_hook {
19 my $self = shift;
20
21 my $root = $self->{server_root} = "/home/pp2/public_html";
22
23 $self->{server}->{port} = '*:8080'; # port and addr to bind
24 # $self->{server}->{user} = 'nobody'; # user to run as
25 # $self->{server}->{group} = 'nobody'; # group to run as
26 # $self->{server}->{setsid} = 1; # daemonize
27 # $self->{server}->{pid_file} = "$root/server.pid"; # pid file
28 # $self->{server}->{log_file} = "$root/server.log";
29
30
31 $self->{document_root} = "$root/";
32 # $self->{access_log} = "$root/access.log";
33 # $self->{error_log} = "$root/error.log";
34
35 $self->{default_index} = [ qw(index.html index.htm main.htm) ];
36
37 }
38
39 sub post_configure_hook {
40 use vars qw{$CRLF};
41 $CRLF = "\015\012";
42
43 my $self = shift;
44
45 # open(STDERR, ">>". $self->{error_log}) || die "Couldn't open STDERR: $!";
46 # open($LOG, ">>". $self->{access_log}) || die "Couldn't open log file: $!";
47 # autoflush $LOG 1;
48 # autoflush STDERR 1;
49 }
50
51 ### process the request
52 sub process_request {
53 my $self = shift;
54
55 local $/ = "$CRLF$CRLF";
56 my $request = <STDIN>; # read the request header
57 # warn "header:\n$request\n";
58
59 my $r = HTTP::Request->parse( $request );
60 my $method = $r->method; # GET | HEAD | ...
61 my $url = $r->uri;
62
63 warn join(" ", time, $method, "$url")."\n";
64
65 ### do we support the type
66 if ($method !~ /GET|HEAD/) {
67 return $self->error(RC_BAD_REQUEST(), "Unsupported Method");
68 }
69
70 ### clean up uri
71 my $path = URI::Escape::uri_unescape($url);
72 $path =~ s/\?.*$//; # ignore query
73 $path =~ s/\#.*$//; # get rid of fragment
74
75 ### at this point the path should be ready to use
76 $path = "$self->{document_root}$path";
77
78 ### see if there's an index page
79 if (-d $path) {
80 foreach (@{ $self->{default_index} }){
81 if (-e "$path/$_") {
82 return redirect("$url/$_");
83 }
84 }
85 }
86
87 ### error 404
88 return $self->error(RC_NOT_FOUND(), "file not found") unless -e $path;
89
90 ### spit it out
91 open(my $fh, "<$path") || return $self->error(RC_INTERNAL_SERVER_ERROR(), "Can't open file [$!]");
92 my $length = (stat($fh))[7]; # file size
93
94 my $mimeobj = MIME::Types->new->mimeTypeOf($path);
95 my $type = $mimeobj->type if defined($mimeobj);
96
97 # print the header
98 print STDOUT "HTTP/1.0 ".RC_OK." OK$CRLF";
99 print STDOUT "Content-length: $length$CRLF";
100 print STDOUT "Content-type: $type; charset=utf-8";
101 print STDOUT "$CRLF$CRLF";
102
103 return unless $method eq 'GET';
104
105 # print the content
106 my $buffer;
107 while ( read($fh,$buffer,1024) ) {
108 print STDOUT $buffer;
109 }
110 close $fh;
111 }
112
113 sub error {
114 my ($self, $code, $message) = @_;
115 my $status_message = status_message($code);
116
117 print STDOUT "HTTP/1.0 $code Bad request$CRLF";
118 print STDOUT "Content-type: text/html$CRLF$CRLF";
119 print STDOUT <<"END";
120 <HTML>
121 <HEAD><TITLE>$code Bad Request</TITLE></HEAD>
122 <BODY><H1>$status_message</H1>
123 <P>$message</P>
124 </BODY>
125 </HTML>
126 END
127 }
128
129 sub redirect {
130 my ($url) = @_;
131
132 my $moved_to = "$url";
133 print STDOUT "HTTP/1.0 301 Moved permanently$CRLF";
134 print STDOUT "Location: $moved_to$CRLF";
135 print STDOUT "Content-type: text/html$CRLF$CRLF";
136 print STDOUT <<"END";
137 <HTML>
138 <HEAD><TITLE>301 Moved</TITLE></HEAD>
139 <BODY><H1>Moved</H1>
140 <P>The requested document has moved
141 <A HREF="$moved_to">here</A>.</P>
142 </BODY>
143 </HTML>
144 END
145 }
146
147 1;
top, ps, etc.
Casiano Rodríguez León
