| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Arriba::Server; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 16 |  |  | 16 |  | 184 | use warnings; | 
|  | 16 |  |  |  |  | 56 |  | 
|  | 16 |  |  |  |  | 1928 |  | 
| 4 | 16 |  |  | 16 |  | 280 | use strict; | 
|  | 16 |  |  |  |  | 48 |  | 
|  | 16 |  |  |  |  | 1360 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 16 |  |  | 16 |  | 200 | use base 'Net::Server::PreFork'; | 
|  | 16 |  |  |  |  | 1200 |  | 
|  | 16 |  |  |  |  | 28248 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 | 16 |  |  | 16 |  | 752600 | use HTTP::Date; | 
|  | 16 |  |  |  |  | 105744 |  | 
|  | 16 |  |  |  |  | 1112 |  | 
| 9 | 16 |  |  | 16 |  | 144 | use HTTP::Status qw(status_message); | 
|  | 16 |  |  |  |  | 32 |  | 
|  | 16 |  |  |  |  | 26176 |  | 
| 10 | 16 |  |  | 16 |  | 16760 | use HTTP::Parser::XS qw(parse_http_request); | 
|  | 16 |  |  |  |  | 28344 |  | 
|  | 16 |  |  |  |  | 1192 |  | 
| 11 | 16 |  |  | 16 |  | 25368 | use IO::Socket::SSL; | 
|  | 16 |  |  |  |  | 1318800 |  | 
|  | 16 |  |  |  |  | 224 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 | 16 |  |  | 16 |  | 4376 | use Plack::Util; | 
|  | 16 |  |  |  |  | 32 |  | 
|  | 16 |  |  |  |  | 504 |  | 
| 14 | 16 |  |  | 16 |  | 14728 | use Plack::TempBuffer; | 
|  | 16 |  |  |  |  | 5408 |  | 
|  | 16 |  |  |  |  | 536 |  | 
| 15 |  |  |  |  |  |  |  | 
| 16 | 16 |  |  | 16 |  | 104 | use constant DEBUG => $ENV{ARRIBA_DEBUG}; | 
|  | 16 |  |  |  |  | 24 |  | 
|  | 16 |  |  |  |  | 1112 |  | 
| 17 | 16 |  |  | 16 |  | 80 | use constant CHUNKSIZE => 64 * 1024; | 
|  | 16 |  |  |  |  | 32 |  | 
|  | 16 |  |  |  |  | 1400 |  | 
| 18 |  |  |  |  |  |  |  | 
| 19 | 16 |  |  | 16 |  | 112 | my $null_io = do { open my $io, "<", \""; $io }; | 
|  | 16 |  |  |  |  | 32 |  | 
|  | 16 |  |  |  |  | 440 |  | 
| 20 |  |  |  |  |  |  |  | 
| 21 | 16 |  |  | 16 |  | 88 | use Net::Server::SIG qw(register_sig); | 
|  | 16 |  |  |  |  | 32 |  | 
|  | 16 |  |  |  |  | 14608 |  | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | # Override Net::Server's HUP handling - just restart all the workers and that's | 
| 24 |  |  |  |  |  |  | # about it | 
| 25 |  |  |  |  |  |  | sub sig_hup { | 
| 26 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 27 | 0 |  |  |  |  | 0 | $self->hup_children; | 
| 28 |  |  |  |  |  |  | } | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | sub run { | 
| 31 | 16 |  |  | 16 | 1 | 432 | my ($self, $app, $options) = @_; | 
| 32 |  |  |  |  |  |  |  | 
| 33 | 16 |  |  |  |  | 616 | $self->{app} = $app; | 
| 34 | 16 |  |  |  |  | 40 | $self->{options} = $options; | 
| 35 |  |  |  |  |  |  |  | 
| 36 | 16 |  |  |  |  | 48 | my %extra = (); | 
| 37 | 16 | 50 |  |  |  | 80 | if ($options->{pid}) { | 
| 38 | 0 |  |  |  |  | 0 | $extra{pid_file} = $options->{pid}; | 
| 39 |  |  |  |  |  |  | } | 
| 40 | 16 | 50 |  |  |  | 56 | if ($options->{daemonize}) { | 
| 41 | 0 |  |  |  |  | 0 | $extra{setsid} = $extra{background} = 1; | 
| 42 |  |  |  |  |  |  | } | 
| 43 | 16 | 100 |  |  |  | 152 | if ($options->{ssl_cert}) { | 
| 44 | 8 |  |  |  |  | 16 | $extra{SSL_cert_file} = $options->{ssl_cert}; | 
| 45 |  |  |  |  |  |  | } | 
| 46 | 16 | 100 |  |  |  | 48 | if ($options->{ssl_key}) { | 
| 47 | 8 |  |  |  |  | 16 | $extra{SSL_key_file} = $options->{ssl_key}; | 
| 48 |  |  |  |  |  |  | } | 
| 49 | 16 | 50 |  |  |  | 64 | if (!exists $options->{keepalive}) { | 
| 50 | 16 |  |  |  |  | 40 | $options->{keepalive} = 1; | 
| 51 |  |  |  |  |  |  | } | 
| 52 | 16 | 50 |  |  |  | 48 | if (!exists $options->{keepalive_timeout}) { | 
| 53 | 16 |  |  |  |  | 32 | $options->{keepalive_timeout} = 1; | 
| 54 |  |  |  |  |  |  | } | 
| 55 |  |  |  |  |  |  |  | 
| 56 | 16 |  |  |  |  | 24 | my @port; | 
| 57 | 16 | 50 |  |  |  | 24 | for my $listen (@{$options->{listen} || [ "$options->{host}:$options->{port}" ]}) { | 
|  | 16 |  |  |  |  | 360 |  | 
| 58 | 16 |  |  |  |  | 32 | my %listen; | 
| 59 | 16 | 50 |  |  |  | 88 | if ($listen =~ /:/) { | 
| 60 | 16 |  |  |  |  | 56 | my($h, $p, $opt) = split /:/, $listen, 3; | 
| 61 | 16 | 50 |  |  |  | 80 | $listen{host} = $h if $h; | 
| 62 | 16 |  |  |  |  | 40 | $listen{port} = $p; | 
| 63 | 16 | 50 |  |  |  | 2456 | $listen{proto} = 'ssl' if 'ssl' eq lc $opt; | 
| 64 |  |  |  |  |  |  | } | 
| 65 |  |  |  |  |  |  | else { | 
| 66 | 0 |  |  |  |  | 0 | %listen = ( | 
| 67 |  |  |  |  |  |  | host  => 'localhost', | 
| 68 |  |  |  |  |  |  | port  => $listen, | 
| 69 |  |  |  |  |  |  | proto => 'unix', | 
| 70 |  |  |  |  |  |  | ); | 
| 71 |  |  |  |  |  |  | } | 
| 72 | 16 |  |  |  |  | 80 | push @port, \%listen; | 
| 73 |  |  |  |  |  |  | } | 
| 74 |  |  |  |  |  |  |  | 
| 75 | 16 |  | 50 |  |  | 112 | my $workers = $options->{workers} || 5; | 
| 76 |  |  |  |  |  |  |  | 
| 77 | 16 |  |  |  |  | 40 | local @ARGV = (); | 
| 78 |  |  |  |  |  |  |  | 
| 79 | 16 | 100 | 33 |  |  | 928 | $self->SUPER::run( | 
|  |  | 50 | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 50 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 50 |  |  |  |  | 
| 80 |  |  |  |  |  |  | port => \@port, | 
| 81 |  |  |  |  |  |  | host => '*', | 
| 82 |  |  |  |  |  |  | proto => $options->{ssl} ? 'ssl' : 'tcp', | 
| 83 |  |  |  |  |  |  | serialize => 'flock', | 
| 84 |  |  |  |  |  |  | log_level => DEBUG ? 4 : 2, | 
| 85 |  |  |  |  |  |  | ($options->{error_log} ? ( log_file => $options->{error_log} ) : () ), | 
| 86 |  |  |  |  |  |  | min_servers => $options->{min_servers} || $workers, | 
| 87 |  |  |  |  |  |  | min_spare_servers => $options->{min_spare_servers} || $workers - 1, | 
| 88 |  |  |  |  |  |  | max_spare_servers => $options->{max_spare_servers} || $workers - 1, | 
| 89 |  |  |  |  |  |  | max_servers => $options->{max_servers} || $workers, | 
| 90 |  |  |  |  |  |  | max_requests => $options->{max_requests} || 1000, | 
| 91 |  |  |  |  |  |  | user => $options->{user} || $>, | 
| 92 |  |  |  |  |  |  | group => $options->{group} || $), | 
| 93 |  |  |  |  |  |  | listen => $options->{backlog} || 1024, | 
| 94 |  |  |  |  |  |  | check_for_waiting => 1, | 
| 95 |  |  |  |  |  |  | no_client_stdout => 1, | 
| 96 |  |  |  |  |  |  | %extra | 
| 97 |  |  |  |  |  |  | ); | 
| 98 |  |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | sub configure_hook { | 
| 101 | 16 |  |  | 16 | 1 | 1536 | my $self = shift; | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | # FIXME: Is this (configure_hook) the best place for this? | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 16 | 50 |  |  |  | 120 | if ($self->{options}->{listen_ssl}) { | 
| 106 | 0 |  |  |  |  | 0 | $self->{server}->{ssl_args}->{SSL_key_file} = | 
| 107 |  |  |  |  |  |  | $self->{options}->{ssl_key_file}; | 
| 108 | 0 |  |  |  |  | 0 | $self->{server}->{ssl_args}->{SSL_cert_file} = | 
| 109 |  |  |  |  |  |  | $self->{options}->{ssl_cert_file}; | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  |  | 
| 112 | 16 |  |  |  |  | 200 | $self->SUPER::configure_hook(@_); | 
| 113 |  |  |  |  |  |  | } | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | sub pre_bind { | 
| 116 | 16 |  |  | 16 | 1 | 10384 | my $self = shift; | 
| 117 |  |  |  |  |  |  |  | 
| 118 | 16 |  |  |  |  | 144 | $self->SUPER::pre_bind(@_); | 
| 119 |  |  |  |  |  |  |  | 
| 120 | 16 | 50 |  |  |  | 58424 | if ($self->{options}->{spdy}) { | 
| 121 |  |  |  |  |  |  | # Enable SPDY on SSL sockets | 
| 122 | 0 |  |  |  |  | 0 | for my $sock (@{$self->{server}->{sock}}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 123 | 0 | 0 |  |  |  | 0 | if ($sock->NS_proto eq 'SSL') { | 
| 124 | 0 |  |  |  |  | 0 | $sock->SSL_npn_protocols(['spdy/3']); | 
| 125 |  |  |  |  |  |  | } | 
| 126 |  |  |  |  |  |  | } | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  | } | 
| 129 |  |  |  |  |  |  |  | 
| 130 |  |  |  |  |  |  | sub pre_loop_hook { | 
| 131 | 16 |  |  | 16 | 1 | 185344 | my $self = shift; | 
| 132 |  |  |  |  |  |  |  | 
| 133 | 16 |  |  |  |  | 64 | my $port = $self->{server}->{port}->[0]; | 
| 134 | 16 | 50 |  |  |  | 96 | my $proto = $port->{proto} eq 'ssl'  ? 'https' : | 
|  |  | 100 |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | $port->{proto} eq 'unix' ? 'unix' : 'http'; | 
| 136 |  |  |  |  |  |  |  | 
| 137 | 16 | 50 |  |  |  | 96 | $self->{options}{server_ready}->({ | 
| 138 |  |  |  |  |  |  | host => $port->{host}, | 
| 139 |  |  |  |  |  |  | port => $port->{port}, | 
| 140 |  |  |  |  |  |  | proto => $proto, | 
| 141 |  |  |  |  |  |  | server_software => 'Arriba', | 
| 142 |  |  |  |  |  |  | }) if $self->{options}{server_ready}; | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | register_sig( | 
| 145 | 0 |  |  | 0 |  | 0 | TTIN => sub { $self->{server}->{$_}++ for qw( min_servers max_servers ) }, | 
| 146 | 0 |  |  | 0 |  | 0 | TTOU => sub { $self->{server}->{$_}-- for qw( min_servers max_servers ) }, | 
| 147 | 0 |  |  | 0 |  | 0 | QUIT => sub { $self->server_close(1) }, | 
| 148 | 16 |  |  |  |  | 184 | ); | 
| 149 |  |  |  |  |  |  | } | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | sub server_close { | 
| 152 | 2 |  |  | 2 | 1 | 3680106 | my($self, $quit) = @_; | 
| 153 |  |  |  |  |  |  |  | 
| 154 | 2 | 50 |  |  |  | 56 | if ($quit) { | 
| 155 | 0 |  |  |  |  | 0 | $self->log(2, $self->log_time . " Received QUIT. Running a graceful shutdown\n"); | 
| 156 | 0 |  |  |  |  | 0 | $self->{server}->{$_} = 0 for qw( min_servers max_servers ); | 
| 157 | 0 |  |  |  |  | 0 | $self->hup_children; | 
| 158 | 0 |  |  |  |  | 0 | while (1) { | 
| 159 | 0 |  |  |  |  | 0 | Net::Server::SIG::check_sigs(); | 
| 160 | 0 |  |  |  |  | 0 | $self->coordinate_children; | 
| 161 | 0 | 0 |  |  |  | 0 | last if !keys %{$self->{server}{children}}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 162 | 0 |  |  |  |  | 0 | sleep 1; | 
| 163 |  |  |  |  |  |  | } | 
| 164 | 0 |  |  |  |  | 0 | $self->log(2, $self->log_time . " Worker processes cleaned up\n"); | 
| 165 |  |  |  |  |  |  | } | 
| 166 |  |  |  |  |  |  |  | 
| 167 | 2 |  |  |  |  | 177 | $self->SUPER::server_close(); | 
| 168 |  |  |  |  |  |  | } | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | sub run_parent { | 
| 171 | 6 |  |  | 6 | 0 | 58593 | my $self = shift; | 
| 172 | 6 | 50 |  |  |  | 111 | $0 = "arriba master " . join(" ", @{$self->{options}{argv} || []}); | 
|  | 6 |  |  |  |  | 552 |  | 
| 173 | 16 |  |  | 16 |  | 88 | no warnings 'redefine'; | 
|  | 16 |  |  |  |  | 16 |  | 
|  | 16 |  |  |  |  | 13520 |  | 
| 174 |  |  |  |  |  |  | local *Net::Server::PreFork::register_sig = sub { | 
| 175 | 6 |  |  | 6 |  | 1581 | my %args = @_; | 
| 176 | 6 |  |  |  |  | 72 | delete $args{QUIT}; | 
| 177 | 6 |  |  |  |  | 303 | Net::Server::SIG::register_sig(%args); | 
| 178 | 6 |  |  |  |  | 459 | }; | 
| 179 | 6 |  |  |  |  | 459 | $self->SUPER::run_parent(@_); | 
| 180 |  |  |  |  |  |  | } | 
| 181 |  |  |  |  |  |  |  | 
| 182 |  |  |  |  |  |  | sub child_init_hook { | 
| 183 | 14 |  |  | 14 | 1 | 3201065 | my $self = shift; | 
| 184 | 14 |  |  |  |  | 1871 | srand(); | 
| 185 | 14 | 50 |  |  |  | 322 | if ($self->{options}->{psgi_app_builder}) { | 
| 186 | 0 |  |  |  |  | 0 | $self->{app} = $self->{options}->{psgi_app_builder}->(); | 
| 187 |  |  |  |  |  |  | } | 
| 188 | 14 | 50 |  |  |  | 679 | $0 = "arriba worker " . join(" ", @{$self->{options}{argv} || []}); | 
|  | 14 |  |  |  |  | 2364 |  | 
| 189 |  |  |  |  |  |  | } | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | sub post_accept_hook { | 
| 192 | 3 |  |  | 3 | 1 | 422803 | my $self = shift; | 
| 193 |  |  |  |  |  |  |  | 
| 194 | 3 |  |  |  |  | 54 | $self->{client} = { }; | 
| 195 |  |  |  |  |  |  | } | 
| 196 |  |  |  |  |  |  |  | 
| 197 |  |  |  |  |  |  | sub process_request { | 
| 198 | 3 |  |  | 3 | 1 | 230 | my $self = shift; | 
| 199 |  |  |  |  |  |  |  | 
| 200 | 3 |  |  |  |  | 26 | my $client = $self->{server}->{client}; | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | # Is this an SSL connection? | 
| 203 | 3 |  |  |  |  | 54 | my $ssl = $client->NS_proto eq 'SSL'; | 
| 204 |  |  |  |  |  |  |  | 
| 205 | 3 | 50 | 66 |  |  | 161 | if ($ssl && $client->next_proto_negotiated && | 
|  |  |  | 33 |  |  |  |  | 
| 206 |  |  |  |  |  |  | $client->next_proto_negotiated eq 'spdy/3') | 
| 207 |  |  |  |  |  |  | { | 
| 208 |  |  |  |  |  |  | # SPDY connection | 
| 209 | 0 |  |  |  |  | 0 | require Arriba::Connection::SPDY; | 
| 210 | 0 |  |  |  |  | 0 | $self->{client}->{connection} = | 
| 211 |  |  |  |  |  |  | Arriba::Connection::SPDY->new($client); | 
| 212 |  |  |  |  |  |  | } | 
| 213 |  |  |  |  |  |  | else { | 
| 214 |  |  |  |  |  |  | # HTTP(S) connection | 
| 215 | 3 |  |  |  |  | 5936 | require Arriba::Connection::HTTP; | 
| 216 | 3 |  |  |  |  | 58 | $self->{client}->{connection} = | 
| 217 |  |  |  |  |  |  | Arriba::Connection::HTTP->new($client, ssl => $ssl, | 
| 218 |  |  |  |  |  |  | chunk_size => CHUNKSIZE); | 
| 219 |  |  |  |  |  |  | } | 
| 220 |  |  |  |  |  |  |  | 
| 221 | 3 |  |  |  |  | 12 | my $connection = $self->{client}->{connection}; | 
| 222 |  |  |  |  |  |  |  | 
| 223 | 3 |  |  |  |  | 15 | while (my $req = $connection->read_request) { | 
| 224 | 82 |  |  |  |  | 162 | my $env; | 
| 225 |  |  |  |  |  |  | my $conn_header; | 
| 226 |  |  |  |  |  |  |  | 
| 227 | 82 | 100 |  |  |  | 455 | if ($req->{env}) { | 
| 228 |  |  |  |  |  |  | # Headers already parsed | 
| 229 | 8 |  |  |  |  | 20 | $env = $req->{env}; | 
| 230 |  |  |  |  |  |  | } | 
| 231 |  |  |  |  |  |  | else { | 
| 232 | 74 |  | 33 |  |  | 4859 | $env = { | 
|  |  |  | 50 |  |  |  |  | 
|  |  |  | 50 |  |  |  |  | 
|  |  |  | 50 |  |  |  |  | 
| 233 |  |  |  |  |  |  | REMOTE_ADDR => $self->{server}->{peeraddr}, | 
| 234 |  |  |  |  |  |  | REMOTE_HOST => $self->{server}->{peerhost} || $self->{server}->{peeraddr}, | 
| 235 |  |  |  |  |  |  | REMOTE_PORT => $self->{server}->{peerport} || 0, | 
| 236 |  |  |  |  |  |  | SERVER_NAME => $self->{server}->{sockaddr} || 0, # XXX: needs to be resolved? | 
| 237 |  |  |  |  |  |  | SERVER_PORT => $self->{server}->{sockport} || 0, | 
| 238 |  |  |  |  |  |  | SCRIPT_NAME => '', | 
| 239 |  |  |  |  |  |  | 'psgi.version' => [ 1, 1 ], | 
| 240 |  |  |  |  |  |  | 'psgi.errors' => *STDERR, | 
| 241 |  |  |  |  |  |  | 'psgi.url_scheme' => $req->{scheme}, | 
| 242 |  |  |  |  |  |  | 'psgi.nonblocking' => Plack::Util::FALSE, | 
| 243 |  |  |  |  |  |  | 'psgi.streaming' => Plack::Util::TRUE, | 
| 244 |  |  |  |  |  |  | 'psgi.run_once' => Plack::Util::FALSE, | 
| 245 |  |  |  |  |  |  | 'psgi.multithread' => Plack::Util::FALSE, | 
| 246 |  |  |  |  |  |  | 'psgi.multiprocess' => Plack::Util::TRUE, | 
| 247 |  |  |  |  |  |  | 'psgix.io' => $client, | 
| 248 |  |  |  |  |  |  | 'psgix.input.buffered' => Plack::Util::TRUE, | 
| 249 |  |  |  |  |  |  | 'psgix.harakiri' => Plack::Util::TRUE, | 
| 250 |  |  |  |  |  |  | }; | 
| 251 |  |  |  |  |  |  |  | 
| 252 | 74 |  |  |  |  | 2379 | my $reqlen = parse_http_request($req->{headers}, $env); | 
| 253 |  |  |  |  |  |  |  | 
| 254 | 74 | 50 |  |  |  | 225 | if ($reqlen < 0) { | 
| 255 |  |  |  |  |  |  | # Bad request | 
| 256 | 0 |  |  |  |  | 0 | $self->_http_error($req, 400); | 
| 257 | 0 |  |  |  |  | 0 | last; | 
| 258 |  |  |  |  |  |  | } | 
| 259 |  |  |  |  |  |  |  | 
| 260 | 74 |  |  |  |  | 196 | $conn_header = delete $env->{HTTP_CONNECTION}; | 
| 261 | 74 |  |  |  |  | 173 | my $proto = $env->{SERVER_PROTOCOL}; | 
| 262 |  |  |  |  |  |  |  | 
| 263 | 74 | 50 | 33 |  |  | 759 | if ($proto && $proto eq 'HTTP/1.0' ) { | 
|  |  | 50 | 33 |  |  |  |  | 
| 264 | 0 | 0 | 0 |  |  | 0 | if ($conn_header && $conn_header =~ /^keep-alive$/i) { | 
| 265 |  |  |  |  |  |  | # Keep-alive only with explicit header in HTTP/1.0 | 
| 266 | 0 |  |  |  |  | 0 | $connection->{_keepalive} = 1; | 
| 267 |  |  |  |  |  |  | } | 
| 268 |  |  |  |  |  |  | else { | 
| 269 | 0 |  |  |  |  | 0 | $connection->{_keepalive} = 0; | 
| 270 |  |  |  |  |  |  | } | 
| 271 |  |  |  |  |  |  | } | 
| 272 |  |  |  |  |  |  | elsif ($proto && $proto eq 'HTTP/1.1') { | 
| 273 | 74 | 50 | 33 |  |  | 294 | if ($conn_header && $conn_header =~ /^close$/i ) { | 
| 274 | 0 |  |  |  |  | 0 | $connection->{_keepalive} = 0; | 
| 275 |  |  |  |  |  |  | } | 
| 276 |  |  |  |  |  |  | else { | 
| 277 |  |  |  |  |  |  | # Keep-alive assumed in HTTP/1.1 | 
| 278 | 74 |  |  |  |  | 173 | $connection->{_keepalive} = 1; | 
| 279 |  |  |  |  |  |  | } | 
| 280 |  |  |  |  |  |  |  | 
| 281 |  |  |  |  |  |  | # Do we need to send 100 Continue? | 
| 282 | 74 | 50 |  |  |  | 212 | if ($env->{HTTP_EXPECT}) { | 
| 283 | 0 | 0 |  |  |  | 0 | if ($env->{HTTP_EXPECT} eq '100-continue') { | 
| 284 |  |  |  |  |  |  | # FIXME: | 
| 285 |  |  |  |  |  |  | #syswrite $client, 'HTTP/1.1 100 Continue' . $CRLF . $CRLF; | 
| 286 |  |  |  |  |  |  | } | 
| 287 |  |  |  |  |  |  | else { | 
| 288 | 0 |  |  |  |  | 0 | $self->_http_error(417, $env); | 
| 289 | 0 |  |  |  |  | 0 | last; | 
| 290 |  |  |  |  |  |  | } | 
| 291 |  |  |  |  |  |  | } | 
| 292 |  |  |  |  |  |  |  | 
| 293 | 74 | 50 |  |  |  | 247 | unless ($env->{HTTP_HOST}) { | 
| 294 |  |  |  |  |  |  | # No host, bad request | 
| 295 | 0 |  |  |  |  | 0 | $self->_http_error(400, $env); | 
| 296 | 0 |  |  |  |  | 0 | last; | 
| 297 |  |  |  |  |  |  | } | 
| 298 |  |  |  |  |  |  | } | 
| 299 |  |  |  |  |  |  |  | 
| 300 | 74 | 50 |  |  |  | 334 | unless ($self->{options}->{keepalive}) { | 
| 301 | 0 |  |  |  |  | 0 | $connection->{_keepalive} = 0; | 
| 302 |  |  |  |  |  |  | } | 
| 303 |  |  |  |  |  |  |  | 
| 304 | 74 |  |  |  |  | 209 | $req->{env} = $env; | 
| 305 |  |  |  |  |  |  | } | 
| 306 |  |  |  |  |  |  |  | 
| 307 |  |  |  |  |  |  | # Process this request later if it's not ready yet | 
| 308 | 82 | 100 |  |  |  | 361 | next if !$req->{complete}; | 
| 309 |  |  |  |  |  |  |  | 
| 310 | 74 | 100 |  |  |  | 203 | if ($req->{body_stream}) { | 
| 311 | 8 |  |  |  |  | 125 | $env->{'psgi.input'} = $req->{body_stream}->rewind; | 
| 312 |  |  |  |  |  |  | } | 
| 313 |  |  |  |  |  |  | else { | 
| 314 | 66 |  |  |  |  | 355 | $env->{'psgi.input'} = $null_io; | 
| 315 |  |  |  |  |  |  | } | 
| 316 |  |  |  |  |  |  |  | 
| 317 | 74 |  |  |  |  | 1393 | my $res = Plack::Util::run_app($self->{app}, $env); | 
| 318 |  |  |  |  |  |  |  | 
| 319 | 74 | 100 |  |  |  | 23323 | if (ref $res eq 'CODE') { | 
| 320 | 4 |  |  | 4 |  | 51 | $res->(sub { $connection->write_response($req, $_[0]) }); | 
|  | 4 |  |  |  |  | 449 |  | 
| 321 |  |  |  |  |  |  | } | 
| 322 |  |  |  |  |  |  | else { | 
| 323 | 70 |  |  |  |  | 350 | $connection->write_response($req, $res); | 
| 324 |  |  |  |  |  |  | } | 
| 325 |  |  |  |  |  |  |  | 
| 326 | 74 |  |  |  |  | 2229 | my $sel = IO::Select->new($client); | 
| 327 | 74 | 50 |  |  |  | 8594 | last unless $sel->can_read($self->{options}->{keepalive_timeout}); | 
| 328 |  |  |  |  |  |  | } | 
| 329 |  |  |  |  |  |  | } | 
| 330 |  |  |  |  |  |  |  | 
| 331 |  |  |  |  |  |  | sub _http_error { | 
| 332 | 0 |  |  | 0 |  |  | my ($self, $req, $code) = @_; | 
| 333 |  |  |  |  |  |  |  | 
| 334 | 0 |  | 0 |  |  |  | my $status = $code || 500; | 
| 335 | 0 |  |  |  |  |  | my $msg = status_message($status); | 
| 336 |  |  |  |  |  |  |  | 
| 337 | 0 |  |  |  |  |  | my $res = [ | 
| 338 |  |  |  |  |  |  | $status, | 
| 339 |  |  |  |  |  |  | [ 'Content-Type' => 'text/plain', 'Content-Length' => length($msg) ], | 
| 340 |  |  |  |  |  |  | [ $msg ], | 
| 341 |  |  |  |  |  |  | ]; | 
| 342 |  |  |  |  |  |  |  | 
| 343 | 0 |  |  |  |  |  | $self->{client}->{connection}->{_keepalive} = 0; | 
| 344 | 0 |  |  |  |  |  | $self->{client}->{connection}->write_response($req, $res); | 
| 345 |  |  |  |  |  |  | } | 
| 346 |  |  |  |  |  |  |  | 
| 347 |  |  |  |  |  |  | 1; | 
| 348 |  |  |  |  |  |  |  |