From b94bf792585a9297851bdb965c4bbd6bdadeeb42 Mon Sep 17 00:00:00 2001 From: Haojun Bao Date: Thu, 3 Mar 2011 17:48:26 +0800 Subject: [PATCH] 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 Signed-off-by: Nicolas Sebrecht --- Changelog.draft.rst | 1 + offlineimap/imaplibutil.py | 9 ++++++++- offlineimap/imapserver.py | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Changelog.draft.rst b/Changelog.draft.rst index e754f50..b8c82f8 100644 --- a/Changelog.draft.rst +++ b/Changelog.draft.rst @@ -19,6 +19,7 @@ Changes Bug Fixes --------- +* Fix hang because of infinite loop reading EOF. * Fix regression (UIBase is no more). * Make profiling mode really enforce single-threading diff --git a/offlineimap/imaplibutil.py b/offlineimap/imaplibutil.py index cf82996..4f69d41 100644 --- a/offlineimap/imaplibutil.py +++ b/offlineimap/imaplibutil.py @@ -48,7 +48,10 @@ class IMAP4_Tunnel(IMAP4): def read(self, size): retval = '' 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 def readline(self): @@ -188,6 +191,8 @@ class WrappedIMAP4_SSL(IMAP4_SSL): read = 0 while read < n: data = self._read_upto (n-read) + if not data: + break read += len(data) chunks.append(data) @@ -200,6 +205,8 @@ class WrappedIMAP4_SSL(IMAP4_SSL): retval = '' while 1: linebuf = self._read_upto(1024) + if not linebuf: + return retval nlindex = linebuf.find("\n") if nlindex != -1: retval += linebuf[:nlindex + 1] diff --git a/offlineimap/imapserver.py b/offlineimap/imapserver.py index 2a9f247..c298aa3 100644 --- a/offlineimap/imapserver.py +++ b/offlineimap/imapserver.py @@ -71,6 +71,8 @@ class UsefulIMAP4(UsefulIMAPMixIn, imaplibutil.WrappedIMAP4): io = StringIO() while read < size: data = imaplib.IMAP4.read (self, min(size-read,8192)) + if not data: + break read += len(data) io.write(data) return io.getvalue() @@ -86,6 +88,8 @@ class UsefulIMAP4_SSL(UsefulIMAPMixIn, imaplibutil.WrappedIMAP4_SSL): io = StringIO() while read < size: data = imaplibutil.WrappedIMAP4_SSL.read (self, min(size-read,8192)) + if not data: + break read += len(data) io.write(data) return io.getvalue()