Amazon-S3
view release on metacpan or search on metacpan
lib/Amazon/S3.pm view on Meta::CPAN
raise_error
retry
_region
secure
_signer
timeout
ua
verify_checksums
),
);
our $VERSION = '2.1.2'; ## no critic (RequireInterpolation)
our @EXPORT_OK = qw(is_domain_bucket);
########################################################################
sub new {
########################################################################
my ( $class, @args ) = @_;
my %options = ref $args[0] ? %{ $args[0] } : @args;
$options{timeout} //= $DEFAULT_TIMEOUT;
$options{cache_signer} //= $FALSE;
$options{retry} //= $FALSE;
$options{express} //= $FALSE;
$options{verify_checksums} //= $TRUE;
$options{checksum_algorithm} //= 'crc64nvme';
$options{raise_error} //= $FALSE;
croak "ERROR: pass endpoint_url or host but not both\n"
if $options{endpoint_url} && $options{host};
if ( my $endpoint_url = $options{endpoint_url} ) {
@options{qw(secure host)} = _parse_endpoint($endpoint_url);
}
elsif ( $options{host} ) {
if ( $options{host} =~ m{\Ahttps?://}xsm ) {
warn "host containing a URL is deprecated; use endpoint_url instead\n";
@options{qw(secure host)} = _parse_endpoint( $options{host} );
}
else {
$options{secure} //= $TRUE;
}
}
else {
$options{secure} = $TRUE;
$options{host} = $DEFAULT_HOST;
}
$options{dns_bucket_names} //= $TRUE;
croak sprintf "ERROR: invalid checksum_algorithm: '%s'\nMust be one of: %s\n", $options{checksum_algorithm}, join q{,},
@AWS_CHECKSUM_TYPES
if none { $options{checksum_algorithm} eq $_ } @AWS_CHECKSUM_TYPES;
$options{_region} = delete $options{region};
$options{_signer} = delete $options{signer};
# convenience for level => 'debug' & for consistency with
# Amazon::Credentials only do this if we are using internal logger,
# call should NOT use debug flag but rather use their own logger's
# level to turn on higher levels of logging...
if ( !$options{logger} ) {
if ( delete $options{debug} ) {
$options{level} = 'debug';
}
$options{log_level} = delete $options{level};
$options{log_level} //= $DEFAULT_LOG_LEVEL;
$options{logger}
= Amazon::S3::Logger->new( log_level => $options{log_level} );
}
my $self = $class->SUPER::new( \%options );
# setup logger internal logging
$self->get_logger->debug(
sub {
my %safe_options = %options;
if ( $safe_options{aws_secret_access_key} ) {
$safe_options{aws_secret_access_key} = '****';
$safe_options{aws_access_key_id} = '****';
}
return Dumper( [ options => \%safe_options ] );
},
);
if ( !$self->credentials ) {
croak 'No aws_access_key_id'
if !$self->aws_access_key_id;
croak 'No aws_secret_access_key'
if !$self->aws_secret_access_key;
# encrypt credentials
$self->aws_access_key_id( _encrypt( $self->aws_access_key_id ) );
$self->aws_secret_access_key( _encrypt( $self->aws_secret_access_key ) );
$self->token( _encrypt( $self->token ) );
}
my $ua;
if ( $self->retry ) {
$ua = LWP::UserAgent::Determined->new(
keep_alive => $KEEP_ALIVE_CACHESIZE,
requests_redirectable => [qw(GET HEAD DELETE)],
);
$ua->timing( join $COMMA, map { 2**$_ } 0 .. $MAX_RETRIES );
}
else {
$ua = LWP::UserAgent->new(
keep_alive => $KEEP_ALIVE_CACHESIZE,
requests_redirectable => [qw(GET HEAD DELETE)],
);
}
$ua->timeout( $self->timeout );
$ua->env_proxy;
$self->ua($ua);
$self->region( $self->_region // $DEFAULT_REGION );
if ( !$self->_signer && $self->cache_signer ) {
$self->_signer( $self->signer );
}
if ( $self->express ) {
$self->use_express_one_zone();
}
$self->turn_on_special_retry();
$self->_init_checksum_types;
lib/Amazon/S3.pm view on Meta::CPAN
my ($self) = @_;
return _decrypt( $self->aws_secret_access_key );
}
########################################################################
sub get_token {
########################################################################
my ($self) = @_;
return _decrypt( $self->token );
}
########################################################################
sub turn_on_special_retry {
########################################################################
my ($self) = @_;
return
if !$self->retry;
# In the field we are seeing issue of Amazon returning with a 400
# code in the case of timeout. From AWS S3 logs: REST.PUT.PART
# Backups/2017-05-04/<account>.tar.gz "PUT
# /Backups<path>?partNumber=27&uploadId=<id> - HTTP/1.1" 400
# RequestTimeout 360 20971520 20478 - "-" "libwww-perl/6.15"
my $http_codes_hr = $self->ua->codes_to_determinate();
$http_codes_hr->{$HTTP_BAD_REQUEST} = $TRUE;
return;
}
########################################################################
sub turn_off_special_retry {
########################################################################
my ($self) = @_;
return
if !$self->retry;
# In the field we are seeing issue with Amazon returning a 400
# code in the case of timeout. From AWS S3 logs: REST.PUT.PART
# Backups/2017-05-04/<account>.tar.gz "PUT
# /Backups<path>?partNumber=27&uploadId=<id> - HTTP/1.1" 400
# RequestTimeout 360 20971520 20478 - "-" "libwww-perl/6.15"
my $http_codes_hr = $self->ua->codes_to_determinate();
delete $http_codes_hr->{$HTTP_BAD_REQUEST};
return;
}
########################################################################
sub region {
########################################################################
my ( $self, @args ) = @_;
if (@args) {
$self->_region( $args[0] );
}
$self->get_logger->debug( sub { return 'region: ' . ( $self->_region // $EMPTY ) } );
if ( $self->_region ) {
my $host = $self->host;
$self->get_logger->debug( sub { return 'host: ' . $self->host } );
# only add region if host was not populated from endpoint_url
if ( !$self->endpoint_url && $host =~ /\As3[.](.*)?amazonaws/xsm ) {
$self->host( sprintf 's3.%s.amazonaws.com', $self->_region );
}
}
return $self->_region;
}
########################################################################
sub buckets {
########################################################################
my ( $self, $verify_region ) = @_;
# The "default" region for Amazon is us-east-1
# This is the region to set it to for listing buckets
# You may need to reset the signer's endpoint to 'us-east-1'
# temporarily cache signer
my $region = $self->_region;
my $bucket_list;
$self->reset_signer_region($DEFAULT_REGION); # default region for buckets op
my $r = $self->send_request(
{ method => 'GET',
path => $EMPTY,
headers => {},
region => $DEFAULT_REGION,
},
);
return $bucket_list
if !$r || $self->errstr;
my $owner_id = $r->{Owner}{ID};
my $owner_displayname = $r->{Owner}{DisplayName};
my @buckets;
if ( ref $r->{Buckets} ) {
my $buckets = $r->{Buckets}{Bucket};
if ( !ref $buckets || reftype($buckets) ne 'ARRAY' ) {
$buckets = [$buckets];
}
foreach my $node ( @{$buckets} ) {
push @buckets,
Amazon::S3::Bucket->new(
{ bucket => $node->{Name},
creation_date => $node->{CreationDate},
account => $self,
buffer_size => $self->buffer_size,
verify_region => $verify_region // $FALSE,
},
);
}
lib/Amazon/S3.pm view on Meta::CPAN
);
$self->express($express);
return $result;
}
########################################################################
sub list_bucket_v2 {
########################################################################
my ( $self, $conf ) = @_;
$conf->{'list-type'} = '2';
goto &list_bucket;
}
########################################################################
sub list_bucket {
########################################################################
my ( $self, $conf ) = @_;
my $bucket = delete $conf->{bucket};
croak 'must specify bucket'
if !$bucket;
$conf //= {};
my $bucket_list; # return this
my $path = $bucket . $SLASH;
my $headers = delete $conf->{headers};
my $list_type = $conf->{'list-type'} // '1';
my ( $marker, $next_marker, $query_next )
= @{ $LIST_OBJECT_MARKERS{$list_type} };
if ( $conf->{marker} ) {
$conf->{$query_next} = delete $conf->{marker};
}
if ( %{$conf} ) {
my @vars = keys %{$conf};
# remove undefined elements
foreach (@vars) {
next if defined $conf->{$_};
delete $conf->{$_};
}
my $query_string = $QUESTION_MARK . join $AMPERSAND, map { $_ . $EQUAL_SIGN . urlencode( $conf->{$_} ) }
keys %{$conf};
$path .= $query_string;
}
$self->get_logger->debug( sprintf 'PATH: %s', $path );
my $r = $self->send_request(
{ method => 'GET',
path => $path,
headers => $headers // {}, # { 'Content-Length' => 0 },
region => $self->region,
},
);
$self->get_logger->trace(
Dumper(
[ r => $r,
errstr => $self->errstr,
]
)
);
return $bucket_list
if !$r || $self->errstr;
$self->get_logger->trace(
sub {
return Dumper(
[ marker => $marker,
next_marker => $next_marker,
response => $r,
],
);
},
);
$bucket_list = {
bucket => $r->{Name},
prefix => $r->{Prefix} // $EMPTY,
marker => $r->{$marker} // $EMPTY,
next_marker => $r->{$next_marker} // $EMPTY,
max_keys => $r->{MaxKeys},
is_truncated => (
( defined $r->{IsTruncated} && scalar $r->{IsTruncated} eq 'true' )
? $TRUE
: $FALSE
),
};
my @keys;
foreach my $node ( @{ $r->{Contents} } ) {
my $etag = $node->{ETag};
if ( defined $etag ) {
$etag =~ s{(^"|"$)}{}gxsm;
}
push @keys,
{
key => $node->{Key},
last_modified => $node->{LastModified},
etag => $etag,
size => $node->{Size},
storage_class => $node->{StorageClass},
lib/Amazon/S3.pm view on Meta::CPAN
# x-amz-request-payer: RequestPayer
# x-amz-optional-object-attributes: OptionalObjectAtttributes
#
# Parameters:
# delimiter => Delimiter
# encoding-type => EncodingType
# key-marker => KeyMarker
# max-keys => MaxKeys
# prefix => Prefix
# version-id-marker => VersionIdMarker
#
# Response
########################################################################
sub list_object_versions {
########################################################################
my ( $self, $conf ) = @_;
my $bucket = delete $conf->{bucket};
die 'no bucket'
if !$bucket;
my $headers = delete $conf->{headers};
croak 'must specify bucket'
if !$bucket;
$conf ||= {};
my ( $marker, $next_marker, $query_next )
= @{ $LIST_OBJECT_MARKERS{'3'} };
if ( $conf->{'key-marker'} ) {
$conf->{$query_next} = delete $conf->{'key-marker'};
}
if ( %{$conf} ) {
# remove undefined elements
foreach ( keys %{$conf} ) {
next if defined $conf->{$_};
delete $conf->{$_};
}
}
my $path = create_api_uri( path => "$bucket/", api => 'versions', %{$conf} );
my $r = $self->send_request(
{ method => 'GET',
path => $path,
headers => $headers // {},
region => $self->region,
},
);
return
if !$r || $self->errstr;
$self->get_logger->debug(
sub {
return Dumper(
[ marker => $marker,
next_marker => $next_marker,
response => $r,
],
);
},
);
return $r;
}
########################################################################
sub get_credentials {
########################################################################
my ($self) = @_;
my $aws_access_key_id;
my $aws_secret_access_key;
my $token;
if ( $self->credentials ) {
$aws_access_key_id = $self->credentials->get_aws_access_key_id;
$aws_secret_access_key = $self->credentials->get_aws_secret_access_key;
$token = $self->credentials->get_token;
}
else {
$aws_access_key_id = $self->aws_access_key_id;
$aws_secret_access_key = $self->aws_secret_access_key;
$token = $self->token;
}
return ( $aws_access_key_id, $aws_secret_access_key, $token );
}
# Log::Log4perl compatibility routines
########################################################################
sub get_logger {
########################################################################
my ($self) = @_;
return $self->logger;
}
########################################################################
sub level {
########################################################################
my ( $self, @args ) = @_;
if (@args) {
$self->log_level( $args[0] );
$self->get_logger->level( uc $args[0] );
}
return $self->get_logger->level;
}
########################################################################
lib/Amazon/S3.pm view on Meta::CPAN
return $FALSE
if length $bucketname > $MAX_BUCKET_NAME_LENGTH - 1;
return $FALSE
if length $bucketname < $MIN_BUCKET_NAME_LENGTH;
return $FALSE
if $bucketname !~ m{\A[[:lower:]][[:lower:]\d-]*\z}xsm;
return $FALSE
if $bucketname !~ m{[[:lower:]\d]\z}xsm;
return $TRUE;
}
########################################################################
sub _make_request {
########################################################################
my ( $self, @args ) = @_;
my $parameters = get_parameters(@args);
my ( $method, $path, $headers, $data, $metadata, $region )
= @{$parameters}{qw(method path headers data metadata region)};
# reset region on every call...every bucket can have it's own region
$self->region( $region // $self->_region );
croak 'must specify method'
if !$method;
croak 'must specify path'
if !defined $path;
$headers //= {};
$metadata //= {};
$data //= $EMPTY;
$headers->{'Content-Length'} //= length $data;
my $http_headers = $self->_merge_meta( $headers, $metadata );
my $protocol = $self->secure ? 'https' : 'http';
my $host = $self->host;
$path =~ s/\A\///xsm;
my $url = sprintf '%s://%s/%s', $protocol, $host, $path;
# if ( $path =~ m{\A([^/?]+)([^?]+)(.*)}xsm
if ( $path =~ /\A([^\/?]+)([^?]+)(.*)/xsm
&& $self->dns_bucket_names
&& is_domain_bucket($1) ) {
my $bucket = $1;
$path = $2;
my $query_string = $3;
$self->logger->debug(
sub {
return Dumper(
[ bucket => $bucket,
path => $path,
query_string => $query_string,
]
);
}
);
if ( $host =~ /([^:]+):([^:]\d+)$/xsm ) {
my $port;
$url = eval {
$port = $2;
$host = $1;
my $uri = URI->new;
$uri->scheme('http');
$uri->host("$bucket.$host");
$uri->port($port);
$uri->path($path);
return $uri . $query_string;
};
die sprintf
"error creating uri for bucket: [%s], host: [%s], path: [%s], port: [%s]\n%s",
$bucket, $host, $path, $port, $EVAL_ERROR
if !$url || $EVAL_ERROR;
}
else {
$url = sprintf '%s://%s.%s%s%s', $protocol, $bucket, $host, $path, $query_string;
}
}
my $request = HTTP::Request->new( $method, $url, $http_headers );
$self->last_request($request);
if ($data) {
$request->content($data);
}
$self->signer->region($region); # always set regional endpoint for signing
$self->signer->sign($request);
return $request;
}
########################################################################
sub send_request {
########################################################################
my ( $self, @args ) = @_;
my $logger = $self->get_logger;
$logger->trace(
sub {
return Dumper( [ args => \@args ] );
},
);
my $keep_root = $FALSE;
my $request = eval {
return $args[0]
if ref( $args[0] ) =~ /HTTP::Request/xsm;
return {@args}
if @args > 1 && !@args % 2;
return $args[0]
if ref $args[0];
croak 'invalid argument to send_request';
};
if ( ref($request) !~ /HTTP::Request/xsm ) {
$keep_root = delete $request->{keep_root};
$request = $self->_make_request($request);
}
my $response = $self->_do_http($request);
$self->last_response($response);
$logger->debug(
sub {
return Dumper( [ response => $response ] );
}
);
return $self->_decode_response( $response, $keep_root );
}
########################################################################
sub is_json_response {
########################################################################
my ($rsp) = @_;
return $FALSE
if !$rsp->content;
my $content_type = $rsp->content_type // $EMPTY;
return $TRUE
if $content_type eq 'application/json';
return $TRUE
if $content_type =~ m{\Aapplication/[^/]+\+json\z}xsm;
return $FALSE;
}
########################################################################
sub _decode_response {
########################################################################
my ( $self, $response, $keep_root ) = @_;
if ( $response->code !~ /\A2\d{2}\z/xsm ) {
$self->_handle_response_error($response);
return;
}
return
if !$response->content;
my $content;
if ( is_xml_response($response) && $response->content =~ /\A\s*</xsm ) {
$content = eval { return $self->_xpc_of_content( $response->content, $keep_root, ); };
}
elsif ( is_json_response($response) ) {
$content = eval { return JSON::PP->new->decode( $response->content ); };
}
if ( !defined $content || $EVAL_ERROR ) {
$content = eval { return JSON::PP->new->decode( $response->content ); };
}
return $response->content
if !defined $content || $EVAL_ERROR;
return $content;
}
########################################################################
lib/Amazon/S3.pm view on Meta::CPAN
# where an exact host has been given
if ( !$called_from_redirect ) {
$self->host( sprintf 's3-%s-amazonaws.com', $region );
}
return $TRUE;
},
IllegalLocationConstraintException => sub {
# This is hackish; but in this case the region name only appears in the message
if ( $message =~ /The (\S+) location/xsm ) {
my $new_region = $1;
# Correct the region for the signer
$self->{signer}->{endpoint} = $new_region;
# Set the proper host for the region
$self->host( sprintf 's3.%s.amazonaws.com', $new_region );
return $TRUE;
}
},
'Other' => sub {
# Some other error
$self->_remember_errors( $response->content, 1 );
return $FALSE;
},
);
return $error_handlers{$condition}->();
}
########################################################################
sub reset_errors {
########################################################################
my ($self) = @_;
$self->err(undef);
$self->errstr(undef);
$self->error(undef);
return $self;
}
########################################################################
sub _do_http {
########################################################################
my ( $self, $request, $filename ) = @_;
# convenient time to reset any error conditions
$self->reset_errors;
my $response = $self->ua->request( $request, $filename );
# For new buckets at non-standard locations, amazon will sometimes
# respond with a temporary redirect. In this case it is necessary
# to try again with the new URL
my $location = $response->header('Location');
if ( $response->code =~ /\A3/xsm and defined $location ) {
$self->get_logger->debug(
sub {
return { sprintf 'Redirecting to: %s', $location };
}
);
$request->uri($location);
$response = $self->ua->request( $request, $filename );
}
$self->get_logger->debug( sub { return Dumper( [$response] ) } );
$self->last_response($response);
return $response;
}
# Call this if handling any temporary redirect issues
# (Like needing to probe with a HEAD request when file handle are involved)
########################################################################
sub _do_http_no_redirect {
########################################################################
my ( $self, $request, $filename ) = @_;
# convenient time to reset any error conditions
$self->reset_errors;
my $response = $self->ua->request( $request, $filename );
$self->get_logger->debug( sub { return Dumper( [$response] ) } );
$self->last_response($response);
return $response;
}
########################################################################
sub send_request_expect_nothing {
########################################################################
my ( $self, @args ) = @_;
my $request = $self->_make_request(@args);
my $response = $self->_do_http($request);
my $content = $response->content;
return $TRUE
if $response->code =~ /^2\d\d$/xsm;
# anything else is a failure, and we save the parsed result
$self->_handle_response_error($response);
return $FALSE;
}
# Send a HEAD request first, to find out if we'll be hit with a 307 redirect.
# Since currently LWP does not have true support for 100 Continue, it simply
# slams the PUT body into the socket without waiting for any possible redirect.
# Thus when we're reading from a filehandle, when LWP goes to reissue the request
# having followed the redirect, the filehandle's already been closed from the
# first time we used it. Thus, we need to probe first to find out what's going on,
# before we start sending any actual data.
########################################################################
sub send_request_expect_nothing_probed {
########################################################################
my ( $self, @args ) = @_;
my $parameters = get_parameters(@args);
my ( $method, $path, $conf, $value, $region )
= @{$parameters}{qw(method path headers data region)};
$region = $region // $self->region;
my $request = $self->_make_request(
{ method => 'HEAD',
path => $path,
region => $region,
},
);
my $override_uri;
my $old_redirectable = $self->ua->requests_redirectable;
$self->ua->requests_redirectable( [] );
my $response = $self->_do_http_no_redirect($request);
if ( $response->code =~ /^3/xsm ) {
if ( defined $response->header('Location') ) {
$override_uri = $response->header('Location');
}
else {
$self->_handle_response_error( $response, $TRUE );
}
$self->get_logger->debug(
sub {
return sprintf 'setting override URI: [%s]', $override_uri;
}
);
}
$request = $self->_make_request(
{ method => $method,
path => $path,
headers => $conf,
data => $value,
region => $region,
},
);
if ( defined $override_uri ) {
$request->uri($override_uri);
}
$response = $self->_do_http_no_redirect($request);
$self->ua->requests_redirectable($old_redirectable);
my $content = $response->content;
return $TRUE
if $response->code =~ /^2\d\d$/xsm;
# anything else is a failure, and we save the parsed result
$self->_handle_response_error($response);
return $FALSE;
}
########################################################################
sub _croak_if_response_error {
########################################################################
my ( $self, $response ) = @_;
return
if $response->code =~ /^2\d{2}$/xsm;
return $self->_handle_response_error( $response, $TRUE );
}
########################################################################
sub _xpc_of_content {
########################################################################
my ( $self, $src, $keep_root ) = @_;
my $xml_hr
= eval { XMLin( $src, SuppressEmpty => $EMPTY, ForceArray => ['Contents'], KeepRoot => $keep_root, NoAttr => $TRUE, ); };
if ( !$xml_hr && $EVAL_ERROR ) {
confess "Error parsing $src: $EVAL_ERROR";
}
return $xml_hr;
}
lib/Amazon/S3.pm view on Meta::CPAN
AWS access key ID.
This option is required when a C<credentials> object is not supplied.
When explicit credentials are supplied, C<Amazon::S3> stores them
internally for use when signing requests. Applications should avoid
dumping the client object to logs.
See L</AUTHENTICATION AND CREDENTIALS>.
=item aws_secret_access_key
AWS secret access key.
This option is required when a C<credentials> object is not supplied.
See L</AUTHENTICATION AND CREDENTIALS>.
=item buffer_size
Default buffer size, in bytes, used by operations that stream object
data.
The default is 4096.
=item cache_signer
When true, retain and reuse the Signature Version 4 signer.
When false, construct a signer when one is needed.
The default is false.
See L</AUTHENTICATION AND CREDENTIALS>.
=item checksum_algorithm
Checksum algorithm used when C<Amazon::S3> supplies a checksum with an
upload.
The default is C<crc64nvme>.
Recognized S3 checksum algorithm names are validated by the
constructor. Local checksum implementations provided by this release
are described in L</CHECKSUMS>.
=item credentials
Credentials provider object.
The object must provide:
get_aws_access_key_id()
get_aws_secret_access_key()
get_token()
L<Amazon::Credentials> is one implementation of this interface.
See L</AUTHENTICATION AND CREDENTIALS>.
=item debug
Compatibility option that sets the default logger level to C<debug>.
Applications should normally use C<level> instead.
This option affects the internally created logger only.
=item dns_bucket_names
Controls whether virtual-hosted-style bucket names are used when
possible.
The default is true.
A bucket name that cannot be used as a DNS subdomain is placed in the
request path instead.
=item endpoint_url
Optional explicit S3 service endpoint.
When C<endpoint_url> is supplied, C<Amazon::S3> uses that endpoint as
specified and does not rewrite the host when the configured region
changes.
The C<region> setting still controls the AWS signing region.
This is useful for S3-compatible services, local test environments, and
other cases where the caller must select the service endpoint explicitly.
For example:
my $s3 = Amazon::S3->new(
{ endpoint_url => 'http://localhost:4566',
region => 'us-east-1',
...
}
);
When C<endpoint_url> is not supplied, C<Amazon::S3> may derive the
standard AWS S3 endpoint from the configured region.
C<endpoint_url> and C<host> may not both be supplied.
=item host
S3 service endpoint.
The default is C<s3.amazonaws.com>.
When C<region()> is set and the host is a standard Amazon S3 endpoint,
C<Amazon::S3> adjusts the host for the configured region.
This option can also be used with S3-compatible and local testing
services.
=item level
Logging level used when C<Amazon::S3> creates its default logger.
The default is C<error>.
lib/Amazon/S3.pm view on Meta::CPAN
=item 2.
AWS secret access key.
=item 3.
Session token, or C<undef> when no token is configured.
=back
See L</AUTHENTICATION AND CREDENTIALS>.
=head3 get_default_region
my $region = $s3->get_default_region;
Attempts to determine the default AWS region.
The method checks, in order:
=over 4
=item 1.
C<AWS_REGION>.
=item 2.
C<AWS_DEFAULT_REGION>.
=item 3.
The EC2 instance metadata availability-zone endpoint.
=back
When an availability zone is obtained from instance metadata, the
zone suffix is removed to derive the region.
If no region can be determined, C<us-east-1> is returned.
=head3 get_logger
my $logger = $s3->get_logger;
Returns the logger associated with the client.
If no logger was supplied to C<new()>, this is the
L<Amazon::S3::Logger> instance created by the constructor.
This method is provided for compatibility with logger interfaces that
expect C<get_logger()>.
See L</LOGGING AND DEBUGGING>.
=head3 level
my $level = $s3->level;
$s3->level('debug');
Gets or sets the logging level.
When a level is supplied, both the stored logging level and the
associated logger level are updated.
When called without an argument, returns the current logger level.
The constructor default is C<error>.
See L</LOGGING AND DEBUGGING>.
=head3 region
my $region = $s3->region;
$s3->region('us-west-2');
Gets or sets the region used by the client.
The region is used for account-level requests and as the default
region assigned to bucket objects when no bucket-specific region is
supplied.
When the configured host uses the standard C<s3.amazonaws.com> form,
setting the region also adjusts the host to the regional Amazon S3
endpoint.
The constructor default is C<us-east-1>.
=head3 signer
my $signer = $s3->signer;
Returns the Signature Version 4 signer used for requests.
If a signer was supplied to the constructor, that signer is returned.
Otherwise a signer is constructed from the current credentials,
region, and session token.
When C<cache_signer> is true, a generated signer is retained and
reused. When it is false, a signer can be generated as needed.
This method does not accept a signer argument. Supply a custom signer
using the C<signer> constructor option.
See L</AUTHENTICATION AND CREDENTIALS>.
=head2 BUCKET MANAGEMENT
=head3 add_bucket
my $bucket = $s3->add_bucket(\%configuration);
Creates a bucket.
The argument is a hash reference containing the bucket configuration.
=over 4
lib/Amazon/S3.pm view on Meta::CPAN
=item prefix
Optional prefix used to restrict returned keys.
=item version-id-marker
Optional version ID marker used with C<key-marker> when continuing a
paginated listing.
=back
On success, returns the parsed ListObjectVersions service response.
This method does not automatically follow pagination.
On failure, returns C<undef> and records error information on the
client.
See L</LISTING OBJECTS> and
L<https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectVersions.html>.
=head2 ADVANCED AND COMPATIBILITY METHODS
=head3 turn_off_special_retry
$s3->turn_off_special_retry;
Removes the additional HTTP 400 retry condition installed by
C<turn_on_special_retry()>.
When retry handling is disabled, this method has no effect.
This method exists primarily for internal and compatibility use.
=head3 turn_on_special_retry
$s3->turn_on_special_retry;
When retry handling is enabled, adds HTTP 400 to the conditions
handled by the retry-aware user agent.
This behavior exists because some S3 request timeouts have historically
been returned as HTTP 400 responses.
The constructor calls this method automatically.
When retry handling is disabled, this method has no effect.
This method exists primarily for internal and compatibility use.
=head1 LOGGING AND DEBUGGING
Logging is controlled by the configured logger and logging level.
When no logger is supplied, C<Amazon::S3::Logger> is used.
Valid levels include:
fatal
error
warn
info
debug
trace
The default level is C<error>.
At C<debug> level, C<Amazon::S3> records higher-level request and
configuration information.
At C<trace> level, HTTP request and response information may also be
logged.
Applications should review trace output before retaining or sharing
it. Request and response data may contain sensitive application
information even when authentication values are sanitized.
=head1 S3-COMPATIBLE SERVICES
C<Amazon::S3> can be used with S3-compatible services and local S3
implementations by configuring the service endpoint and related
connection options.
The C<host>, C<secure>, and C<dns_bucket_names> settings are commonly
relevant when using a non-AWS endpoint.
S3-compatible implementations may differ from AWS in supported APIs,
request validation, checksum behavior, or edge cases.
The integration tests used during development include LocalStack, but
applications targeting another S3-compatible implementation should
test against that implementation directly.
=head1 COMPARISON TO OTHER PERL S3 MODULES
Perl applications have several choices for accessing Amazon S3,
including L<Net::Amazon::S3>, L<Paws::S3>, L<Amazon::S3::Lite>, and
L<Amazon::API::S3>. Each takes a different approach.
C<Amazon::S3> provides a dedicated S3 interface with a long-established
API. The distribution combines the account-level C<Amazon::S3>
interface with L<Amazon::S3::Bucket> for common object workflows and
L<Amazon::S3::BucketV2> for broader low-level API access.
C<Net::Amazon::S3> is the project from which C<Amazon::S3> originally
forked. The distributions have since diverged and should not be
considered drop-in replacements for one another.
C<Paws::S3> is part of the larger L<Paws> AWS SDK for Perl and follows
AWS service APIs through its generated service model.
L<Amazon::S3::Lite> is a smaller client intended for applications
where dependency size and startup cost are important.
L<Amazon::API::S3> is generated from the AWS Botocore service model
and is intended to closely reflect the current low-level S3 API.
The appropriate client depends primarily on the interface and level of
abstraction required by the application.
=head1 COMPATIBILITY AND LIMITATIONS
=head2 Minimum Perl Version
C<Amazon::S3> declares Perl 5.10 as its minimum supported Perl
version.
Dependencies may impose additional constraints on older Perl
installations.
Applications using an older Perl should run the complete distribution
test suite after installation.
=head2 Signature Version 4
AWS API requests are signed using Signature Version 4.
Signature Version 2 is not supported.
Because Signature Version 4 includes the AWS region in the signature,
bucket operations must use the region containing the bucket.
A bucket region can be supplied explicitly or determined using bucket
region verification.
=head2 Directory Buckets
Directory bucket support is currently limited to account-level create
and list operations.
See L</DIRECTORY BUCKETS>.
=head1 TESTING
The distribution includes unit tests and integration tests that
exercise behavior requiring an S3 endpoint.
Run the normal distribution test suite with:
make test
Integration testing during development includes LocalStack.
See F<README-TESTING.md> in the distribution root for test
environment setup, integration-test requirements, and additional
testing instructions.
=head1 SUPPORT
Bug reports and feature requests should be submitted through the
project issue tracker.
When reporting a problem, include the C<Amazon::S3> version, Perl
version, operating system, and enough information to reproduce the
behavior.
For request or protocol problems, debug or trace logging may also be
useful. Review logs before sharing them to ensure that they do not
contain credentials, authorization information, or sensitive object
data.
=head1 REPOSITORY
The source repository, issue tracker, and development history are
available at:
L<https://github.com/rlauer6/Amazon-S3>
=head1 AUTHOR
Original author: Timothy Appnel <tima@cpan.org>
Current maintainer: Rob Lauer <bigfoot@cpan.org>
=head1 SEE ALSO
L<Amazon::S3::Bucket>
L<Amazon::S3::BucketV2>
L<Amazon::S3::Constants>
L<Amazon::S3::Logger>
L<Amazon::Credentials>
L<Net::Amazon::S3>
L<Amazon S3 API Reference|https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html>
L<Amazon S3 bucket naming rules|https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html>
L<Amazon S3 bucket restrictions and limitations|https://docs.aws.amazon.com/AmazonS3/latest/userguide/BucketRestrictions.html>
L<AWS Signature Version 4|https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html>
L<Amazon S3 directory buckets|https://docs.aws.amazon.com/AmazonS3/latest/userguide/directory-buckets-overview.html>
L<LocalStack|https://localstack.io>
=head1 LICENCE
This library is free software; you may redistribute it and/or modify
it under the same terms as Perl itself.
Portions of this distribution contain code modified from Amazon. That
code is made available under the following notice:
# This software code is made available "AS IS" without warranties of any
# kind. You may copy, display, modify and redistribute the software
# code either by itself or as incorporated into your code; provided that
# you do not remove any proprietary notices. Your use of this software
# code is at your own risk and you waive any claim against Amazon
# Digital Services, Inc. or its affiliates with respect to your use of
# this software code. (c) 2006 Amazon Digital Services, Inc. or its
# affiliates.
( run in 1.462 second using v1.01-cache-2.11-cpan-062aa07a564 )