From 62d4ea24173ab70b1e52b3b8c187c5238ce05a29 Mon Sep 17 00:00:00 2001 From: Illia Batozskyi Date: Thu, 21 Jan 2021 15:55:50 -0500 Subject: [PATCH] Fall back to Transfer-Encoding 'chunked' if AWSRequest body is not seekable stream --- botocore/awsrequest.py | 19 +++++++++++++------ tests/unit/test_utils.py | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/botocore/awsrequest.py b/botocore/awsrequest.py index 535b91bed4..f47f0cc01e 100644 --- a/botocore/awsrequest.py +++ b/botocore/awsrequest.py @@ -11,6 +11,7 @@ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. +import io import sys import logging import functools @@ -404,12 +405,18 @@ def _determine_content_length(self, body): # Try getting the length from a seekable stream if hasattr(body, 'seek') and hasattr(body, 'tell'): - orig_pos = body.tell() - body.seek(0, 2) - end_file_pos = body.tell() - body.seek(orig_pos) - return end_file_pos - orig_pos - + try: + orig_pos = body.tell() + body.seek(0, 2) + end_file_pos = body.tell() + body.seek(orig_pos) + return end_file_pos - orig_pos + except io.UnsupportedOperation: + # in case when body is, for example, io.BufferedIOBase object + # it has "seek" method which throws "UnsupportedOperation" + # exception in such case we want to fall back to "chunked" + # encoding + pass # Failed to determine the length return None diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index d55f03f8ba..9dd8fd7858 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -10,6 +10,8 @@ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. +import io + from tests import unittest from tests import RawResponse from dateutil.tz import tzutc, tzoffset @@ -918,6 +920,19 @@ def test_is_unaffected_by_sigv4(self): 'https://bucket.s3.amazonaws.com/key.txt') +class TestSwitchToChunkedEncodingForNonSeekableObjects(unittest.TestCase): + def test_switch_to_chunked_encodeing_for_stream_like_object(self): + request = AWSRequest( + method='POST', headers={}, + data=io.BufferedIOBase(b"some initial binary data"), + url='https://foo.amazonaws.com/bucket/key.txt' + ) + prepared_request = request.prepare() + self.assertEqual( + prepared_request.headers, {'Transfer-Encoding': 'chunked'} + ) + + class TestInstanceCache(unittest.TestCase): class DummyClass(object): def __init__(self, cache):