Merge "Fix response of DELETE Multiple Objects without bucket write permission"
This commit is contained in:
		@@ -17,7 +17,7 @@ from swift3.controllers.base import Controller, bucket_operation
 | 
			
		||||
from swift3.etree import Element, SubElement, fromstring, tostring, \
 | 
			
		||||
    XMLSyntaxError, DocumentInvalid
 | 
			
		||||
from swift3.response import HTTPOk, S3NotImplemented, NoSuchKey, \
 | 
			
		||||
    ErrorResponse, MalformedXML, UserKeyMustBeSpecified
 | 
			
		||||
    ErrorResponse, MalformedXML, UserKeyMustBeSpecified, AccessDenied
 | 
			
		||||
from swift3.cfg import CONF
 | 
			
		||||
from swift3.utils import LOGGER
 | 
			
		||||
 | 
			
		||||
@@ -29,6 +29,19 @@ class MultiObjectDeleteController(Controller):
 | 
			
		||||
    Handles Delete Multiple Objects, which is logged as a MULTI_OBJECT_DELETE
 | 
			
		||||
    operation in the S3 server log.
 | 
			
		||||
    """
 | 
			
		||||
    def _gen_error_body(self, error, elem, delete_list):
 | 
			
		||||
        for key, version in delete_list:
 | 
			
		||||
            if version is not None:
 | 
			
		||||
                # TODO: delete the specific version of the object
 | 
			
		||||
                raise S3NotImplemented()
 | 
			
		||||
 | 
			
		||||
            error_elem = SubElement(elem, 'Error')
 | 
			
		||||
            SubElement(error_elem, 'Key').text = key
 | 
			
		||||
            SubElement(error_elem, 'Code').text = error.__class__.__name__
 | 
			
		||||
            SubElement(error_elem, 'Message').text = error._msg
 | 
			
		||||
 | 
			
		||||
        return tostring(elem)
 | 
			
		||||
 | 
			
		||||
    @bucket_operation
 | 
			
		||||
    def POST(self, req):
 | 
			
		||||
        """
 | 
			
		||||
@@ -45,9 +58,6 @@ class MultiObjectDeleteController(Controller):
 | 
			
		||||
 | 
			
		||||
                yield key, version
 | 
			
		||||
 | 
			
		||||
        # check bucket existence
 | 
			
		||||
        req.get_response(self.app, 'HEAD')
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            xml = req.xml(MAX_MULTI_DELETE_BODY_SIZE, check_md5=True)
 | 
			
		||||
            elem = fromstring(xml, 'Delete')
 | 
			
		||||
@@ -71,6 +81,13 @@ class MultiObjectDeleteController(Controller):
 | 
			
		||||
 | 
			
		||||
        elem = Element('DeleteResult')
 | 
			
		||||
 | 
			
		||||
        # check bucket existence
 | 
			
		||||
        try:
 | 
			
		||||
            req.get_response(self.app, 'HEAD')
 | 
			
		||||
        except AccessDenied as error:
 | 
			
		||||
            body = self._gen_error_body(error, elem, delete_list)
 | 
			
		||||
            return HTTPOk(body=body)
 | 
			
		||||
 | 
			
		||||
        for key, version in delete_list:
 | 
			
		||||
            if version is not None:
 | 
			
		||||
                # TODO: delete the specific version of the object
 | 
			
		||||
 
 | 
			
		||||
@@ -173,13 +173,16 @@ class TestSwift3MultiDelete(Swift3TestCase):
 | 
			
		||||
        self.assertEquals(self._get_error_code(body), 'MalformedXML')
 | 
			
		||||
 | 
			
		||||
    def _test_object_multi_DELETE(self, account):
 | 
			
		||||
        self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key1',
 | 
			
		||||
                            swob.HTTPNoContent, {}, None)
 | 
			
		||||
        self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key2',
 | 
			
		||||
                            swob.HTTPNotFound, {}, None)
 | 
			
		||||
        self.keys = ['Key1', 'Key2']
 | 
			
		||||
        self.swift.register(
 | 
			
		||||
            'DELETE', '/v1/AUTH_test/bucket/%s' % self.keys[0],
 | 
			
		||||
            swob.HTTPNoContent, {}, None)
 | 
			
		||||
        self.swift.register(
 | 
			
		||||
            'DELETE', '/v1/AUTH_test/bucket/%s' % self.keys[1],
 | 
			
		||||
            swob.HTTPNotFound, {}, None)
 | 
			
		||||
 | 
			
		||||
        elem = Element('Delete')
 | 
			
		||||
        for key in ['Key1', 'Key2']:
 | 
			
		||||
        for key in self.keys:
 | 
			
		||||
            obj = SubElement(elem, 'Object')
 | 
			
		||||
            SubElement(obj, 'Key').text = key
 | 
			
		||||
        body = tostring(elem, use_s3ns=False)
 | 
			
		||||
@@ -198,14 +201,21 @@ class TestSwift3MultiDelete(Swift3TestCase):
 | 
			
		||||
    @s3acl(s3acl_only=True)
 | 
			
		||||
    def test_object_multi_DELETE_without_permission(self):
 | 
			
		||||
        status, headers, body = self._test_object_multi_DELETE('test:other')
 | 
			
		||||
        self.assertEquals(self._get_error_code(body), 'AccessDenied')
 | 
			
		||||
        self.assertEquals(status.split()[0], '200')
 | 
			
		||||
        elem = fromstring(body)
 | 
			
		||||
        errors = elem.findall('Error')
 | 
			
		||||
        self.assertEquals(len(errors), len(self.keys))
 | 
			
		||||
        for e in errors:
 | 
			
		||||
            self.assertTrue(e.find('Key').text in self.keys)
 | 
			
		||||
            self.assertEquals(e.find('Code').text, 'AccessDenied')
 | 
			
		||||
            self.assertEquals(e.find('Message').text, 'Access Denied.')
 | 
			
		||||
 | 
			
		||||
    @s3acl(s3acl_only=True)
 | 
			
		||||
    def test_object_multi_DELETE_with_write_permission(self):
 | 
			
		||||
        status, headers, body = self._test_object_multi_DELETE('test:write')
 | 
			
		||||
        self.assertEquals(status.split()[0], '200')
 | 
			
		||||
        elem = fromstring(body)
 | 
			
		||||
        self.assertEquals(len(elem.findall('Deleted')), 2)
 | 
			
		||||
        self.assertEquals(len(elem.findall('Deleted')), len(self.keys))
 | 
			
		||||
 | 
			
		||||
    @s3acl(s3acl_only=True)
 | 
			
		||||
    def test_object_multi_DELETE_with_fullcontrol_permission(self):
 | 
			
		||||
@@ -213,7 +223,7 @@ class TestSwift3MultiDelete(Swift3TestCase):
 | 
			
		||||
            self._test_object_multi_DELETE('test:full_control')
 | 
			
		||||
        self.assertEquals(status.split()[0], '200')
 | 
			
		||||
        elem = fromstring(body)
 | 
			
		||||
        self.assertEquals(len(elem.findall('Deleted')), 2)
 | 
			
		||||
        self.assertEquals(len(elem.findall('Deleted')), len(self.keys))
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    unittest.main()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user