From 7d36d94aefa94b07e45103086a3dd01b0ff411ad Mon Sep 17 00:00:00 2001 From: wim glenn Date: Mon, 16 Nov 2020 14:23:51 -0600 Subject: [PATCH 1/2] Include Content-MD5 header when body is empty (#1985) * Include Content-MD5 header even when body is empty. Closes https://github.com/boto/botocore/issues/1979 --- botocore/handlers.py | 6 +----- botocore/utils.py | 2 +- tests/unit/test_handlers.py | 11 +++++++++++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/botocore/handlers.py b/botocore/handlers.py index 0766e31da1..2126be6ba7 100644 --- a/botocore/handlers.py +++ b/botocore/handlers.py @@ -25,7 +25,7 @@ from botocore.compat import ( unquote, json, six, unquote_str, ensure_bytes, get_md5, - MD5_AVAILABLE, OrderedDict, urlsplit, urlunsplit, XMLParseError, + OrderedDict, urlsplit, urlunsplit, XMLParseError, ETree, ) from botocore.docs.utils import AutoPopulatedParam @@ -37,15 +37,11 @@ from botocore.exceptions import ParamValidationError from botocore.exceptions import AliasConflictParameterError from botocore.exceptions import UnsupportedTLSVersionWarning -from botocore.exceptions import MissingServiceIdError from botocore.utils import percent_encode, SAFE_CHARS from botocore.utils import switch_host_with_param -from botocore.utils import hyphenize_service_id from botocore.utils import conditionally_calculate_md5 -from botocore import retryhandler from botocore import utils -from botocore import translate import botocore import botocore.auth diff --git a/botocore/utils.py b/botocore/utils.py index a643d888d4..8eda6148b6 100644 --- a/botocore/utils.py +++ b/botocore/utils.py @@ -2215,7 +2215,7 @@ def conditionally_calculate_md5(params, **kwargs): """Only add a Content-MD5 if the system supports it.""" headers = params['headers'] body = params['body'] - if MD5_AVAILABLE and body and 'Content-MD5' not in headers: + if MD5_AVAILABLE and body is not None and 'Content-MD5' not in headers: md5_digest = calculate_md5(body, **kwargs) params['headers']['Content-MD5'] = md5_digest diff --git a/tests/unit/test_handlers.py b/tests/unit/test_handlers.py index 7857ef67a8..fde22e34e6 100644 --- a/tests/unit/test_handlers.py +++ b/tests/unit/test_handlers.py @@ -1217,6 +1217,17 @@ def test_add_md5_with_bytes_object(self): request_dict['headers']['Content-MD5'], 'OFj2IjCsPJFfMAxmQxLGPw==') + def test_add_md5_with_empty_body(self): + request_dict = { + 'body': b'', + 'headers': {} + } + self.md5_digest.return_value = b'8X\xf6"0\xac<\x91_0\x0cfC\x12\xc6?' + conditionally_calculate_md5(request_dict) + self.assertEqual( + request_dict['headers']['Content-MD5'], + 'OFj2IjCsPJFfMAxmQxLGPw==') + def test_add_md5_with_bytearray_object(self): request_dict = { 'body': bytearray(b'foobar'), From 861bce8d1e4fe014d80ff53b4083829db455bcc8 Mon Sep 17 00:00:00 2001 From: Nate Prewitt Date: Mon, 16 Nov 2020 13:34:56 -0800 Subject: [PATCH 2/2] Add S3 tests for PutObject empty body --- botocore/handlers.py | 6 +++++- tests/functional/test_s3.py | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/botocore/handlers.py b/botocore/handlers.py index 2126be6ba7..0766e31da1 100644 --- a/botocore/handlers.py +++ b/botocore/handlers.py @@ -25,7 +25,7 @@ from botocore.compat import ( unquote, json, six, unquote_str, ensure_bytes, get_md5, - OrderedDict, urlsplit, urlunsplit, XMLParseError, + MD5_AVAILABLE, OrderedDict, urlsplit, urlunsplit, XMLParseError, ETree, ) from botocore.docs.utils import AutoPopulatedParam @@ -37,11 +37,15 @@ from botocore.exceptions import ParamValidationError from botocore.exceptions import AliasConflictParameterError from botocore.exceptions import UnsupportedTLSVersionWarning +from botocore.exceptions import MissingServiceIdError from botocore.utils import percent_encode, SAFE_CHARS from botocore.utils import switch_host_with_param +from botocore.utils import hyphenize_service_id from botocore.utils import conditionally_calculate_md5 +from botocore import retryhandler from botocore import utils +from botocore import translate import botocore import botocore.auth diff --git a/tests/functional/test_s3.py b/tests/functional/test_s3.py index 00917d93f1..b7645125d0 100644 --- a/tests/functional/test_s3.py +++ b/tests/functional/test_s3.py @@ -919,6 +919,18 @@ def test_content_md5_set(self): self.client.put_object(Bucket='foo', Key='bar', Body='baz') self.assertIn('content-md5', self.get_sent_headers()) + def test_content_md5_set_empty_body(self): + with self.http_stubber: + self.client.put_object(Bucket='foo', Key='bar', Body='') + self.assertIn('content-md5', self.get_sent_headers()) + + def test_content_md5_set_empty_file(self): + with self.http_stubber: + with temporary_file('rb') as f: + assert f.read() == b'' + self.client.put_object(Bucket='foo', Key='bar', Body=f) + self.assertIn('content-md5', self.get_sent_headers()) + def test_content_sha256_set_if_config_value_is_true(self): config = Config(signature_version='s3v4', s3={ 'payload_signing_enabled': True