Merge "s3api: Increase max body size for Delete Multiple Objects requests"

This commit is contained in:
Zuul
2018-10-03 22:39:48 +00:00
committed by Gerrit Code Review
3 changed files with 43 additions and 13 deletions

View File

@@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from swift.common.constraints import MAX_OBJECT_NAME_LENGTH
from swift.common.utils import public
from swift.common.middleware.s3api.controllers.base import Controller, \
@@ -23,8 +24,6 @@ from swift.common.middleware.s3api.s3response import HTTPOk, S3NotImplemented, \
NoSuchKey, ErrorResponse, MalformedXML, UserKeyMustBeSpecified, \
AccessDenied, MissingRequestBodyError
MAX_MULTI_DELETE_BODY_SIZE = 61365
class MultiObjectDeleteController(Controller):
"""
@@ -61,8 +60,16 @@ class MultiObjectDeleteController(Controller):
yield key, version
max_body_size = min(
# FWIW, AWS limits multideletes to 1000 keys, and swift limits
# object names to 1024 bytes (by default). Add a factor of two to
# allow some slop.
2 * self.conf.max_multi_delete_objects * MAX_OBJECT_NAME_LENGTH,
# But, don't let operators shoot themselves in the foot
10 * 1024 * 1024)
try:
xml = req.xml(MAX_MULTI_DELETE_BODY_SIZE)
xml = req.xml(max_body_size)
if not xml:
raise MissingRequestBodyError()

View File

@@ -18,8 +18,6 @@ import os
import test.functional as tf
from swift.common.middleware.s3api.etree import fromstring, tostring, Element, \
SubElement
from swift.common.middleware.s3api.controllers.multi_delete import \
MAX_MULTI_DELETE_BODY_SIZE
from test.functional.s3api import S3ApiBase
from test.functional.s3api.s3_test_client import Connection
@@ -172,11 +170,12 @@ class TestS3ApiMultiDelete(S3ApiBase):
query=query)
self.assertEqual(get_error_code(body), 'UserKeyMustBeSpecified')
max_deletes = tf.cluster_info.get('s3api', {}).get(
'max_multi_delete_objects', 1000)
# specified number of objects are over max_multi_delete_objects
# (Default 1000), but xml size is smaller than 61365 bytes.
req_objects = ['obj%s' for var in xrange(1001)]
# (Default 1000), but xml size is relatively small
req_objects = ['obj%s' for var in xrange(max_deletes + 1)]
xml = self._gen_multi_delete_xml(req_objects)
self.assertTrue(len(xml.encode('utf-8')) <= MAX_MULTI_DELETE_BODY_SIZE)
content_md5 = calculate_md5(xml)
status, headers, body = \
self.conn.make_request('POST', bucket, body=xml,
@@ -184,12 +183,11 @@ class TestS3ApiMultiDelete(S3ApiBase):
query=query)
self.assertEqual(get_error_code(body), 'MalformedXML')
# specified xml size is over 61365 bytes, but number of objects are
# specified xml size is large, but number of objects are
# smaller than max_multi_delete_objects.
obj = 'a' * 1024
req_objects = [obj + str(var) for var in xrange(999)]
obj = 'a' * 102400
req_objects = [obj + str(var) for var in xrange(max_deletes - 1)]
xml = self._gen_multi_delete_xml(req_objects)
self.assertTrue(len(xml.encode('utf-8')) > MAX_MULTI_DELETE_BODY_SIZE)
content_md5 = calculate_md5(xml)
status, headers, body = \
self.conn.make_request('POST', bucket, body=xml,

View File

@@ -179,12 +179,37 @@ class TestS3ApiMultiDelete(S3ApiTestCase):
status, headers, body = self.call_s3api(req)
self.assertEqual(self._get_error_code(body), 'InvalidRequest')
@s3acl
def test_object_multi_DELETE_lots_of_keys(self):
elem = Element('Delete')
for i in range(self.conf.max_multi_delete_objects):
name = 'x' * 1000 + str(i)
self.swift.register('HEAD', '/v1/AUTH_test/bucket/%s' % name,
swob.HTTPNotFound, {}, None)
obj = SubElement(elem, 'Object')
SubElement(obj, 'Key').text = name
body = tostring(elem, use_s3ns=False)
content_md5 = md5(body).digest().encode('base64').strip()
req = Request.blank('/bucket?delete',
environ={'REQUEST_METHOD': 'POST'},
headers={'Authorization': 'AWS test:tester:hmac',
'Date': self.get_date_header(),
'Content-MD5': content_md5},
body=body)
status, headers, body = self.call_s3api(req)
self.assertEqual('200 OK', status)
elem = fromstring(body)
self.assertEqual(len(elem.findall('Deleted')),
self.conf.max_multi_delete_objects)
@s3acl
def test_object_multi_DELETE_too_many_keys(self):
elem = Element('Delete')
for i in range(self.conf.max_multi_delete_objects + 1):
obj = SubElement(elem, 'Object')
SubElement(obj, 'Key').text = str(i)
SubElement(obj, 'Key').text = 'x' * 1000 + str(i)
body = tostring(elem, use_s3ns=False)
content_md5 = md5(body).digest().encode('base64').strip()