summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorSergey Shepelev <temotor@gmail.com>2013-02-22 14:19:48 +0400
committerSergey Shepelev <temotor@gmail.com>2013-02-22 14:19:53 +0400
commite06b8698e7e080aee9b4542c1546265eab2b1f95 (patch)
tree5c43b9fe8d7ef652318bb55d05b6559727039d52 /tests
parente0b30d4f77d56db96fc7fdba75bc5d1a55326260 (diff)
downloadeventlet-e06b8698e7e080aee9b4542c1546265eab2b1f95.tar.gz
tests: wsgi: close socket on error in the middle of chunked response
http://rhodesmill.org/brandon/2013/chunked-wsgi/
Diffstat (limited to 'tests')
-rw-r--r--tests/wsgi_test.py49
1 files changed, 48 insertions, 1 deletions
diff --git a/tests/wsgi_test.py b/tests/wsgi_test.py
index 4ccdc4b..d03c061 100644
--- a/tests/wsgi_test.py
+++ b/tests/wsgi_test.py
@@ -43,12 +43,35 @@ def chunked_app(env, start_response):
yield "chunked"
+def chunked_fail_app(environ, start_response):
+ """http://rhodesmill.org/brandon/2013/chunked-wsgi/
+ """
+ headers = [('Content-Type', 'text/plain')]
+ start_response('200 OK', headers)
+
+ # We start streaming data just fine.
+ yield "The dwarves of yore made mighty spells,"
+ yield "While hammers fell like ringing bells"
+
+ # Then the back-end fails!
+ try:
+ 1 / 0
+ except Exception:
+ start_response('500 Error', headers, sys.exc_info())
+ return
+
+ # So rest of the response data is not available.
+ yield "In places deep, where dark things sleep,"
+ yield "In hollow halls beneath the fells."
+
+
def big_chunks(env, start_response):
start_response('200 OK', [('Content-type', 'text/plain')])
line = 'a' * 8192
for x in range(10):
yield line
+
def use_write(env, start_response):
if env['PATH_INFO'] == '/a':
write = start_response('200 OK', [('Content-type', 'text/plain'),
@@ -59,6 +82,7 @@ def use_write(env, start_response):
write('abcde')
return []
+
def chunked_post(env, start_response):
start_response('200 OK', [('Content-type', 'text/plain')])
if env['PATH_INFO'] == '/a':
@@ -68,10 +92,12 @@ def chunked_post(env, start_response):
elif env['PATH_INFO'] == '/c':
return [x for x in iter(lambda: env['wsgi.input'].read(1), '')]
+
def already_handled(env, start_response):
start_response('200 OK', [('Content-type', 'text/plain')])
return wsgi.ALREADY_HANDLED
+
class Site(object):
def __init__(self):
self.application = hello_world
@@ -79,6 +105,7 @@ class Site(object):
def __call__(self, env, start_response):
return self.application(env, start_response)
+
class IterableApp(object):
def __init__(self, send_start_response=False, return_val=wsgi.ALREADY_HANDLED):
@@ -92,6 +119,7 @@ class IterableApp(object):
start_response('200 OK', [('Content-type', 'text/plain')])
return self.return_val
+
class IterableSite(Site):
def __call__(self, env, start_response):
it = self.application(env, start_response)
@@ -99,7 +127,6 @@ class IterableSite(Site):
yield i
-
CONTENT_LENGTH = 'content-length'
@@ -111,6 +138,7 @@ Content-length: 11
hello world
"""
+
class ConnectionClosed(Exception):
pass
@@ -758,6 +786,25 @@ class TestHttpd(_TestBase):
self.assertNotEqual(headers.get('transfer-encoding'), 'chunked')
self.assertEquals(body, "thisischunked")
+ def test_error_in_chunked_closes_connection(self):
+ # From http://rhodesmill.org/brandon/2013/chunked-wsgi/
+ greenthread.kill(self.killer)
+ eventlet.sleep(0)
+ self.spawn_server(minimum_chunk_size=1)
+
+ self.site.application = chunked_fail_app
+ sock = eventlet.connect(('localhost', self.port))
+
+ sock.sendall('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
+
+ response_line, headers, body = read_http(sock)
+ self.assertEqual(response_line, 'HTTP/1.1 200 OK\r\n')
+ self.assertEqual(headers.get('transfer-encoding'), 'chunked')
+ self.assertEqual(body, '27\r\nThe dwarves of yore made mighty spells,\r\n25\r\nWhile hammers fell like ringing bells\r\n')
+
+ # verify that socket is closed by server
+ self.assertEqual(sock.recv(1), '')
+
def test_026_http_10_nokeepalive(self):
# verify that if an http/1.0 client sends connection: keep-alive
# and the server doesn't accept keep-alives, we close the connection