Skip to content

Commit

Permalink
Merge pull request #54 from tannewt/test_read_before_response
Browse files Browse the repository at this point in the history
Don't trust send works. Do one recv before creating Response
  • Loading branch information
brentru authored Nov 25, 2020
2 parents 531e845 + af04194 commit 5390215
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 8 deletions.
26 changes: 22 additions & 4 deletions adafruit_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ class _SendFailed(Exception):
"""Custom exception to abort sending a request."""


class OutOfRetries(Exception):
"""Raised when requests has retried to make a request unsuccessfully."""


class Response:
"""The response from a request, contains all the headers/content"""

Expand Down Expand Up @@ -570,13 +574,27 @@ def request(
while retry_count < 2:
retry_count += 1
socket = self._get_socket(host, port, proto, timeout=timeout)
ok = True
try:
self._send_request(socket, host, method, path, headers, data, json)
break
except _SendFailed:
self._close_socket(socket)
if retry_count > 1:
raise
ok = False
if ok:
# Read the H of "HTTP/1.1" to make sure the socket is alive. send can appear to work
# even when the socket is closed.
if hasattr(socket, "recv"):
result = socket.recv(1)
else:
result = bytearray(1)
socket.recv_into(result)
if result == b"H":
# Things seem to be ok so break with socket set.
break
self._close_socket(socket)
socket = None

if not socket:
raise OutOfRetries()

resp = Response(socket, self) # our response
if "location" in resp.headers and 300 <= resp.status_code <= 399:
Expand Down
13 changes: 9 additions & 4 deletions tests/legacy_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,13 @@ def test_second_send_fails():
def test_first_read_fails():
mocket.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
sock = mocket.Mocket(b"")
sock2 = mocket.Mocket(headers + encoded)
mocket.socket.call_count = 0 # Reset call count
mocket.socket.side_effect = [sock]
mocket.socket.side_effect = [sock, sock2]

adafruit_requests.set_socket(mocket, mocket.interface)

with pytest.raises(RuntimeError):
r = adafruit_requests.get("http://" + host + "/testwifi/index.html")
r = adafruit_requests.get("http://" + host + "/testwifi/index.html")

sock.send.assert_has_calls(
[mock.call(b"testwifi/index.html"),]
Expand All @@ -131,10 +131,15 @@ def test_first_read_fails():
[mock.call(b"Host: "), mock.call(host.encode("utf-8")), mock.call(b"\r\n"),]
)

sock2.send.assert_has_calls(
[mock.call(b"Host: "), mock.call(host.encode("utf-8")), mock.call(b"\r\n"),]
)

sock.connect.assert_called_once_with((ip, 80))
sock2.connect.assert_called_once_with((ip, 80))
# Make sure that the socket is closed after the first receive fails.
sock.close.assert_called_once()
assert mocket.socket.call_count == 1
assert mocket.socket.call_count == 2


def test_second_tls_connect_fails():
Expand Down
31 changes: 31 additions & 0 deletions tests/reuse_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,34 @@ def test_second_send_fails():
sock.close.assert_called_once()
assert sock2.close.call_count == 0
assert pool.socket.call_count == 2


def test_second_send_lies_recv_fails():
pool = mocket.MocketPool()
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
sock = mocket.Mocket(response)
sock2 = mocket.Mocket(response)
pool.socket.side_effect = [sock, sock2]

ssl = mocket.SSLContext()

s = adafruit_requests.Session(pool, ssl)
r = s.get("https://" + host + path)

sock.send.assert_has_calls(
[mock.call(b"testwifi/index.html"),]
)

sock.send.assert_has_calls(
[mock.call(b"Host: "), mock.call(b"wifitest.adafruit.com"), mock.call(b"\r\n"),]
)
assert r.text == str(text, "utf-8")

s.get("https://" + host + path + "2")

sock.connect.assert_called_once_with((host, 443))
sock2.connect.assert_called_once_with((host, 443))
# Make sure that the socket is closed after send fails.
sock.close.assert_called_once()
assert sock2.close.call_count == 0
assert pool.socket.call_count == 2

0 comments on commit 5390215

Please sign in to comment.