Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Respect socket timeout #431

Merged
merged 3 commits into from May 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 9 additions & 2 deletions httpretty/core.py
Expand Up @@ -74,7 +74,7 @@
from errno import EAGAIN

class __internals__:
thread_timeout = 0 # https://github.com/gabrielfalcao/HTTPretty/issues/426
thread_timeout = 0.1 # https://github.com/gabrielfalcao/HTTPretty/issues/430
temp_files = []
threads = []

Expand Down Expand Up @@ -692,13 +692,20 @@ def makefile(self, mode='r', bufsize=-1):
target=self._entry.fill_filekind, args=(self.fd,)
)

# execute body callback and send http response in a
# thread, wait for thread to finish within the timeout
# set via socket.settimeout()
t.start()
if self.timeout == SOCKET_GLOBAL_DEFAULT_TIMEOUT:
timeout = get_default_thread_timeout()
else:
timeout = self.timeout
t.join(None)

# fake socket timeout error by checking if the thread
# finished in time.
t.join(timeout)
if t.is_alive():
# For more info check issue https://github.com/gabrielfalcao/HTTPretty/issues/430
raise socket.timeout(timeout)

return self.fd
Expand Down
54 changes: 54 additions & 0 deletions tests/bugfixes/nosetests/test_430_respect_timeout.py
@@ -0,0 +1,54 @@
# This test is based on @mariojonke snippet:
# https://github.com/gabrielfalcao/HTTPretty/issues/430
import time
from requests import Session
from requests.adapters import HTTPAdapter
from requests.exceptions import ReadTimeout

from threading import Event

from httpretty import httprettified
from httpretty import HTTPretty


def http(max_connections=1):
session = Session()
adapter = HTTPAdapter(
pool_connections=max_connections,
pool_maxsize=max_connections
)
session.mount('http://', adapter)
session.mount('https://', adapter)
return session



@httprettified(verbose=True, allow_net_connect=False)
def test_read_timeout():
"#430 httpretty should respect read timeout"
event = Event()
uri = "http://example.com"

# Given that I register a uri with a callback body that delays 10 seconds
wait_seconds = 10

def my_callback(request, url, headers):
event.wait(wait_seconds)
return 200, headers, "Received"

HTTPretty.register_uri(HTTPretty.GET, uri, body=my_callback)

# And I use a thread pool with 1 TCP connection max
max_connections = 1
request = http(max_connections)
started_at = time.time()
# When I make an HTTP request with a read timeout of 0.1 and an indefinite connect timeout
when_called = request.get.when.called_with(uri, timeout=(None, 0.1))

# Then the request should have raised a connection timeout
when_called.should.have.raised(ReadTimeout)

# And the total execution time should be less than 0.2 seconds
event.set()
total_time = time.time() - started_at
total_time.should.be.lower_than(0.2)