File Coverage

blib/lib/Perlbal/BackendHTTP.pm
Criterion Covered Total %
statement 266 364 73.0
branch 87 154 56.4
condition 44 84 52.3
subroutine 27 36 75.0
pod 7 21 33.3
total 431 659 65.4


line stmt bran cond sub pod time code
1             ######################################################################
2             # HTTP connection to backend node
3             #
4             # Copyright 2004, Danga Interactive, Inc.
5             # Copyright 2005-2007, Six Apart, Ltd.
6             #
7              
8             package Perlbal::BackendHTTP;
9 22     22   141 use strict;
  22         45  
  22         874  
10 22     22   9741 use warnings;
  22         60  
  22         708  
11 22     22   126 no warnings qw(deprecated);
  22         99  
  22         810  
12              
13 22     22   213 use base "Perlbal::Socket";
  22         51  
  22         20442  
14 22         683 use fields ('client', # Perlbal::ClientProxy connection, or undef
15             'service', # Perlbal::Service
16             'pool', # Perlbal::Pool; whatever pool we spawned from
17             'ip', # IP scalar
18             'port', # port scalar
19             'ipport', # "$ip:$port"
20             'reportto', # object; must implement reporter interface
21              
22             'has_attention', # has been accepted by a webserver and
23             # we know for sure we're not just talking
24             # to the TCP stack
25              
26             'waiting_options', # if true, we're waiting for an OPTIONS *
27             # response to determine when we have attention
28              
29             'disconnect_at', # time this connection will be disconnected,
30             # if it's kept-alive and backend told us.
31             # otherwise undef for unknown.
32              
33             # The following only apply when the backend server sends
34             # a content-length header
35             'content_length', # length of document being transferred
36             'content_length_remain', # bytes remaining to be read
37              
38             'use_count', # number of requests this backend's been used for
39             'generation', # int; counts what generation we were spawned in
40             'buffered_upload_mode', # bool; if on, we're doing a buffered upload transmit
41              
42             'scratch' # for plugins
43 22     22   192 );
  22         66  
44 22         3694 use Socket qw(PF_INET IPPROTO_TCP SOCK_STREAM SOL_SOCKET SO_ERROR
45             AF_UNIX PF_UNSPEC
46 22     22   3390 );
  22         49  
47 22     22   220 use IO::Handle;
  22         50  
  22         956  
48              
49 22     22   23920 use Perlbal::ClientProxy;
  22         80  
  22         1066  
50              
51             # if this is made too big, (say, 128k), then perl does malloc instead
52             # of using its slab cache.
53 22     22   284 use constant BACKEND_READ_SIZE => 61440; # 60k, to fit in a 64k slab
  22         55  
  22         133620  
54              
55             # keys set here when an endpoint is found to not support persistent
56             # connections and/or the OPTIONS method
57             our %NoVerify; # { "ip:port" => next-verify-time }
58             our %NodeStats; # { "ip:port" => { ... } }; keep statistics about nodes
59              
60             # constructor for a backend connection takes a service (pool) that it's
61             # for, and uses that service to get its backend IP/port, as well as the
62             # client that will be using this backend connection. final parameter is
63             # an options hashref that contains some options:
64             # reportto => object obeying reportto interface
65             sub new {
66 23     23 1 58 my Perlbal::BackendHTTP $self = shift;
67 23         75 my ($svc, $ip, $port, $opts) = @_;
68 23   50     96 $opts ||= {};
69              
70 23         49 my $sock;
71 23         1256 socket $sock, PF_INET, SOCK_STREAM, IPPROTO_TCP;
72              
73 23 50 33     191 unless ($sock && defined fileno($sock)) {
74 0         0 Perlbal::log('crit', "Error creating socket: $!");
75 0         0 return undef;
76             }
77 23         197 my $inet_aton = Socket::inet_aton($ip);
78 23 50       107 unless ($inet_aton) {
79 0         0 Perlbal::log('crit', "inet_aton failed creating socket for $ip");
80 0         0 return undef;
81             }
82              
83 23         359 IO::Handle::blocking($sock, 0);
84 23         145 connect $sock, Socket::sockaddr_in($port, $inet_aton);
85              
86 23 50       23447 $self = fields::new($self) unless ref $self;
87 23         11775 $self->SUPER::new($sock);
88              
89 23         81 Perlbal::objctor($self);
90              
91 23         65 $self->{ip} = $ip; # backend IP
92 23         71 $self->{port} = $port; # backend port
93 23         92 $self->{ipport} = "$ip:$port"; # often used as key
94 23         59 $self->{service} = $svc; # the service we're serving for
95 23         112 $self->{pool} = $opts->{pool}; # what pool we came from.
96 23   66     184 $self->{reportto} = $opts->{reportto} || $svc; # reportto if specified
97 23         128 $self->state("connecting");
98              
99             # mark another connection to this ip:port
100 23         111 $NodeStats{$self->{ipport}}->{attempts}++;
101 23         91 $NodeStats{$self->{ipport}}->{lastattempt} = $self->{create_time};
102              
103             # setup callback in case we get stuck in connecting land
104             Perlbal::Socket::register_callback(15, sub {
105 1 50 33 1   8 if ($self->state eq 'connecting' || $self->state eq 'verifying_backend') {
106             # shouldn't still be connecting/verifying ~15 seconds after create
107 0         0 $self->close('callback_timeout');
108             }
109 1         4 return 0;
110 23         237 });
111              
112             # for header reading:
113 23         120 $self->init;
114              
115 23         137 $self->watch_write(1);
116 23         1447 return $self;
117             }
118              
119             sub init {
120 23     23 0 49 my $self = shift;
121 23         63 $self->{req_headers} = undef;
122 23         60 $self->{res_headers} = undef; # defined w/ headers object once all headers in
123 23         52 $self->{headers_string} = ""; # blank to start
124 23         79 $self->{generation} = $self->{service}->{generation};
125 23         45 $self->{read_size} = 0; # total bytes read from client
126              
127 23         50 $self->{client} = undef; # Perlbal::ClientProxy object, initially empty
128             # until we ask our service for one
129              
130 23         56 $self->{has_attention} = 0;
131 23         50 $self->{use_count} = 0;
132 23         57 $self->{buffered_upload_mode} = 0;
133             }
134              
135              
136             sub new_process {
137 0     0 0 0 my ($class, $svc, $prog) = @_;
138              
139 0         0 my ($psock, $csock);
140 0 0       0 socketpair($csock, $psock, AF_UNIX, SOCK_STREAM, PF_UNSPEC)
141             or die "socketpair: $!";
142              
143 0         0 $csock->autoflush(1);
144 0         0 $psock->autoflush(1);
145              
146 0         0 my $pid = fork;
147 0 0       0 unless (defined $pid) {
148 0         0 warn "fork failed: $!\n";
149 0         0 return undef;
150             }
151              
152             # child process
153 0 0       0 unless ($pid) {
154 0         0 close(STDIN);
155 0         0 close(STDOUT);
156             #close(STDERR);
157 0         0 open(STDIN, '<&', $psock);
158 0         0 open(STDOUT, '>&', $psock);
159             #open(STDERR, ">/dev/null");
160 0         0 exec $prog;
161             }
162              
163 0         0 close($psock);
164 0         0 my $sock = $csock;
165              
166 0         0 my $self = fields::new($class);
167 0         0 $self->SUPER::new($sock);
168 0         0 Perlbal::objctor($self);
169              
170 0         0 $self->{ipport} = $prog; # often used as key
171 0         0 $self->{service} = $svc; # the service we're serving for
172 0         0 $self->{reportto} = $svc; # reportto interface (same as service)
173 0         0 $self->state("connecting");
174              
175 0         0 $self->init;
176 0         0 $self->watch_write(1);
177 0         0 return $self;
178             }
179              
180             sub close {
181 18     18 1 39 my Perlbal::BackendHTTP $self = shift;
182              
183             # OSX Gives EPIPE on bad connects, and doesn't fail the connect
184             # so lets treat EPIPE as a event_err so the logic there does
185             # the right thing
186 18 50 33     166 if (defined $_[0] && $_[0] eq 'EPIPE') {
187 0         0 $self->event_err;
188 0         0 return;
189             }
190              
191             # don't close twice
192 18 50       74 return if $self->{closed};
193              
194             # this closes the socket and sets our closed flag
195 18         167 $self->SUPER::close(@_);
196              
197             # tell our client that we're gone
198 18 100       1561 if (my $client = $self->{client}) {
199 16         96 $client->backend(undef);
200 16         42 $self->{client} = undef;
201             }
202              
203             # tell our owner that we're gone
204 18 50       76 if (my $reportto = $self->{reportto}) {
205 18         99 $reportto->note_backend_close($self);
206 18         96 $self->{reportto} = undef;
207             }
208             }
209              
210             # return our defined generation counter with no parameter,
211             # or set our generation if given a parameter
212             sub generation {
213 254     254 0 455 my Perlbal::BackendHTTP $self = $_[0];
214 254 50       2288 return $self->{generation} unless $_[1];
215 0         0 return $self->{generation} = $_[1];
216             }
217              
218             # return what ip and port combination we're using
219             sub ipport {
220 0     0 0 0 my Perlbal::BackendHTTP $self = $_[0];
221 0         0 return $self->{ipport};
222             }
223              
224             # called to tell backend that the client has gone on to do something else now.
225             sub forget_client {
226 0     0 0 0 my Perlbal::BackendHTTP $self = $_[0];
227 0         0 $self->{client} = undef;
228             }
229              
230             # called by service when it's got a client for us, or by ourselves
231             # when we asked for a client.
232             # returns true if client assignment was accepted.
233             sub assign_client {
234 135     135 0 316 my Perlbal::BackendHTTP $self = shift;
235 135         257 my Perlbal::ClientProxy $client = shift;
236 135 50       513 return 0 if $self->{client};
237              
238 135         318 my $svc = $self->{service};
239              
240             # set our client, and the client's backend to us
241 135         1398 $svc->mark_node_used($self->{ipport});
242 135         556 $self->{client} = $client;
243 135         673 $self->state("sending_req");
244 135         764 $self->{client}->backend($self);
245              
246 135         1081 my Perlbal::HTTPHeaders $hds = $client->{req_headers}->clone;
247 135         463 $self->{req_headers} = $hds;
248              
249 135         1241 my $client_ip = $client->peer_ip_string;
250              
251             # I think I've seen this be undef in practice. Double-check
252 135 50       2166 unless ($client_ip) {
253 0         0 warn "Undef client_ip ($client) in assign_client. Closing.";
254 0         0 $client->close;
255 0         0 return 0;
256             }
257              
258             # Use HTTP/1.0 to backend (FIXME: use 1.1 and support chunking)
259 135         654 $hds->set_version("1.0");
260              
261 135         651 my $persist = $svc->{persist_backend};
262              
263 135 100       815 $hds->header("Connection", $persist ? "keep-alive" : "close");
264              
265 135 100       488 if ($svc->{enable_reproxy}) {
266 24         80 $hds->header("X-Proxy-Capabilities", "reproxy-file");
267             }
268              
269             # decide whether we trust the upstream or not, to give us useful
270             # forwarding info headers
271 135 50       684 if ($svc->trusted_ip($client_ip)) {
272             # yes, we trust our upstream, so just append our client's IP
273             # to the existing list of forwarded IPs, if we're a blind proxy
274             # then don't append our IP to the end of the list.
275 0 0       0 unless ($svc->{blind_proxy}) {
276 0   0     0 my @ips = split /,\s*/, ($hds->header("X-Forwarded-For") || '');
277 0         0 $hds->header("X-Forwarded-For", join ", ", @ips, $client_ip);
278             }
279             } else {
280             # no, don't trust upstream (untrusted client), so remove all their
281             # forwarding headers and tag their IP as the x-forwarded-for
282 135         511 $hds->header("X-Forwarded-For", $client_ip);
283 135         479 $hds->header("X-Host", undef);
284 135         2421 $hds->header("X-Forwarded-Host", undef);
285             }
286              
287 135         761 $self->tcp_cork(1);
288 135         4961 $client->state('backend_req_sent');
289              
290 135         489 $self->{content_length} = undef;
291 135         556 $self->{content_length_remain} = undef;
292              
293             # run hooks
294 135 50       2012 return 1 if $svc->run_hook('backend_client_assigned', $self);
295              
296             # now cleanup the headers before we send to the backend
297 135 50       870 $svc->munge_headers($hds) if $svc;
298              
299 135         781 $self->write($hds->to_string_ref);
300             $self->write(sub {
301 135     135   18014 $self->tcp_cork(0);
302 135 50       98996 if (my $client = $self->{client}) {
303             # start waiting on a reply
304 135         892 $self->watch_read(1);
305 135         27595 $self->state("wait_res");
306 135         1307 $client->state('wait_res');
307 135         2673 $client->backend_ready($self);
308             }
309 135         1600 });
310              
311 135         1462 return 1;
312             }
313              
314             # called by ClientProxy after we tell it our backend is ready and
315             # it has an upload ready on disk
316             sub invoke_buffered_upload_mode {
317 29     29 0 63 my Perlbal::BackendHTTP $self = shift;
318              
319             # so, we're receiving a buffered upload, we need to go ahead and
320             # start the buffered upload retransmission to backend process. we
321             # have to turn watching for writes on, since that's what is doing
322             # the triggering, NOT the normal client proxy watch for read
323 29         82 $self->{buffered_upload_mode} = 1;
324 29         142 $self->watch_write(1);
325             }
326              
327             # Backend
328             sub event_write {
329 113     113 1 191673 my Perlbal::BackendHTTP $self = shift;
330 113         187 print "Backend $self is writeable!\n" if Perlbal::DEBUG >= 2;
331              
332 113         326 my $now = time();
333 113 50 33     685 delete $NoVerify{$self->{ipport}} if
334             defined $NoVerify{$self->{ipport}} &&
335             $NoVerify{$self->{ipport}} < $now;
336              
337 113 100 66     652 if (! $self->{client} && $self->{state} eq "connecting") {
338             # not interested in writes again until something else is
339 23         98 $self->watch_write(0);
340 23         1555 $NodeStats{$self->{ipport}}->{connects}++;
341 23         146 $NodeStats{$self->{ipport}}->{lastconnect} = $now;
342              
343             # OSX returns writeable even if the connect fails
344             # so explicitly check for the error
345             # TODO: make a smaller test case and show to the world
346 23 100       292 if (my $error = unpack('i', getsockopt($self->{sock}, SOL_SOCKET, SO_ERROR))) {
347 1         5 $self->event_err;
348 1         3 return;
349             }
350              
351 22 100 66     274 if (defined $self->{service} && $self->{service}->{verify_backend} &&
      66        
      66        
352             !$self->{has_attention} && !defined $NoVerify{$self->{ipport}}) {
353              
354 1 50       8 return if $self->{service}->run_hook('backend_write_verify', $self);
355              
356             # the backend should be able to answer this incredibly quickly.
357 1         11 $self->write("OPTIONS " . $self->{service}->{verify_backend_path} . " HTTP/1.0\r\nConnection: keep-alive\r\n\r\n");
358 1         7 $self->watch_read(1);
359 1         28 $self->{waiting_options} = 1;
360 1         4 $self->{content_length_remain} = undef;
361 1         5 $self->state("verifying_backend");
362             } else {
363             # register our boredom (readiness for a client/request)
364 21         87 $self->state("bored");
365 21         130 $self->{reportto}->register_boredom($self);
366             }
367 22         157 return;
368             }
369              
370             # if we have a client, and we're currently doing a buffered upload
371             # sendfile, then tell the client to continue sending us data
372 90 100 66     674 if ($self->{client} && $self->{buffered_upload_mode}) {
373 38         230 $self->{client}->continue_buffered_upload($self);
374 38         415 return;
375             }
376              
377 52         258 my $done = $self->write(undef);
378 52 100       287 $self->watch_write(0) if $done;
379             }
380              
381             sub verify_success {
382 1     1 0 2 my Perlbal::BackendHTTP $self = shift;
383 1         2 $self->{waiting_options} = 0;
384 1         2 $self->{has_attention} = 1;
385 1         8 $NodeStats{$self->{ipport}}->{verifies}++;
386 1         5 $self->next_request(1); # initial
387 1         2 return;
388             }
389              
390             sub verify_failure {
391 0     0 0 0 my Perlbal::BackendHTTP $self = shift;
392 0         0 $NoVerify{$self->{ipport}} = time() + 60;
393 0         0 $self->{reportto}->note_bad_backend_connect($self);
394 0         0 $self->close('no_keep_alive');
395 0         0 return;
396             }
397              
398             sub event_read_waiting_options { # : void
399 1     1 0 4 my Perlbal::BackendHTTP $self = shift;
400              
401 1 50       14 if (defined $self->{service}) {
402 1 50       10 return if $self->{service}->run_hook('backend_readable_verify', $self);
403             }
404              
405 1 50       11 if ($self->{content_length_remain}) {
    50          
406             # the HTTP/1.1 spec says OPTIONS responses can have content-lengths,
407             # but the meaning of the response is reserved for a future spec.
408             # this just gobbles it up for.
409 0         0 my $bref = $self->read(BACKEND_READ_SIZE);
410 0 0       0 return $self->verify_failure unless defined $bref;
411 0         0 $self->{content_length_remain} -= length($$bref);
412             } elsif (my $hd = $self->read_response_headers) {
413             # see if we have keep alive support
414 1 50       6 return $self->verify_failure unless $hd->res_keep_alive_options;
415 1         4 $self->{content_length_remain} = $hd->header("Content-Length");
416             }
417              
418             # if we've got the option response and read any response data
419             # if present:
420 1 50 33     9 if ($self->{res_headers} && ! $self->{content_length_remain}) {
421 1         6 $self->verify_success;
422             }
423 1         6 return;
424             }
425              
426             sub handle_response { # : void
427 150     150 0 380 my Perlbal::BackendHTTP $self = shift;
428 150         366 my Perlbal::HTTPHeaders $hd = $self->{res_headers};
429 150         357 my Perlbal::ClientProxy $client = $self->{client};
430              
431 150         195 print "BackendHTTP: handle_response\n" if Perlbal::DEBUG >= 2;
432              
433 150         966 my $res_code = $hd->response_code;
434              
435             # keep a rolling window of the last 500 response codes
436 150   100     1079 my $ref = ($NodeStats{$self->{ipport}}->{responsecodes} ||= []);
437 150         384 push @$ref, $res_code;
438 150 50       484 if (scalar(@$ref) > 500) {
439 0         0 shift @$ref;
440             }
441              
442             # call service response received function
443 150 100       1376 return if $self->{reportto}->backend_response_received($self);
444              
445             # standard handling
446 149         1385 $self->state("xfer_res");
447 149         1288 $client->state("xfer_res");
448 149         369 $self->{has_attention} = 1;
449              
450             # RFC 2616, Sec 4.4: Messages MUST NOT include both a
451             # Content-Length header field and a non-identity
452             # transfer-coding. If the message does include a non-
453             # identity transfer-coding, the Content-Length MUST be
454             # ignored.
455 149         1026 my $te = $hd->header("Transfer-Encoding");
456 149 50 33     633 if ($te && $te !~ /\bidentity\b/i) {
457 0         0 $hd->header("Content-Length", undef);
458             }
459              
460 149         454 my Perlbal::HTTPHeaders $rqhd = $self->{req_headers};
461              
462             # setup our content length so we know how much data to expect, in general
463             # we want the content-length from the response, but if this was a head request
464             # we know it's a 0 length message the client wants
465 149 100       716 if ($rqhd->request_method eq 'HEAD') {
466 2         8 $self->{content_length} = 0;
467             } else {
468 147         674 $self->{content_length} = $hd->content_length;
469             }
470 149   100     835 $self->{content_length_remain} = $self->{content_length} || 0;
471              
472 149   100     700 my $reproxy_cache_for = $hd->header('X-REPROXY-CACHE-FOR') || 0;
473              
474             # special cases: reproxying and retrying after server errors:
475 149 100 66     547 if ((my $rep = $hd->header('X-REPROXY-FILE')) && $self->may_reproxy) {
    100 66        
    50 33        
    50 66        
      33        
476             # make the client begin the async IO while we move on
477 6         24 $self->next_request;
478 6         33 $client->start_reproxy_file($rep, $hd);
479 6         120 return;
480             } elsif ((my $urls = $hd->header('X-REPROXY-URL')) && $self->may_reproxy) {
481 13         48 $self->next_request;
482 13 100       39 $self->{service}->add_to_reproxy_url_cache($rqhd, $hd)
483             if $reproxy_cache_for;
484 13         72 $client->start_reproxy_uri($hd, $urls);
485 13         72 return;
486             } elsif ((my $svcname = $hd->header('X-REPROXY-SERVICE')) && $self->may_reproxy) {
487 0         0 $self->next_request;
488 0         0 $self->{client} = undef;
489 0         0 $client->start_reproxy_service($hd, $svcname);
490 0         0 return;
491             } elsif ($res_code == 500 &&
492             $rqhd->request_method =~ /^GET|HEAD$/ &&
493             $client->should_retry_after_500($self)) {
494             # eh, 500 errors are rare. just close and don't spend effort reading
495             # rest of body's error message to no client.
496 0         0 $self->close;
497              
498             # and tell the client to try again with a new backend
499 0         0 $client->retry_after_500($self->{service});
500 0         0 return;
501             }
502              
503             # regular path:
504 130   66     1268 my $res_source = $client->{primary_res_hdrs} || $hd;
505 130         840 my $thd = $client->{res_headers} = $res_source->clone;
506              
507             # if we had an alternate primary response header, make sure
508             # we send the real content-length (from the reproxied URL)
509             # and not the one the first server gave us
510 130 100       809 if ($client->{primary_res_hdrs}) {
511 15         57 $thd->header('Content-Length', $hd->header('Content-Length'));
512 15         54 $thd->header('X-REPROXY-FILE', undef);
513 15         53 $thd->header('X-REPROXY-URL', undef);
514 15         48 $thd->header('X-REPROXY-EXPECTED-SIZE', undef);
515 15         51 $thd->header('X-REPROXY-CACHE-FOR', undef);
516              
517             # also update the response code, in case of 206 partial content
518 15         43 my $rescode = $hd->response_code;
519 15 50 33     90 if ($rescode == 206 || $rescode == 416) {
520 0         0 $thd->code($rescode);
521 0 0       0 $thd->header('Accept-Ranges', $hd->header('Accept-Ranges')) if $hd->header('Accept-Ranges');
522 0 0       0 $thd->header('Content-Range', $hd->header('Content-Range')) if $hd->header('Content-Range');
523             }
524 15 100       43 $thd->code(200) if $thd->response_code == 204; # upgrade HTTP No Content (204) to 200 OK.
525             }
526              
527             # setup_keepalive will set Connection: and Keep-Alive: headers for us
528             # as well as setup our HTTP version appropriately
529 130         942 $client->setup_keepalive($thd);
530              
531 130 100       1425 my $svc = ref $self->{service} eq 'Perlbal::Service' ? $self->{service} : $client->{service};
532 130         727 $svc->run_hook('modify_response_headers', $self, $client);
533              
534 130         220 print " writing response headers to client\n" if Perlbal::DEBUG >= 3;
535 130         569 $client->write($thd->to_string_ref);
536              
537 130         229 print(" content_length=", (defined $self->{content_length} ? $self->{content_length} : "(undef)"),
538             " remain=", (defined $self->{content_length_remain} ? $self->{content_length_remain} : "(undef)"), "\n")
539             if Perlbal::DEBUG >= 3;
540              
541 130         522 $svc->run_hook('prepend_body', $self, $client);
542              
543 130 100 66     3504 if (defined $self->{content_length} && ! $self->{content_length_remain}) {
544 2         5 print " done. detaching.\n" if Perlbal::DEBUG >= 3;
545             # order important: next_request detaches us from client, so
546             # $client->close can't kill us
547 2         13 $self->next_request;
548             $client->write(sub {
549 2     2   100 $client->backend_finished;
550 2         20 });
551             }
552             }
553              
554             sub may_reproxy {
555 19     19 0 65 my Perlbal::BackendHTTP $self = shift;
556 19         45 my Perlbal::Service $svc = $self->{service};
557 19 50       55 return 0 unless $svc;
558 19         95 return $svc->{enable_reproxy};
559             }
560              
561             # Backend
562             sub event_read {
563 280     280 1 4361413 my Perlbal::BackendHTTP $self = shift;
564 280         516 print "Backend $self is readable!\n" if Perlbal::DEBUG >= 2;
565              
566 280 100       1155 return $self->event_read_waiting_options if $self->{waiting_options};
567              
568 279         1226 my Perlbal::ClientProxy $client = $self->{client};
569              
570             # with persistent connections, sometimes we have a backend and
571             # no client, and backend becomes readable, either to signal
572             # to use the end of the stream, or because a bad request error,
573             # which I can't totally understand. in any case, we have
574             # no client so all we can do is close this backend.
575 279 50       774 return $self->close('read_with_no_client') unless $client;
576              
577 279 100       1958 unless ($self->{res_headers}) {
578 150 50       1308 return unless $self->read_response_headers;
579 150         919 return $self->handle_response;
580             }
581              
582             # if our client's behind more than the max limit, stop buffering
583 129 50       1205 if ($client->too_far_behind_backend) {
584 0         0 $self->watch_read(0);
585 0         0 $client->{backend_stalled} = 1;
586 0         0 return;
587             }
588              
589 129         1449 my $bref = $self->read(BACKEND_READ_SIZE);
590              
591 129 50       3707 if (defined $bref) {
592 129         470 $client->write($bref);
593              
594             # HTTP/1.0 keep-alive support to backend. we just count bytes
595             # until we hit the end, then we know we can send another
596             # request on this connection
597 129 50       568 if ($self->{content_length}) {
598 129         357 $self->{content_length_remain} -= length($$bref);
599 129 100       606 if (! $self->{content_length_remain}) {
600             # order important: next_request detaches us from client, so
601             # $client->close can't kill us
602 128         580 $self->next_request;
603 128     128   920 $client->write(sub { $client->backend_finished; });
  128         7518  
604             }
605             }
606 129         1303 return;
607             } else {
608             # backend closed
609 0         0 print "Backend $self is done; closing...\n" if Perlbal::DEBUG >= 1;
610              
611 0         0 $client->backend(undef); # disconnect ourselves from it
612 0         0 $self->{client} = undef; # .. and it from us
613 0         0 $self->close('backend_disconnect'); # close ourselves
614              
615 0     0   0 $client->write(sub { $client->backend_finished; });
  0         0  
616 0         0 return;
617             }
618             }
619              
620             # if $initial is on, then don't increment use count
621             sub next_request {
622 150     150 0 406 my Perlbal::BackendHTTP $self = $_[0];
623 150         267 my $initial = $_[1];
624              
625             # don't allow this if we're closed
626 150 50       599 return if $self->{closed};
627              
628             # set alive_time so reproxy can intelligently reuse this backend
629 150         325 my $now = time();
630 150         692 $self->{alive_time} = $now;
631 150 100       940 $NodeStats{$self->{ipport}}->{requests}++ unless $initial;
632 150         428 $NodeStats{$self->{ipport}}->{lastresponse} = $now;
633              
634 150         336 my $hd = $self->{res_headers}; # response headers
635              
636             # verify that we have keep-alive support. by passing $initial to res_keep_alive,
637             # we signal that req_headers may be undef (if we just did an options request)
638 150 100       1478 return $self->close('next_request_no_persist')
639             unless $hd->res_keep_alive($self->{req_headers}, $initial);
640              
641             # and now see if we should closed based on the pool we're from
642 135 50 66     1909 return $self->close('pool_requested_closure')
643             if $self->{pool} && ! $self->{pool}->backend_should_live($self);
644              
645             # we've been used
646 135 100       448 $self->{use_count}++ unless $initial;
647              
648             # service specific
649 135 50       520 if (my Perlbal::Service $svc = $self->{service}) {
650             # keep track of how many times we've been used, and don't
651             # keep using this connection more times than the service
652             # is configured for.
653 135 50 33     695 if ($svc->{max_backend_uses} && ($self->{use_count} > $svc->{max_backend_uses})) {
654 0         0 return $self->close('exceeded_max_uses');
655             }
656             }
657              
658             # if backend told us, keep track of when the backend
659             # says it's going to boot us, so we don't use it within
660             # a few seconds of that time
661 135 100 100     480 if (($hd->header("Keep-Alive") || '') =~ /\btimeout=(\d+)/i) {
662 15         69 $self->{disconnect_at} = $now + $1;
663             } else {
664 120         294 $self->{disconnect_at} = undef;
665             }
666              
667 135         277 $self->{client} = undef;
668              
669 135         790 $self->state("bored");
670 135         842 $self->watch_write(0);
671              
672 135         2324 $self->{req_headers} = undef;
673 135         823 $self->{res_headers} = undef;
674 135         319 $self->{headers_string} = "";
675 135         347 $self->{req_headers} = undef;
676              
677 135         289 $self->{read_size} = 0;
678 135         361 $self->{content_length_remain} = undef;
679 135         337 $self->{content_length} = undef;
680 135         247 $self->{buffered_upload_mode} = 0;
681              
682 135         1471 $self->{reportto}->register_boredom($self);
683 135         466 return;
684             }
685              
686             # Backend: bad connection to backend
687             sub event_err {
688 1     1 1 4 my Perlbal::BackendHTTP $self = shift;
689              
690             # FIXME: we get this after backend is done reading and we disconnect,
691             # hence the misc checks below for $self->{client}.
692              
693 1         2 print "BACKEND event_err\n" if
694             Perlbal::DEBUG >= 2;
695              
696 1 50       5 if ($self->{client}) {
697             # request already sent to backend, then an error occurred.
698             # we don't want to duplicate POST requests, so for now
699             # just fail
700             # TODO: if just a GET request, retry?
701 0         0 $self->{client}->close('backend_error');
702 0         0 $self->close('error');
703 0         0 return;
704             }
705              
706 1 50 33     6 if ($self->{state} eq "connecting" ||
707             $self->{state} eq "verifying_backend") {
708             # then tell the service manager that this connection
709             # failed, so it can spawn a new one and note the dead host
710 1         7 $self->{reportto}->note_bad_backend_connect($self, 1);
711             }
712              
713             # close ourselves first
714 1         4 $self->close("error");
715             }
716              
717             # Backend
718             sub event_hup {
719 0     0 1   my Perlbal::BackendHTTP $self = shift;
720 0           print "HANGUP for $self\n" if Perlbal::DEBUG;
721 0           $self->close("after_hup");
722             }
723              
724             sub as_string {
725 0     0 1   my Perlbal::BackendHTTP $self = shift;
726              
727 0           my $ret = $self->SUPER::as_string;
728 0 0         my $name = $self->{sock} ? getsockname($self->{sock}) : undef;
729 0 0         my $lport = $name ? (Socket::sockaddr_in($name))[0] : undef;
730 0 0         $ret .= ": localport=$lport" if $lport;
731 0 0         if (my Perlbal::ClientProxy $cp = $self->{client}) {
732 0           $ret .= "; client=$cp->{fd}";
733             }
734 0           $ret .= "; uses=$self->{use_count}; $self->{state}";
735 0 0 0       if (defined $self->{service} && $self->{service}->{verify_backend}) {
736 0           $ret .= "; has_attention=";
737 0 0         $ret .= $self->{has_attention} ? 'yes' : 'no';
738             }
739              
740 0           return $ret;
741             }
742              
743             sub die_gracefully {
744             # see if we need to die
745 0     0 0   my Perlbal::BackendHTTP $self = shift;
746 0 0         $self->close('graceful_death') if $self->state eq 'bored';
747             }
748              
749             sub DESTROY {
750 0     0     Perlbal::objdtor($_[0]);
751 0           $_[0]->SUPER::DESTROY;
752             }
753              
754             1;
755              
756             # Local Variables:
757             # mode: perl
758             # c-basic-indent: 4
759             # indent-tabs-mode: nil
760             # End: