diff options
author | shugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-05-03 11:32:22 +0000 |
---|---|---|
committer | shugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-05-03 11:32:22 +0000 |
commit | 8b51a725db69b403c2304745d715954b8fd1a778 (patch) | |
tree | 732b56309a91891fe8a19388bb2110ca1a265944 /lib/net | |
parent | 929807a9e0f8aa47f107a5f3a64b417906c085e4 (diff) | |
download | ruby-8b51a725db69b403c2304745d715954b8fd1a778.tar.gz |
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
Diffstat (limited to 'lib/net')
-rw-r--r-- | lib/net/imap.rb | 55 |
1 files changed, 49 insertions, 6 deletions
diff --git a/lib/net/imap.rb b/lib/net/imap.rb index 7a4d4da301..f069ec5149 100644 --- a/lib/net/imap.rb +++ b/lib/net/imap.rb @@ -18,6 +18,7 @@ require "socket" require "monitor" require "digest/md5" require "strscan" +require 'net/protocol' begin require "openssl" rescue LoadError @@ -199,7 +200,7 @@ module Net # Goldsmith, D. and Davis, M., "UTF-7: A Mail-Safe Transformation Format of # Unicode", RFC 2152, May 1997. # - class IMAP + class IMAP < Protocol include MonitorMixin if defined?(OpenSSL::SSL) include OpenSSL @@ -221,6 +222,16 @@ module Net # Returns all 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. attr_accessor :client_thread @@ -1048,6 +1059,8 @@ module Net # be installed. # If options[:ssl] is a hash, it's passed to # 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: # @@ -1076,8 +1089,10 @@ module Net @port = options[:port] || (options[:ssl] ? SSL_PORT : PORT) @tag_prefix = "RUBY" @tagno = 0 + @open_timeout = options[:open_timeout] || 30 + @read_timeout = options[:read_timeout] || 60 @parser = ResponseParser.new - @sock = TCPSocket.open(@host, @port) + @sock = tcp_socket(@host, @port) begin if options[:ssl] start_tls_session(options[:ssl]) @@ -1117,6 +1132,13 @@ module Net 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 connection_closed = false until connection_closed @@ -1199,14 +1221,35 @@ module Net 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 buff = String.new while true - s = @sock.gets(CRLF) - break unless s + s = get_response_data(1, CRLF) + break if s.length == 0 buff.concat(s) if /\{(\d+)\}\r\n/n =~ s - s = @sock.read($1.to_i) + s = get_response_data($1.to_i) buff.concat(s) else break @@ -1487,7 +1530,7 @@ module Net end @sock = SSLSocket.new(@sock, context) @sock.sync_close = true - @sock.connect + ssl_socket_connect(@sock, @open_timeout) if context.verify_mode != VERIFY_NONE @sock.post_connection_check(@host) end |