diff --git a/moto/s3/models.py b/moto/s3/models.py index 8acb65448..a737340b3 100644 --- a/moto/s3/models.py +++ b/moto/s3/models.py @@ -64,5 +64,9 @@ class S3Backend(BaseBackend): bucket = self.buckets[bucket_name] return bucket.keys.pop(key_name) + def copy_key(self, src_bucket_name, src_key_name, dest_bucket_name, dest_key_name): + src_bucket = self.buckets[src_bucket_name] + dest_bucket = self.buckets[dest_bucket_name] + dest_bucket.keys[dest_key_name] = src_bucket.keys[src_key_name] s3_backend = S3Backend() diff --git a/moto/s3/responses.py b/moto/s3/responses.py index 10445eda2..74f80ec81 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -1,7 +1,7 @@ from jinja2 import Template from .models import s3_backend -from .utils import bucket_name_from_hostname +from .utils import bucket_name_from_hostname, headers_to_dict def all_buckets(uri, body, method): @@ -51,6 +51,7 @@ def key_response(uri_info, body, headers): key_name = uri_info.path.lstrip('/') hostname = uri_info.hostname method = uri_info.method + headers = headers_to_dict(headers) bucket_name = bucket_name_from_hostname(hostname) @@ -59,6 +60,11 @@ def key_response(uri_info, body, headers): return key.value if method == 'PUT': + if 'x-amz-copy-source' in headers: + # Copy key + src_bucket, src_key = headers.get("x-amz-copy-source").split("/") + s3_backend.copy_key(src_bucket, src_key, bucket_name, key_name) + return S3_OBJECT_COPY_RESPONSE if body: new_key = s3_backend.set_key(bucket_name, key_name, body) return S3_OBJECT_RESPONSE, dict(etag=new_key.etag) @@ -147,4 +153,11 @@ S3_OBJECT_RESPONSE = """""" + +S3_OBJECT_COPY_RESPONSE = """ + + "asdfadsfdsafjsadfdafsadf" + 2008-02-18T13:54:10.183Z + +""" diff --git a/moto/s3/utils.py b/moto/s3/utils.py index 4f1325aae..40cbf99f0 100644 --- a/moto/s3/utils.py +++ b/moto/s3/utils.py @@ -6,3 +6,13 @@ bucket_name_regex = re.compile("(.+).s3.amazonaws.com") def bucket_name_from_hostname(hostname): bucket_result = bucket_name_regex.search(hostname) return bucket_result.groups()[0] + + +def headers_to_dict(headers): + result = {} + for header in headers.split("\r\n"): + if ':' in header: + key, value = header.split(":", 1) + result[key.strip()] = value.strip() + + return result diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index cff2899d4..16189aa33 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -40,6 +40,20 @@ def test_missing_key(): bucket.get_key("the-key").should.equal(None) +@mock_s3 +def test_copy_key(): + conn = boto.connect_s3('the_key', 'the_secret') + bucket = conn.create_bucket("foobar") + key = Key(bucket) + key.key = "the-key" + key.set_contents_from_string("some value") + + bucket.copy_key('new-key', 'foobar', 'the-key') + + bucket.get_key("the-key").get_contents_as_string().should.equal("some value") + bucket.get_key("new-key").get_contents_as_string().should.equal("some value") + + @mock_s3 def test_missing_bucket(): conn = boto.connect_s3('the_key', 'the_secret')