mirror of
https://github.com/kennethreitz/requests.git
synced 2026-06-05 22:50:18 +00:00
#4965 fix: Accessing response.content twice removes forgets read error.
This commit is contained in:
+16
-7
@@ -640,7 +640,9 @@ class Response(object):
|
||||
#: is a response.
|
||||
self.request = None
|
||||
|
||||
self.error = None
|
||||
#: If there was an error in the processing of content,
|
||||
#: then save the error that would return the same error when you re-appeal.
|
||||
self._error = None
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
@@ -751,15 +753,21 @@ class Response(object):
|
||||
try:
|
||||
for chunk in self.raw.stream(chunk_size, decode_content=True):
|
||||
yield chunk
|
||||
|
||||
except ProtocolError as e:
|
||||
self._error = e
|
||||
raise ChunkedEncodingError(e)
|
||||
self._error = ChunkedEncodingError(e)
|
||||
|
||||
except DecodeError as e:
|
||||
self._error = e
|
||||
raise ContentDecodingError(e)
|
||||
self._error = ContentDecodingError(e)
|
||||
|
||||
except ReadTimeoutError as e:
|
||||
self._error = e
|
||||
raise ConnectionError(e)
|
||||
self._error = ConnectionError(e)
|
||||
|
||||
finally:
|
||||
# if we had an error - throw the saved error
|
||||
if self._error:
|
||||
raise self._error
|
||||
|
||||
else:
|
||||
# Standard file-like object.
|
||||
while True:
|
||||
@@ -832,6 +840,7 @@ class Response(object):
|
||||
else:
|
||||
self._content = b''.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b''
|
||||
|
||||
# if we had an error - throw the saved error
|
||||
if self._error is not None:
|
||||
raise self._error
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import pytest
|
||||
import threading
|
||||
import requests
|
||||
from requests.exceptions import ChunkedEncodingError
|
||||
|
||||
from tests.testserver.server import Server, consume_socket_content
|
||||
|
||||
@@ -307,3 +308,43 @@ def test_fragment_update_on_redirect():
|
||||
assert r.url == 'http://{}:{}/final-url/#relevant-section'.format(host, port)
|
||||
|
||||
close_server.set()
|
||||
|
||||
|
||||
def test_response_content_retains_error():
|
||||
"""Verify that accessing response.content retains an error.
|
||||
|
||||
See https://github.com/kennethreitz/requests/issues/4965
|
||||
"""
|
||||
|
||||
data = "Some random stuff to read from remove server.\n"
|
||||
|
||||
def response_handler(sock):
|
||||
req = consume_socket_content(sock, timeout=0.5)
|
||||
|
||||
# Send invalid chunked data (length mismatch)
|
||||
sock.send(
|
||||
b'HTTP/1.1 200 OK\r\n'
|
||||
b'Transfer-Encoding: chunked\r\n'
|
||||
b'\r\n2\r\n42\r\n8\r\n123\r\n' # 5 bytes missing
|
||||
)
|
||||
|
||||
close_server = threading.Event()
|
||||
server = Server(response_handler, wait_to_close_event=close_server)
|
||||
|
||||
with server as (host, port):
|
||||
url = 'http://{}:{}/path'.format(host, port)
|
||||
r = requests.post(url, stream=True)
|
||||
with pytest.raises(ChunkedEncodingError):
|
||||
r.content
|
||||
|
||||
# Access the bad response data again, I would expect the same
|
||||
# error again.
|
||||
|
||||
try:
|
||||
content = r.content
|
||||
except ChunkedEncodingError:
|
||||
pass # fine, same exception
|
||||
else:
|
||||
assert False, "error response has content: {0!r}".format(content)
|
||||
close_server.set()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user