From a2e56afef83e4be4eaa3793b28d5382c732c098f Mon Sep 17 00:00:00 2001 From: Steve Pulec Date: Wed, 10 Dec 2014 20:20:43 -0500 Subject: [PATCH] Add special S3 bucket create logic for us-east-1. Closes #273. --- moto/s3/responses.py | 17 ++++++++++++++--- moto/s3/utils.py | 2 +- tests/test_s3/test_s3.py | 19 ++++++++++++++++++- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/moto/s3/responses.py b/moto/s3/responses.py index 8a0931ec6..7f98c91cf 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -12,6 +12,9 @@ from .models import s3_backend from .utils import bucket_name_from_url, metadata_from_headers from xml.dom import minidom +REGION_URL_REGEX = r'\.s3-(.+?)\.amazonaws\.com' +DEFAULT_REGION_NAME = 'us-east-1' + def parse_key_name(pth): return pth.lstrip("/") @@ -45,6 +48,10 @@ class ResponseObject(object): parsed_url = urlparse(full_url) querystring = parse_qs(parsed_url.query, keep_blank_values=True) method = request.method + region_name = DEFAULT_REGION_NAME + region_match = re.search(REGION_URL_REGEX, full_url) + if region_match: + region_name = region_match.groups()[0] bucket_name = self.bucket_name_from_url(full_url) if not bucket_name: @@ -56,7 +63,7 @@ class ResponseObject(object): elif method == 'GET': return self._bucket_response_get(bucket_name, querystring, headers) elif method == 'PUT': - return self._bucket_response_put(request, bucket_name, querystring, headers) + return self._bucket_response_put(request, region_name, bucket_name, querystring, headers) elif method == 'DELETE': return self._bucket_response_delete(bucket_name, headers) elif method == 'POST': @@ -130,7 +137,7 @@ class ResponseObject(object): result_folders=result_folders ) - def _bucket_response_put(self, request, bucket_name, querystring, headers): + def _bucket_response_put(self, request, region_name, bucket_name, querystring, headers): if 'versioning' in querystring: ver = re.search('([A-Za-z]+)', request.body.decode('utf-8')) if ver: @@ -143,7 +150,11 @@ class ResponseObject(object): try: new_bucket = self.backend.create_bucket(bucket_name) except BucketAlreadyExists: - return 409, headers, "" + if region_name == DEFAULT_REGION_NAME: + # us-east-1 has different behavior + new_bucket = self.backend.get_bucket(bucket_name) + else: + return 409, headers, "" template = Template(S3_BUCKET_CREATE_RESPONSE) return 200, headers, template.render(bucket=new_bucket) diff --git a/moto/s3/utils.py b/moto/s3/utils.py index 3431bb3f6..e86578ec5 100644 --- a/moto/s3/utils.py +++ b/moto/s3/utils.py @@ -6,7 +6,7 @@ import six from six.moves.urllib.parse import urlparse, unquote import sys -bucket_name_regex = re.compile("(.+).s3.amazonaws.com") +bucket_name_regex = re.compile("(.+).s3(.*).amazonaws.com") def bucket_name_from_url(url): diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index b9b90c8b1..2edde307e 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -307,12 +307,29 @@ def test_bucket_with_dash(): @mock_s3 def test_create_existing_bucket(): "Trying to create a bucket that already exists should raise an Error" - conn = boto.connect_s3('the_key', 'the_secret') + conn = boto.s3.connect_to_region("us-west-2") conn.create_bucket("foobar") with assert_raises(S3CreateError): conn.create_bucket('foobar') +@mock_s3 +def test_create_existing_bucket_in_us_east_1(): + "Trying to create a bucket that already exists in us-east-1 returns the bucket" + + """" + http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html + Your previous request to create the named bucket succeeded and you already + own it. You get this error in all AWS regions except US Standard, + us-east-1. In us-east-1 region, you will get 200 OK, but it is no-op (if + bucket exists it Amazon S3 will not do anything). + """ + conn = boto.s3.connect_to_region("us-east-1") + conn.create_bucket("foobar") + bucket = conn.create_bucket("foobar") + bucket.name.should.equal("foobar") + + @mock_s3 def test_other_region(): conn = S3Connection('key', 'secret', host='s3-website-ap-southeast-2.amazonaws.com')