diff --git a/moto/s3/models.py b/moto/s3/models.py
index 67c48beb..a5fddda9 100644
--- a/moto/s3/models.py
+++ b/moto/s3/models.py
@@ -63,12 +63,8 @@ class FakeMultipart(object):
def complete(self):
total = bytearray()
- for part_id, index in enumerate(sorted(self.parts.keys()), start=1):
- # Make sure part ids are continuous
- if part_id != index:
- return
-
- total.extend(self.parts[part_id].value)
+ for part in self.list_parts():
+ total.extend(part.value)
if len(total) < 5242880:
return
@@ -83,6 +79,17 @@ class FakeMultipart(object):
self.parts[part_id] = key
return key
+ def list_parts(self):
+ parts = []
+
+ for part_id, index in enumerate(sorted(self.parts.keys()), start=1):
+ # Make sure part ids are continuous
+ if part_id != index:
+ return
+ parts.append(self.parts[part_id])
+
+ return parts
+
class FakeBucket(object):
def __init__(self, name):
@@ -156,6 +163,10 @@ class S3Backend(BaseBackend):
return self.set_key(bucket_name, multipart.key_name, value)
+ def list_multipart(self, bucket_name, multipart_id):
+ bucket = self.buckets[bucket_name]
+ return bucket.multiparts[multipart_id].list_parts()
+
def set_part(self, bucket_name, multipart_id, part_id, value):
bucket = self.buckets[bucket_name]
multipart = bucket.multiparts[multipart_id]
diff --git a/moto/s3/responses.py b/moto/s3/responses.py
index fe37c6f8..a0a6a698 100644
--- a/moto/s3/responses.py
+++ b/moto/s3/responses.py
@@ -122,6 +122,17 @@ def _key_response(request, full_url, headers):
body = request.data
if method == 'GET':
+ if 'uploadId' in query:
+ upload_id = query['uploadId'][0]
+ parts = s3_backend.list_multipart(bucket_name, upload_id)
+ template = Template(S3_MULTIPART_LIST_RESPONSE)
+ return 200, headers, template.render(
+ bucket_name=bucket_name,
+ key_name=key_name,
+ upload_id=upload_id,
+ count=len(parts),
+ parts=parts
+ )
key = s3_backend.get_key(bucket_name, key_name)
if key:
headers.update(key.metadata)
@@ -316,6 +327,35 @@ S3_MULTIPART_UPLOAD_RESPONSE = """
{{ part.etag }}
"""
+S3_MULTIPART_LIST_RESPONSE = """
+
+ {{ bucket_name }}
+ {{ key_name }}
+ {{ upload_id }}
+ STANDARD
+
+ 75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a
+ webfile
+
+
+ 75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a
+ webfile
+
+ STANDARD
+ 1
+ {{ count }}
+ {{ count }}
+ false
+ {% for part in parts %}
+
+ {{ part.name }}
+ {{ part.last_modified_ISO8601 }}
+ {{ part.etag }}
+ {{ part.size }}
+
+ {% endfor %}
+"""
+
S3_MULTIPART_COMPLETE_RESPONSE = """
http://{{ bucket_name }}.s3.amazonaws.com/{{ key_name }}