Issue #16220: wsgiref now always calls close() on an iterable response.
Patch by Brent Tubbs.
This commit is contained in:
commit
d3a3e640b6
|
@ -41,9 +41,6 @@ class MockHandler(WSGIRequestHandler):
|
|||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def hello_app(environ,start_response):
|
||||
start_response("200 OK", [
|
||||
('Content-Type','text/plain'),
|
||||
|
@ -65,28 +62,6 @@ def run_amock(app=hello_app, data=b"GET / HTTP/1.0\n\n"):
|
|||
|
||||
return out.getvalue(), err.getvalue()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def compare_generic_iter(make_it,match):
|
||||
"""Utility to compare a generic 2.1/2.2+ iterator with an iterable
|
||||
|
||||
|
@ -124,10 +99,6 @@ def compare_generic_iter(make_it,match):
|
|||
raise AssertionError("Too many items from .__next__()", it)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class IntegrationTests(TestCase):
|
||||
|
||||
def check_hello(self, out, has_length=True):
|
||||
|
@ -201,8 +172,6 @@ class IntegrationTests(TestCase):
|
|||
out)
|
||||
|
||||
|
||||
|
||||
|
||||
class UtilityTests(TestCase):
|
||||
|
||||
def checkShift(self,sn_in,pi_in,part,sn_out,pi_out):
|
||||
|
@ -241,11 +210,6 @@ class UtilityTests(TestCase):
|
|||
util.setup_testing_defaults(kw)
|
||||
self.assertEqual(util.request_uri(kw,query),uri)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def checkFW(self,text,size,match):
|
||||
|
||||
def make_it(text=text,size=size):
|
||||
|
@ -264,7 +228,6 @@ class UtilityTests(TestCase):
|
|||
it.close()
|
||||
self.assertTrue(it.filelike.closed)
|
||||
|
||||
|
||||
def testSimpleShifts(self):
|
||||
self.checkShift('','/', '', '/', '')
|
||||
self.checkShift('','/x', 'x', '/x', '')
|
||||
|
@ -272,7 +235,6 @@ class UtilityTests(TestCase):
|
|||
self.checkShift('/a','/x/y', 'x', '/a/x', '/y')
|
||||
self.checkShift('/a','/x/', 'x', '/a/x', '/')
|
||||
|
||||
|
||||
def testNormalizedShifts(self):
|
||||
self.checkShift('/a/b', '/../y', '..', '/a', '/y')
|
||||
self.checkShift('', '/../y', '..', '', '/y')
|
||||
|
@ -286,7 +248,6 @@ class UtilityTests(TestCase):
|
|||
self.checkShift('/a/b', '/x//', 'x', '/a/b/x', '/')
|
||||
self.checkShift('/a/b', '/.', None, '/a/b', '')
|
||||
|
||||
|
||||
def testDefaults(self):
|
||||
for key, value in [
|
||||
('SERVER_NAME','127.0.0.1'),
|
||||
|
@ -306,7 +267,6 @@ class UtilityTests(TestCase):
|
|||
]:
|
||||
self.checkDefault(key,value)
|
||||
|
||||
|
||||
def testCrossDefaults(self):
|
||||
self.checkCrossDefault('HTTP_HOST',"foo.bar",SERVER_NAME="foo.bar")
|
||||
self.checkCrossDefault('wsgi.url_scheme',"https",HTTPS="on")
|
||||
|
@ -316,7 +276,6 @@ class UtilityTests(TestCase):
|
|||
self.checkCrossDefault('SERVER_PORT',"80",HTTPS="foo")
|
||||
self.checkCrossDefault('SERVER_PORT',"443",HTTPS="on")
|
||||
|
||||
|
||||
def testGuessScheme(self):
|
||||
self.assertEqual(util.guess_scheme({}), "http")
|
||||
self.assertEqual(util.guess_scheme({'HTTPS':"foo"}), "http")
|
||||
|
@ -324,10 +283,6 @@ class UtilityTests(TestCase):
|
|||
self.assertEqual(util.guess_scheme({'HTTPS':"yes"}), "https")
|
||||
self.assertEqual(util.guess_scheme({'HTTPS':"1"}), "https")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def testAppURIs(self):
|
||||
self.checkAppURI("http://127.0.0.1/")
|
||||
self.checkAppURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam")
|
||||
|
@ -452,15 +407,6 @@ class TestHandler(ErrorHandler):
|
|||
raise # for testing, we want to see what's happening
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class HandlerTests(TestCase):
|
||||
|
||||
def checkEnvironAttrs(self, handler):
|
||||
|
@ -501,7 +447,6 @@ class HandlerTests(TestCase):
|
|||
h=TestHandler(); h.setup_environ()
|
||||
self.assertEqual(h.environ['wsgi.url_scheme'],'http')
|
||||
|
||||
|
||||
def testAbstractMethods(self):
|
||||
h = BaseHandler()
|
||||
for name in [
|
||||
|
@ -510,7 +455,6 @@ class HandlerTests(TestCase):
|
|||
self.assertRaises(NotImplementedError, getattr(h,name))
|
||||
self.assertRaises(NotImplementedError, h._write, "test")
|
||||
|
||||
|
||||
def testContentLength(self):
|
||||
# Demo one reason iteration is better than write()... ;)
|
||||
|
||||
|
@ -602,7 +546,6 @@ class HandlerTests(TestCase):
|
|||
"\r\n".encode("iso-8859-1")+MSG))
|
||||
self.assertIn("AssertionError", h.stderr.getvalue())
|
||||
|
||||
|
||||
def testHeaderFormats(self):
|
||||
|
||||
def non_error_app(e,s):
|
||||
|
@ -662,40 +605,27 @@ class HandlerTests(TestCase):
|
|||
b"data",
|
||||
h.stdout.getvalue())
|
||||
|
||||
# This epilogue is needed for compatibility with the Python 2.5 regrtest module
|
||||
def testCloseOnError(self):
|
||||
side_effects = {'close_called': False}
|
||||
MSG = b"Some output has been sent"
|
||||
def error_app(e,s):
|
||||
s("200 OK",[])(MSG)
|
||||
class CrashyIterable(object):
|
||||
def __iter__(self):
|
||||
while True:
|
||||
yield b'blah'
|
||||
raise AssertionError("This should be caught by handler")
|
||||
def close(self):
|
||||
side_effects['close_called'] = True
|
||||
return CrashyIterable()
|
||||
|
||||
h = ErrorHandler()
|
||||
h.run(error_app)
|
||||
self.assertEqual(side_effects['close_called'], True)
|
||||
|
||||
|
||||
def test_main():
|
||||
support.run_unittest(__name__)
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# the above lines intentionally left blank
|
||||
|
|
|
@ -174,11 +174,13 @@ class BaseHandler:
|
|||
in the event loop to iterate over the data, and to call
|
||||
'self.close()' once the response is finished.
|
||||
"""
|
||||
if not self.result_is_file() or not self.sendfile():
|
||||
for data in self.result:
|
||||
self.write(data)
|
||||
self.finish_content()
|
||||
self.close()
|
||||
try:
|
||||
if not self.result_is_file() or not self.sendfile():
|
||||
for data in self.result:
|
||||
self.write(data)
|
||||
self.finish_content()
|
||||
finally:
|
||||
self.close()
|
||||
|
||||
|
||||
def get_scheme(self):
|
||||
|
|
|
@ -1178,6 +1178,7 @@ Alberto Trevino
|
|||
Matthias Troffaes
|
||||
John Tromp
|
||||
Jason Trowbridge
|
||||
Brent Tubbs
|
||||
Anthony Tuininga
|
||||
Erno Tukia
|
||||
David Turner
|
||||
|
|
Loading…
Reference in New Issue