Skip to content
This repository was archived by the owner on Jan 13, 2021. It is now read-only.

Commit 75f25f7

Browse files
hyxbiaoLukasa
authored andcommitted
Add connection/read timeout for requests adapter (#342)
* Add connection/read timeout for requests adapter * Add connection/read timeout for requests adapter * update requests integration test * explicit timeout and more timeout tests * update timeout tests for py3 * update timeout tests for py3 * explicit timeout in send method and update timeout tests * add timeout in common/HTTPConnection and update timeout tests * move timeout in _h1/2_kwargs; add timeout for _create_tunnel funciton; add more tests
1 parent 021af18 commit 75f25f7

10 files changed

+333
-23
lines changed

hyper/common/connection.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,23 @@ def __init__(self,
5858
proxy_host=None,
5959
proxy_port=None,
6060
proxy_headers=None,
61+
timeout=None,
6162
**kwargs):
6263

6364
self._host = host
6465
self._port = port
6566
self._h1_kwargs = {
6667
'secure': secure, 'ssl_context': ssl_context,
6768
'proxy_host': proxy_host, 'proxy_port': proxy_port,
68-
'proxy_headers': proxy_headers, 'enable_push': enable_push
69+
'proxy_headers': proxy_headers, 'enable_push': enable_push,
70+
'timeout': timeout
6971
}
7072
self._h2_kwargs = {
7173
'window_manager': window_manager, 'enable_push': enable_push,
7274
'secure': secure, 'ssl_context': ssl_context,
7375
'proxy_host': proxy_host, 'proxy_port': proxy_port,
74-
'proxy_headers': proxy_headers
76+
'proxy_headers': proxy_headers,
77+
'timeout': timeout
7578
}
7679

7780
# Add any unexpected kwargs to both dictionaries.

hyper/contrib.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def __init__(self, *args, **kwargs):
3333
self.connections = {}
3434

3535
def get_connection(self, host, port, scheme, cert=None, verify=True,
36-
proxy=None):
36+
proxy=None, timeout=None):
3737
"""
3838
Gets an appropriate HTTP/2 connection object based on
3939
host/port/scheme/cert tuples.
@@ -77,13 +77,14 @@ def get_connection(self, host, port, scheme, cert=None, verify=True,
7777
secure=secure,
7878
ssl_context=ssl_context,
7979
proxy_host=proxy_netloc,
80-
proxy_headers=proxy_headers)
80+
proxy_headers=proxy_headers,
81+
timeout=timeout)
8182
self.connections[connection_key] = conn
8283

8384
return conn
8485

8586
def send(self, request, stream=False, cert=None, verify=True, proxies=None,
86-
**kwargs):
87+
timeout=None, **kwargs):
8788
"""
8889
Sends a HTTP message to the server.
8990
"""
@@ -98,7 +99,8 @@ def send(self, request, stream=False, cert=None, verify=True, proxies=None,
9899
parsed.scheme,
99100
cert=cert,
100101
verify=verify,
101-
proxy=proxy)
102+
proxy=proxy,
103+
timeout=timeout)
102104

103105
# Build the selector.
104106
selector = parsed.path

hyper/http11/connection.py

+21-6
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@
3939

4040

4141
def _create_tunnel(proxy_host, proxy_port, target_host, target_port,
42-
proxy_headers=None):
42+
proxy_headers=None, timeout=None):
4343
"""
4444
Sends CONNECT method to a proxy and returns a socket with established
4545
connection to the target.
4646
4747
:returns: socket
4848
"""
49-
conn = HTTP11Connection(proxy_host, proxy_port)
49+
conn = HTTP11Connection(proxy_host, proxy_port, timeout=timeout)
5050
conn.request('CONNECT', '%s:%d' % (target_host, target_port),
5151
headers=proxy_headers)
5252

@@ -101,7 +101,7 @@ class HTTP11Connection(object):
101101

102102
def __init__(self, host, port=None, secure=None, ssl_context=None,
103103
proxy_host=None, proxy_port=None, proxy_headers=None,
104-
**kwargs):
104+
timeout=None, **kwargs):
105105
if port is None:
106106
self.host, self.port = to_host_port_tuple(host, default_port=80)
107107
else:
@@ -150,6 +150,9 @@ def __init__(self, host, port=None, secure=None, ssl_context=None,
150150
#: the standard hyper parsing interface.
151151
self.parser = Parser()
152152

153+
# timeout
154+
self._timeout = timeout
155+
153156
def connect(self):
154157
"""
155158
Connect to the server specified when the object was created. This is a
@@ -159,23 +162,32 @@ def connect(self):
159162
"""
160163
if self._sock is None:
161164

165+
if isinstance(self._timeout, tuple):
166+
connect_timeout = self._timeout[0]
167+
read_timeout = self._timeout[1]
168+
else:
169+
connect_timeout = self._timeout
170+
read_timeout = self._timeout
171+
162172
if self.proxy_host and self.secure:
163173
# Send http CONNECT method to a proxy and acquire the socket
164174
sock = _create_tunnel(
165175
self.proxy_host,
166176
self.proxy_port,
167177
self.host,
168178
self.port,
169-
proxy_headers=self.proxy_headers
179+
proxy_headers=self.proxy_headers,
180+
timeout=self._timeout
170181
)
171182
elif self.proxy_host:
172183
# Simple http proxy
173184
sock = socket.create_connection(
174185
(self.proxy_host, self.proxy_port),
175-
5
186+
timeout=connect_timeout
176187
)
177188
else:
178-
sock = socket.create_connection((self.host, self.port), 5)
189+
sock = socket.create_connection((self.host, self.port),
190+
timeout=connect_timeout)
179191
proto = None
180192

181193
if self.secure:
@@ -184,6 +196,9 @@ def connect(self):
184196
log.debug("Selected protocol: %s", proto)
185197
sock = BufferedSocket(sock, self.network_buffer_size)
186198

199+
# Set read timeout
200+
sock.settimeout(read_timeout)
201+
187202
if proto not in ('http/1.1', None):
188203
raise TLSUpgrade(proto, sock)
189204

hyper/http20/connection.py

+20-4
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class HTTP20Connection(object):
102102
def __init__(self, host, port=None, secure=None, window_manager=None,
103103
enable_push=False, ssl_context=None, proxy_host=None,
104104
proxy_port=None, force_proto=None, proxy_headers=None,
105-
**kwargs):
105+
timeout=None, **kwargs):
106106
"""
107107
Creates an HTTP/2 connection to a specific server.
108108
"""
@@ -151,6 +151,9 @@ def __init__(self, host, port=None, secure=None, window_manager=None,
151151
self.__wm_class = window_manager or FlowControlManager
152152
self.__init_state()
153153

154+
# timeout
155+
self._timeout = timeout
156+
154157
return
155158

156159
def __init_state(self):
@@ -343,22 +346,32 @@ def connect(self):
343346
if self._sock is not None:
344347
return
345348

349+
if isinstance(self._timeout, tuple):
350+
connect_timeout = self._timeout[0]
351+
read_timeout = self._timeout[1]
352+
else:
353+
connect_timeout = self._timeout
354+
read_timeout = self._timeout
355+
346356
if self.proxy_host and self.secure:
347357
# Send http CONNECT method to a proxy and acquire the socket
348358
sock = _create_tunnel(
349359
self.proxy_host,
350360
self.proxy_port,
351361
self.host,
352362
self.port,
353-
proxy_headers=self.proxy_headers
363+
proxy_headers=self.proxy_headers,
364+
timeout=self._timeout
354365
)
355366
elif self.proxy_host:
356367
# Simple http proxy
357368
sock = socket.create_connection(
358-
(self.proxy_host, self.proxy_port)
369+
(self.proxy_host, self.proxy_port),
370+
timeout=connect_timeout
359371
)
360372
else:
361-
sock = socket.create_connection((self.host, self.port))
373+
sock = socket.create_connection((self.host, self.port),
374+
timeout=connect_timeout)
362375

363376
if self.secure:
364377
sock, proto = wrap_socket(sock, self.host, self.ssl_context,
@@ -374,6 +387,9 @@ def connect(self):
374387

375388
self._sock = BufferedSocket(sock, self.network_buffer_size)
376389

390+
# Set read timeout
391+
self._sock.settimeout(read_timeout)
392+
377393
self._send_preamble()
378394

379395
def _connect_upgrade(self, sock):

test/server.py

+10-5
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,13 @@ class SocketLevelTest(object):
108108
A test-class that defines a few helper methods for running socket-level
109109
tests.
110110
"""
111-
def set_up(self, secure=True, proxy=False):
111+
def set_up(self, secure=True, proxy=False, timeout=None):
112112
self.host = None
113113
self.port = None
114114
self.socket_security = SocketSecuritySetting(secure)
115115
self.proxy = proxy
116116
self.server_thread = None
117+
self.timeout = timeout
117118

