From 2ba64e1322c0e62b0604b04e9f5a34342e4acadb Mon Sep 17 00:00:00 2001 From: Konstantinos Koukopoulos Date: Wed, 26 Mar 2014 16:02:14 +0200 Subject: [PATCH] support replacing key metadata when copying --- moto/s3/models.py | 3 +++ moto/s3/responses.py | 26 +++++++++++++++++--------- tests/test_s3/test_s3.py | 16 ++++++++++++++++ 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/moto/s3/models.py b/moto/s3/models.py index 2def8db00..af96f0516 100644 --- a/moto/s3/models.py +++ b/moto/s3/models.py @@ -22,6 +22,9 @@ class FakeKey(object): def set_metadata(self, key, metadata): self._metadata[key] = metadata + def clear_metadata(self): + self._metadata = {} + def append_to_value(self, value): self.value += value self.last_modified = datetime.datetime.now() diff --git a/moto/s3/responses.py b/moto/s3/responses.py index 27aa0118d..998d1e304 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -125,6 +125,18 @@ class ResponseObject(object): status_code, headers, response_content = response return status_code, headers, response_content + def _key_set_metadata(self, request, key, replace=False): + meta_regex = re.compile('^x-amz-meta-([a-zA-Z0-9\-_]+)$', flags=re.IGNORECASE) + if replace is True: + key.clear_metadata() + for header in request.headers: + if isinstance(header, basestring): + result = meta_regex.match(header) + if result: + meta_key = result.group(0).lower() + metadata = request.headers[header] + key.set_metadata(meta_key, metadata) + def _key_response(self, request, full_url, headers): parsed_url = urlparse(full_url) query = parse_qs(parsed_url.query) @@ -182,6 +194,10 @@ class ResponseObject(object): # Copy key src_bucket, src_key = request.headers.get("x-amz-copy-source").split("/", 1) self.backend.copy_key(src_bucket, src_key, bucket_name, key_name) + mdirective = request.headers.get('x-amz-metadata-directive') + if mdirective is not None and mdirective == 'REPLACE': + new_key = self.backend.get_key(bucket_name, key_name) + self._key_set_metadata(request, new_key, replace=True) template = Template(S3_OBJECT_COPY_RESPONSE) return template.render(key=src_key) streaming_request = hasattr(request, 'streaming') and request.streaming @@ -196,16 +212,8 @@ class ResponseObject(object): # Initial data new_key = self.backend.set_key(bucket_name, key_name, body) request.streaming = True + self._key_set_metadata(request, new_key) - #Metadata - meta_regex = re.compile('^x-amz-meta-([a-zA-Z0-9\-_]+)$', flags=re.IGNORECASE) - for header in request.headers: - if isinstance(header, basestring): - result = meta_regex.match(header) - if result: - meta_key = result.group(0).lower() - metadata = request.headers[header] - new_key.set_metadata(meta_key, metadata) template = Template(S3_OBJECT_RESPONSE) headers.update(new_key.response_dict) return 200, headers, template.render(key=new_key) diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index 66866335a..b39bd6cb8 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -143,6 +143,22 @@ def test_set_metadata(): bucket.get_key('the-key').get_metadata('md').should.equal('Metadatastring') +@mock_s3 +def test_copy_key_replace_metadata(): + conn = boto.connect_s3('the_key', 'the_secret') + bucket = conn.create_bucket("foobar") + key = Key(bucket) + key.key = "the-key" + key.set_metadata('md', 'Metadatastring') + key.set_contents_from_string("some value") + + bucket.copy_key('new-key', 'foobar', 'the-key', + metadata={'momd': 'Mometadatastring'}) + + bucket.get_key("new-key").get_metadata('md').should.be.none + bucket.get_key("new-key").get_metadata('momd').should.equal('Mometadatastring') + + @freeze_time("2012-01-01 12:00:00") @mock_s3 def test_last_modified():