# HG changeset patch # Parent dd2522058ce8043cb7e4caa968afe932bfef723e Issue #22350: Close NNTP connection after failures to avoid attempting QUIT diff -r dd2522058ce8 Lib/nntplib.py --- a/Lib/nntplib.py Thu Dec 18 01:20:29 2014 +0100 +++ b/Lib/nntplib.py Mon May 25 07:14:18 2015 +0000 @@ -477,26 +477,33 @@ if resp[:3] not in _LONGRESP: raise NNTPReplyError(resp) - lines = [] - if file is not None: - # XXX lines = None instead? - terminators = (b'.' + _CRLF, b'.\n') - while 1: - line = self._getline(False) - if line in terminators: - break - if line.startswith(b'..'): - line = line[1:] - file.write(line) - else: - terminator = b'.' - while 1: - line = self._getline() - if line == terminator: - break - if line.startswith(b'..'): - line = line[1:] - lines.append(line) + try: + lines = [] + if file is not None: + # XXX lines = None instead? + terminators = (b'.' + _CRLF, b'.\n') + while 1: + line = self._getline(False) + if line in terminators: + break + if line.startswith(b'..'): + line = line[1:] + file.write(line) + else: + terminator = b'.' + while 1: + line = self._getline() + if line == terminator: + break + if line.startswith(b'..'): + line = line[1:] + lines.append(line) + except: # Response not completely read, so abort the connection + try: + self._close() + except Exception: # Avoid masking the original exception + pass + raise finally: # If this method created the file, then it must close it if openedFile: diff -r dd2522058ce8 Lib/test/test_nntplib.py --- a/Lib/test/test_nntplib.py Thu Dec 18 01:20:29 2014 +0100 +++ b/Lib/test/test_nntplib.py Mon May 25 07:14:18 2015 +0000 @@ -1190,6 +1190,16 @@ self.assertRaises(nntplib.NNTPDataError, self.server.newnews, "comp.lang.python", dt) + def test_unrecoverable_cleanup(self): + """Check cleanup after unrecoverable error (Issue 22350)""" + class Aborter(io.BufferedIOBase): + def write(self, data): + raise OSError() + with self.server: + # Break protocol state by aborting in middle of response + self.assertRaises(OSError, self.server.body, file=Aborter()) + self.assertTrue(self.sio.closed, "Connection should be aborted") + class NNTPv1Tests(NNTPv1v2TestsMixin, MockedNNTPTestsMixin, unittest.TestCase): """Tests an NNTP v1 server (no capabilities)."""