118119
def _start_server(self, socket_handler):
119120
"""
@@ -146,18 +147,22 @@ def secure(self, value):
146147
def get_connection(self):
147148
if self.h2:
148149
if not self.proxy:
149-
return HTTP20Connection(self.host, self.port, self.secure)
150+
return HTTP20Connection(self.host, self.port, self.secure,
151+
timeout=self.timeout)
150152
else:
151153
return HTTP20Connection('http2bin.org', secure=self.secure,
152154
proxy_host=self.host,
153-
proxy_port=self.port)
155+
proxy_port=self.port,
156+
timeout=self.timeout)
154157
else:
155158
if not self.proxy:
156-
return HTTP11Connection(self.host, self.port, self.secure)
159+
return HTTP11Connection(self.host, self.port, self.secure,
160+
timeout=self.timeout)
157161
else:
158162
return HTTP11Connection('httpbin.org', secure=self.secure,
159163
proxy_host=self.host,
160-
proxy_port=self.port)
164+
proxy_port=self.port,
165+
timeout=self.timeout)
161166

162167
def get_encoder(self):
163168
"""

test/test_abstraction.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def test_h1_kwargs(self):
1010
c = HTTPConnection(
1111
'test', 443, secure=False, window_manager=True, enable_push=True,
1212
ssl_context=False, proxy_host=False, proxy_port=False,
13-
proxy_headers=False, other_kwarg=True
13+
proxy_headers=False, other_kwarg=True, timeout=5
1414
)
1515

