Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Resolve https://rt.cpan.org/Ticket/Display.html?id=92423 #6

Merged
merged 3 commits into from

2 participants

@leejo

See commit message for details.

leejo added some commits
@leejo leejo correct and sort MANIFEST file
currently perl Makefile.PL gives:

	Checking if your kit is complete...
	Warning: the following files are missing in your kit:
			lib/AWS/S3/Request.pm
	Please inform the author.

it appears the lib/AWS/S3/Request.pm has been moved to Roles/ so
correct the MANIFEST file (also added missing BucketAction.pm)
0497499
@leejo leejo resolve rt.cpan.org #92423 - add endpoint attribute
currently this is hardcoded to s3.amazonaws.com, which is no good
if you want to hit one of the alternative endpoints:

	http://docs.aws.amazon.com/govcloud-us/latest/UserGuide/using-govcloud-endpoints.html

there is also the ability, with this change, to create an emulator
locally so you don't have to go out to the real Amazon endpoint for
testing - this may go someway to addressing the issue that there is
zero test coverage without having the AWS_ACCESS_KEY_ID and
AWS_SECRET_ACCESS_KEY environment variables set. this is problematic
as the module will install cleanly through cpan/cpanm but may not
be actually working as expected

add t/020_endpoint.t test to check the set endpoint attribute is
used - currently this uses a bad hostname and then checks the error
raised when the connection to it fails

update the README.markdown file using pod2markdown to bring it up
to date with the current POD, along with adding the documentation
for the changes in this commit

add Makefile.old to .gitignore
4e7d93b
@leejo leejo use the set endpoint in bucket name check
fixes the last hardcoded url. the others instances of this url are
only in the XML schema/namespace values so do not require changing
4d7e277
@jdrago999 jdrago999 merged commit 605ea25 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 23, 2014
  1. @leejo

    correct and sort MANIFEST file

    leejo authored
    currently perl Makefile.PL gives:
    
    	Checking if your kit is complete...
    	Warning: the following files are missing in your kit:
    			lib/AWS/S3/Request.pm
    	Please inform the author.
    
    it appears the lib/AWS/S3/Request.pm has been moved to Roles/ so
    correct the MANIFEST file (also added missing BucketAction.pm)
  2. @leejo

    resolve rt.cpan.org #92423 - add endpoint attribute

    leejo authored
    currently this is hardcoded to s3.amazonaws.com, which is no good
    if you want to hit one of the alternative endpoints:
    
    	http://docs.aws.amazon.com/govcloud-us/latest/UserGuide/using-govcloud-endpoints.html
    
    there is also the ability, with this change, to create an emulator
    locally so you don't have to go out to the real Amazon endpoint for
    testing - this may go someway to addressing the issue that there is
    zero test coverage without having the AWS_ACCESS_KEY_ID and
    AWS_SECRET_ACCESS_KEY environment variables set. this is problematic
    as the module will install cleanly through cpan/cpanm but may not
    be actually working as expected
    
    add t/020_endpoint.t test to check the set endpoint attribute is
    used - currently this uses a bad hostname and then checks the error
    raised when the connection to it fails
    
    update the README.markdown file using pod2markdown to bring it up
    to date with the current POD, along with adding the documentation
    for the changes in this commit
    
    add Makefile.old to .gitignore
Commits on Jul 25, 2014
  1. @leejo

    use the set endpoint in bucket name check

    leejo authored
    fixes the last hardcoded url. the others instances of this url are
    only in the XML schema/namespace values so do not require changing
This page is out of date. Refresh to see the latest.
View
1  .gitignore
@@ -4,3 +4,4 @@
/Makefile
MYMETA.yml
MYMETA.json
+Makefile.old
View
12 MANIFEST
@@ -1,4 +1,8 @@
Changes
+MANIFEST
+META.yml
+Makefile.PL
+README.markdown
inc/Module/Install.pm
inc/Module/Install/Base.pm
inc/Module/Install/Can.pm
@@ -13,7 +17,6 @@ lib/AWS/S3/File.pm
lib/AWS/S3/FileIterator.pm
lib/AWS/S3/HTTPRequest.pm
lib/AWS/S3/Owner.pm
-lib/AWS/S3/Request.pm
lib/AWS/S3/Request/CreateBucket.pm
lib/AWS/S3/Request/DeleteBucket.pm
lib/AWS/S3/Request/DeleteFile.pm
@@ -29,9 +32,8 @@ lib/AWS/S3/Request/SetBucketAccessControl.pm
lib/AWS/S3/Request/SetBucketPolicy.pm
lib/AWS/S3/Request/SetFileContents.pm
lib/AWS/S3/ResponseParser.pm
+lib/AWS/S3/Roles/BucketAction.pm
+lib/AWS/S3/Roles/Request.pm
lib/AWS/S3/Signer.pm
-Makefile.PL
-MANIFEST This list of files
-META.yml
-README.markdown
t/010-basic/010-basic.t
+t/020_endpoint.t
View
70 README.markdown
@@ -6,30 +6,25 @@ AWS::S3 - Lightweight interface to Amazon S3 (Simple Storage Service)
use AWS::S3;
-
my $s3 = AWS::S3->new(
access_key_id => 'E654SAKIASDD64ERAF0O',
secret_access_key => 'LgTZ25nCD+9LiCV6ujofudY1D6e2vfK0R4GLsI4H',
);
-
# Add a bucket:
my $bucket = $s3->add_bucket(
name => 'foo-bucket',
);
-
# Set the acl:
$bucket->acl( 'private' );
-
# Add a file:
my $new_file = $bucket->add_file(
key => 'foo/bar.txt',
contents => \'This is the contents of the file',
);
-
# You can also set the contents with a coderef:
# Coderef should eturn a reference, not the actual string of content:
$new_file = $bucket->add_file(
@@ -37,28 +32,22 @@ AWS::S3 - Lightweight interface to Amazon S3 (Simple Storage Service)
contents => sub { return \"This is the contents" }
);
-
# Get the file:
my $same_file = $bucket->file( 'foo/bar.txt' );
-
# Get the contents:
my $scalar_ref = $same_file->contents;
print $$scalar_ref;
-
# Update the contents with a scalar ref:
$same_file->contents( \"New file contents" );
-
# Update the contents with a code ref:
$same_file->contents( sub { return \"New file contents" } );
-
# Delete the file:
$same_file->delete();
-
# Iterate through lots of files:
my $iterator = $bucket->files(
page_size => 100,
@@ -76,19 +65,16 @@ AWS::S3 - Lightweight interface to Amazon S3 (Simple Storage Service)
}# end foreach()
}# end while()
-
# You can't delete a bucket until it's empty.
# Empty a bucket like this:
while( my @files = $iterator->next_page )
{
map { $_->delete } @files;
-
# Return to page 1:
$iterator->page_number( 1 );
}# end while()
-
# Now you can delete the bucket:
$bucket->delete();
@@ -96,25 +82,25 @@ AWS::S3 - Lightweight interface to Amazon S3 (Simple Storage Service)
AWS::S3 attempts to provide an alternate interface to the Amazon S3 Simple Storage Service.
-__NOTE:__ Until AWS::S3 gets to version 1.000 it will not implement the full S3 interface.
+**NOTE:** Until AWS::S3 gets to version 1.000 it will not implement the full S3 interface.
-__Disclaimer:__ Several portions of AWS::S3 have been adopted from [Net::Amazon::S3](http://search.cpan.org/perldoc?Net::Amazon::S3).
+**Disclaimer:** Several portions of AWS::S3 have been adopted from [Net::Amazon::S3](https://metacpan.org/pod/Net::Amazon::S3).
-__NOTE:__ AWS::S3 is NOT a drop-in replacement for [Net::Amazon::S3](http://search.cpan.org/perldoc?Net::Amazon::S3).
+**NOTE:** AWS::S3 is NOT a drop-in replacement for [Net::Amazon::S3](https://metacpan.org/pod/Net::Amazon::S3).
-__TODO:__ CloudFront integration.
+**TODO:** CloudFront integration.
# CONSTRUCTOR
Call `new()` with the following parameters.
-## access_key_id
+## access\_key\_id
Required. String.
Provided by Amazon, this is your access key id.
-## secret_access_key
+## secret\_access\_key
Required. String.
@@ -126,19 +112,25 @@ Optional. Boolean.
Default is `0`
+## endpoint
+
+Optional. String.
+
+Default is `s3.amazonaws.com`
+
## ua
-Optional. Should be an instance of [LWP::UserAgent](http://search.cpan.org/perldoc?LWP::UserAgent) or a subclass of it.
+Optional. Should be an instance of [LWP::UserAgent](https://metacpan.org/pod/LWP::UserAgent) or a subclass of it.
-Defaults to creating a new instance of [LWP::UserAgent::Determined](http://search.cpan.org/perldoc?LWP::UserAgent::Determined)
+Defaults to creating a new instance of [LWP::UserAgent::Determined](https://metacpan.org/pod/LWP::UserAgent::Determined)
# PUBLIC PROPERTIES
-## access_key_id
+## access\_key\_id
String. Read-only
-## secret_access_key
+## secret\_access\_key
String. Read-only.
@@ -146,55 +138,59 @@ String. Read-only.
Boolean. Read-only.
+## endpoint
+
+String. Read-only.
+
## ua
-[LWP::UserAgent](http://search.cpan.org/perldoc?LWP::UserAgent) object. Read-only.
+[LWP::UserAgent](https://metacpan.org/pod/LWP::UserAgent) object. Read-only.
## owner
-[AWS::S3::Owner](http://search.cpan.org/perldoc?AWS::S3::Owner) object. Read-only.
+[AWS::S3::Owner](https://metacpan.org/pod/AWS::S3::Owner) object. Read-only.
# PUBLIC METHODS
## buckets
-Returns an array of [AWS::S3::Bucket](http://search.cpan.org/perldoc?AWS::S3::Bucket) objects.
+Returns an array of [AWS::S3::Bucket](https://metacpan.org/pod/AWS::S3::Bucket) objects.
## bucket( $name )
-Returns the [AWS::S3::Bucket](http://search.cpan.org/perldoc?AWS::S3::Bucket) object matching `$name` if found.
+Returns the [AWS::S3::Bucket](https://metacpan.org/pod/AWS::S3::Bucket) object matching `$name` if found.
Returns nothing otherwise.
-## add_bucket( name => $name )
+## add\_bucket( name => $name )
Attempts to create a new bucket with the name provided.
-On success, returns the new [AWS::S3::Bucket](http://search.cpan.org/perldoc?AWS::S3::Bucket)
+On success, returns the new [AWS::S3::Bucket](https://metacpan.org/pod/AWS::S3::Bucket)
On failure, dies with the error message.
-See [AWS::S3::Bucket](http://search.cpan.org/perldoc?AWS::S3::Bucket) for details on how to use buckets (and access their files).
+See [AWS::S3::Bucket](https://metacpan.org/pod/AWS::S3::Bucket) for details on how to use buckets (and access their files).
# SEE ALSO
[The Amazon S3 API Documentation](http://docs.amazonwebservices.com/AmazonS3/latest/API/)
-[AWS::S3::Bucket](http://search.cpan.org/perldoc?AWS::S3::Bucket)
+[AWS::S3::Bucket](https://metacpan.org/pod/AWS::S3::Bucket)
-[AWS::S3::File](http://search.cpan.org/perldoc?AWS::S3::File)
+[AWS::S3::File](https://metacpan.org/pod/AWS::S3::File)
-[AWS::S3::FileIterator](http://search.cpan.org/perldoc?AWS::S3::FileIterator)
+[AWS::S3::FileIterator](https://metacpan.org/pod/AWS::S3::FileIterator)
-[AWS::S3::Owner](http://search.cpan.org/perldoc?AWS::S3::Owner)
+[AWS::S3::Owner](https://metacpan.org/pod/AWS::S3::Owner)
# AUTHOR
-John Drago <jdrago_999@yahoo.com>
+John Drago <jdrago\_999@yahoo.com>
# LICENSE AND COPYRIGHT
This software is Free software and may be used and redistributed under the same
terms as any version of perl itself.
-Copyright John Drago 2011 all rights reserved.
+Copyright John Drago 2011 all rights reserved.
View
17 lib/AWS/S3.pm
@@ -24,6 +24,13 @@ has 'secure' => (
default => 0
);
+has 'endpoint' => (
+ is => 'ro',
+ isa => 'Str',
+ lazy => 1,
+ default => sub { 's3.amazonaws.com' },
+);
+
has 'ua' => (
is => 'ro',
isa => 'LWP::UserAgent',
@@ -214,6 +221,12 @@ Optional. Boolean.
Default is C<0>
+=head2 endpoint
+
+Optional. String.
+
+Default is C<s3.amazonaws.com>
+
=head2 ua
Optional. Should be an instance of L<LWP::UserAgent> or a subclass of it.
@@ -234,6 +247,10 @@ String. Read-only.
Boolean. Read-only.
+=head2 endpoint
+
+String. Read-only.
+
=head2 ua
L<LWP::UserAgent> object. Read-only.
View
5 lib/AWS/S3/HTTPRequest.pm
@@ -75,9 +75,10 @@ sub http_request {
my $metadata = $s->metadata;
my $protocol = $s->s3->secure ? 'https' : 'http';
- my $uri = "$protocol://s3.amazonaws.com/$path";
+ my $endpoint = $s->s3->endpoint;
+ my $uri = "$protocol://$endpoint/$path";
if ( $path =~ m{^([^/?]+)(.*)} && _is_dns_bucket( $1 ) ) {
- $uri = "$protocol://$1.s3.amazonaws.com$2";
+ $uri = "$protocol://$1.$endpoint$2";
} # end if()
my $signer = AWS::S3::Signer->new(
View
6 lib/AWS/S3/Request/CreateBucket.pm
@@ -2,6 +2,8 @@
package AWS::S3::Request::CreateBucket;
use Moose;
+use AWS::S3::Signer;
+
with 'AWS::S3::Roles::Request';
has 'bucket' => (
@@ -30,7 +32,7 @@ XML
my $signer = AWS::S3::Signer->new(
s3 => $s->s3,
method => 'PUT',
- uri => $s->protocol . '://' . $s->bucket . '.s3.amazonaws.com/',
+ uri => $s->protocol . '://' . $s->bucket . '.' . $s->endpoint . '/',
content_type => 'text/plain',
content_md5 => '',
content => \$xml,
@@ -48,7 +50,7 @@ XML
my $signer = AWS::S3::Signer->new(
s3 => $s->s3,
method => 'PUT',
- uri => $s->protocol . '://s3.amazonaws.com/' . $s->bucket,
+ uri => $s->protocol . '://' . $s->endpoint . '/' . $s->bucket,
);
return $s->_send_request(
$signer->method => $signer->uri => {
View
2  lib/AWS/S3/Request/ListBucket.pm
@@ -48,7 +48,7 @@ sub request {
my $signer = AWS::S3::Signer->new(
s3 => $s->s3,
method => 'GET',
- uri => $s->protocol . '://' . $s->bucket . '.s3.amazonaws.com/' . ( @params ? '?' . join( '&', @params ) : '' ),
+ uri => $s->protocol . '://' . $s->bucket . '.' . $s->endpoint . '/' . ( @params ? '?' . join( '&', @params ) : '' ),
);
$s->_send_request(
$signer->method => $signer->uri => {
View
4 lib/AWS/S3/Request/SetBucketAccessControl.pm
@@ -33,7 +33,7 @@ sub request {
my $signer = AWS::S3::Signer->new(
s3 => $s->s3,
method => 'PUT',
- uri => $s->protocol . '://' . $s->bucket . '.s3.amazonaws.com/?acl',
+ uri => $s->protocol . '://' . $s->bucket . '.' . $s->endpoint . '/?acl',
headers => [ 'x-amz-acl' => $s->acl_short ]
);
return $s->_send_request(
@@ -48,7 +48,7 @@ sub request {
my $signer = AWS::S3::Signer->new(
s3 => $s->s3,
method => 'PUT',
- uri => $s->protocol . '://' . $s->bucket . '.s3.amazonaws.com/?acl',
+ uri => $s->protocol . '://' . $s->bucket . '.' . $s->endpoint . '/?acl',
content => \$s->acl_xml,
'content-type' => 'text/xml',
);
View
2  lib/AWS/S3/Request/SetFileContents.pm
@@ -45,7 +45,7 @@ sub request {
my $signer = AWS::S3::Signer->new(
s3 => $s->s3,
method => 'PUT',
- uri => $s->protocol . '://' . $s->bucket . '.s3.amazonaws.com/' . $s->file->key,
+ uri => $s->protocol . '://' . $s->bucket . '.' . $s->endpoint . '/' . $s->file->key,
content_type => $s->content_type,
content => $contents,
headers => [ 'x-amz-storage-class', $s->file->storage_class ],
View
12 lib/AWS/S3/Roles/Request.pm
@@ -25,6 +25,15 @@ has 'protocol' => (
}
);
+has 'endpoint' => (
+ is => 'ro',
+ isa => 'Str',
+ lazy => 1,
+ default => sub {
+ shift->s3->endpoint;
+ }
+);
+
# XXX should be required=>1; https://rt.cpan.org/Ticket/Display.html?id=77863
has "_action" => (
isa => 'Str',
@@ -46,7 +55,8 @@ has '_uri' => (
my $uri = URI->new(
$self->protocol . '://'
. ( $m->has_attribute('bucket') ? $self->bucket . '.' : '' )
- . 's3.amazonaws.com/'
+ . $self->endpoint
+ . '/'
);
$uri->path( $self->key )
View
3  lib/AWS/S3/Signer.pm
@@ -35,7 +35,8 @@ has 'bucket_name' => (
lazy => 1,
default => sub {
my $s = shift;
- if ( my ( $name ) = $s->uri->host =~ m{^(.+?)\.s3\.amazonaws} ) {
+ my $endpoint = $s->s3->endpoint;
+ if ( my ( $name ) = $s->uri->host =~ m{^(.+?)\.\Q$endpoint\E} ) {
return $name;
} else {
return '';
View
30 t/020_endpoint.t
@@ -0,0 +1,30 @@
+#!perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+use FindBin qw/ $Bin /;
+
+use Carp 'confess';
+$SIG{__DIE__} = \&confess;
+
+use_ok('AWS::S3');
+
+my $s3 = AWS::S3->new(
+ access_key_id => $ENV{AWS_ACCESS_KEY_ID} // 'foo',
+ secret_access_key => $ENV{AWS_SECRET_ACCESS_KEY} // 'bar',
+ endpoint => 'bad.hostname',
+);
+
+my $bucket_name = "aws-s3-test-" . int(rand() * 1_000_000) . '-' . time() . "-foo";
+
+eval {
+ my $bucket = $s3->add_bucket( name => $bucket_name, location => 'us-west-1' ),
+};
+
+like(
+ $@,
+ qr/Can't connect to aws-s3-test-.*?bad\.hostname/,
+ 'endpoint was used'
+);
Something went wrong with that request. Please try again.