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:
Tim Burke 2018-06-15 13:29:16 -07:00
parent 53f9fd2b61
commit bd640cdbae
4 changed files with 35 additions and 22 deletions

View File

@ -20,7 +20,7 @@ from swift.common.utils import public
from swift.common.middleware.s3api.utils import S3Timestamp
from swift.common.middleware.s3api.controllers.base import Controller
from swift.common.middleware.s3api.s3response import S3NotImplemented, \
InvalidRange, NoSuchKey, InvalidArgument
InvalidRange, NoSuchKey, InvalidArgument, HTTPNoContent
class ObjectController(Controller):
@ -143,5 +143,6 @@ class ObjectController(Controller):
except NoSuchKey:
# expect to raise NoSuchBucket when the bucket doesn't exist
req.get_container_info(self.app)
raise
# else -- it's gone! Success.
return HTTPNoContent()
return resp

View File

@ -139,6 +139,12 @@ class TestS3ApiObject(S3ApiBase):
self.assertEqual(status, 204)
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):
auth_error_conn = Connection(aws_secret_key='invalid')
status, headers, body = \
@ -238,11 +244,6 @@ class TestS3ApiObject(S3ApiBase):
self.assertEqual(get_error_code(body), 'SignatureDoesNotMatch')
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 = \
self.conn.make_request('DELETE', 'invalid', obj)
self.assertEqual(get_error_code(body), 'NoSuchBucket')

View File

@ -17,7 +17,6 @@ import unittest
from datetime import datetime
from hashlib import md5
from six.moves import urllib
from swift.common import swob
from swift.common.swob import Request
@ -87,11 +86,14 @@ class TestS3ApiMultiDelete(S3ApiTestCase):
elem = fromstring(body)
self.assertEqual(len(elem.findall('Deleted')), 3)
_, path, _ = self.swift.calls_with_headers[-1]
path, query_string = path.split('?', 1)
self.assertEqual(path, '/v1/AUTH_test/bucket/Key3')
query = dict(urllib.parse.parse_qsl(query_string))
self.assertEqual(query['multipart-manifest'], 'delete')
self.assertEqual(self.swift.calls, [
('HEAD', '/v1/AUTH_test/bucket'),
('HEAD', '/v1/AUTH_test/bucket/Key1'),
('DELETE', '/v1/AUTH_test/bucket/Key1'),
('HEAD', '/v1/AUTH_test/bucket/Key2'),
('HEAD', '/v1/AUTH_test/bucket/Key3'),
('DELETE', '/v1/AUTH_test/bucket/Key3?multipart-manifest=delete'),
])
@s3acl
def test_object_multi_DELETE_quiet(self):

View File

@ -767,13 +767,6 @@ class TestS3ApiObj(S3ApiTestCase):
swob.HTTPServiceUnavailable)
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(
'swift.common.middleware.s3api.s3request.get_container_info',
return_value={'status': 404}):
@ -809,11 +802,27 @@ class TestS3ApiObj(S3ApiTestCase):
self.assertIn(('HEAD', '/v1/AUTH_test/bucket/object'),
self.swift.calls)
self.assertIn(('DELETE', '/v1/AUTH_test/bucket/object'),
self.swift.calls)
self.assertEqual(('DELETE', '/v1/AUTH_test/bucket/object'),
self.swift.calls[-1])
_, path = self.swift.calls[-1]
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
def test_slo_object_DELETE(self):
self.swift.register('HEAD', '/v1/AUTH_test/bucket/object',