fix hang because of infinite loop reading EOF

Read() should return empty string when EOF happen, instead of looping
forever. This is the right semantics of read(), and a wrapped version
should not change it.

If you read the read(2) system call manpage, it tells you that when EOF
is seen, return value is 0; it does not say

	``loop forever when EOF happen''.

After the EOF detection is patched you can see the
following exception:

  WARNING: ERROR attempting to copy message 344 for account Gmail:Traceback (most recent call last):
    File "/usr/lib/pymodules/python2.6/offlineimap/folder/Base.py", line 282, in copymessageto
      message = self.getmessage(uid)
    File "/usr/lib/pymodules/python2.6/offlineimap/folder/IMAP.py", line 216, in getmessage
      initialresult = imapobj.uid('fetch', '%d' % uid, '(BODY.PEEK[])')
    File "/usr/lib/python2.6/imaplib.py", line 753, in uid
      typ, dat = self._simple_command(name, command, *args)
    File "/usr/lib/python2.6/imaplib.py", line 1060, in _simple_command
      return self._command_complete(name, self._command(name, *args))
    File "/usr/lib/python2.6/imaplib.py", line 890, in _command_complete
      raise self.abort('command: %s => %s' % (name, val))
  abort: command: UID => socket error: EOF

Signed-off-by: Bao Haojun <baohaojun@gmail.com>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
This commit is contained in:
Haojun Bao 2011-03-03 17:48:26 +08:00 committed by Nicolas Sebrecht
parent 2ab51e6855
commit b94bf79258
3 changed files with 13 additions and 1 deletions

View File

@ -19,6 +19,7 @@ Changes
Bug Fixes Bug Fixes
--------- ---------
* Fix hang because of infinite loop reading EOF.
* Fix regression (UIBase is no more). * Fix regression (UIBase is no more).
* Make profiling mode really enforce single-threading * Make profiling mode really enforce single-threading

View File

@ -48,7 +48,10 @@ class IMAP4_Tunnel(IMAP4):
def read(self, size): def read(self, size):
retval = '' retval = ''
while len(retval) < size: while len(retval) < size:
retval += self.infd.read(size - len(retval)) buf = self.infd.read(size - len(retval))
if not buf:
break
retval += buf
return retval return retval
def readline(self): def readline(self):
@ -188,6 +191,8 @@ class WrappedIMAP4_SSL(IMAP4_SSL):
read = 0 read = 0
while read < n: while read < n:
data = self._read_upto (n-read) data = self._read_upto (n-read)
if not data:
break
read += len(data) read += len(data)
chunks.append(data) chunks.append(data)
@ -200,6 +205,8 @@ class WrappedIMAP4_SSL(IMAP4_SSL):
retval = '' retval = ''
while 1: while 1:
linebuf = self._read_upto(1024) linebuf = self._read_upto(1024)
if not linebuf:
return retval
nlindex = linebuf.find("\n") nlindex = linebuf.find("\n")
if nlindex != -1: if nlindex != -1:
retval += linebuf[:nlindex + 1] retval += linebuf[:nlindex + 1]

View File

@ -71,6 +71,8 @@ class UsefulIMAP4(UsefulIMAPMixIn, imaplibutil.WrappedIMAP4):
io = StringIO() io = StringIO()
while read < size: while read < size:
data = imaplib.IMAP4.read (self, min(size-read,8192)) data = imaplib.IMAP4.read (self, min(size-read,8192))
if not data:
break
read += len(data) read += len(data)
io.write(data) io.write(data)
return io.getvalue() return io.getvalue()
@ -86,6 +88,8 @@ class UsefulIMAP4_SSL(UsefulIMAPMixIn, imaplibutil.WrappedIMAP4_SSL):
io = StringIO() io = StringIO()
while read < size: while read < size:
data = imaplibutil.WrappedIMAP4_SSL.read (self, min(size-read,8192)) data = imaplibutil.WrappedIMAP4_SSL.read (self, min(size-read,8192))
if not data:
break
read += len(data) read += len(data)
io.write(data) io.write(data)
return io.getvalue() return io.getvalue()