aboutsummaryrefslogtreecommitdiff
path: root/test/with_dummyserver/test_socketlevel.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/with_dummyserver/test_socketlevel.py')
-rw-r--r--test/with_dummyserver/test_socketlevel.py71
1 files changed, 71 insertions, 0 deletions
diff --git a/test/with_dummyserver/test_socketlevel.py b/test/with_dummyserver/test_socketlevel.py
index d09002b..1e6113f 100644
--- a/test/with_dummyserver/test_socketlevel.py
+++ b/test/with_dummyserver/test_socketlevel.py
@@ -30,6 +30,7 @@ except ImportError:
class MimeToolMessage(object):
pass
from threading import Event
+import select
import socket
import ssl
@@ -366,6 +367,72 @@ class TestSocketClosing(SocketDummyServerTestCase):
self.assertRaises(ProtocolError, response.read)
self.assertEqual(poolsize, pool.pool.qsize())
+ def test_connection_closed_on_read_timeout_preload_false(self):
+ timed_out = Event()
+
+ def socket_handler(listener):
+ sock = listener.accept()[0]
+
+ # Consume request
+ buf = b''
+ while not buf.endswith(b'\r\n\r\n'):
+ buf = sock.recv(65535)
+
+ # Send partial chunked response and then hang.
+ sock.send((
+ 'HTTP/1.1 200 OK\r\n'
+ 'Content-Type: text/plain\r\n'
+ 'Transfer-Encoding: chunked\r\n'
+ '\r\n'
+ '8\r\n'
+ '12345678\r\n').encode('utf-8')
+ )
+ timed_out.wait(5)
+
+ # Expect a new request, but keep hold of the old socket to avoid
+ # leaking it. Because we don't want to hang this thread, we
+ # actually use select.select to confirm that a new request is
+ # coming in: this lets us time the thread out.
+ rlist, _, _ = select.select([listener], [], [], 1)
+ assert rlist
+ new_sock = listener.accept()[0]
+
+ # Consume request
+ buf = b''
+ while not buf.endswith(b'\r\n\r\n'):
+ buf = new_sock.recv(65535)
+
+ # Send complete chunked response.
+ new_sock.send((
+ 'HTTP/1.1 200 OK\r\n'
+ 'Content-Type: text/plain\r\n'
+ 'Transfer-Encoding: chunked\r\n'
+ '\r\n'
+ '8\r\n'
+ '12345678\r\n'
+ '0\r\n\r\n').encode('utf-8')
+ )
+
+ new_sock.close()
+ sock.close()
+
+ self._start_server(socket_handler)
+ with HTTPConnectionPool(self.host, self.port) as pool:
+ # First request should fail.
+ response = pool.urlopen('GET', '/', retries=0,
+ preload_content=False,
+ timeout=Timeout(connect=1, read=0.001))
+ try:
+ self.assertRaises(ReadTimeoutError, response.read)
+ finally:
+ timed_out.set()
+
+ # Second should succeed.
+ response = pool.urlopen('GET', '/', retries=0,
+ preload_content=False,
+ timeout=Timeout(connect=1, read=0.1))
+ self.assertEqual(len(response.read()), 8)
+
class TestProxyManager(SocketDummyServerTestCase):
@@ -437,6 +504,8 @@ class TestProxyManager(SocketDummyServerTestCase):
self.assertTrue(b'For The Proxy: YEAH!\r\n' in r.data)
def test_retries(self):
+ close_event = Event()
+
def echo_socket_handler(listener):
sock = listener.accept()[0]
# First request, which should fail
@@ -455,6 +524,7 @@ class TestProxyManager(SocketDummyServerTestCase):
'\r\n'
'%s' % (len(buf), buf.decode('utf-8'))).encode('utf-8'))
sock.close()
+ close_event.set()
self._start_server(echo_socket_handler)
base_url = 'http://%s:%d' % (self.host, self.port)
@@ -466,6 +536,7 @@ class TestProxyManager(SocketDummyServerTestCase):
assert_same_host=False, retries=1)
self.assertEqual(r.status, 200)
+ close_event.wait(timeout=1)
self.assertRaises(ProxyError, conn.urlopen, 'GET',
'http://www.google.com',
assert_same_host=False, retries=False)