From: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 May 2019 16:28:38 +0000 (-0700) Subject: bpo-29183: Fix double exceptions in wsgiref.handlers.BaseHandler (GH-12914) X-Git-Tag: v3.7.4rc1~129 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f393e8eb463d60ce559982613429568c518ab8d9;p=thirdparty%2FPython%2Fcpython.git bpo-29183: Fix double exceptions in wsgiref.handlers.BaseHandler (GH-12914) (cherry picked from commit 7c59362a15dfce538512ff1fce4e07d33a925cfb) Co-authored-by: Berker Peksag --- diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py index 5502ece576f4..7650e1392c57 100644 --- a/Lib/test/test_wsgiref.py +++ b/Lib/test/test_wsgiref.py @@ -798,6 +798,31 @@ class HandlerTests(TestCase): self.assertFalse(stderr.getvalue()) + def testDontResetInternalStateOnException(self): + class CustomException(ValueError): + pass + + # We are raising CustomException here to trigger an exception + # during the execution of SimpleHandler.finish_response(), so + # we can easily test that the internal state of the handler is + # preserved in case of an exception. + class AbortingWriter: + def write(self, b): + raise CustomException + + stderr = StringIO() + environ = {"SERVER_PROTOCOL": "HTTP/1.0"} + h = SimpleHandler(BytesIO(), AbortingWriter(), stderr, environ) + h.run(hello_app) + + self.assertIn("CustomException", stderr.getvalue()) + + # Test that the internal state of the handler is preserved. + self.assertIsNotNone(h.result) + self.assertIsNotNone(h.headers) + self.assertIsNotNone(h.status) + self.assertIsNotNone(h.environ) + if __name__ == "__main__": unittest.main() diff --git a/Lib/wsgiref/handlers.py b/Lib/wsgiref/handlers.py index f04cef9b9d06..eee3f948c723 100644 --- a/Lib/wsgiref/handlers.py +++ b/Lib/wsgiref/handlers.py @@ -183,7 +183,16 @@ class BaseHandler: for data in self.result: self.write(data) self.finish_content() - finally: + except: + # Call close() on the iterable returned by the WSGI application + # in case of an exception. + if hasattr(self.result, 'close'): + self.result.close() + raise + else: + # We only call close() when no exception is raised, because it + # will set status, result, headers, and environ fields to None. + # See bpo-29183 for more details. self.close() diff --git a/Misc/NEWS.d/next/Library/2019-04-22-22-55-29.bpo-29183.MILvsk.rst b/Misc/NEWS.d/next/Library/2019-04-22-22-55-29.bpo-29183.MILvsk.rst new file mode 100644 index 000000000000..1d19f191eede --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-04-22-22-55-29.bpo-29183.MILvsk.rst @@ -0,0 +1,3 @@ +Fix double exceptions in :class:`wsgiref.handlers.BaseHandler` by calling +its :meth:`~wsgiref.handlers.BaseHandler.close` method only when no +exception is raised.