Author martin.panter
Recipients martin.panter
Date 2014-09-07.03:40:17
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1410061219.03.0.0230581897355.issue22350@psf.upfronthosting.co.za>
In-reply-to
Content
The following code triggers an NNTPProtocolError, as long as the body is large enough to cause an intermediate flush of the output file. The reason I think is that the body() method aborts in the middle of reading the BODY response, and when the context manager exits, a QUIT command is attempted, which continues to read the BODY response.

>>> with NNTP("localhost") as nntp:
...     nntp.body("<example>", file="/dev/full")
... 
Traceback (most recent call last):
  File "/usr/lib/python3.4/nntplib.py", line 491, in _getlongresp
    file.write(line)
OSError: [Errno 28] No space left on device

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/usr/lib/python3.4/nntplib.py", line 757, in body
    return self._artcmd(cmd, file)
  File "/usr/lib/python3.4/nntplib.py", line 727, in _artcmd
    resp, lines = self._longcmd(line, file)
  File "/usr/lib/python3.4/nntplib.py", line 518, in _longcmd
    return self._getlongresp(file)
  File "/usr/lib/python3.4/nntplib.py", line 504, in _getlongresp
    openedFile.close()
OSError: [Errno 28] No space left on device

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/usr/lib/python3.4/nntplib.py", line 367, in __exit__
    self.quit()
  File "/usr/lib/python3.4/nntplib.py", line 936, in quit
    resp = self._shortcmd('QUIT')
  File "/usr/lib/python3.4/nntplib.py", line 512, in _shortcmd
    return self._getresp()
  File "/usr/lib/python3.4/nntplib.py", line 459, in _getresp
    raise NNTPProtocolError(resp)
nntplib.NNTPProtocolError: <line of data from BODY command>

It is hard to work around because the context manager and quit() methods seem to be the only public interfaces for closing the connection, and they both try to do a QUIT command first. I am thinking of something equivalent to this for a workaround, however it is bit hacky and may not be reliable in all cases:

nntp = NNTP("localhost")
abort = False
try:
    ...
    try:
        nntp.body("<example>", file="/dev/full")
    except (NNTPTemporaryError, NNTPPermanentError):
        raise  # NNTP connection still intact
    except:
        abort = True
        raise
    ...
finally:
    try:
        nntp.quit()
    except NNTPError:
        # Connection cleaned up despite exception
        if not abort:
            raise

Perhaps the “nntplib” module could abort the connection itself if any command does not complete according to the protocol. Or at the very least, provide an API to manually abort the connection without poking at the internals.
History
Date User Action Args
2014-09-07 03:40:19martin.pantersetrecipients: + martin.panter
2014-09-07 03:40:19martin.pantersetmessageid: <1410061219.03.0.0230581897355.issue22350@psf.upfronthosting.co.za>
2014-09-07 03:40:18martin.panterlinkissue22350 messages
2014-09-07 03:40:17martin.pantercreate