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

ruby-changes:22293

From: naruse <ko1@a...>
Date: Fri, 20 Jan 2012 14:56:49 +0900 (JST)
Subject: [ruby-changes:22293] naruse:r34341 (trunk): * lib/net/http.rb (Net::HTTP#transport_request): retry a idempotent

naruse	2012-01-20 14:56:35 +0900 (Fri, 20 Jan 2012)

  New Revision: 34341

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=34341

  Log:
    * lib/net/http.rb (Net::HTTP#transport_request): retry a idempotent
      request automatically. [ruby-dev:45030] [Bug #5790]
      [ruby-core:41821] [Bug #5813]
    
    * lib/net/http.rb (Net::HTTP#keep_alive_timeout=): added to specify
      the second to reconnect the TCP connection on Keep-Alive.
      The default value is 2 second because current servers uses 2 sec.
      http://ftp-admin.blogspot.com/2009/09/keepalivetimeout2.html
    
    * lib/net/http.rb (Net::HTTP#begin_transport): reconnect TCP
      connection on keep-alive timeout.

  Modified files:
    trunk/ChangeLog
    trunk/lib/net/http.rb
    trunk/test/net/http/test_http.rb
    trunk/test/net/http/utils.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 34340)
+++ ChangeLog	(revision 34341)
@@ -1,3 +1,17 @@
+Fri Jan 20 14:31:43 2012  NARUSE, Yui  <naruse@r...>
+
+	* lib/net/http.rb (Net::HTTP#transport_request): retry a idempotent
+	  request automatically. [ruby-dev:45030] [Bug #5790]
+	  [ruby-core:41821] [Bug #5813]
+
+	* lib/net/http.rb (Net::HTTP#keep_alive_timeout=): added to specify
+	  the second to reconnect the TCP connection on Keep-Alive.
+	  The default value is 2 second because current servers uses 2 sec.
+	  http://ftp-admin.blogspot.com/2009/09/keepalivetimeout2.html
+
+	* lib/net/http.rb (Net::HTTP#begin_transport): reconnect TCP
+	  connection on keep-alive timeout.
+
 Thu Jan 19 07:53:09 2012  Tadayoshi Funaba  <tadf@d...>
 
 	* ext/date/date_strptime.c: moved detector of leftover.
Index: lib/net/http.rb
===================================================================
--- lib/net/http.rb	(revision 34340)
+++ lib/net/http.rb	(revision 34341)
@@ -578,7 +578,8 @@
       @address = address
       @port    = (port || HTTP.default_port)
       @curr_http_version = HTTPVersion
-      @no_keepalive_server = false
+      @keep_alive_timeout = 2
+      @last_communicated = nil
       @close_on_empty_response = false
       @socket  = nil
       @started = false
@@ -648,6 +649,12 @@
       @continue_timeout = sec
     end
 
+    # Seconds to reuse the connection of the previous request.
+    # If the idle time is less than this Keep-Alive Timeout,
+    # Net::HTTP reuses the TCP/IP socket used by the previous communication.
+    # The default value is 2 seconds.
+    attr_accessor :keep_alive_timeout
+
     # Returns true if the HTTP session has been started.
     def started?
       @started
@@ -1332,7 +1339,10 @@
       res
     end
 
+    IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc:
+
     def transport_request(req)
+      count = 0
       begin_transport req
       res = catch(:response) {
         req.exec @socket, @curr_http_version, edit_path(req.path)
@@ -1346,6 +1356,16 @@
       }
       end_transport req, res
       res
+    rescue EOFError, Errno::ECONNRESET => exception
+      if count == 0 && IDEMPOTENT_METHODS_.include?(req.method)
+        count += 1
+        @socket.close if @socket and not @socket.closed?
+        D "Conn close because of error #{exception}, and retry"
+        retry
+      end
+      D "Conn close because of error #{exception}"
+      @socket.close if @socket and not @socket.closed?
+      raise
     rescue => exception
       D "Conn close because of error #{exception}"
       @socket.close if @socket and not @socket.closed?
@@ -1353,7 +1373,14 @@
     end
 
     def begin_transport(req)
-      connect if @socket.closed?
+      if @socket.closed?
+        connect
+      elsif @last_communicated && @last_communicated + @keep_alive_timeout < Time.now
+        D 'Conn close because of keep_alive_timeout'
+        @socket.close
+        connect
+      end
+
       if not req.response_body_permitted? and @close_on_empty_response
         req['connection'] ||= 'close'
       end
@@ -1362,6 +1389,7 @@
 
     def end_transport(req, res)
       @curr_http_version = res.http_version
+      @last_communicated = nil
       if @socket.closed?
         D 'Conn socket closed'
       elsif not res.body and @close_on_empty_response
@@ -1369,6 +1397,7 @@
         @socket.close
       elsif keep_alive?(req, res)
         D 'Conn keep-alive'
+        @last_communicated = Time.now
       else
         D 'Conn close'
         @socket.close
Index: test/net/http/test_http.rb
===================================================================
--- test/net/http/test_http.rb	(revision 34340)
+++ test/net/http/test_http.rb	(revision 34341)
@@ -564,3 +564,47 @@
     assert_not_match(/HTTP\/1.1 100 continue/, @debug.string)
   end
 end
+
+class TestNetHTTPKeepAlive < Test::Unit::TestCase
+  CONFIG = {
+    'host' => '127.0.0.1',
+    'port' => 10081,
+    'proxy_host' => nil,
+    'proxy_port' => nil,
+    'RequestTimeout' => 1,
+  }
+
+  include TestNetHTTPUtils
+
+  def test_keep_alive_get_auto_reconnect
+    start {|http|
+      http.set_debug_output($stderr)
+      res = http.get('/')
+      http.keep_alive_timeout = 1
+      assert_kind_of Net::HTTPResponse, res
+      assert_kind_of String, res.body
+      sleep 1.5
+      assert_nothing_raised {
+        res = http.get('/')
+      }
+      assert_kind_of Net::HTTPResponse, res
+      assert_kind_of String, res.body
+    }
+  end
+
+  def test_keep_alive_get_auto_retry
+    start {|http|
+      http.set_debug_output($stderr)
+      res = http.get('/')
+      http.keep_alive_timeout = 5
+      assert_kind_of Net::HTTPResponse, res
+      assert_kind_of String, res.body
+      sleep 1.5
+      assert_nothing_raised {
+        res = http.get('/')
+      }
+      assert_kind_of Net::HTTPResponse, res
+      assert_kind_of String, res.body
+    }
+  end
+end
Index: test/net/http/utils.rb
===================================================================
--- test/net/http/utils.rb	(revision 34340)
+++ test/net/http/utils.rb	(revision 34341)
@@ -51,6 +51,7 @@
       :ServerType => Thread,
     }
     server_config[:OutputBufferSize] = 4 if config('chunked')
+    server_config[:RequestTimeout] = config('RequestTimeout') if config('RequestTimeout')
     if defined?(OpenSSL) and config('ssl_enable')
       server_config.update({
         :SSLEnable      => true,

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

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