Kaydet (Commit) d3a3e640 authored tarafından Antoine Pitrou's avatar Antoine Pitrou

Issue #16220: wsgiref now always calls close() on an iterable response.

Patch by Brent Tubbs.
...@@ -41,9 +41,6 @@ class MockHandler(WSGIRequestHandler): ...@@ -41,9 +41,6 @@ class MockHandler(WSGIRequestHandler):
pass pass
def hello_app(environ,start_response): def hello_app(environ,start_response):
start_response("200 OK", [ start_response("200 OK", [
('Content-Type','text/plain'), ('Content-Type','text/plain'),
...@@ -65,28 +62,6 @@ def run_amock(app=hello_app, data=b"GET / HTTP/1.0\n\n"): ...@@ -65,28 +62,6 @@ def run_amock(app=hello_app, data=b"GET / HTTP/1.0\n\n"):
return out.getvalue(), err.getvalue() return out.getvalue(), err.getvalue()
def compare_generic_iter(make_it,match): def compare_generic_iter(make_it,match):
"""Utility to compare a generic 2.1/2.2+ iterator with an iterable """Utility to compare a generic 2.1/2.2+ iterator with an iterable
...@@ -124,10 +99,6 @@ def compare_generic_iter(make_it,match): ...@@ -124,10 +99,6 @@ def compare_generic_iter(make_it,match):
raise AssertionError("Too many items from .__next__()", it) raise AssertionError("Too many items from .__next__()", it)
class IntegrationTests(TestCase): class IntegrationTests(TestCase):
def check_hello(self, out, has_length=True): def check_hello(self, out, has_length=True):
...@@ -201,8 +172,6 @@ class IntegrationTests(TestCase): ...@@ -201,8 +172,6 @@ class IntegrationTests(TestCase):
out) out)
class UtilityTests(TestCase): class UtilityTests(TestCase):
def checkShift(self,sn_in,pi_in,part,sn_out,pi_out): def checkShift(self,sn_in,pi_in,part,sn_out,pi_out):
...@@ -241,11 +210,6 @@ class UtilityTests(TestCase): ...@@ -241,11 +210,6 @@ class UtilityTests(TestCase):
util.setup_testing_defaults(kw) util.setup_testing_defaults(kw)
self.assertEqual(util.request_uri(kw,query),uri) self.assertEqual(util.request_uri(kw,query),uri)
def checkFW(self,text,size,match): def checkFW(self,text,size,match):
def make_it(text=text,size=size): def make_it(text=text,size=size):
...@@ -264,7 +228,6 @@ class UtilityTests(TestCase): ...@@ -264,7 +228,6 @@ class UtilityTests(TestCase):
it.close() it.close()
self.assertTrue(it.filelike.closed) self.assertTrue(it.filelike.closed)
def testSimpleShifts(self): def testSimpleShifts(self):
self.checkShift('','/', '', '/', '') self.checkShift('','/', '', '/', '')
self.checkShift('','/x', 'x', '/x', '') self.checkShift('','/x', 'x', '/x', '')
...@@ -272,7 +235,6 @@ class UtilityTests(TestCase): ...@@ -272,7 +235,6 @@ class UtilityTests(TestCase):
self.checkShift('/a','/x/y', 'x', '/a/x', '/y') self.checkShift('/a','/x/y', 'x', '/a/x', '/y')
self.checkShift('/a','/x/', 'x', '/a/x', '/') self.checkShift('/a','/x/', 'x', '/a/x', '/')
def testNormalizedShifts(self): def testNormalizedShifts(self):
self.checkShift('/a/b', '/../y', '..', '/a', '/y') self.checkShift('/a/b', '/../y', '..', '/a', '/y')
self.checkShift('', '/../y', '..', '', '/y') self.checkShift('', '/../y', '..', '', '/y')
...@@ -286,7 +248,6 @@ class UtilityTests(TestCase): ...@@ -286,7 +248,6 @@ class UtilityTests(TestCase):
self.checkShift('/a/b', '/x//', 'x', '/a/b/x', '/') self.checkShift('/a/b', '/x//', 'x', '/a/b/x', '/')
self.checkShift('/a/b', '/.', None, '/a/b', '') self.checkShift('/a/b', '/.', None, '/a/b', '')
def testDefaults(self): def testDefaults(self):
for key, value in [ for key, value in [
('SERVER_NAME','127.0.0.1'), ('SERVER_NAME','127.0.0.1'),
...@@ -306,7 +267,6 @@ class UtilityTests(TestCase): ...@@ -306,7 +267,6 @@ class UtilityTests(TestCase):
]: ]:
self.checkDefault(key,value) self.checkDefault(key,value)
def testCrossDefaults(self): def testCrossDefaults(self):
self.checkCrossDefault('HTTP_HOST',"foo.bar",SERVER_NAME="foo.bar") self.checkCrossDefault('HTTP_HOST',"foo.bar",SERVER_NAME="foo.bar")
self.checkCrossDefault('wsgi.url_scheme',"https",HTTPS="on") self.checkCrossDefault('wsgi.url_scheme',"https",HTTPS="on")
...@@ -316,7 +276,6 @@ class UtilityTests(TestCase): ...@@ -316,7 +276,6 @@ class UtilityTests(TestCase):
self.checkCrossDefault('SERVER_PORT',"80",HTTPS="foo") self.checkCrossDefault('SERVER_PORT',"80",HTTPS="foo")
self.checkCrossDefault('SERVER_PORT',"443",HTTPS="on") self.checkCrossDefault('SERVER_PORT',"443",HTTPS="on")
def testGuessScheme(self): def testGuessScheme(self):
self.assertEqual(util.guess_scheme({}), "http") self.assertEqual(util.guess_scheme({}), "http")
self.assertEqual(util.guess_scheme({'HTTPS':"foo"}), "http") self.assertEqual(util.guess_scheme({'HTTPS':"foo"}), "http")
...@@ -324,10 +283,6 @@ class UtilityTests(TestCase): ...@@ -324,10 +283,6 @@ class UtilityTests(TestCase):
self.assertEqual(util.guess_scheme({'HTTPS':"yes"}), "https") self.assertEqual(util.guess_scheme({'HTTPS':"yes"}), "https")
self.assertEqual(util.guess_scheme({'HTTPS':"1"}), "https") self.assertEqual(util.guess_scheme({'HTTPS':"1"}), "https")
def testAppURIs(self): def testAppURIs(self):
self.checkAppURI("http://127.0.0.1/") self.checkAppURI("http://127.0.0.1/")
self.checkAppURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam") self.checkAppURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam")
...@@ -452,15 +407,6 @@ class TestHandler(ErrorHandler): ...@@ -452,15 +407,6 @@ class TestHandler(ErrorHandler):
raise # for testing, we want to see what's happening raise # for testing, we want to see what's happening
class HandlerTests(TestCase): class HandlerTests(TestCase):
def checkEnvironAttrs(self, handler): def checkEnvironAttrs(self, handler):
...@@ -501,7 +447,6 @@ class HandlerTests(TestCase): ...@@ -501,7 +447,6 @@ class HandlerTests(TestCase):
h=TestHandler(); h.setup_environ() h=TestHandler(); h.setup_environ()
self.assertEqual(h.environ['wsgi.url_scheme'],'http') self.assertEqual(h.environ['wsgi.url_scheme'],'http')
def testAbstractMethods(self): def testAbstractMethods(self):
h = BaseHandler() h = BaseHandler()
for name in [ for name in [
...@@ -510,7 +455,6 @@ class HandlerTests(TestCase): ...@@ -510,7 +455,6 @@ class HandlerTests(TestCase):
self.assertRaises(NotImplementedError, getattr(h,name)) self.assertRaises(NotImplementedError, getattr(h,name))
self.assertRaises(NotImplementedError, h._write, "test") self.assertRaises(NotImplementedError, h._write, "test")
def testContentLength(self): def testContentLength(self):
# Demo one reason iteration is better than write()... ;) # Demo one reason iteration is better than write()... ;)
...@@ -602,7 +546,6 @@ class HandlerTests(TestCase): ...@@ -602,7 +546,6 @@ class HandlerTests(TestCase):
"\r\n".encode("iso-8859-1")+MSG)) "\r\n".encode("iso-8859-1")+MSG))
self.assertIn("AssertionError", h.stderr.getvalue()) self.assertIn("AssertionError", h.stderr.getvalue())
def testHeaderFormats(self): def testHeaderFormats(self):
def non_error_app(e,s): def non_error_app(e,s):
...@@ -662,40 +605,27 @@ class HandlerTests(TestCase): ...@@ -662,40 +605,27 @@ class HandlerTests(TestCase):
b"data", b"data",
h.stdout.getvalue()) 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(): def test_main():
support.run_unittest(__name__) support.run_unittest(__name__)
if __name__ == "__main__": if __name__ == "__main__":
test_main() test_main()
# the above lines intentionally left blank
...@@ -174,11 +174,13 @@ class BaseHandler: ...@@ -174,11 +174,13 @@ class BaseHandler:
in the event loop to iterate over the data, and to call in the event loop to iterate over the data, and to call
'self.close()' once the response is finished. 'self.close()' once the response is finished.
""" """
if not self.result_is_file() or not self.sendfile(): try:
for data in self.result: if not self.result_is_file() or not self.sendfile():
self.write(data) for data in self.result:
self.finish_content() self.write(data)
self.close() self.finish_content()
finally:
self.close()
def get_scheme(self): def get_scheme(self):
......
...@@ -1178,6 +1178,7 @@ Alberto Trevino ...@@ -1178,6 +1178,7 @@ Alberto Trevino
Matthias Troffaes Matthias Troffaes
John Tromp John Tromp
Jason Trowbridge Jason Trowbridge
Brent Tubbs
Anthony Tuininga Anthony Tuininga
Erno Tukia Erno Tukia
David Turner David Turner
......
...@@ -59,6 +59,9 @@ Core and Builtins ...@@ -59,6 +59,9 @@ Core and Builtins
Library Library
------- -------
- Issue #16220: wsgiref now always calls close() on an iterable response.
Patch by Brent Tubbs.
- Issue #16270: urllib may hang when used for retrieving files via FTP by using - Issue #16270: urllib may hang when used for retrieving files via FTP by using
a context manager. Patch by Giampaolo Rodola'. a context manager. Patch by Giampaolo Rodola'.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment