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

ruby-changes:46678

From: shugo <ko1@a...>
Date: Fri, 19 May 2017 18:25:57 +0900 (JST)
Subject: [ruby-changes:46678] shugo:r58792 (trunk): net/imap: Net::IMAP#append should not block when NO response is received

shugo	2017-05-19 18:25:52 +0900 (Fri, 19 May 2017)

  New Revision: 58792

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

  Log:
    net/imap: Net::IMAP#append should not block when NO response is received
    
    [ruby-dev:50129] [Bug#13579]

  Modified files:
    trunk/lib/net/imap.rb
    trunk/test/net/imap/test_imap.rb
Index: lib/net/imap.rb
===================================================================
--- lib/net/imap.rb	(revision 58791)
+++ lib/net/imap.rb	(revision 58792)
@@ -1098,6 +1098,7 @@ module Net https://github.com/ruby/ruby/blob/trunk/lib/net/imap.rb#L1098
         @tagged_responses = {}
         @response_handlers = []
         @tagged_response_arrival = new_cond
+        @continued_command_tag = nil
         @continuation_request_arrival = new_cond
         @idle_done_cond = nil
         @logout_command_tag = nil
@@ -1160,8 +1161,12 @@ module Net https://github.com/ruby/ruby/blob/trunk/lib/net/imap.rb#L1161
             when TaggedResponse
               @tagged_responses[resp.tag] = resp
               @tagged_response_arrival.broadcast
-              if resp.tag == @logout_command_tag
+              case resp.tag
+              when @logout_command_tag
                 return
+              when @continued_command_tag
+                @exception = RESPONSE_ERRORS[resp.name].new(resp)
+                @continuation_request_arrival.signal
               end
             when UntaggedResponse
               record_response(resp.name, resp.data)
@@ -1251,7 +1256,7 @@ module Net https://github.com/ruby/ruby/blob/trunk/lib/net/imap.rb#L1256
         put_string(tag + " " + cmd)
         args.each do |i|
           put_string(" ")
-          send_data(i)
+          send_data(i, tag)
         end
         put_string(CRLF)
         if cmd == "LOGOUT"
@@ -1307,7 +1312,7 @@ module Net https://github.com/ruby/ruby/blob/trunk/lib/net/imap.rb#L1312
       end
     end
 
-    def send_data(data)
+    def send_data(data, tag = nil)
       case data
       when nil
         put_string("NIL")
@@ -1322,7 +1327,7 @@ module Net https://github.com/ruby/ruby/blob/trunk/lib/net/imap.rb#L1327
       when Symbol
         send_symbol_data(data)
       else
-        data.send_data(self)
+        data.send_data(self, tag)
       end
     end
 
@@ -1345,11 +1350,16 @@ module Net https://github.com/ruby/ruby/blob/trunk/lib/net/imap.rb#L1350
       put_string('"' + str.gsub(/["\\]/n, "\\\\\\&") + '"')
     end
 
-    def send_literal(str)
+    def send_literal(str, tag)
       put_string("{" + str.bytesize.to_s + "}" + CRLF)
-      @continuation_request_arrival.wait
-      raise @exception if @exception
-      put_string(str)
+      @continued_command_tag = tag
+      begin
+        @continuation_request_arrival.wait
+        raise @exception if @exception
+        put_string(str)
+      ensure
+        @continued_command_tag = nil
+      end
     end
 
     def send_number_data(num)
@@ -1510,7 +1520,7 @@ module Net https://github.com/ruby/ruby/blob/trunk/lib/net/imap.rb#L1520
     end
 
     class RawData # :nodoc:
-      def send_data(imap)
+      def send_data(imap, tag)
         imap.send(:put_string, @data)
       end
 
@@ -1525,7 +1535,7 @@ module Net https://github.com/ruby/ruby/blob/trunk/lib/net/imap.rb#L1535
     end
 
     class Atom # :nodoc:
-      def send_data(imap)
+      def send_data(imap, tag)
         imap.send(:put_string, @data)
       end
 
@@ -1540,7 +1550,7 @@ module Net https://github.com/ruby/ruby/blob/trunk/lib/net/imap.rb#L1550
     end
 
     class QuotedString # :nodoc:
-      def send_data(imap)
+      def send_data(imap, tag)
         imap.send(:send_quoted_string, @data)
       end
 
@@ -1555,8 +1565,8 @@ module Net https://github.com/ruby/ruby/blob/trunk/lib/net/imap.rb#L1565
     end
 
     class Literal # :nodoc:
-      def send_data(imap)
-        imap.send(:send_literal, @data)
+      def send_data(imap, tag)
+        imap.send(:send_literal, @data, tag)
       end
 
       def validate
@@ -1570,7 +1580,7 @@ module Net https://github.com/ruby/ruby/blob/trunk/lib/net/imap.rb#L1580
     end
 
     class MessageSet # :nodoc:
-      def send_data(imap)
+      def send_data(imap, tag)
         imap.send(:put_string, format_internal(@data))
       end
 
@@ -3653,6 +3663,10 @@ module Net https://github.com/ruby/ruby/blob/trunk/lib/net/imap.rb#L3663
     # out due to inactivity.
     class ByeResponseError < ResponseError
     end
+    
+    RESPONSE_ERRORS = Hash.new(ResponseError)
+    RESPONSE_ERRORS["NO"] = NoResponseError
+    RESPONSE_ERRORS["BAD"] = BadResponseError
 
     # Error raised when too many flags are interned to symbols.
     class FlagCountError < Error
Index: test/net/imap/test_imap.rb
===================================================================
--- test/net/imap/test_imap.rb	(revision 58791)
+++ test/net/imap/test_imap.rb	(revision 58792)
@@ -559,6 +559,91 @@ class IMAPTest < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/net/imap/test_imap.rb#L559
     end
   end
 
+  def test_append
+    server = create_tcp_server
+    port = server.addr[1]
+    mail = <<EOF.gsub(/\n/, "\r\n")
+From: shugo@e...
+To: matz@e...
+Subject: hello
+
+hello world
+EOF
+    requests = []
+    received_mail = nil
+    @threads << Thread.start do
+      sock = server.accept
+      begin
+        sock.print("* OK test server\r\n")
+        line = sock.gets
+        requests.push(line)
+        size = line.slice(/{(\d+)}\r\n/, 1).to_i
+        sock.print("+ Ready for literal data\r\n")
+        received_mail = sock.read(size)
+        sock.gets
+        sock.print("RUBY0001 OK APPEND completed\r\n")
+        sock.gets
+        sock.print("* BYE terminating connection\r\n")
+        sock.print("RUBY0002 OK LOGOUT completed\r\n")
+      ensure
+        sock.close
+        server.close
+      end
+    end
+
+    begin
+      imap = Net::IMAP.new(SERVER_ADDR, :port => port)
+      resp = imap.append("INBOX", mail)
+      assert_equal(1, requests.length)
+      assert_equal("RUBY0001 APPEND INBOX {#{mail.size}}\r\n", requests[0])
+      assert_equal(mail, received_mail)
+      imap.logout
+    ensure
+      imap.disconnect if imap
+    end
+  end
+
+  def test_append_fail
+    server = create_tcp_server
+    port = server.addr[1]
+    mail = <<EOF.gsub(/\n/, "\r\n")
+From: shugo@e...
+To: matz@e...
+Subject: hello
+
+hello world
+EOF
+    requests = []
+    received_mail = nil
+    @threads << Thread.start do
+      sock = server.accept
+      begin
+        sock.print("* OK test server\r\n")
+        line = sock.gets
+        requests.push(line)
+        sock.print("RUBY0001 NO Mailbox doesn't exist\r\n")
+        sock.gets
+        sock.print("* BYE terminating connection\r\n")
+        sock.print("RUBY0002 OK LOGOUT completed\r\n")
+      ensure
+        sock.close
+        server.close
+      end
+    end
+
+    begin
+      imap = Net::IMAP.new(SERVER_ADDR, :port => port)
+      assert_raise(Net::IMAP::NoResponseError) do
+        imap.append("INBOX", mail)
+      end
+      assert_equal(1, requests.length)
+      assert_equal("RUBY0001 APPEND INBOX {#{mail.size}}\r\n", requests[0])
+      imap.logout
+    ensure
+      imap.disconnect if imap
+    end
+  end
+
   private
 
   def imaps_test

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

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