Merge "Support x-amz-copy-source-if-* for Upload Part Copy"

This commit is contained in:
Jenkins
2015-01-16 00:33:10 +00:00
committed by Gerrit Code Review
3 changed files with 164 additions and 17 deletions

View File

@@ -19,7 +19,6 @@ from swift3.response import MissingSecurityHeader, \
from swift3.etree import fromstring, XMLSyntaxError, DocumentInvalid
from swift3.utils import LOGGER, MULTIUPLOAD_SUFFIX
from swift.common.utils import split_path
"""
Acl Handlers:
@@ -102,14 +101,6 @@ class BaseAclHandler(object):
self.user_id = self.req.user_id
self.headers = self.req.headers if headers is None else headers
def _check_copy_source(self, app):
if 'X-Amz-Copy-Source' in self.req.headers:
src_path = self.req.headers['X-Amz-Copy-Source']
src_path = src_path if src_path.startswith('/') else \
('/' + src_path)
src_bucket, src_obj = split_path(src_path, 0, 2, True)
self._handle_acl(app, 'HEAD', src_bucket, src_obj, 'READ')
def handle_acl(self, app, method):
method = method or self.method
if hasattr(self, method):
@@ -292,9 +283,23 @@ class PartAclHandler(MultiUploadAclHandler):
"""
PartAclHandler: Handler for PartController
"""
def PUT(self, app):
# Upload Part
self._check_copy_source(app)
def __init__(self, req, container, obj, headers):
# pylint: disable-msg=E1003
super(MultiUploadAclHandler, self).__init__(req, container, obj,
headers)
self.check_copy_src = False
if self.container.endswith(MULTIUPLOAD_SUFFIX):
self.container = self.container[:-len(MULTIUPLOAD_SUFFIX)]
else:
self.check_copy_src = True
def HEAD(self, app):
if self.check_copy_src:
# For check_copy_source
return self._handle_acl(app, 'HEAD', self.container, self.obj)
else:
# For _check_upload_info
self._handle_acl(app, 'HEAD', self.container, '')
class UploadsAclHandler(MultiUploadAclHandler):
@@ -359,7 +364,7 @@ ACL_MAP = {
# GET Object
('GET', 'GET', 'object'):
{'Permission': 'READ'},
# PUT Object Copy
# PUT Object Copy, Upload Part Copy
('PUT', 'HEAD', 'object'):
{'Permission': 'READ'},
# Initiate Multipart Upload

View File

@@ -108,6 +108,7 @@ class PartController(Controller):
req.object_name = '%s/%s/%d' % (req.object_name, upload_id,
part_number)
req.check_copy_source(self.app)
resp = req.get_response(self.app)
# TODO: set xml body for copy requests.

View File

@@ -658,19 +658,22 @@ class TestSwift3MultiUpload(Swift3TestCase):
self.assertEquals(status.split()[0], '200')
def _test_copy_for_s3acl(self, account, src_permission=None,
src_path='/src_bucket/src_obj'):
src_path='/src_bucket/src_obj',
head_resp=swob.HTTPOk, put_header={}):
owner = 'test:tester'
grants = [Grant(User(account), src_permission)] \
if src_permission else [Grant(User(owner), 'FULL_CONTROL')]
src_o_headers = encode_acl('object', ACL(Owner(owner, owner), grants))
self.swift.register('HEAD', '/v1/AUTH_test/src_bucket/src_obj',
swob.HTTPOk, src_o_headers, None)
head_resp, src_o_headers, None)
put_headers = {'Authorization': 'AWS %s:hmac' % account,
'X-Amz-Copy-Source': src_path}
put_headers.update(put_header)
req = Request.blank(
'/bucket/object?partNumber=1&uploadId=X',
environ={'REQUEST_METHOD': 'PUT'},
headers={'Authorization': 'AWS %s:hmac' % account,
'X-Amz-Copy-Source': src_path})
headers=put_headers)
return self.call_swift3(req)
@s3acl(s3acl_only=True)
@@ -721,5 +724,143 @@ class TestSwift3MultiUpload(Swift3TestCase):
self._test_copy_for_s3acl('test:write', 'WRITE', '/bucket/')
self.assertEquals(status.split()[0], '400')
@s3acl
def test_upload_part_copy_headers_error(self):
account = 'test:tester'
etag = '7dfa07a8e59ddbcd1dc84d4c4f82aea1'
last_modified_since = 'Fri, 01 Apr 2014 12:00:00 GMT'
header = {'X-Amz-Copy-Source-If-Match': etag}
status, header, body = \
self._test_copy_for_s3acl(account,
head_resp=swob.HTTPPreconditionFailed,
put_header=header)
self.assertEquals(self._get_error_code(body), 'PreconditionFailed')
header = {'X-Amz-Copy-Source-If-None-Match': etag}
status, header, body = \
self._test_copy_for_s3acl(account,
head_resp=swob.HTTPNotModified,
put_header=header)
self.assertEquals(self._get_error_code(body), 'PreconditionFailed')
header = {'X-Amz-Copy-Source-If-Modified-Since': last_modified_since}
status, header, body = \
self._test_copy_for_s3acl(account,
head_resp=swob.HTTPNotModified,
put_header=header)
self.assertEquals(self._get_error_code(body), 'PreconditionFailed')
header = \
{'X-Amz-Copy-Source-If-Unmodified-Since': last_modified_since}
status, header, body = \
self._test_copy_for_s3acl(account,
head_resp=swob.HTTPPreconditionFailed,
put_header=header)
self.assertEquals(self._get_error_code(body), 'PreconditionFailed')
def test_upload_part_copy_headers_with_match(self):
account = 'test:tester'
etag = '7dfa07a8e59ddbcd1dc84d4c4f82aea1'
last_modified_since = 'Fri, 01 Apr 2014 12:00:00 GMT'
header = {'X-Amz-Copy-Source-If-Match': etag,
'X-Amz-Copy-Source-If-Modified-Since': last_modified_since}
status, header, body = \
self._test_copy_for_s3acl(account, put_header=header)
self.assertEquals(status.split()[0], '200')
self.assertEquals(len(self.swift.calls_with_headers), 3)
_, _, headers = self.swift.calls_with_headers[-2]
self.assertEquals(headers['If-Match'], etag)
self.assertEquals(headers['If-Modified-Since'], last_modified_since)
_, _, headers = self.swift.calls_with_headers[-1]
self.assertTrue(headers.get('If-Match') is None)
self.assertTrue(headers.get('If-Modified-Since') is None)
_, _, headers = self.swift.calls_with_headers[0]
self.assertTrue(headers.get('If-Match') is None)
self.assertTrue(headers.get('If-Modified-Since') is None)
@s3acl(s3acl_only=True)
def test_upload_part_copy_headers_with_match_and_s3acl(self):
account = 'test:tester'
etag = '7dfa07a8e59ddbcd1dc84d4c4f82aea1'
last_modified_since = 'Fri, 01 Apr 2014 12:00:00 GMT'
header = {'X-Amz-Copy-Source-If-Match': etag,
'X-Amz-Copy-Source-If-Modified-Since': last_modified_since}
status, header, body = \
self._test_copy_for_s3acl(account, put_header=header)
self.assertEquals(status.split()[0], '200')
self.assertEquals(len(self.swift.calls_with_headers), 4)
# Before the check of the copy source in the case of s3acl is valid,
# Swift3 check the bucket write permissions and the object existence
# of the destination.
_, _, headers = self.swift.calls_with_headers[-3]
self.assertTrue(headers.get('If-Match') is None)
self.assertTrue(headers.get('If-Modified-Since') is None)
_, _, headers = self.swift.calls_with_headers[-2]
self.assertEquals(headers['If-Match'], etag)
self.assertEquals(headers['If-Modified-Since'], last_modified_since)
_, _, headers = self.swift.calls_with_headers[-1]
self.assertTrue(headers.get('If-Match') is None)
self.assertTrue(headers.get('If-Modified-Since') is None)
_, _, headers = self.swift.calls_with_headers[0]
self.assertTrue(headers.get('If-Match') is None)
self.assertTrue(headers.get('If-Modified-Since') is None)
def test_upload_part_copy_headers_with_not_match(self):
account = 'test:tester'
etag = '7dfa07a8e59ddbcd1dc84d4c4f82aea1'
last_modified_since = 'Fri, 01 Apr 2014 12:00:00 GMT'
header = {'X-Amz-Copy-Source-If-None-Match': etag,
'X-Amz-Copy-Source-If-Unmodified-Since': last_modified_since}
status, header, body = \
self._test_copy_for_s3acl(account, put_header=header)
self.assertEquals(status.split()[0], '200')
self.assertEquals(len(self.swift.calls_with_headers), 3)
_, _, headers = self.swift.calls_with_headers[-2]
self.assertEquals(headers['If-None-Match'], etag)
self.assertEquals(headers['If-Unmodified-Since'], last_modified_since)
_, _, headers = self.swift.calls_with_headers[-1]
self.assertTrue(headers.get('If-None-Match') is None)
self.assertTrue(headers.get('If-Unmodified-Since') is None)
_, _, headers = self.swift.calls_with_headers[0]
self.assertTrue(headers.get('If-None-Match') is None)
self.assertTrue(headers.get('If-Unmodified-Since') is None)
@s3acl(s3acl_only=True)
def test_upload_part_copy_headers_with_not_match_and_s3acl(self):
account = 'test:tester'
etag = '7dfa07a8e59ddbcd1dc84d4c4f82aea1'
last_modified_since = 'Fri, 01 Apr 2014 12:00:00 GMT'
header = {'X-Amz-Copy-Source-If-None-Match': etag,
'X-Amz-Copy-Source-If-Unmodified-Since': last_modified_since}
status, header, body = \
self._test_copy_for_s3acl(account, put_header=header)
self.assertEquals(status.split()[0], '200')
self.assertEquals(len(self.swift.calls_with_headers), 4)
# Before the check of the copy source in the case of s3acl is valid,
# Swift3 check the bucket write permissions and the object existence
# of the destination.
_, _, headers = self.swift.calls_with_headers[-3]
self.assertTrue(headers.get('If-Match') is None)
self.assertTrue(headers.get('If-Modified-Since') is None)
_, _, headers = self.swift.calls_with_headers[-2]
self.assertEquals(headers['If-None-Match'], etag)
self.assertEquals(headers['If-Unmodified-Since'], last_modified_since)
self.assertTrue(headers.get('If-Match') is None)
self.assertTrue(headers.get('If-Modified-Since') is None)
_, _, headers = self.swift.calls_with_headers[-1]
self.assertTrue(headers.get('If-None-Match') is None)
self.assertTrue(headers.get('If-Unmodified-Since') is None)
_, _, headers = self.swift.calls_with_headers[0]
if __name__ == '__main__':
unittest.main()