Subject: | Selecting on an SSL socket in Mail::IMAPClient |
Date: | Thu, 2 Oct 2008 17:25:38 +0100 |
To: | bug-Mail-IMAPClient [...] rt.cpan.org |
From: | "David Sansome" <me [...] davidsansome.com> |
Hi,
I've discovered some strange behaviour in Mail::IMAPClient when using
a IO::Socket::SSL. The problem only occurs when I connect to a
Dovecot IMAP server - I was unable to reproduce with Courier.
I'm using:
Ubuntu 8.04
Perl 5.8.8
Mail::IMAPClient 3.10 from CPAN
IO::Socket::SSL 1.02-1 from Ubuntu packages
Dovecot 1.0.10 from Ubuntu packages
The problem occurs when I try to download a message body from Dovecot
over SSL. It hangs for 30 seconds and eventually gives me the
message:
ERROR: Tag 9: Timeout after 30 seconds waiting for data from server
Oddly, downloading the same message from Courier over SSL works fine.
I turned on debugging and looked at the differences.
This is from Courier (which worked):
Sending: 11 UID FETCH 1 BODY[]
Sent 23 bytes
LITERAL: received literal in line * 1 FETCH (UID 1 BODY[] of length
1082; attempting to retrieve from the 1109 bytes in:
[snip]<END_OF_iBuffer>
Read: [snip]
Mail::IMAPClient reads the whole of the message in one go - including
the "11 OK FETCH completed" message that comes after.
However, from Dovecot I see this:
Sending: 9 UID FETCH 1 BODY[]
Sent 22 bytes
LITERAL: received literal in line * 1 FETCH (UID 1 BODY[] of length
1082; attempting to retrieve from the 992 bytes in: [snip]
Received ret=90 and buffer = [snip]<END>
while processing LITERAL
ERROR: Tag 9: Timeout after 30 seconds waiting for data from server
Mail::IMAPClient only gets 992 bytes from the server (for whatever
reason), and so waits for more to be available and reads it in
IMAPClient.pm line 1404. It only reads ($expected_size - length
$litstring) bytes - the number of bytes in the message that it hasn't
got yet. It seems that the SSL socket decodes a larger chunk than
this (perhaps all the data that is available on the socket) and stores
it in an internal buffer.
This means that the next time IMAPClient returns to its loop and does
CORE::select to wait for more data (the "OK FETCH completed" message),
the select times out because there is no more data actually waiting to
be processed.
Calling sysread on the socket at this point actually does read some
data, so this suggests that IO::Socket::SSL's select behaviour is a
bit broken.
I've attached a patch that checks if the socket isa IO::Socket::SSL,
and if so calls its pending() function to get the number of bytes that
are really available for reading.
This seems to fix the problem for me - although I admit it's a bit of a hack :)
Thanks,
David
Message body is not shown because sender requested not to inline it.