1616
assert c._h1_kwargs == {
@@ -21,13 +21,14 @@ def test_h1_kwargs(self):
2121
'proxy_headers': False,
2222
'other_kwarg': True,
2323
'enable_push': True,
24+
'timeout': 5,
2425
}
2526

2627
def test_h2_kwargs(self):
2728
c = HTTPConnection(
2829
'test', 443, secure=False, window_manager=True, enable_push=True,
2930
ssl_context=True, proxy_host=False, proxy_port=False,
30-
proxy_headers=False, other_kwarg=True
31+
proxy_headers=False, other_kwarg=True, timeout=(10, 30)
3132
)
3233

3334
assert c._h2_kwargs == {
@@ -39,6 +40,7 @@ def test_h2_kwargs(self):
3940
'proxy_port': False,
4041
'proxy_headers': False,
4142
'other_kwarg': True,
43+
'timeout': (10, 30),
4244
}
4345

4446
def test_tls_upgrade(self, monkeypatch):

test/test_http11.py

+10
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,16 @@ def test_initialization_with_ipv6_addresses_proxy_inline_port(self):
110110
assert c.proxy_host == 'ffff:aaaa::1'
111111
assert c.proxy_port == 8443
112112

113+
def test_initialization_timeout(self):
114+
c = HTTP11Connection('httpbin.org', timeout=30)
115+
116+
assert c._timeout == 30
117+
118+
def test_initialization_tuple_timeout(self):
119+
c = HTTP11Connection('httpbin.org', timeout=(5, 60))
120+
121+
assert c._timeout == (5, 60)
122+
113123
def test_basic_request(self):
114124
c = HTTP11Connection('httpbin.org')
115125
c._sock = sock = DummySocket()

test/test_hyper.py

+10
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ def test_connection_version(self):
9898
c = HTTP20Connection('www.google.com')
9999
assert c.version is HTTPVersion.http20
100100

101+
def test_connection_timeout(self):
102+
c = HTTP20Connection('httpbin.org', timeout=30)
103+
104+
assert c._timeout == 30
105+
106+
def test_connection_tuple_timeout(self):
107+
c = HTTP20Connection('httpbin.org', timeout=(5, 60))
108+
109+
assert c._timeout == (5, 60)
110+
101111
def test_ping(self, frame_buffer):
102112
def data_callback(chunk, **kwargs):
103113
frame_buffer.add_data(chunk)

0 commit comments

Comments
 (0)