Fix the deletion of non-existent keys
On vanilla Swift, deleting an object that doesn't exist will 404. On AWS, deleting a key that doesn't exist will either 404 if the bucket doesn't exist (with a NoSuchBucket code) or 204 (because yep, that's not accessible). Change-Id: Ied2a78b56522316bb374f23961621641af3adc83 Related-Change: I6e154594dfda6c3065774c23b24f728625a842bc
This commit is contained in:
parent
53f9fd2b61
commit
bd640cdbae
@ -20,7 +20,7 @@ from swift.common.utils import public
|
|||||||
from swift.common.middleware.s3api.utils import S3Timestamp
|
from swift.common.middleware.s3api.utils import S3Timestamp
|
||||||
from swift.common.middleware.s3api.controllers.base import Controller
|
from swift.common.middleware.s3api.controllers.base import Controller
|
||||||
from swift.common.middleware.s3api.s3response import S3NotImplemented, \
|
from swift.common.middleware.s3api.s3response import S3NotImplemented, \
|
||||||
InvalidRange, NoSuchKey, InvalidArgument
|
InvalidRange, NoSuchKey, InvalidArgument, HTTPNoContent
|
||||||
|
|
||||||
|
|
||||||
class ObjectController(Controller):
|
class ObjectController(Controller):
|
||||||
@ -143,5 +143,6 @@ class ObjectController(Controller):
|
|||||||
except NoSuchKey:
|
except NoSuchKey:
|
||||||
# expect to raise NoSuchBucket when the bucket doesn't exist
|
# expect to raise NoSuchBucket when the bucket doesn't exist
|
||||||
req.get_container_info(self.app)
|
req.get_container_info(self.app)
|
||||||
raise
|
# else -- it's gone! Success.
|
||||||
|
return HTTPNoContent()
|
||||||
return resp
|
return resp
|
||||||
|
@ -139,6 +139,12 @@ class TestS3ApiObject(S3ApiBase):
|
|||||||
self.assertEqual(status, 204)
|
self.assertEqual(status, 204)
|
||||||
self.assertCommonResponseHeaders(headers)
|
self.assertCommonResponseHeaders(headers)
|
||||||
|
|
||||||
|
# DELETE Non-Existent Object
|
||||||
|
status, headers, body = \
|
||||||
|
self.conn.make_request('DELETE', self.bucket, 'does-not-exist')
|
||||||
|
self.assertEqual(status, 204)
|
||||||
|
self.assertCommonResponseHeaders(headers)
|
||||||
|
|
||||||
def test_put_object_error(self):
|
def test_put_object_error(self):
|
||||||
auth_error_conn = Connection(aws_secret_key='invalid')
|
auth_error_conn = Connection(aws_secret_key='invalid')
|
||||||
status, headers, body = \
|
status, headers, body = \
|
||||||
@ -238,11 +244,6 @@ class TestS3ApiObject(S3ApiBase):
|
|||||||
self.assertEqual(get_error_code(body), 'SignatureDoesNotMatch')
|
self.assertEqual(get_error_code(body), 'SignatureDoesNotMatch')
|
||||||
self.assertEqual(headers['content-type'], 'application/xml')
|
self.assertEqual(headers['content-type'], 'application/xml')
|
||||||
|
|
||||||
status, headers, body = \
|
|
||||||
self.conn.make_request('DELETE', self.bucket, 'invalid')
|
|
||||||
self.assertEqual(get_error_code(body), 'NoSuchKey')
|
|
||||||
self.assertEqual(headers['content-type'], 'application/xml')
|
|
||||||
|
|
||||||
status, headers, body = \
|
status, headers, body = \
|
||||||
self.conn.make_request('DELETE', 'invalid', obj)
|
self.conn.make_request('DELETE', 'invalid', obj)
|
||||||
self.assertEqual(get_error_code(body), 'NoSuchBucket')
|
self.assertEqual(get_error_code(body), 'NoSuchBucket')
|
||||||
|
@ -17,7 +17,6 @@ import unittest
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
|
|
||||||
from six.moves import urllib
|
|
||||||
from swift.common import swob
|
from swift.common import swob
|
||||||
from swift.common.swob import Request
|
from swift.common.swob import Request
|
||||||
|
|
||||||
@ -87,11 +86,14 @@ class TestS3ApiMultiDelete(S3ApiTestCase):
|
|||||||
|
|
||||||
elem = fromstring(body)
|
elem = fromstring(body)
|
||||||
self.assertEqual(len(elem.findall('Deleted')), 3)
|
self.assertEqual(len(elem.findall('Deleted')), 3)
|
||||||
_, path, _ = self.swift.calls_with_headers[-1]
|
self.assertEqual(self.swift.calls, [
|
||||||
path, query_string = path.split('?', 1)
|
('HEAD', '/v1/AUTH_test/bucket'),
|
||||||
self.assertEqual(path, '/v1/AUTH_test/bucket/Key3')
|
('HEAD', '/v1/AUTH_test/bucket/Key1'),
|
||||||
query = dict(urllib.parse.parse_qsl(query_string))
|
('DELETE', '/v1/AUTH_test/bucket/Key1'),
|
||||||
self.assertEqual(query['multipart-manifest'], 'delete')
|
('HEAD', '/v1/AUTH_test/bucket/Key2'),
|
||||||
|
('HEAD', '/v1/AUTH_test/bucket/Key3'),
|
||||||
|
('DELETE', '/v1/AUTH_test/bucket/Key3?multipart-manifest=delete'),
|
||||||
|
])
|
||||||
|
|
||||||
@s3acl
|
@s3acl
|
||||||
def test_object_multi_DELETE_quiet(self):
|
def test_object_multi_DELETE_quiet(self):
|
||||||
|
@ -767,13 +767,6 @@ class TestS3ApiObj(S3ApiTestCase):
|
|||||||
swob.HTTPServiceUnavailable)
|
swob.HTTPServiceUnavailable)
|
||||||
self.assertEqual(code, 'InternalError')
|
self.assertEqual(code, 'InternalError')
|
||||||
|
|
||||||
with patch(
|
|
||||||
'swift.common.middleware.s3api.s3request.get_container_info',
|
|
||||||
return_value={'status': 204}):
|
|
||||||
code = self._test_method_error('DELETE', '/bucket/object',
|
|
||||||
swob.HTTPNotFound)
|
|
||||||
self.assertEqual(code, 'NoSuchKey')
|
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
'swift.common.middleware.s3api.s3request.get_container_info',
|
'swift.common.middleware.s3api.s3request.get_container_info',
|
||||||
return_value={'status': 404}):
|
return_value={'status': 404}):
|
||||||
@ -809,11 +802,27 @@ class TestS3ApiObj(S3ApiTestCase):
|
|||||||
|
|
||||||
self.assertIn(('HEAD', '/v1/AUTH_test/bucket/object'),
|
self.assertIn(('HEAD', '/v1/AUTH_test/bucket/object'),
|
||||||
self.swift.calls)
|
self.swift.calls)
|
||||||
self.assertIn(('DELETE', '/v1/AUTH_test/bucket/object'),
|
self.assertEqual(('DELETE', '/v1/AUTH_test/bucket/object'),
|
||||||
self.swift.calls)
|
self.swift.calls[-1])
|
||||||
_, path = self.swift.calls[-1]
|
_, path = self.swift.calls[-1]
|
||||||
self.assertEqual(path.count('?'), 0)
|
self.assertEqual(path.count('?'), 0)
|
||||||
|
|
||||||
|
@s3acl
|
||||||
|
def test_object_DELETE_missing(self):
|
||||||
|
self.swift.register('HEAD', '/v1/AUTH_test/bucket/object',
|
||||||
|
swob.HTTPNotFound, {}, None)
|
||||||
|
req = Request.blank('/bucket/object',
|
||||||
|
environ={'REQUEST_METHOD': 'DELETE'},
|
||||||
|
headers={'Authorization': 'AWS test:tester:hmac',
|
||||||
|
'Date': self.get_date_header()})
|
||||||
|
status, headers, body = self.call_s3api(req)
|
||||||
|
self.assertEqual(status.split()[0], '204')
|
||||||
|
|
||||||
|
self.assertIn(('HEAD', '/v1/AUTH_test/bucket/object'),
|
||||||
|
self.swift.calls)
|
||||||
|
self.assertNotIn(('DELETE', '/v1/AUTH_test/bucket/object'),
|
||||||
|
self.swift.calls)
|
||||||
|
|
||||||
@s3acl
|
@s3acl
|
||||||
def test_slo_object_DELETE(self):
|
def test_slo_object_DELETE(self):
|
||||||
self.swift.register('HEAD', '/v1/AUTH_test/bucket/object',
|
self.swift.register('HEAD', '/v1/AUTH_test/bucket/object',
|
||||||
|
Loading…
Reference in New Issue
Block a user