Support x-amz-meta-* for Initiate Multipart Upload
Object metadata specified at InitiateMultipartUpload Reqest must be applied to a manifest at Complete Multipart Upload. Object metadata is registered in upload information at Initiate Multipart Upload. So, I modified to acquire Object metadata from upload information, and to set it to object created by Complete Multipart Upload. Change-Id: Ib08e236f854f56107f72d4a836eee720a641b655
This commit is contained in:
@@ -64,17 +64,22 @@ DEFAULT_MAX_UPLOADS = 1000
|
|||||||
MAX_COMPLETE_UPLOAD_BODY_SIZE = 2048 * 1024
|
MAX_COMPLETE_UPLOAD_BODY_SIZE = 2048 * 1024
|
||||||
|
|
||||||
|
|
||||||
def _check_upload_info(req, app, upload_id):
|
def _get_upload_info(req, app, upload_id):
|
||||||
|
|
||||||
container = req.container_name + MULTIUPLOAD_SUFFIX
|
container = req.container_name + MULTIUPLOAD_SUFFIX
|
||||||
obj = '%s/%s' % (req.object_name, upload_id)
|
obj = '%s/%s' % (req.object_name, upload_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
req.get_response(app, 'HEAD', container=container, obj=obj)
|
return req.get_response(app, 'HEAD', container=container, obj=obj)
|
||||||
except NoSuchKey:
|
except NoSuchKey:
|
||||||
raise NoSuchUpload(upload_id=upload_id)
|
raise NoSuchUpload(upload_id=upload_id)
|
||||||
|
|
||||||
|
|
||||||
|
def _check_upload_info(req, app, upload_id):
|
||||||
|
|
||||||
|
_get_upload_info(req, app, upload_id)
|
||||||
|
|
||||||
|
|
||||||
class PartController(Controller):
|
class PartController(Controller):
|
||||||
"""
|
"""
|
||||||
Handles the following APIs:
|
Handles the following APIs:
|
||||||
@@ -402,7 +407,12 @@ class UploadController(Controller):
|
|||||||
Handles Complete Multipart Upload.
|
Handles Complete Multipart Upload.
|
||||||
"""
|
"""
|
||||||
upload_id = req.params['uploadId']
|
upload_id = req.params['uploadId']
|
||||||
_check_upload_info(req, self.app, upload_id)
|
resp = _get_upload_info(req, self.app, upload_id)
|
||||||
|
headers = {}
|
||||||
|
for key, val in resp.headers.iteritems():
|
||||||
|
_key = key.lower()
|
||||||
|
if _key.startswith('x-amz-meta-'):
|
||||||
|
headers['x-object-meta-' + _key[11:]] = val
|
||||||
|
|
||||||
# Query for the objects in the segments area to make sure it completed
|
# Query for the objects in the segments area to make sure it completed
|
||||||
query = {
|
query = {
|
||||||
@@ -454,7 +464,8 @@ class UploadController(Controller):
|
|||||||
try:
|
try:
|
||||||
# TODO: add support for versioning
|
# TODO: add support for versioning
|
||||||
resp = req.get_response(self.app, 'PUT', body=dumps(manifest),
|
resp = req.get_response(self.app, 'PUT', body=dumps(manifest),
|
||||||
query={'multipart-manifest': 'put'})
|
query={'multipart-manifest': 'put'},
|
||||||
|
headers=headers)
|
||||||
except BadSwiftRequest as e:
|
except BadSwiftRequest as e:
|
||||||
msg = str(e)
|
msg = str(e)
|
||||||
if msg.startswith('Each segment, except the last, '
|
if msg.startswith('Each segment, except the last, '
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class TestSwift3MultiUpload(Swift3TestCase):
|
|||||||
self.swift.register('GET', segment_bucket, swob.HTTPOk, {},
|
self.swift.register('GET', segment_bucket, swob.HTTPOk, {},
|
||||||
object_list)
|
object_list)
|
||||||
self.swift.register('HEAD', segment_bucket + '/object/X',
|
self.swift.register('HEAD', segment_bucket + '/object/X',
|
||||||
swob.HTTPOk, {}, None)
|
swob.HTTPOk, {'x-object-meta-foo': 'bar'}, None)
|
||||||
self.swift.register('PUT', segment_bucket + '/object/X',
|
self.swift.register('PUT', segment_bucket + '/object/X',
|
||||||
swob.HTTPCreated, {}, None)
|
swob.HTTPCreated, {}, None)
|
||||||
self.swift.register('DELETE', segment_bucket + '/object/X',
|
self.swift.register('DELETE', segment_bucket + '/object/X',
|
||||||
@@ -345,11 +345,15 @@ class TestSwift3MultiUpload(Swift3TestCase):
|
|||||||
req = Request.blank('/bucket/object?uploads',
|
req = Request.blank('/bucket/object?uploads',
|
||||||
environ={'REQUEST_METHOD': 'POST'},
|
environ={'REQUEST_METHOD': 'POST'},
|
||||||
headers={'Authorization':
|
headers={'Authorization':
|
||||||
'AWS test:tester:hmac'})
|
'AWS test:tester:hmac',
|
||||||
|
'x-amz-meta-foo': 'bar'})
|
||||||
status, headers, body = self.call_swift3(req)
|
status, headers, body = self.call_swift3(req)
|
||||||
fromstring(body, 'InitiateMultipartUploadResult')
|
fromstring(body, 'InitiateMultipartUploadResult')
|
||||||
self.assertEquals(status.split()[0], '200')
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
_, _, req_headers = self.swift.calls_with_headers[-1]
|
||||||
|
self.assertEquals(req_headers.get('X-Object-Meta-Foo'), 'bar')
|
||||||
|
|
||||||
@s3acl(s3acl_only=True)
|
@s3acl(s3acl_only=True)
|
||||||
@patch('swift3.controllers.multi_upload.unique_id', lambda: 'X')
|
@patch('swift3.controllers.multi_upload.unique_id', lambda: 'X')
|
||||||
def test_object_multipart_upload_initiate_s3acl(self):
|
def test_object_multipart_upload_initiate_s3acl(self):
|
||||||
@@ -357,12 +361,14 @@ class TestSwift3MultiUpload(Swift3TestCase):
|
|||||||
environ={'REQUEST_METHOD': 'POST'},
|
environ={'REQUEST_METHOD': 'POST'},
|
||||||
headers={'Authorization':
|
headers={'Authorization':
|
||||||
'AWS test:tester:hmac',
|
'AWS test:tester:hmac',
|
||||||
'x-amz-acl': 'public-read'})
|
'x-amz-acl': 'public-read',
|
||||||
|
'x-amz-meta-foo': 'bar'})
|
||||||
status, headers, body = self.call_swift3(req)
|
status, headers, body = self.call_swift3(req)
|
||||||
fromstring(body, 'InitiateMultipartUploadResult')
|
fromstring(body, 'InitiateMultipartUploadResult')
|
||||||
self.assertEquals(status.split()[0], '200')
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
_, _, req_headers = self.swift.calls_with_headers[-1]
|
_, _, req_headers = self.swift.calls_with_headers[-1]
|
||||||
|
self.assertEquals(req_headers.get('X-Object-Meta-Foo'), 'bar')
|
||||||
tmpacl_header = req_headers.get(sysmeta_header('object', 'tmpacl'))
|
tmpacl_header = req_headers.get(sysmeta_header('object', 'tmpacl'))
|
||||||
self.assertTrue(tmpacl_header)
|
self.assertTrue(tmpacl_header)
|
||||||
acl_header = encode_acl('object',
|
acl_header = encode_acl('object',
|
||||||
@@ -390,6 +396,9 @@ class TestSwift3MultiUpload(Swift3TestCase):
|
|||||||
fromstring(body, 'CompleteMultipartUploadResult')
|
fromstring(body, 'CompleteMultipartUploadResult')
|
||||||
self.assertEquals(status.split()[0], '200')
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
_, _, headers = self.swift.calls_with_headers[-2]
|
||||||
|
self.assertEquals(headers.get('X-Object-Meta-Foo'), 'bar')
|
||||||
|
|
||||||
@s3acl(s3acl_only=True)
|
@s3acl(s3acl_only=True)
|
||||||
def test_object_multipart_upload_complete_s3acl(self):
|
def test_object_multipart_upload_complete_s3acl(self):
|
||||||
acl_headers = encode_acl('object', ACLPublicRead(Owner('test:tester',
|
acl_headers = encode_acl('object', ACLPublicRead(Owner('test:tester',
|
||||||
@@ -397,6 +406,7 @@ class TestSwift3MultiUpload(Swift3TestCase):
|
|||||||
headers = {}
|
headers = {}
|
||||||
headers[sysmeta_header('object', 'tmpacl')] = \
|
headers[sysmeta_header('object', 'tmpacl')] = \
|
||||||
acl_headers.get(sysmeta_header('object', 'acl'))
|
acl_headers.get(sysmeta_header('object', 'acl'))
|
||||||
|
headers['X-Object-Meta-Foo'] = 'bar'
|
||||||
self.swift.register('HEAD', '/v1/AUTH_test/bucket+segments/object/X',
|
self.swift.register('HEAD', '/v1/AUTH_test/bucket+segments/object/X',
|
||||||
swob.HTTPOk, headers, None)
|
swob.HTTPOk, headers, None)
|
||||||
req = Request.blank('/bucket/object?uploadId=X',
|
req = Request.blank('/bucket/object?uploadId=X',
|
||||||
@@ -407,7 +417,8 @@ class TestSwift3MultiUpload(Swift3TestCase):
|
|||||||
fromstring(body, 'CompleteMultipartUploadResult')
|
fromstring(body, 'CompleteMultipartUploadResult')
|
||||||
self.assertEquals(status.split()[0], '200')
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
_, _, headers = self.swift.calls_with_headers[-1]
|
_, _, headers = self.swift.calls_with_headers[-2]
|
||||||
|
self.assertEquals(headers.get('X-Object-Meta-Foo'), 'bar')
|
||||||
self.assertEquals(tostring(ACLPublicRead(Owner('test:tester',
|
self.assertEquals(tostring(ACLPublicRead(Owner('test:tester',
|
||||||
'test:tester')).elem()),
|
'test:tester')).elem()),
|
||||||
tostring(decode_acl('object', headers).elem()))
|
tostring(decode_acl('object', headers).elem()))
|
||||||
|
|||||||
Reference in New Issue
Block a user