1 | #!/usr/bin/perl |
1 | #!/usr/bin/perl |
|
|
2 | |
|
|
3 | # this is a relatively small web-server, using coroutines |
|
|
4 | # for connections. play around with it but do not use |
|
|
5 | # it in production. ask myhttpd@plan9.de for a better |
|
|
6 | # version that's more usable and bugfixed. |
2 | |
7 | |
3 | use Coro; |
8 | use Coro; |
4 | use Coro::Semaphore; |
9 | use Coro::Semaphore; |
5 | use Coro::Event; |
10 | use Coro::Event; |
6 | use Coro::Socket; |
11 | use Coro::Socket; |
… | |
… | |
83 | use HTTP::Date; |
88 | use HTTP::Date; |
84 | |
89 | |
85 | sub new { |
90 | sub new { |
86 | my $class = shift; |
91 | my $class = shift; |
87 | my $fh = shift; |
92 | my $fh = shift; |
88 | my (undef, $iaddr) = unpack_sockaddr_in $fh->getpeername |
93 | my (undef, $iaddr) = unpack_sockaddr_in $fh->peername |
89 | or $self->err(500, "unable to get peername"); |
94 | or $self->err(500, "unable to get peername"); |
90 | $self->{remote_address} = inet_ntoa $iaddr; |
95 | $self->{remote_address} = inet_ntoa $iaddr; |
91 | bless { fh => $fh }, $class; |
96 | bless { fh => $fh }, $class; |
92 | } |
97 | } |
93 | |
98 | |
… | |
… | |
146 | ([^\040]+) \040+ |
151 | ([^\040]+) \040+ |
147 | HTTP\/([0-9]+\.[0-9]+) |
152 | HTTP\/([0-9]+\.[0-9]+) |
148 | \015\012/gx |
153 | \015\012/gx |
149 | or $self->err(403, "method not allowed", { Allow => "GET,HEAD" }); |
154 | or $self->err(403, "method not allowed", { Allow => "GET,HEAD" }); |
150 | |
155 | |
151 | $2 ne "1.0" |
156 | $2 >= 2 |
152 | or $self->err(506, "http protocol version not supported"); |
157 | or $self->err(506, "http protocol version not supported"); |
153 | |
158 | |
154 | $self->{method} = $1; |
159 | $self->{method} = $1; |
155 | $self->{uri} = $2; |
160 | $self->{uri} = $2; |
156 | |
161 | |
… | |
… | |
201 | $self->{path} = "$::DOCROOT/$host$uri"; |
206 | $self->{path} = "$::DOCROOT/$host$uri"; |
202 | } |
207 | } |
203 | |
208 | |
204 | sub server_address { |
209 | sub server_address { |
205 | my $self = shift; |
210 | my $self = shift; |
206 | my ($port, $iaddr) = unpack_sockaddr_in $self->{fh}->getsockname |
211 | my ($port, $iaddr) = unpack_sockaddr_in $self->{fh}->sockname |
207 | or $self->err(500, "unable to get socket name"); |
212 | or $self->err(500, "unable to get socket name"); |
208 | ((inet_ntoa $iaddr), $port); |
213 | ((inet_ntoa $iaddr), $port); |
209 | } |
214 | } |
210 | |
215 | |
211 | sub server_host { |
216 | sub server_host { |
… | |
… | |
227 | } |
232 | } |
228 | $port = $port == 80 ? "" : ":$port"; |
233 | $port = $port == 80 ? "" : ":$port"; |
229 | $host.$port; |
234 | $host.$port; |
230 | } |
235 | } |
231 | |
236 | |
|
|
237 | # no, this doesn't do cgi, but it's close enough |
|
|
238 | # for the no-longer-used directory indexing script. |
232 | sub _cgi { |
239 | sub _cgi { |
233 | my $self = shift; |
240 | my $self = shift; |
234 | my $path = shift; |
241 | my $path = shift; |
235 | my $fh; |
242 | my $fh; |
236 | |
243 | |
… | |
… | |
337 | |
344 | |
338 | $self->print_response(@code, $hdr, ""); |
345 | $self->print_response(@code, $hdr, ""); |
339 | |
346 | |
340 | if ($self->{method} eq "GET") { |
347 | if ($self->{method} eq "GET") { |
341 | my ($fh, $buf); |
348 | my ($fh, $buf); |
342 | open $fh, "<", $self->{path} |
349 | cpen $fh, "<", $self->{path} |
343 | or die "$self->{path}: late open failure ($!)"; |
350 | or die "$self->{path}: late open failure ($!)"; |
344 | |
351 | |
345 | if ($l) { |
352 | if ($l) { |
346 | sysseek $fh, $l, 0 |
353 | sysseek $fh, $l, 0 |
347 | or die "$self->{path}: cannot seek to $l ($!)"; |
354 | or die "$self->{path}: cannot seek to $l ($!)"; |