From e034dd1140cb6b6862d5ebc633ba94d332fc2bb2 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Mon, 7 Mar 2016 08:31:23 +0000 Subject: [PATCH 1/3] Allow for exceptions from tell() --- requests/utils.py | 7 ++++++- tests/test_utils.py | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/requests/utils.py b/requests/utils.py index c5c3fd01..c9746d64 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -83,7 +83,12 @@ def super_len(o): ) if hasattr(o, 'tell'): - current_position = o.tell() + try: + current_position = o.tell() + except (OSError, IOError): + # This can happen in some weird situations, such as when the file + # is actually a special file descriptor like stdin. + current_position = 0 return max(0, total_length - current_position) diff --git a/tests/test_utils.py b/tests/test_utils.py index 5a50e366..afb38315 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -15,7 +15,6 @@ from .compat import StringIO, cStringIO class TestSuperLen: - @pytest.mark.parametrize( 'stream, value', ( (StringIO.StringIO, 'Test'), @@ -33,6 +32,20 @@ class TestSuperLen: s.write('foobarbogus') assert super_len(s) == 0 + @pytest.mark.parametrize('error', [IOError, OSError]) + def test_super_len_handles_files_raising_weird_errors_in_tell(self, error): + """ + If tell() raises errors, assume the cursor is at position zero. + """ + class BoomFile(object): + def __len__(self): + return 5 + + def tell(self): + raise error() + + assert super_len(BoomFile()) == 5 + class TestGetEnvironProxies: """Ensures that IP addresses are correctly matches with ranges From 6cc0b56d51d13e2a8553f7abffa06e9fbaf795db Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Mon, 7 Mar 2016 09:05:43 +0000 Subject: [PATCH 2/3] Switch to treat files without tell() as zero-length --- requests/utils.py | 6 ++++-- tests/test_utils.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/requests/utils.py b/requests/utils.py index c9746d64..16f7b98f 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -87,8 +87,10 @@ def super_len(o): current_position = o.tell() except (OSError, IOError): # This can happen in some weird situations, such as when the file - # is actually a special file descriptor like stdin. - current_position = 0 + # is actually a special file descriptor like stdin. In this + # instance, we don't know what the length is, so set it to zero and + # let requests chunk it instead. + current_position = total_length return max(0, total_length - current_position) diff --git a/tests/test_utils.py b/tests/test_utils.py index afb38315..24b40b96 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -44,7 +44,7 @@ class TestSuperLen: def tell(self): raise error() - assert super_len(BoomFile()) == 5 + assert super_len(BoomFile()) == 0 class TestGetEnvironProxies: From 90a166d44ae2d6b0887140f64c0c79051fd8c0f3 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Fri, 11 Mar 2016 09:57:59 +0000 Subject: [PATCH 3/3] Release note. --- HISTORY.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HISTORY.rst b/HISTORY.rst index 1fa26b7f..969ad843 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -9,6 +9,8 @@ Release History **Bugfixes** - Don't use redirect_cache if allow_redirects=False +- When passed objects that throw exceptions from ``tell()``, send them via + chunked transfer encoding instead of failing. 2.9.1 (2015-12-21) ++++++++++++++++++