From 5854219a4c41cef103af63a1a9baf293f58fb519 Mon Sep 17 00:00:00 2001 From: Lucian Branescu Mihaila Date: Tue, 26 Mar 2013 15:50:18 +0000 Subject: [PATCH] Upload part and complete upload. Somehow, boto doesn't like output I send it, even though it's copy-pasted from its own logs. --- moto/s3/models.py | 14 ++++++++------ moto/s3/responses.py | 41 ++++++++++++++++++++++++++++++++--------- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/moto/s3/models.py b/moto/s3/models.py index 2462d59be..a2547ea47 100644 --- a/moto/s3/models.py +++ b/moto/s3/models.py @@ -37,7 +37,7 @@ class FakeMultipart(object): if part_id != index: return - total.extend(self.parts[part_id]) + total.extend(self.parts[part_id].value) if len(total) < 5242880: return @@ -46,10 +46,11 @@ class FakeMultipart(object): def set_part(self, part_id, value): if part_id < 1: - return False + return - self.parts[part_id] = value - return True + key = FakeKey(part_id, value) + self.parts[part_id] = key + return key class FakeBucket(object): @@ -109,9 +110,10 @@ class S3Backend(BaseBackend): multipart = bucket.multiparts[multipart_id] value = multipart.complete() if value is None: - return False + return + del bucket.multiparts[multipart_id] - self.set_key(bucket_name, multipart.key_name, value) + return self.set_key(bucket_name, multipart.key_name, value) def set_part(self, bucket_name, multipart_id, part_id, value): bucket = self.buckets[bucket_name] diff --git a/moto/s3/responses.py b/moto/s3/responses.py index 370c7cf5b..fc1fdcec2 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -64,6 +64,7 @@ def key_response(uri_info, method, body, headers): key_name = uri_info.path.lstrip('/') hostname = uri_info.hostname headers = headers_to_dict(headers) + query = parse_qs(uri_info.query) bucket_name = bucket_name_from_hostname(hostname) @@ -74,12 +75,20 @@ def key_response(uri_info, method, body, headers): else: return "", dict(status=404) if method == 'PUT': + if 'uploadId' in query and 'partNumber' in query and body: + upload_id = query['uploadId'][0] + part_number = int(query['partNumber'][0]) + key = s3_backend.set_part(bucket_name, upload_id, part_number, body) + + return '', dict(etag=key.etag) + 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) template = Template(S3_OBJECT_COPY_RESPONSE) return template.render(key=src_key) + if body is not None: key = s3_backend.get_key(bucket_name, key_name) if not key or body: @@ -107,19 +116,30 @@ def key_response(uri_info, method, body, headers): template = Template(S3_DELETE_OBJECT_SUCCESS) return template.render(bucket=removed_key), dict(status=204) elif method == 'POST': + import pdb; pdb.set_trace() if body == '' and uri_info.query == 'uploads': multipart = s3_backend.initiate_multipart(bucket_name, key_name) - template = Template(S3_MULTIPART_RESPONSE) + template = Template(S3_MULTIPART_INITIATE_RESPONSE) response = template.render( bucket_name=bucket_name, key_name=key_name, multipart_id=multipart.id, ) - print response return response, dict() + + if body == '' and 'uploadId' in query: + upload_id = query['uploadId'][0] + key = s3_backend.complete_multipart(bucket_name, upload_id) + + if key is not None: + template = Template(S3_MULTIPART_COMPLETE_RESPONSE) + return template.render( + bucket_name=bucket_name, + key_name=key.name, + etag=key.etag, + ) else: - import pdb; pdb.set_trace() - raise NotImplementedError("POST is only allowed for multipart uploads") + raise NotImplementedError("Method POST had only been implemented for multipart uploads so far") else: raise NotImplementedError("Method {} has not been impelemented in the S3 backend yet".format(method)) @@ -217,15 +237,18 @@ S3_OBJECT_COPY_RESPONSE = """ +S3_MULTIPART_INITIATE_RESPONSE = """ {{ bucket_name }} {{ key_name }} {{ upload_id }} """ -S3_MULTIPART_COMPLETE_RESPONSE = """ -""" - -S3_MULTIPART_ERROR_RESPONSE = """ +S3_MULTIPART_COMPLETE_RESPONSE = """ + + http://{{ bucket_name }}.s3.amazonaws.com/{{ key_name }} + {{ bucket_name }} + {{ key_name }} + {{ etag }} + """