s3api: Make the 'Quiet' key value case insensitive

When deleting multiple objects, S3 allows to enable
a quiet mode with the 'Quiet' key.

At AWS S3, the value of this key is case-insensitive.
- Quiet mode is enabled if the value is 'true'
  (regardless of case).
- Otherwise, in all other cases (even a non-boolean value),
  this mode will be disabled.

Also, some tools (like Minio's python API) send the value 'True'
(and not 'true').

Change-Id: Id9d1da2017b8d13242ae1f410347febb013e9ce1
This commit is contained in:
Aymeric Ducroquetz
2022-03-23 17:48:51 +01:00
parent 0651d8175d
commit fd2dd11562
4 changed files with 23 additions and 24 deletions

View File

@@ -1,6 +1,6 @@
start = start =
element Delete { element Delete {
element Quiet { xsd:boolean }? & element Quiet { xsd:string }? &
element Object { element Object {
element Key { xsd:string } & element Key { xsd:string } &
element VersionId { xsd:string }? element VersionId { xsd:string }?

View File

@@ -81,10 +81,7 @@ class MultiObjectDeleteController(Controller):
elem = fromstring(xml, 'Delete', self.logger) elem = fromstring(xml, 'Delete', self.logger)
quiet = elem.find('./Quiet') quiet = elem.find('./Quiet')
if quiet is not None and quiet.text.lower() == 'true': self.quiet = quiet is not None and quiet.text.lower() == 'true'
self.quiet = True
else:
self.quiet = False
delete_list = list(object_key_iter(elem)) delete_list = list(object_key_iter(elem))
if len(delete_list) > self.conf.max_multi_delete_objects: if len(delete_list) > self.conf.max_multi_delete_objects:

View File

@@ -5,7 +5,7 @@
<interleave> <interleave>
<optional> <optional>
<element name="Quiet"> <element name="Quiet">
<data type="boolean"/> <data type="string"/>
</element> </element>
</optional> </optional>
<oneOrMore> <oneOrMore>

View File

@@ -249,26 +249,28 @@ class TestS3ApiMultiDelete(S3ApiTestCase):
self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key2', self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key2',
swob.HTTPNotFound, {}, None) swob.HTTPNotFound, {}, None)
elem = Element('Delete') for true_value in ('true', 'True', 'TRUE', 'trUE'):
SubElement(elem, 'Quiet').text = 'true' elem = Element('Delete')
for key in ['Key1', 'Key2']: SubElement(elem, 'Quiet').text = true_value
obj = SubElement(elem, 'Object') for key in ['Key1', 'Key2']:
SubElement(obj, 'Key').text = key obj = SubElement(elem, 'Object')
body = tostring(elem, use_s3ns=False) SubElement(obj, 'Key').text = key
content_md5 = base64.b64encode( body = tostring(elem, use_s3ns=False)
md5(body, usedforsecurity=False).digest()).strip() content_md5 = base64.b64encode(
md5(body, usedforsecurity=False).digest()).strip()
req = Request.blank('/bucket?delete', req = Request.blank('/bucket?delete',
environ={'REQUEST_METHOD': 'POST'}, environ={'REQUEST_METHOD': 'POST'},
headers={'Authorization': 'AWS test:tester:hmac', headers={
'Date': self.get_date_header(), 'Authorization': 'AWS test:tester:hmac',
'Content-MD5': content_md5}, 'Date': self.get_date_header(),
body=body) 'Content-MD5': content_md5},
status, headers, body = self.call_s3api(req) body=body)
self.assertEqual(status.split()[0], '200') status, headers, body = self.call_s3api(req)
self.assertEqual(status.split()[0], '200')
elem = fromstring(body) elem = fromstring(body)
self.assertEqual(len(elem.findall('Deleted')), 0) self.assertEqual(len(elem.findall('Deleted')), 0)
@s3acl @s3acl
def test_object_multi_DELETE_no_key(self): def test_object_multi_DELETE_no_key(self):