Amazon-S3-Lite
view release on metacpan or search on metacpan
lib/Amazon/S3/Lite.pm view on Meta::CPAN
};
}
########################################################################
# put_object( $bucket, $key, $data, %options )
#
# Stores an object in S3. $data may be a scalar string, a reference to
# a scalar, or an open filehandle / IO::File object.
#
# Options: content_type, content_length, metadata (hashref), acl
#
# Returns the ETag of the stored object. Croaks on failure.
########################################################################
sub put_object {
########################################################################
my ( $self, $bucket, $key, $data, %options ) = @_;
croak 'bucket is required' if !defined $bucket || !length $bucket;
croak 'key is required' if !defined $key || !length $key;
croak 'data is required' if !defined $data;
my $url = $self->_endpoint( $bucket, $key );
my %headers;
$headers{'Content-Type'} = $options{content_type} // 'application/octet-stream';
# x-amz-acl header
if ( $options{acl} ) {
$headers{'x-amz-acl'} = $options{acl};
}
# User metadata â prefix bare keys with x-amz-meta-
if ( my $meta = $options{metadata} ) {
for my $k ( keys %{$meta} ) {
my $header = $k =~ /^x-amz-meta-/xsm ? $k : "x-amz-meta-$k";
$headers{$header} = $meta->{$k};
}
}
my $body;
if ( openhandle($data) || ( blessed($data) && $data->can('read') ) ) {
# --- Filehandle path ---
my $content_length = $options{content_length};
# Try to stat the handle for real files; suppress warning on
# in-memory handles (IO::Scalar etc.) that have no underlying fd
if ( !defined $content_length ) {
my $fd = eval { fileno($data) };
if ( defined $fd && $fd >= 0 ) {
my @st = stat $data;
$content_length = $st[7] if @st && defined $st[7];
}
}
croak 'content_length is required for in-memory filehandles'
if !defined $content_length;
$headers{'Content-Length'} = $content_length;
# Wrap filehandle in a code ref for HTTP::Tiny streaming
my $chunk_size = 1024 * 64; # 64KB chunks
$body = sub {
my $buf;
my $n = read( $data, $buf, $chunk_size );
return $buf if $n;
return q{};
};
}
elsif ( ref $data eq 'SCALAR' ) {
# --- Scalar ref path ---
$body = ${$data};
$headers{'Content-Length'} = length $body;
$headers{'Content-MD5'} = encode_base64( md5($body), q{} );
}
else {
# --- Plain scalar path ---
$body = $data;
$headers{'Content-Length'} = length $body;
$headers{'Content-MD5'} = encode_base64( md5($body), q{} );
}
my $response = $self->_request( 'PUT', $url, \%headers, $body );
$self->_croak_on_error( $response, 'put_object' );
my $etag = $response->{headers}{etag};
$etag =~ s/\A"|"\z//gxsm if defined $etag;
return $etag;
}
########################################################################
# list_objects_v2( $bucket, %options )
#
# Lists objects in a bucket using the S3 ListObjectsV2 API.
# Returns a hashref with keys: bucket, prefix, key_count, max_keys,
# is_truncated, next_continuation_token, objects, common_prefixes.
########################################################################
sub list_objects_v2 {
########################################################################
my ( $self, $bucket, %options ) = @_;
croak 'bucket is required'
if !defined $bucket || !length $bucket;
# Map our option names to S3 query parameter names
my %param_map = (
prefix => 'prefix',
delimiter => 'delimiter',
max_keys => 'max-keys',
continuation_token => 'continuation-token',
start_after => 'start-after',
);
my %params = ( 'list-type' => '2' );
for my $opt ( keys %param_map ) {
if ( defined $options{$opt} ) {
$params{ $param_map{$opt} } = $options{$opt};
}
( run in 2.040 seconds using v1.01-cache-2.11-cpan-cdf2f3d4e48 )