[前][次][番号順一覧][スレッド一覧]

ruby-changes:44503

From: shugo <ko1@a...>
Date: Sat, 5 Nov 2016 15:47:42 +0900 (JST)
Subject: [ruby-changes:44503] shugo:r56576 (trunk): * lib/net/smtp.rb (tlsconnect): support timeout for TLS handshake.

shugo	2016-11-05 15:47:36 +0900 (Sat, 05 Nov 2016)

  New Revision: 56576

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=56576

  Log:
    * lib/net/smtp.rb (tlsconnect): support timeout for TLS handshake.
      [ruby-core:76893] [Bug #12678]
    
    * lib/net/protocol.rb (ssl_socket_connect): new method to implement
      timeout for TLS handshake.
    
    * lib/net/http.rb (connect): use Net::Protocol#ssl_socket_connect.

  Modified files:
    trunk/ChangeLog
    trunk/lib/net/http.rb
    trunk/lib/net/protocol.rb
    trunk/lib/net/smtp.rb
    trunk/test/net/smtp/test_smtp.rb
    trunk/test/net/smtp/test_ssl_socket.rb
Index: lib/net/http.rb
===================================================================
--- lib/net/http.rb	(revision 56575)
+++ lib/net/http.rb	(revision 56576)
@@ -930,21 +930,7 @@ module Net   #:nodoc: https://github.com/ruby/ruby/blob/trunk/lib/net/http.rb#L930
              Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout
             s.session = @ssl_session if @ssl_session
           end
-          if timeout = @open_timeout
-            while true
-              raise Net::OpenTimeout if timeout <= 0
-              start = Process.clock_gettime Process::CLOCK_MONOTONIC
-              # to_io is required because SSLSocket doesn't have wait_readable yet
-              case s.connect_nonblock(exception: false)
-              when :wait_readable; s.to_io.wait_readable(timeout)
-              when :wait_writable; s.to_io.wait_writable(timeout)
-              else; break
-              end
-              timeout -= Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
-            end
-          else
-            s.connect
-          end
+          ssl_socket_connect(s, @open_timeout)
           if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
             s.post_connection_check(@address)
           end
Index: lib/net/protocol.rb
===================================================================
--- lib/net/protocol.rb	(revision 56575)
+++ lib/net/protocol.rb	(revision 56576)
@@ -34,6 +34,24 @@ module Net # :nodoc: https://github.com/ruby/ruby/blob/trunk/lib/net/protocol.rb#L34
         end
       End
     end
+
+    def ssl_socket_connect(s, timeout)
+      if timeout
+        while true
+          raise Net::OpenTimeout if timeout <= 0
+          start = Process.clock_gettime Process::CLOCK_MONOTONIC
+          # to_io is required because SSLSocket doesn't have wait_readable yet
+          case s.connect_nonblock(exception: false)
+          when :wait_readable; s.to_io.wait_readable(timeout)
+          when :wait_writable; s.to_io.wait_writable(timeout)
+          else; break
+          end
+          timeout -= Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
+        end
+      else
+        s.connect
+      end
+    end
   end
 
 
Index: lib/net/smtp.rb
===================================================================
--- lib/net/smtp.rb	(revision 56575)
+++ lib/net/smtp.rb	(revision 56576)
@@ -167,7 +167,7 @@ module Net https://github.com/ruby/ruby/blob/trunk/lib/net/smtp.rb#L167
   #     Net::SMTP.start('your.smtp.server', 25, 'mail.from.domain',
   #                     'Your Account', 'Your Password', :cram_md5)
   #
-  class SMTP
+  class SMTP < Protocol
 
     Revision = %q$Revision$.split[1]
 
@@ -581,7 +581,7 @@ module Net https://github.com/ruby/ruby/blob/trunk/lib/net/smtp.rb#L581
       s = ssl_socket(s, @ssl_context)
       logging "TLS connection started"
       s.sync_close = true
-      s.connect
+      ssl_socket_connect(s, @open_timeout)
       if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
         s.post_connection_check(@address)
       end
Index: test/net/smtp/test_ssl_socket.rb
===================================================================
--- test/net/smtp/test_ssl_socket.rb	(revision 56575)
+++ test/net/smtp/test_ssl_socket.rb	(revision 56576)
@@ -7,6 +7,11 @@ module Net https://github.com/ruby/ruby/blob/trunk/test/net/smtp/test_ssl_socket.rb#L7
     class MySMTP < SMTP
       attr_accessor :fake_tcp, :fake_ssl
 
+      def initialize(*args)
+        super(*args)
+        @open_timeout = nil
+      end
+
       def tcp_socket address, port
         fake_tcp
       end
Index: test/net/smtp/test_smtp.rb
===================================================================
--- test/net/smtp/test_smtp.rb	(revision 56575)
+++ test/net/smtp/test_smtp.rb	(revision 56576)
@@ -5,6 +5,10 @@ require 'test/unit' https://github.com/ruby/ruby/blob/trunk/test/net/smtp/test_smtp.rb#L5
 
 module Net
   class TestSMTP < Test::Unit::TestCase
+    CA_FILE = File.expand_path("../imap/cacert.pem", __dir__)
+    SERVER_KEY = File.expand_path("../imap/server.key", __dir__)
+    SERVER_CERT = File.expand_path("../imap/server.crt", __dir__)
+
     class FakeSocket
       attr_reader :write_io
 
@@ -98,5 +102,57 @@ module Net https://github.com/ruby/ruby/blob/trunk/test/net/smtp/test_smtp.rb#L102
         smtp.rcptto("foo\r\nbar")
       end
     end
+
+    def test_tls_connect
+      server = TCPServer.new("127.0.0.1", 0)
+      ctx = OpenSSL::SSL::SSLContext.new
+      ctx.ca_file = CA_FILE
+      ctx.key = File.open(SERVER_KEY) { |f|
+        OpenSSL::PKey::RSA.new(f)
+      }
+      ctx.cert = File.open(SERVER_CERT) { |f|
+        OpenSSL::X509::Certificate.new(f)
+      }
+      ssl_server = OpenSSL::SSL::SSLServer.new(server, ctx)
+      begin
+        sock = nil
+        Thread.start do
+          sock = ssl_server.accept
+          sock.write("220 localhost Service ready\r\n")
+          sock.gets
+          sock.write("250 localhost\r\n")
+          sock.gets
+          sock.write("221 localhost Service closing transmission channel\r\n")
+        end
+        smtp = Net::SMTP.new("localhost", server.addr[1])
+        smtp.enable_tls
+        smtp.open_timeout = 0.1
+        smtp.start do
+        end
+      ensure
+        sock.close if sock
+        ssl_server.close
+      end
+    end
+
+    def test_tls_connect_timeout
+      server = TCPServer.new("127.0.0.1", 0)
+      begin
+        sock = nil
+        Thread.start do
+          sock = server.accept
+        end
+        smtp = Net::SMTP.new("127.0.0.1", server.addr[1])
+        smtp.enable_tls
+        smtp.open_timeout = 0.1
+        assert_raise(Net::OpenTimeout) do
+          smtp.start do
+          end
+        end
+      ensure
+        sock.close if sock
+        server.close
+      end
+    end
   end
 end
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 56575)
+++ ChangeLog	(revision 56576)
@@ -1,3 +1,13 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sat Nov  5 15:42:52 2016  Shugo Maeda  <shugo@r...>
+
+	* lib/net/smtp.rb (tlsconnect): support timeout for TLS handshake.
+	  [ruby-core:76893] [Bug #12678]
+
+	* lib/net/protocol.rb (ssl_socket_connect): new method to implement
+	  timeout for TLS handshake.
+
+	* lib/net/http.rb (connect): use Net::Protocol#ssl_socket_connect.
+
 Sat Nov  5 14:17:20 2016  Nobuyoshi Nakada  <nobu@r...>
 
 	* parse.y (brace_body, do_body): since cmdarg_stack is saved in

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]