mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
net/imap: handle timeouts
Patch by Pavel Rosický. [Feature #13379] [ruby-core:80440] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58549 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
929807a9e0
commit
8b51a725db
1 changed files with 49 additions and 6 deletions
|
@ -18,6 +18,7 @@ require "socket"
|
||||||
require "monitor"
|
require "monitor"
|
||||||
require "digest/md5"
|
require "digest/md5"
|
||||||
require "strscan"
|
require "strscan"
|
||||||
|
require 'net/protocol'
|
||||||
begin
|
begin
|
||||||
require "openssl"
|
require "openssl"
|
||||||
rescue LoadError
|
rescue LoadError
|
||||||
|
@ -199,7 +200,7 @@ module Net
|
||||||
# Goldsmith, D. and Davis, M., "UTF-7: A Mail-Safe Transformation Format of
|
# Goldsmith, D. and Davis, M., "UTF-7: A Mail-Safe Transformation Format of
|
||||||
# Unicode", RFC 2152, May 1997.
|
# Unicode", RFC 2152, May 1997.
|
||||||
#
|
#
|
||||||
class IMAP
|
class IMAP < Protocol
|
||||||
include MonitorMixin
|
include MonitorMixin
|
||||||
if defined?(OpenSSL::SSL)
|
if defined?(OpenSSL::SSL)
|
||||||
include OpenSSL
|
include OpenSSL
|
||||||
|
@ -221,6 +222,16 @@ module Net
|
||||||
# Returns all response handlers.
|
# Returns all response handlers.
|
||||||
attr_reader :response_handlers
|
attr_reader :response_handlers
|
||||||
|
|
||||||
|
# Seconds to wait until a connection is opened.
|
||||||
|
# If the IMAP object cannot open a connection within this time,
|
||||||
|
# it raises a Net::OpenTimeout exception. The default value is 30 seconds.
|
||||||
|
attr_reader :open_timeout
|
||||||
|
|
||||||
|
# Seconds to wait until reading one block (by one read(1) call).
|
||||||
|
# If the IMAP object cannot complete a read() within this time,
|
||||||
|
# it raises a Net::ReadTimeout exception. The default value is 60 seconds.
|
||||||
|
attr_reader :read_timeout
|
||||||
|
|
||||||
# The thread to receive exceptions.
|
# The thread to receive exceptions.
|
||||||
attr_accessor :client_thread
|
attr_accessor :client_thread
|
||||||
|
|
||||||
|
@ -1048,6 +1059,8 @@ module Net
|
||||||
# be installed.
|
# be installed.
|
||||||
# If options[:ssl] is a hash, it's passed to
|
# If options[:ssl] is a hash, it's passed to
|
||||||
# OpenSSL::SSL::SSLContext#set_params as parameters.
|
# OpenSSL::SSL::SSLContext#set_params as parameters.
|
||||||
|
# open_timeout:: Seconds to wait until a connection is opened
|
||||||
|
# read_timeout:: Seconds to wait until reading one block
|
||||||
#
|
#
|
||||||
# The most common errors are:
|
# The most common errors are:
|
||||||
#
|
#
|
||||||
|
@ -1076,8 +1089,10 @@ module Net
|
||||||
@port = options[:port] || (options[:ssl] ? SSL_PORT : PORT)
|
@port = options[:port] || (options[:ssl] ? SSL_PORT : PORT)
|
||||||
@tag_prefix = "RUBY"
|
@tag_prefix = "RUBY"
|
||||||
@tagno = 0
|
@tagno = 0
|
||||||
|
@open_timeout = options[:open_timeout] || 30
|
||||||
|
@read_timeout = options[:read_timeout] || 60
|
||||||
@parser = ResponseParser.new
|
@parser = ResponseParser.new
|
||||||
@sock = TCPSocket.open(@host, @port)
|
@sock = tcp_socket(@host, @port)
|
||||||
begin
|
begin
|
||||||
if options[:ssl]
|
if options[:ssl]
|
||||||
start_tls_session(options[:ssl])
|
start_tls_session(options[:ssl])
|
||||||
|
@ -1117,6 +1132,13 @@ module Net
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def tcp_socket(host, port)
|
||||||
|
Socket.tcp(host, port, :connect_timeout => @open_timeout)
|
||||||
|
rescue Errno::ETIMEDOUT
|
||||||
|
raise Net::OpenTimeout, "Timeout to open TCP connection to " +
|
||||||
|
"#{host}:#{port} (exceeds #{@open_timeout} seconds)"
|
||||||
|
end
|
||||||
|
|
||||||
def receive_responses
|
def receive_responses
|
||||||
connection_closed = false
|
connection_closed = false
|
||||||
until connection_closed
|
until connection_closed
|
||||||
|
@ -1199,14 +1221,35 @@ module Net
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_response_data(length, terminator = nil)
|
||||||
|
str = nil
|
||||||
|
buff = String.new
|
||||||
|
while true
|
||||||
|
str = @sock.read_nonblock(length, :exception => false)
|
||||||
|
case str
|
||||||
|
when :wait_readable
|
||||||
|
@sock.to_io.wait_readable(@read_timeout) or
|
||||||
|
raise Net::ReadTimeout, "#{@host}:#{@port} read timeout (exceeds #{@read_timeout} seconds)"
|
||||||
|
when nil
|
||||||
|
break
|
||||||
|
else
|
||||||
|
buff.concat(str)
|
||||||
|
if terminator ? buff.include?(terminator) : (buff.length >= length)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
buff
|
||||||
|
end
|
||||||
|
|
||||||
def get_response
|
def get_response
|
||||||
buff = String.new
|
buff = String.new
|
||||||
while true
|
while true
|
||||||
s = @sock.gets(CRLF)
|
s = get_response_data(1, CRLF)
|
||||||
break unless s
|
break if s.length == 0
|
||||||
buff.concat(s)
|
buff.concat(s)
|
||||||
if /\{(\d+)\}\r\n/n =~ s
|
if /\{(\d+)\}\r\n/n =~ s
|
||||||
s = @sock.read($1.to_i)
|
s = get_response_data($1.to_i)
|
||||||
buff.concat(s)
|
buff.concat(s)
|
||||||
else
|
else
|
||||||
break
|
break
|
||||||
|
@ -1487,7 +1530,7 @@ module Net
|
||||||
end
|
end
|
||||||
@sock = SSLSocket.new(@sock, context)
|
@sock = SSLSocket.new(@sock, context)
|
||||||
@sock.sync_close = true
|
@sock.sync_close = true
|
||||||
@sock.connect
|
ssl_socket_connect(@sock, @open_timeout)
|
||||||
if context.verify_mode != VERIFY_NONE
|
if context.verify_mode != VERIFY_NONE
|
||||||
@sock.post_connection_check(@host)
|
@sock.post_connection_check(@host)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue