From 79addb8926a14db5146bb44ab60a2221bb6b699a Mon Sep 17 00:00:00 2001 From: Steve Pulec Date: Thu, 5 May 2016 22:52:12 -0400 Subject: [PATCH] Add S3 functionality to copy range. Closes #526. --- moto/s3/models.py | 7 +++++-- moto/s3/responses.py | 10 +++++++++- tests/test_s3/test_s3.py | 4 ++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/moto/s3/models.py b/moto/s3/models.py index 685254eba..c6baa3f79 100644 --- a/moto/s3/models.py +++ b/moto/s3/models.py @@ -438,12 +438,15 @@ class S3Backend(BaseBackend): return multipart.set_part(part_id, value) def copy_part(self, dest_bucket_name, multipart_id, part_id, - src_bucket_name, src_key_name): + src_bucket_name, src_key_name, start_byte, end_byte): src_key_name = clean_key_name(src_key_name) src_bucket = self.get_bucket(src_bucket_name) dest_bucket = self.get_bucket(dest_bucket_name) multipart = dest_bucket.multiparts[multipart_id] - return multipart.set_part(part_id, src_bucket.keys[src_key_name].value) + src_value = src_bucket.keys[src_key_name].value + if start_byte is not None: + src_value = src_value[start_byte:end_byte + 1] + return multipart.set_part(part_id, src_value) def prefix_query(self, bucket, prefix, delimiter): key_results = set() diff --git a/moto/s3/responses.py b/moto/s3/responses.py index d465f2432..700561035 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -409,9 +409,17 @@ class ResponseObject(_TemplateEnvironmentMixin): if 'x-amz-copy-source' in request.headers: src = request.headers.get("x-amz-copy-source") src_bucket, src_key = src.split("/", 1) + src_range = request.headers.get('x-amz-copy-source-range', '').split("bytes=")[-1] + + try: + start_byte, end_byte = src_range.split("-") + start_byte, end_byte = int(start_byte), int(end_byte) + except ValueError: + start_byte, end_byte = None, None + key = self.backend.copy_part( bucket_name, upload_id, part_number, src_bucket, - src_key) + src_key, start_byte, end_byte) template = self.response_template(S3_MULTIPART_UPLOAD_RESPONSE) response = template.render(part=key) else: diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index f37096bb1..25668400c 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -156,9 +156,9 @@ def test_multipart_upload_with_copy_key(): multipart = bucket.initiate_multipart_upload("the-key") part1 = b'0' * REDUCED_PART_SIZE multipart.upload_part_from_file(BytesIO(part1), 1) - multipart.copy_part_from_key("foobar", "original-key", 2) + multipart.copy_part_from_key("foobar", "original-key", 2, 0, 3) multipart.complete_upload() - bucket.get_key("the-key").get_contents_as_string().should.equal(part1 + b"key_value") + bucket.get_key("the-key").get_contents_as_string().should.equal(part1 + b"key_") @mock_s3