Compare commits

...

2 Commits

Author SHA1 Message Date
coletdjnz
02e06c0727
misc cleanup 2023-11-25 13:43:52 +13:00
coletdjnz
b887020dae
set LOW_SPEED_LIMIT and LOW_SPEED_TIME for a read timeout 2023-11-25 12:43:34 +13:00
2 changed files with 36 additions and 4 deletions

View File

@ -517,13 +517,13 @@ class TestHTTPRequestHandler(TestRequestHandlerBase):
assert b'test3: test3' in data
@pytest.mark.parametrize('handler', ['Urllib', 'Requests', 'CurlCFFI'], indirect=True)
def test_timeout(self, handler):
def test_read_timeout(self, handler):
with handler() as rh:
# Default timeout is 20 seconds, so this should go through
validate_and_send(
rh, Request(f'http://127.0.0.1:{self.http_port}/timeout_3'))
rh, Request(f'http://127.0.0.1:{self.http_port}/timeout_1'))
with handler(timeout=0.5) as rh:
with handler(timeout=0.01) as rh:
with pytest.raises(TransportError):
validate_and_send(
rh, Request(f'http://127.0.0.1:{self.http_port}/timeout_1'))
@ -532,6 +532,25 @@ class TestHTTPRequestHandler(TestRequestHandlerBase):
validate_and_send(
rh, Request(f'http://127.0.0.1:{self.http_port}/timeout_1', extensions={'timeout': 4}))
@pytest.mark.parametrize('handler', ['Urllib', 'Requests', 'CurlCFFI'], indirect=True)
def test_connect_timeout(self, handler):
# nothing should be listening on this port
connect_timeout_url = 'http://10.255.255.255'
with handler(timeout=0.01) as rh:
now = time.time()
with pytest.raises(TransportError):
validate_and_send(
rh, Request(connect_timeout_url))
assert 0.01 <= time.time() - now < 20
with handler() as rh:
with pytest.raises(TransportError):
# Per request timeout, should override handler timeout
now = time.time()
validate_and_send(
rh, Request(connect_timeout_url, extensions={'timeout': 0.01}))
assert 0.01 <= time.time() - now < 20
@pytest.mark.parametrize('handler', ['Urllib', 'Requests', 'CurlCFFI'], indirect=True)
def test_source_address(self, handler):
source_address = f'127.0.0.{random.randint(5, 255)}'

View File

@ -1,4 +1,5 @@
import io
import math
from ._helper import InstanceStoreMixin, select_proxy
from .common import (
@ -153,6 +154,18 @@ class CurlCFFIRH(ImpersonateRequestHandler, InstanceStoreMixin):
session.curl.setopt(CurlOpt.SSLKEY, client_certificate_key.encode())
if client_certificate_password:
session.curl.setopt(CurlOpt.KEYPASSWD, client_certificate_password.encode())
timeout = float(request.extensions.get('timeout') or self.timeout)
# set CURLOPT_LOW_SPEED_LIMIT and CURLOPT_LOW_SPEED_TIME to act as a read timeout. [1]
# curl_cffi does not currently do this. [2]
# Note: CURLOPT_LOW_SPEED_TIME is in seconds, so we need to round up to the nearest second. [3]
# [1] https://unix.stackexchange.com/a/305311
# [2] https://github.com/yifeikong/curl_cffi/issues/156
# [3] https://curl.se/libcurl/c/CURLOPT_LOW_SPEED_TIME.html
session.curl.setopt(CurlOpt.LOW_SPEED_LIMIT, 1) # 1 byte per second
session.curl.setopt(CurlOpt.LOW_SPEED_TIME, math.ceil(timeout))
try:
curl_response = session.request(
method=request.method,
@ -161,7 +174,7 @@ class CurlCFFIRH(ImpersonateRequestHandler, InstanceStoreMixin):
data=request.data,
verify=self.verify,
max_redirects=5,
timeout=request.extensions.get('timeout') or self.timeout,
timeout=timeout,
impersonate=self._get_mapped_target(request),
interface=self.source_address,
stream=True