Add connection/read timeout for requests adapter#342
Add connection/read timeout for requests adapter#342Lukasa merged 9 commits intopython-hyper:developmentfrom
Conversation
Lukasa
left a comment
There was a problem hiding this comment.
Thanks for this! I've left a note inline. It'd also be really useful to actually add tests for the timeout functionality that we're implicitly also adding to our lower-level classes.
hyper/contrib.py
Outdated
| proxy_host=proxy_netloc, | ||
| proxy_headers=proxy_headers) | ||
| proxy_headers=proxy_headers, | ||
| **kwargs) |
There was a problem hiding this comment.
We shouldn't be sending arbitrary kwargs from Requests to hyper: there's no reason to assume that those kwargs will match in any sensible way. We should aim to be explicit here.
There was a problem hiding this comment.
OK, I had change to explicit timeout and add more timeout tests
KostyaEsmukov
left a comment
There was a problem hiding this comment.
Thanks for this! I was going to work on timeouts this week but you have started earlier :)
I have one more note on this: the _create_tunnel function of http11 module should respect the timeout too.
PS: Related issue: #187
hyper/http11/connection.py
Outdated
| self.parser = Parser() | ||
|
|
||
| # timeout | ||
| timeout = kwargs.get('timeout') |
There was a problem hiding this comment.
timeout should be optional. I think it should be None - that means no timeout.
There was a problem hiding this comment.
Yes, timeout is optional and default None, is equivalent to socket.setblocking(1)
|
timeout is optional, the default value is None, means that it will block connection/read, it is the same as request/adapters.py: it also can set timeout to socket._GLOBAL_DEFAULT_TIMEOUT |
hyper/contrib.py
Outdated
| proxy = prepend_scheme_if_needed(proxy, 'http') | ||
|
|
||
| parsed = urlparse(request.url) | ||
| timeout = kwargs.get('timeout') |
There was a problem hiding this comment.
Let's just add timeout to our list of kwargs.
test/test_integration.py
Outdated
| conn = self.get_connection() | ||
| try: | ||
| conn.connect() | ||
| assert False |
There was a problem hiding this comment.
This should be pytest.fail, and generally should go in an else block.
test/test_integration.py
Outdated
|
|
||
| # Wait for request | ||
| req_event.wait(5) | ||
| # Now, send the headers for the response. This response has no body |
test/test_integration.py
Outdated
| time.sleep(1) | ||
|
|
||
| # Now, send the headers for the response. This response has no body | ||
| f = build_headers_frame( |
There was a problem hiding this comment.
We never actually need to send this, and doing so could cause exceptions, so let's not send any data here.
test/test_integration.py
Outdated
|
|
||
| try: | ||
| conn.get_response() | ||
| assert False |
There was a problem hiding this comment.
Same note about pytest.fail and else blocks.
|
|
||
| send_event.wait(5) | ||
|
|
||
| assert data[0].startswith(b'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n') |
There was a problem hiding this comment.
How can this possibly pass? If the connection fails, we're never going to see this data.
There was a problem hiding this comment.
default timeout None will block connect, so it will connect sucess and go on
test/test_integration.py
Outdated
|
|
||
| def socket_handler(listener): | ||
| time.sleep(1) | ||
| sock = listener.accept()[0] |
There was a problem hiding this comment.
No point calling accept: it'll usually fail, and throw exceptions, which we don't want.
There was a problem hiding this comment.
if connection timeout smaller than 1s, it will throw timeout exception, in this test connection timeout is set to 0.5, so it will throw exception as expect
There was a problem hiding this comment.
Right, but this exception is not caught, meaning it'll be logged and generally treated badly. We shouldn't do anything in the background thread that we know will fail, and accept will fail here.
There was a problem hiding this comment.
got it, I just updated
| def __init__(self, host, port=None, secure=None, ssl_context=None, | ||
| proxy_host=None, proxy_port=None, proxy_headers=None, | ||
| **kwargs): | ||
| timeout=None, **kwargs): |
There was a problem hiding this comment.
We should probably add this to the common HTTPConnection object as well.
|
|
||
| assert c._connect_timeout == 5 | ||
| assert c._read_timeout == 60 | ||
|
|
There was a problem hiding this comment.
We need these tests for HTTP/2 as well.
There was a problem hiding this comment.
ok,I add this in test/test_hyper.py
test/test_integration.py
Outdated
|
|
||
| def socket_handler(listener): | ||
| time.sleep(1) | ||
| sock = listener.accept()[0] |
There was a problem hiding this comment.
Right, but this exception is not caught, meaning it'll be logged and generally treated badly. We shouldn't do anything in the background thread that we know will fail, and accept will fail here.
test/test_integration.py
Outdated
| # assert 'timed out' in e.message | ||
| pass | ||
| else: | ||
| assert False |
There was a problem hiding this comment.
sorry, i'm not familiar with pytest before, i replace it with pytest.raises or pytest.fail
There was a problem hiding this comment.
pytest.raises is the best thing to do if you don't plan to do anything in the except block.
test/test_integration.py
Outdated
| except (SocketTimeout, ssl.SSLError): | ||
| # Py2 raises this as a BaseSSLError, | ||
| # Py3 raises it as socket timeout. | ||
| # assert 'timed out' in e.message |
There was a problem hiding this comment.
Probably we don't need the assert statement in the comment?
test/test_integration.py
Outdated
| # assert 'timed out' in e.message | ||
| pass | ||
| else: | ||
| assert False |
test/test_integration.py
Outdated
| except (SocketTimeout, ssl.SSLError): | ||
| # Py2 raises this as a BaseSSLError, | ||
| # Py3 raises it as socket timeout. | ||
| assert False |
|
|
||
| send_event.wait(5) | ||
|
|
||
| assert data[0].startswith(b'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n') |
hyper/common/connection.py
Outdated
| self._h1_kwargs.update(kwargs) | ||
| self._h2_kwargs.update(kwargs) | ||
|
|
||
| self._timeout = timeout |
There was a problem hiding this comment.
This should go into _h1_kwargs and _h2_kwargs: it'll also need associated tests.
|
update information: |
[+] Add connection/read timeout for requests adapter, we can use like this: