ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Coro/myhttpd/httpd.pl
(Generate patch)

Comparing cvsroot/Coro/myhttpd/httpd.pl (file contents):
Revision 1.1 by root, Thu Aug 9 02:57:54 2001 UTC vs.
Revision 1.3 by root, Fri Aug 10 02:28:28 2001 UTC

1#!/usr/bin/perl
2
3use Coro; 1use Coro;
4use Coro::Semaphore; 2use Coro::Semaphore;
5use Coro::Event; 3use Coro::Event;
6use Coro::Socket; 4use Coro::Socket;
7 5
30my $connections = new Coro::Semaphore $MAX_CONNECTS; 28my $connections = new Coro::Semaphore $MAX_CONNECTS;
31 29
32my @fh; 30my @fh;
33my @pool; 31my @pool;
34 32
33# one "execution thread"
35sub handler { 34sub handler {
36 while () { 35 while () {
37 my $fh = pop @fh; 36 my $fh = pop @fh;
38 if ($fh) { 37 if ($fh) {
39 eval { 38 eval {
48 schedule; 47 schedule;
49 } 48 }
50 } 49 }
51} 50}
52 51
52# the "main thread"
53async { 53async {
54 slog 1, "accepting connections"; 54 slog 1, "accepting connections";
55 while () { 55 while () {
56 $connections->down; 56 $connections->down;
57 push @fh, $port->accept; 57 push @fh, $port->accept;
58 #slog 3, "accepted @$connections ".scalar(@pool); 58 #slog 3, "accepted @$connections ".scalar(@pool);
59 $::NOW = time;
59 if (@pool) { 60 if (@pool) {
60 (pop @pool)->ready; 61 (pop @pool)->ready;
61 } else { 62 } else {
62 async \&handler; 63 async \&handler;
63 } 64 }
70 71
71package conn; 72package conn;
72 73
73use Socket; 74use Socket;
74use HTTP::Date; 75use HTTP::Date;
76use Convert::Scalar 'weaken';
77
78our %conn; # $conn{ip}{fh} => connobj
79our %blocked;
75 80
76sub new { 81sub new {
77 my $class = shift; 82 my $class = shift;
78 my $fh = shift; 83 my $fh = shift;
84 my $self = bless { fh => $fh }, $class;
79 my (undef, $iaddr) = unpack_sockaddr_in $fh->getpeername 85 my (undef, $iaddr) = unpack_sockaddr_in $fh->getpeername
80 or $self->err(500, "unable to get peername"); 86 or $self->err(500, "unable to get peername");
81 $self->{remote_address} = inet_ntoa $iaddr; 87 $self->{remote_addr} = inet_ntoa $iaddr;
82 bless { fh => $fh }, $class; 88
89 # enter ourselves into various lists
90 weaken ($conn{$self->{remote_addr}}{$self*1} = $self);
91
92 print "$self->{remote_addr}: ".($self*1)." > ".%{$conn{$self->{remote_addr}}},"\n";
93 $self;
94}
95
96sub DESTROY {
97 my $self = shift;
98 delete $conn{$self->{remote_addr}}{$self*1};
99 delete $uri{$self->{uri}}{$self*1};
83} 100}
84 101
85sub slog { 102sub slog {
86 main::slog(@_); 103 main::slog(@_);
87} 104}
88 105
89sub print_response { 106sub print_response {
90 my ($self, $code, $msg, $hdr, $content) = @_; 107 my ($self, $code, $msg, $hdr, $content) = @_;
91 my $res = "HTTP/1.0 $code $msg\015\012"; 108 my $res = "HTTP/1.0 $code $msg\015\012";
92 109
93 $hdr->{Date} = time2str time; # slow? nah. 110 $hdr->{Date} = time2str $::NOW; # slow? nah.
94 111
95 while (my ($h, $v) = each %$hdr) { 112 while (my ($h, $v) = each %$hdr) {
96 $res .= "$h: $v\015\012" 113 $res .= "$h: $v\015\012"
97 } 114 }
98 $res .= "\015\012$content" if defined $content; 115 $res .= "\015\012$content" if defined $content;
116
117 print STDERR "$self->{remote_addr} \"$self->{uri}\" $code ".$hdr->{"Content-Length"}." \"$self->{h}{referer}\"\n";#d#
99 118
100 print {$self->{fh}} $res; 119 print {$self->{fh}} $res;
101} 120}
102 121
103sub err { 122sub err {
115 $self->print_response($code, $msg, $hdr, $content); 134 $self->print_response($code, $msg, $hdr, $content);
116 135
117 die bless {}, err::; 136 die bless {}, err::;
118} 137}
119 138
139sub err_blocked {
140 my $self = shift;
141 my $ip = $self->{remote_addr};
142 my $time = time2str $blocked{$ip} = $::NOW + $::BLOCKTIME;
143 $self->err(403, "too many connections",
144 { "Retry-After" => $::BLOCKTIME },
145 <<EOF);
146You have been blocked because you opened too many connections. You
147may retry at $time. Until then,
148every new access will renew the block.
149EOF
150}
151
120sub handle { 152sub handle {
121 my $self = shift; 153 my $self = shift;
122 my $fh = $self->{fh}; 154 my $fh = $self->{fh};
123 155
124 #while() { 156 #while() {
129 my $req = $fh->readline("\015\012\015\012"); 161 my $req = $fh->readline("\015\012\015\012");
130 $fh->timeout($::RES_TIMEOUT); 162 $fh->timeout($::RES_TIMEOUT);
131 163
132 defined $req or 164 defined $req or
133 $self->err(408, "request timeout"); 165 $self->err(408, "request timeout");
166
167 my $ip = $self->{remote_addr};
168
169 if ($blocked{$ip}) {
170 $self->err_blocked($blocked{$ip})
171 if $blocked{$ip} > $::NOW;
172
173 delete $blocked{$ip};
174 }
175
176 if (%{$conn{$ip}} > $::MAX_CONN_IP) {
177 $self->slog("blocked ip $ip");
178 $self->err_blocked;
179 }
134 180
135 $req =~ /^(?:\015\012)? 181 $req =~ /^(?:\015\012)?
136 (GET|HEAD) \040+ 182 (GET|HEAD) \040+
137 ([^\040]+) \040+ 183 ([^\040]+) \040+
138 HTTP\/([0-9]+\.[0-9]+) 184 HTTP\/([0-9]+\.[0-9]+)
164 while ($h, $v) = each %hdr; 210 while ($h, $v) = each %hdr;
165 } 211 }
166 212
167 $self->{server_port} = $self->{h}{host} =~ s/:([0-9]+)$// ? $1 : 80; 213 $self->{server_port} = $self->{h}{host} =~ s/:([0-9]+)$// ? $1 : 80;
168 214
215 weaken ($uri{$self->{uri}}{$self*1} = $self);
216
169 $self->map_uri; 217 $self->map_uri;
218
219 Coro::Event::do_timer(after => 5);
220
170 $self->respond; 221 $self->respond;
171 #} 222 #}
172} 223}
173 224
174# uri => path mapping 225# uri => path mapping
347 } 398 }
348 } 399 }
349 400
350 close $fh; 401 close $fh;
351} 402}
403
4041;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines