Subject: | PATCH_HTTP_KEEPALIVE breaks connection caching. |
Date: | Sat, 16 May 2015 13:04:16 +0200 |
To: | bug-SOAP-Lite [...] rt.cpan.org |
From: | John Hughes <john [...] calva.com> |
I wrote a little client using SOAP::Lite and was supprised to see that
it was making a new https call for every SOAP call.
Investigation showed the problem was because PATCH_HTTP_KEEPALIVE was set.
in SOAP::Transport::HTTP The "patch" is:
*collect = sub {
if ( defined $_[2]->header('Connection')
&& $_[2]->header('Connection') eq 'Keep-Alive' ) {
my $data = $_[3]->();
my $next =
$_[2]->header('Content-Length') &&
SOAP::Utils::bytelength($$data) ==
$_[2]->header('Content-Length')
? sub { my $str = ''; \$str; }
: $_[3];
my $done = 0;
$_[3] = sub {
$done++ ? &$next : $data;
};
}
goto &$collect;
};
It calls the "collector" subroutine ($_[3]) *once* to get the response
data if the "Connection: Keep-Alive" header is present.
But the collector subroutine in LWP::Protocol::http is:
sub {
my $buf = ""; #prevent use of uninitialized value in SSLeay.xs
my $n;
READ:
{
$n = $socket->read_entity_body($buf, $size);
unless (defined $n) {
redo READ if $!{EINTR} || $!{EAGAIN} || $!{ENOTTY};
die "read failed: $!";
}
redo READ if $n == -1;
}
$complete++ if !$n;
return \$buf;
}
The "$complete" flag is only set when $socket->read_entity_body returns
0, which never happens if the SOAP::Lite patch is in place.
Since LWP::Protocol::http thinks the reply isn't complete it doesn't
cache the connection:
# keep-alive support
unless ($drop_connection) {
if ($cache_key) {
my %connection = map { (lc($_) => 1) }
split(/\s*,\s*/, ($response->header("Connection") || ""));
if (($peer_http_version eq "1.1" && !$connection{close}) ||
$connection{"keep-alive"})
{
$conn_cache->deposit($self->socket_type, $cache_key, $socket);
}
}
}
So, unintuitively, if the server returns "Connection: Keep-Alive" the
connection is not cached.
--
John Hughes, CalvaEDI S.A.S.