Fix max-parts, part-number-marker, and encoding-type in queries of List Parts

I've fixed ToDo in qeuries of  List Part.

encoding-type: Requests Amazon S3 to encode the response and specifies the encoding method to use.
max-parts: Sets the maximum number of parts to return in the response body.
part-number-marker: Specifies the part after which listing should begin. Only parts with higher part numbers will be listed.

For details, refer to the following.
http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadListParts.html

Change-Id: I1a3b3a0aba188fcb928e89e78ad8859dbecca2e8
This commit is contained in:
Masaki Tsukuda
2014-12-18 13:36:27 +09:00
parent 315604c31b
commit 9a95fc22a5
4 changed files with 188 additions and 14 deletions

View File

@@ -56,6 +56,7 @@ from swift3.exception import BadSwiftRequest
from swift3.utils import LOGGER, unique_id, MULTIUPLOAD_SUFFIX
from swift3.etree import Element, SubElement, fromstring, tostring, \
XMLSyntaxError, DocumentInvalid
from swift3.cfg import CONF
DEFAULT_MAX_PARTS = 1000
DEFAULT_MAX_UPLOADS = 1000
@@ -280,6 +281,13 @@ class UploadController(Controller):
"""
Handles List Parts.
"""
def filter_part_num_marker(o):
try:
num = int(os.path.basename(o['name']))
return num > part_num_marker
except ValueError:
return False
encoding_type = req.params.get('encoding-type')
if encoding_type is not None and encoding_type != 'url':
err_msg = 'Invalid Encoding Method specified in Request'
@@ -288,11 +296,43 @@ class UploadController(Controller):
upload_id = req.params['uploadId']
_check_upload_info(req, self.app, upload_id)
maxparts = DEFAULT_MAX_PARTS
part_num_marker = 0
# TODO: add support for max-parts and part-number-marker queries.
if 'max-parts' in req.params:
try:
maxparts = int(req.params['max-parts'])
if maxparts < 0 or CONF.max_parts < maxparts:
err_msg = 'Argument max-parts must be an integer between 0 and' \
' %d' % CONF.max_parts
raise InvalidArgument('max-parts',
req.params['max-parts'],
err_msg)
except ValueError:
err_msg = 'Provided max-parts not an integer or within ' \
'integer range'
raise InvalidArgument('max-parts', req.params['max-parts'],
err_msg)
if 'part-number-marker' in req.params:
try:
part_num_marker = int(req.params['part-number-marker'])
if part_num_marker < 0 or CONF.max_parts < part_num_marker:
err_msg = 'Argument part-number-marker must be an integer ' \
'between 0 and %d' % CONF.max_parts
raise InvalidArgument('part-number-marker',
req.params['part-number-marker'],
err_msg)
except ValueError:
err_msg = 'Provided part-number-marker not an integer or ' \
'within integer range'
raise InvalidArgument('part-number-marker',
req.params['part-number-marker'],
err_msg)
query = {
'format': 'json',
'limit': maxparts + 1,
'prefix': '%s/%s/' % (req.object_name, upload_id),
'delimiter': '/'
}
@@ -304,11 +344,24 @@ class UploadController(Controller):
last_part = 0
# pylint: disable-msg=E1103
objects.sort(key=lambda o: int(o['name'].split('/')[-1]))
# If the caller requested a list starting at a specific part number,
# construct a sub-set of the object list.
objList = filter(filter_part_num_marker, objects)
if len(objects) > 0:
o = objects[-1]
# pylint: disable-msg=E1103
objList.sort(key=lambda o: int(o['name'].split('/')[-1]))
if len(objList) > maxparts:
objList = objList[:maxparts]
truncated = True
else:
truncated = False
# TODO: We have to retrieve object list again when truncated is True
# and some objects filtered by invalid name because there could be no
# enough objects for limit defined by maxparts.
if objList:
o = objList[-1]
last_part = os.path.basename(o['name'])
result_elem = Element('ListPartsResult')
@@ -326,11 +379,14 @@ class UploadController(Controller):
SubElement(result_elem, 'StorageClass').text = 'STANDARD'
SubElement(result_elem, 'PartNumberMarker').text = str(part_num_marker)
SubElement(result_elem, 'NextPartNumberMarker').text = str(last_part)
SubElement(result_elem, 'MaxParts').text = str(DEFAULT_MAX_PARTS)
# TODO: add support for EncodingType
SubElement(result_elem, 'IsTruncated').text = 'false'
SubElement(result_elem, 'MaxParts').text = str(maxparts)
if 'encoding-type' in req.params:
SubElement(result_elem, 'EncodingType').text = \
req.params['encoding-type']
SubElement(result_elem, 'IsTruncated').text = \
'true' if truncated else 'false'
for i in objects:
for i in objList:
part_elem = SubElement(result_elem, 'Part')
SubElement(part_elem, 'PartNumber').text = i['name'].split('/')[-1]
SubElement(part_elem, 'LastModified').text = \