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 )