Net-Async-Webservice-S3

 view release on metacpan or  search on metacpan

lib/Net/Async/Webservice/S3.pm  view on Meta::CPAN

=item key => STR

The name of the key to query

=item on_chunk => CODE

Optional. If supplied, this code will be invoked repeatedly on receipt of more
bytes of the key's value. It will be passed the L<HTTP::Response> object
received in reply to the request, and a byte string containing more bytes of
the value. Its return value is not important.

   $on_chunk->( $header, $bytes )

If this is supplied then the key's value will not be accumulated, and the
final result of the Future will be an empty string.

=item byte_range => STRING

Optional. If supplied, is used to set the C<Range> request header with
C<bytes> as the units. This gives a range of bytes of the object to fetch,
rather than fetching the entire content. The value must be as specified by
HTTP/1.1; i.e. a comma-separated list of ranges, where each range specifies a
start and optionally an inclusive stop byte index, separated by hypens.

=item if_match => STRING

Optional. If supplied, is used to set the C<If-Match> request header to the
given string, which should be an entity etag. If the requested object no
longer has this etag, the request will fail with an C<http> failure whose
response code is 412.

=back

The Future will return a byte string containing the key's value, the
L<HTTP::Response> that was received, and a hash reference containing any of
the metadata fields, if found in the response. If an C<on_chunk> code
reference is passed, the C<$value> string will be empty.

If the entire content of the object is requested (i.e. if C<byte_range> is not
supplied) then stall timeout failures will be handled specially. If a stall
timeout happens while receiving the content, the request will be retried using
the C<Range> header to resume from progress so far. This will be repeated
while every attempt still makes progress, and such resumes will not be counted
as part of the normal retry count. The resume request also uses C<If-Match> to
ensure it only resumes the resource with matching ETag. If a resume request
fails for some reason (either because the ETag no longer matches or something
else) then this error is ignored, and the original stall timeout failure is
returned.

=cut

sub _head_then_get_object
{
   my $self = shift;
   my %args = @_;

   my $if_match = $args{if_match};
   my $byte_range = $args{byte_range};

   # TODO: This doesn't handle retries correctly
   # But that said neither does the rest of this module, wrt: on_chunk streaming

   my $on_chunk = delete $args{on_chunk};

   my $header;
   my $head_future = $self->loop->new_future;
   my $value_future;
   my $value_len = 0;
   my $stall_failure_f;

   my $resume_on_stall = 1;

   # TODO: Right now I can't be bothered to write the logic required to update
   # the user-requested byte_range (which may in complex cases contain multiple
   # discontinuous ranges) after a stall to resume it. This probably could be
   # done at some stage.
   $resume_on_stall = 0 if defined $byte_range;

   ( try_repeat {
      if( my $pos = $value_len ) {
         $byte_range = "$pos-";
      }

      my $request = $self->_make_request(
         method  => $args{method},
         bucket  => $args{bucket},
         path    => $args{key},
         headers => {
            ( defined $if_match   ? ( "If-Match" => $if_match )      : () ),
            ( defined $byte_range ? ( Range => "bytes=$byte_range" ) : () ),
         },
         content => "",
      );

      $self->_do_request( $request,
         timeout       => $args{timeout},
         stall_timeout => $args{stall_timeout} // $self->{stall_timeout},
         on_header => sub {
            my ( $this_header ) = @_;
            my $code = $this_header->code;

            if( $head_future->is_cancelled or $code !~ m/^2/ ) {
               # Just eat the body on cancellation or if it's not a 2xx
               # For failures this will cause ->on_fail to occur and fail the
               # $head_future
               return sub {
                  return if @_;
                  return $this_header;
               };
            }

            my %meta;
            $this_header->scan( sub {
               $_[0] =~ m/^X-Amz-Meta-(.*)$/i and $meta{$1} = $_[1];
            });

            if( !$value_future ) {
               # First response
               $header = $this_header;
               # If we're going to retry this, ensure we only request this exact ETag
               $if_match ||= $header->header( "ETag" );



( run in 0.608 second using v1.01-cache-2.11-cpan-39bf76dae61 )