view release on metacpan or search on metacpan
lib/Amazon/S3/Lite.pm view on Meta::CPAN
$self->logger->debug( sprintf 'Response: %s %s', $response->{status}, $response->{reason} );
return $response;
}
########################################################################
# head_object( $bucket, $key )
#
# Fetches metadata for an object without retrieving the body.
# Returns undef if the key does not exist (404).
# Returns a hashref with content_type, content_length, etag,
# last_modified, and metadata (x-amz-meta-* headers).
########################################################################
sub head_object {
########################################################################
my ( $self, $bucket, $key ) = @_;
croak 'bucket is required' if !defined $bucket || !length $bucket;
croak 'key is required' if !defined $key || !length $key;
lib/Amazon/S3/Lite.pm view on Meta::CPAN
};
}
########################################################################
# get_object( $bucket, $key, %options )
#
# Fetches an object from S3. Options:
# range => 'bytes=0-1023' partial fetch
# filename => '/tmp/foo' stream body to disk; omits content key
#
# Returns undef on 404.
# Returns a hashref with content_type, content_length, etag,
# last_modified, metadata, and content (unless filename is used).
########################################################################
sub get_object {
########################################################################
my ( $self, $bucket, $key, %options ) = @_;
croak 'bucket is required' if !defined $bucket || !length $bucket;
croak 'key is required' if !defined $key || !length $key;
lib/Amazon/S3/Lite.pm view on Meta::CPAN
my @all_objects;
my $continuation_token;
while ($TRUE) {
if ( defined $continuation_token ) {
$options{continuation_token} = $continuation_token;
}
my $result = $self->list_objects_v2( $bucket, %options );
last if !$result; # 404 / empty bucket
push @all_objects, @{ $result->{objects} };
last if !$result->{is_truncated};
$continuation_token = $result->{next_continuation_token};
}
return @all_objects;
}
lib/Amazon/S3/Lite.pm view on Meta::CPAN
# Error checking helpers
########################################################################
sub _is_success {
########################################################################
return $_[0]->{status} =~ /\A2\d{2}\z/;
}
########################################################################
sub _is_not_found {
########################################################################
return $_[0]->{status} == 404;
}
########################################################################
sub _croak_on_error {
########################################################################
my ( $self, $response, $context ) = @_;
return if _is_success($response);
my ( $status, $reason ) = @{$response}{qw(status reason)};
lib/Amazon/S3/Lite.pm view on Meta::CPAN
=item 4.
If none of the above yield credentials, the constructor croaks.
=back
=head1 METHODS
All methods croak on unrecoverable errors (network failure, HTTP 5xx).
HTTP 404 is not an exception - methods that can meaningfully return
C<undef> for a missing resource do so.
=head2 list_objects_v2
my $result = $s3->list_objects_v2($bucket, %options);
Lists objects in C<$bucket> using the S3 ListObjectsV2 API.
Options:
lib/Amazon/S3/Lite.pm view on Meta::CPAN
when no C<logger> object is supplied and Log::Log4perl is not available
or not yet initialized.
=head2 get_object
my $obj = $s3->get_object($bucket, $key);
my $obj = $s3->get_object($bucket, $key, %options);
Fetches the object at C<$key> in C<$bucket>.
Returns C<undef> if the key does not exist (HTTP 404).
Returns a hashref on success:
{
content => '...', # raw bytes; absent when filename is used
content_type => 'application/json',
content_length => 1024,
etag => 'abc123',
last_modified => 'Tue, 01 Jan 2024 00:00:00 GMT',
metadata => { # x-amz-meta-* headers, lowercased
lib/Amazon/S3/Lite.pm view on Meta::CPAN
=back
=head2 head_object
my $meta = $s3->head_object($bucket, $key);
Fetches metadata for C<$key> without retrieving the object body.
Useful for existence checks and reading C<x-amz-meta-*> headers
cheaply.
Returns C<undef> if the key does not exist (HTTP 404).
Returns a hashref on success with the same fields as C<get_object>
except C<content>, which is always absent.
=head2 put_object
$s3->put_object($bucket, $key, $data, %options);
Stores C<$data> at C<$key> in C<$bucket>. C<$data> may be:
lib/Amazon/S3/Lite.pm view on Meta::CPAN
=item * HTTP 5xx responses from S3
=item * Unexpected HTTP 3xx responses that could not be resolved
=back
Methods return C<undef> on:
=over 4
=item * HTTP 404 (key or bucket not found), where the return type allows it
=back
All other HTTP error codes (400, 403, 409, etc.) cause a croak with a
message containing the HTTP status line and the S3 error body where
available.
=head1 DEPENDENCIES
=over 4
share/README.md view on Meta::CPAN
2. Environment variables `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`,
and optionally `AWS_SESSION_TOKEN`.
3. [Amazon::Credentials](https://metacpan.org/pod/Amazon%3A%3ACredentials), if installed. This covers IAM instance roles,
Lambda execution roles, ECS task roles, and `~/.aws/credentials`
profiles.
4. If none of the above yield credentials, the constructor croaks.
# METHODS
All methods croak on unrecoverable errors (network failure, HTTP 5xx).
HTTP 404 is not an exception - methods that can meaningfully return
`undef` for a missing resource do so.
## list\_objects\_v2
my $result = $s3->list_objects_v2($bucket, %options);
Lists objects in `$bucket` using the S3 ListObjectsV2 API.
Options:
share/README.md view on Meta::CPAN
when no `logger` object is supplied and Log::Log4perl is not available
or not yet initialized.
## get\_object
my $obj = $s3->get_object($bucket, $key);
my $obj = $s3->get_object($bucket, $key, %options);
Fetches the object at `$key` in `$bucket`.
Returns `undef` if the key does not exist (HTTP 404).
Returns a hashref on success:
{
content => '...', # raw bytes; absent when filename is used
content_type => 'application/json',
content_length => 1024,
etag => 'abc123',
last_modified => 'Tue, 01 Jan 2024 00:00:00 GMT',
metadata => { # x-amz-meta-* headers, lowercased
share/README.md view on Meta::CPAN
holding the full body in memory is undesirable.
## head\_object
my $meta = $s3->head_object($bucket, $key);
Fetches metadata for `$key` without retrieving the object body.
Useful for existence checks and reading `x-amz-meta-*` headers
cheaply.
Returns `undef` if the key does not exist (HTTP 404).
Returns a hashref on success with the same fields as `get_object`
except `content`, which is always absent.
## put\_object
$s3->put_object($bucket, $key, $data, %options);
Stores `$data` at `$key` in `$bucket`. `$data` may be:
share/README.md view on Meta::CPAN
# ERROR HANDLING
Methods croak on:
- Network-level failures (connection refused, timeout, DNS failure)
- HTTP 5xx responses from S3
- Unexpected HTTP 3xx responses that could not be resolved
Methods return `undef` on:
- HTTP 404 (key or bucket not found), where the return type allows it
All other HTTP error codes (400, 403, 409, etc.) cause a croak with a
message containing the HTTP status line and the S3 error body where
available.
# DEPENDENCIES
- [HTTP::Tiny](https://metacpan.org/pod/HTTP%3A%3ATiny) (core since Perl 5.14)
- [Amazon::Signature4::Lite](https://metacpan.org/pod/Amazon%3A%3ASignature4%3A%3ALite)
- [XML::Twig](https://metacpan.org/pod/XML%3A%3ATwig) (for parsing list and copy responses)
t/01-s3-lite.t view on Meta::CPAN
my $obj = $r->{objects}[0];
is $obj->{key}, 'logs/2024-01-01.gz', 'key';
is $obj->{size}, 1024, 'size is integer';
is $obj->{etag}, 'abc123', 'etag stripped of quotes';
# missing bucket croaks
eval { $s3->list_objects_v2() };
like $@, qr/bucket is required/, 'croaks without bucket';
# 404 returns undef
local *Amazon::S3::Lite::_request = mock_request( status => 404 );
my $not_found = $s3->list_objects_v2('no-such-bucket');
ok !defined $not_found, '404 returns undef';
};
subtest 'list_all_objects_v2 pagination' => sub {
my $s3 = new_s3();
my $page = 0;
no warnings 'redefine';
local *Amazon::S3::Lite::list_objects_v2 = sub {
my ( $self, $bucket, %opts ) = @_;
$page++;
t/01-s3-lite.t view on Meta::CPAN
return { objects => [], is_truncated => 0 };
};
$s3->list_all_objects_v2( 'test-bucket', delimiter => '/' );
};
subtest 'head_object' => sub {
my $s3 = new_s3();
no warnings 'redefine';
# 404 returns undef
local *Amazon::S3::Lite::_request = mock_request( status => 404 );
ok !defined $s3->head_object( 'b', 'k' ), '404 returns undef';
# success
local *Amazon::S3::Lite::_request = mock_request(
headers => {
'content-type' => 'text/plain',
'content-length' => '42',
'etag' => '"abc123"',
'last-modified' => 'Wed, 01 Jan 2025 00:00:00 GMT',
'x-amz-meta-source' => 'lambda',
},
t/01-s3-lite.t view on Meta::CPAN
like $@, qr/bucket is required/, 'croaks without bucket';
eval { $s3->head_object('b') };
like $@, qr/key is required/, 'croaks without key';
};
subtest 'get_object' => sub {
my $s3 = new_s3();
no warnings 'redefine';
# 404 returns undef
local *Amazon::S3::Lite::_request = mock_request( status => 404 );
ok !defined $s3->get_object( 'b', 'k' ), '404 returns undef';
# in-memory success
local *Amazon::S3::Lite::_request = mock_request(
content => 'hello world',
headers => {
'content-type' => 'text/plain',
'content-length' => '11',
'etag' => '"abc123"',
'last-modified' => 'Wed, 01 Jan 2025 00:00:00 GMT',
},
t/01-s3-lite.t view on Meta::CPAN
# get to file
my ( $fh, $fname ) = tempfile( UNLINK => 1 );
close $fh;
my $file_meta = $s3->get_object( 'test-bucket', $key, filename => $fname );
ok defined $file_meta, 'get_object with filename returns meta';
ok !exists $file_meta->{content}, 'no content key';
open my $in, '<', $fname or die $!;
is do { local $/; <$in> }, $content, 'file content correct';
# 404
my $missing = $s3->get_object( 'test-bucket', 'no/such/key.txt' );
ok !defined $missing, '404 returns undef';
# delete
ok $s3->delete_object( 'test-bucket', $key ), 'delete_object returns true';
# confirm gone
my $gone = $s3->head_object( 'test-bucket', $key );
ok !defined $gone, 'object gone after delete';
};
subtest 'LocalStack - list_objects_v2' => sub {