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/