Skip Menu |

This queue is for tickets about the Mail-IMAPClient CPAN distribution.

Report information
The Basics
Id: 31211
Status: resolved
Priority: 0/
Queue: Mail-IMAPClient

People
Owner: Nobody in particular
Requestors: ROBN [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 2.99_07
Fixed in: (no value)



Subject: [PATCH] Reading literals fails when the reply crosses a buffer boundary
This is hard to explain. When a literal arrives in a response, _read_line extracts it from the input buffer and then expects to find the response text (sequence number, OK|NO|BAD, etc) immediately after it. If that response text runs off the end of the buffer, _read_line won't recognise it and will discard the rest of the buffer, then loop and wait for the response text again, which will never receive. This is easy to fix. The code at the end of the literal handling block that tries to find responses after the literal can be removed. The unprocessed data will remain in the input buffer, and because there is both data in the buffer and the last output object is not of type OUTPUT, the loop runs again, it rereads the rest of the response text from the server, appends in to the buffer, and all is well. I think its safe to remove this code. It doesn't appear to be doing anything that isn't handled by the loop running again. Before this change, a test downloading some 1200 messages from a mailbox would trigger this bug and hang on six of them. After this change, all are downloaded successfully. Mail-IMAPClient-3.00 perl 5.8.8 Debian lenny/sid Linux 2.6.22
Subject: literal-reply.patch
diff --git a/lib/Mail/IMAPClient.pm b/lib/Mail/IMAPClient.pm index 0f87b40..88dbb82 100644 --- a/lib/Mail/IMAPClient.pm +++ b/lib/Mail/IMAPClient.pm @@ -1427,29 +1427,8 @@ sub _read_line $self->Fast_io($fast_io) if $fast_io; - # Now let's make sure there are no IMAP server output lines - # (i.e. [tag|*] BAD|NO|OK Text) embedded in the literal string - my $trailer; - if($iBuffer =~ s/\r?\n((?:\*|\d+)\s(?:BAD|NO|OK)[^\n]*\r?\n\z)//i) - { $trailer = $1; - $self->_debug("Got output in literal: $trailer"); - } - - $self->_debug("literal includes ')' of FETCH") - if length $iBuffer - && $current_line =~ m/\bFETCH\b/i - && $iBuffer =~ s/\)$//; - - if(length $iBuffer) - { $self->_debug("literal: too much >>$iBuffer<<"); - $litstring .= $iBuffer; - $iBuffer = ''; - } - push @$oBuffer, [$index++, "OUTPUT", $current_line]; push @$oBuffer, [$index++, "LITERAL", $litstring]; - push @$oBuffer, [$index++, "OUTPUT", $trailer] - if $trailer; } }
This looks like quite a dangerous change, so I need some sleep before I can judge it. Could you read over the new code after a sleep as well? I have converted the code rigorously, but some pieces, like _read_line were made too complex for a fast rewrite. I suspect the routine can be reduces much further.
I wrote the patch yesterday and only submitted it this morning, so I have slept on it ;) It still seems right to me. This morning I've processed some 40000 messages with it without any timeouts. They all appear to be intact. I haven't don't rigorous checks, but it seems reasonable to me. This is all against Sun Messaging Server, though I see no particular reason why it should be different elsewhere. As an aside, it would be good to move the network stuff out of _read_line into a seperate sub so that _read_line could be tested properly.
For unknown reason, this ticket got "resolved" where it wasn't. Anyway. I have really no time to investigate this deeply, and that is not expected to change in the next few days. But it would be an important fix. So I decided to trust you on your blue eyes and accept it. The _read_line and migratie methods both still need a good redo, so feel invited to improve it into something readible and simple!