API-Docker

 view release on metacpan or  search on metacpan

lib/API/Docker/Error/Truncated.pm  view on Meta::CPAN


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

lib/API/Docker/Role/HTTP.pm  view on Meta::CPAN

# socket, which is the same fill semantics this is here to get away from.
#
# A short positive read is never an end of stream and never an expiry. Over
# TLS it is the normal case, one plaintext record at a time; over a plain
# socket it is whatever the kernel had. Both are data.
#
# SSL_WANT_READ and SSL_WANT_WRITE are deliberately not retried. On a blocking
# socket they arrive as EWOULDBLOCK (IO::Socket::SSL's _skip_rw_error does
# `$! ||= EWOULDBLOCK`) and mean the underlying receive would have blocked --
# which, with SO_RCVTIMEO in force, is the bound firing and nothing else.
# Retrying would be a busy loop on WANT_READ and could not make progress on
# WANT_WRITE in any case, so they are reported as the timeout they are.
sub _pull {
  my ($self, $sock, $ctx) = @_;

  my $buf = $self->_read_buffer($sock);

  while (1) {
    # errno immediately before, errno immediately after, nothing in between:
    # it is only meaningful after a failure, and any operation at all would
    # overwrite it. See _timed_out.

lib/API/Docker/Role/HTTP.pm  view on Meta::CPAN


=head2 Failure in the middle of a response

The daemon can also stop saying anything in the middle of saying it. 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, a chunked body with no terminating zero chunk: each
of those is a response that ended before it was finished, and each croaks with
an L<API::Docker::Error::Truncated>.

    my $tar = eval { $docker->images->get_tar('busybox') };
    die $@ if $@ && !(ref $@
        && $@->isa('API::Docker::Error::Truncated'));

It is a structural check, so it needs no option, applies to every request, and
cannot fire on a response that is complete. Which question it asks depends on
how the piece is framed: where the response announced a length, what arrived
is compared 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 is decidable without anything to compare. The exception carries
what did arrive: C<< ->partial >> for a buffered request, C<< ->summary >> for

t/fixtures/images_list.json  view on Meta::CPAN

    ],
    "Names": [
      "docker.io/library/alpine:3",
      "docker.io/library/alpine:latest"
    ]
  },
  {
    "Id": "sha256:c6348fa86ba0fb2108c9334f5fe913ddc6d853313e655891f133a0127c30099f",
    "ParentId": "",
    "RepoTags": [
      "docker.io/library/busybox:latest"
    ],
    "RepoDigests": [
      "docker.io/library/busybox@sha256:1cfa4e2b09e127b9c4ed43578d3f3c18e7d44ea47b9ea98475c0cbe9086525f8",
      "docker.io/library/busybox@sha256:dc2d74b28e4cf8984fa52af1f39bc7c3d9c73760b41a74d629f5d11b1ab28616"
    ],
    "Created": 1778638909,
    "Size": 4690894,
    "SharedSize": -1,
    "Labels": null,
    "Containers": 0,
    "Digest": "sha256:dc2d74b28e4cf8984fa52af1f39bc7c3d9c73760b41a74d629f5d11b1ab28616",
    "History": [
      "docker.io/library/busybox:latest"
    ],
    "Names": [
      "docker.io/library/busybox:latest"
    ]
  },
  {
    "Id": "sha256:26b2eb03618e749084668eaff68cff8f81dda12d06ac641be7a6398b82a6f25b",
    "ParentId": "",
    "RepoTags": [
      "docker.io/library/registry:2"
    ],
    "RepoDigests": [
      "docker.io/library/registry@sha256:46faa9a1ae6813194b53921a370f2f4f8c5e1aae228a89bceafef5847a6a3278",



( run in 2.633 seconds using v1.01-cache-2.11-cpan-54e63673c56 )