Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d3a3e64

Browse files
committed
Issue #16220: wsgiref now always calls close() on an iterable response.
Patch by Brent Tubbs.
2 parents 777d0c5 + 5508412 commit d3a3e64

4 files changed

Lines changed: 29 additions & 93 deletions

File tree

Lib/test/test_wsgiref.py

Lines changed: 18 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ def finish(self):
4141
pass
4242

4343

44-
45-
46-
4744
def hello_app(environ,start_response):
4845
start_response("200 OK", [
4946
('Content-Type','text/plain'),
@@ -65,28 +62,6 @@ def run_amock(app=hello_app, data=b"GET / HTTP/1.0\n\n"):
6562

6663
return out.getvalue(), err.getvalue()
6764

68-
69-
70-
71-
72-
73-
74-
75-
76-
77-
78-
79-
80-
81-
82-
83-
84-
85-
86-
87-
88-
89-
9065
def compare_generic_iter(make_it,match):
9166
"""Utility to compare a generic 2.1/2.2+ iterator with an iterable
9267
@@ -124,10 +99,6 @@ def compare_generic_iter(make_it,match):
12499
raise AssertionError("Too many items from .__next__()", it)
125100

126101

127-
128-
129-
130-
131102
class IntegrationTests(TestCase):
132103

133104
def check_hello(self, out, has_length=True):
@@ -201,8 +172,6 @@ def app(e, s):
201172
out)
202173

203174

204-
205-
206175
class UtilityTests(TestCase):
207176

208177
def checkShift(self,sn_in,pi_in,part,sn_out,pi_out):
@@ -241,11 +210,6 @@ def checkReqURI(self,uri,query=1,**kw):
241210
util.setup_testing_defaults(kw)
242211
self.assertEqual(util.request_uri(kw,query),uri)
243212

244-
245-
246-
247-
248-
249213
def checkFW(self,text,size,match):
250214

251215
def make_it(text=text,size=size):
@@ -264,15 +228,13 @@ def make_it(text=text,size=size):
264228
it.close()
265229
self.assertTrue(it.filelike.closed)
266230

267-
268231
def testSimpleShifts(self):
269232
self.checkShift('','/', '', '/', '')
270233
self.checkShift('','/x', 'x', '/x', '')
271234
self.checkShift('/','', None, '/', '')
272235
self.checkShift('/a','/x/y', 'x', '/a/x', '/y')
273236
self.checkShift('/a','/x/', 'x', '/a/x', '/')
274237

275-
276238
def testNormalizedShifts(self):
277239
self.checkShift('/a/b', '/../y', '..', '/a', '/y')
278240
self.checkShift('', '/../y', '..', '', '/y')
@@ -286,7 +248,6 @@ def testNormalizedShifts(self):
286248
self.checkShift('/a/b', '/x//', 'x', '/a/b/x', '/')
287249
self.checkShift('/a/b', '/.', None, '/a/b', '')
288250

289-
290251
def testDefaults(self):
291252
for key, value in [
292253
('SERVER_NAME','127.0.0.1'),
@@ -306,7 +267,6 @@ def testDefaults(self):
306267
]:
307268
self.checkDefault(key,value)
308269

309-
310270
def testCrossDefaults(self):
311271
self.checkCrossDefault('HTTP_HOST',"foo.bar",SERVER_NAME="foo.bar")
312272
self.checkCrossDefault('wsgi.url_scheme',"https",HTTPS="on")
@@ -316,18 +276,13 @@ def testCrossDefaults(self):
316276
self.checkCrossDefault('SERVER_PORT',"80",HTTPS="foo")
317277
self.checkCrossDefault('SERVER_PORT',"443",HTTPS="on")
318278

319-
320279
def testGuessScheme(self):
321280
self.assertEqual(util.guess_scheme({}), "http")
322281
self.assertEqual(util.guess_scheme({'HTTPS':"foo"}), "http")
323282
self.assertEqual(util.guess_scheme({'HTTPS':"on"}), "https")
324283
self.assertEqual(util.guess_scheme({'HTTPS':"yes"}), "https")
325284
self.assertEqual(util.guess_scheme({'HTTPS':"1"}), "https")
326285

327-
328-
329-
330-
331286
def testAppURIs(self):
332287
self.checkAppURI("http://127.0.0.1/")
333288
self.checkAppURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam")
@@ -452,15 +407,6 @@ def handle_error(self):
452407
raise # for testing, we want to see what's happening
453408

454409

455-
456-
457-
458-
459-
460-
461-
462-
463-
464410
class HandlerTests(TestCase):
465411

466412
def checkEnvironAttrs(self, handler):
@@ -501,7 +447,6 @@ def testScheme(self):
501447
h=TestHandler(); h.setup_environ()
502448
self.assertEqual(h.environ['wsgi.url_scheme'],'http')
503449

504-
505450
def testAbstractMethods(self):
506451
h = BaseHandler()
507452
for name in [
@@ -510,7 +455,6 @@ def testAbstractMethods(self):
510455
self.assertRaises(NotImplementedError, getattr(h,name))
511456
self.assertRaises(NotImplementedError, h._write, "test")
512457

513-
514458
def testContentLength(self):
515459
# Demo one reason iteration is better than write()... ;)
516460

@@ -602,7 +546,6 @@ def error_app(e,s):
602546
"\r\n".encode("iso-8859-1")+MSG))
603547
self.assertIn("AssertionError", h.stderr.getvalue())
604548

605-
606549
def testHeaderFormats(self):
607550

608551
def non_error_app(e,s):
@@ -662,40 +605,27 @@ def app(e, s):
662605
b"data",
663606
h.stdout.getvalue())
664607

665-
# This epilogue is needed for compatibility with the Python 2.5 regrtest module
608+
def testCloseOnError(self):
609+
side_effects = {'close_called': False}
610+
MSG = b"Some output has been sent"
611+
def error_app(e,s):
612+
s("200 OK",[])(MSG)
613+
class CrashyIterable(object):
614+
def __iter__(self):
615+
while True:
616+
yield b'blah'
617+
raise AssertionError("This should be caught by handler")
618+
def close(self):
619+
side_effects['close_called'] = True
620+
return CrashyIterable()
621+
622+
h = ErrorHandler()
623+
h.run(error_app)
624+
self.assertEqual(side_effects['close_called'], True)
625+
666626

667627
def test_main():
668628
support.run_unittest(__name__)
669629

670630
if __name__ == "__main__":
671631
test_main()
672-
673-
674-
675-
676-
677-
678-
679-
680-
681-
682-
683-
684-
685-
686-
687-
688-
689-
690-
691-
692-
693-
694-
695-
696-
697-
698-
699-
700-
701-
# the above lines intentionally left blank

Lib/wsgiref/handlers.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,13 @@ def finish_response(self):
174174
in the event loop to iterate over the data, and to call
175175
'self.close()' once the response is finished.
176176
"""
177-
if not self.result_is_file() or not self.sendfile():
178-
for data in self.result:
179-
self.write(data)
180-
self.finish_content()
181-
self.close()
177+
try:
178+
if not self.result_is_file() or not self.sendfile():
179+
for data in self.result:
180+
self.write(data)
181+
self.finish_content()
182+
finally:
183+
self.close()
182184

183185

184186
def get_scheme(self):

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,6 +1178,7 @@ Alberto Trevino
11781178
Matthias Troffaes
11791179
John Tromp
11801180
Jason Trowbridge
1181+
Brent Tubbs
11811182
Anthony Tuininga
11821183
Erno Tukia
11831184
David Turner

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ Core and Builtins
5959
Library
6060
-------
6161

62+
- Issue #16220: wsgiref now always calls close() on an iterable response.
63+
Patch by Brent Tubbs.
64+
6265
- Issue #16270: urllib may hang when used for retrieving files via FTP by using
6366
a context manager. Patch by Giampaolo Rodola'.
6467

0 commit comments

Comments
 (0)