API-Docker
view release on metacpan or search on metacpan
lib/API/Docker/Error/Truncated.pm view on Meta::CPAN
'""' => sub { $_[0]->as_string },
'bool' => sub { 1 },
fallback => 1;
has message => (
is => 'ro',
required => 1,
);
has location => (
is => 'ro',
default => sub { '' },
);
has endpoint => (
is => 'ro',
default => sub { '' },
);
has phase => (
is => 'ro',
required => 1,
);
has expected => (
is => 'ro',
);
has received => (
is => 'ro',
);
has partial => (
is => 'ro',
default => sub { '' },
);
has summary => (
is => 'ro',
);
sub as_string { $_[0]->message . $_[0]->location }
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
API::Docker::Error::Truncated - The daemon closed before the response it announced was complete
=head1 VERSION
version 0.004
=head1 SYNOPSIS
# A tar the daemon stopped sending halfway is not a tar.
my $tar = eval { $docker->images->get_tar('busybox') };
if (my $err = $@) {
die $err unless ref $err
&& $err->isa('API::Docker::Error::Truncated');
warn 'got ' . length($err->partial) . ' of '
. $err->expected . ' bytes; retrying';
$tar = $docker->images->get_tar('busybox');
}
=head1 DESCRIPTION
L<API::Docker::Role::HTTP> croaks with an object of this class when the daemon
closed the connection in the middle of a response -- a status line with no
terminator, a header block with no blank line to close it, a body shorter than
its C<Content-Length>, a chunk shorter than its own header, a chunk header cut
in half, or a chunked body with no terminating zero chunk. It is raised in one
more place that is not a closed connection but has the same consequence: a
chunk size line that arrived in full and is not a hexadecimal number, which
would otherwise be misread as a zero chunk and end the body early (see
L</phase>).
It is a structural check, not a heuristic, and it asks one of two questions
depending on how the piece is delimited. Where the response announced a length
it compares what arrived against it. Where the framing is by terminator
instead -- the head, and the chunk headers -- it asks whether the terminator
came before the stream ended, which needs nothing to compare and is just as
decidable. Neither is a guess about content: a header block that never closed
is not a short one, it is an unfinished one.
A body delimited by nothing but the close -- C<attach>,
C<< logs(follow => 1) >>, C</exec/{id}/start>, the whole
C<application/vnd.docker.raw-stream> family -- announces no end and has no
terminator either, so there an EOF B<is> the end and this is never raised.
Its B<head> is framed like any other, and is checked like any other.
=head2 Why it is fatal
For the same reason L<API::Docker::Error::Timeout> is, and the two are the
same defect reached by different routes: a short body satisfies every return
shape this role promises and is indistinguishable from a complete one.
C<ndjson> promises an ArrayRef of events and gets a shorter one; C<raw>
promises the response bytes and gets fewer of them; the default promises the
decoded body and gets whatever the truncated bytes happened to parse as. A
half tarball that looks whole is the worst of them, and it is the case this
exists for.
Nothing is lost by raising it: L</partial> carries the bytes a buffered read
had collected and L</summary> the count a streamed one had delivered, so a
( run in 1.560 second using v1.01-cache-2.11-cpan-02e1dfdd527 )