Project

General

Profile

Actions

Bug #5813

closed

net/http's EOFError and Keep-Alive

Added by naruse (Yui NARUSE) over 10 years ago. Updated over 10 years ago.

Status:
Closed
Priority:
Normal
Target version:
-
ruby -v:
ruby 2.0.0dev (2011-12-21 trunk 34086) [x86_64-freebsd9.0]
Backport:
[ruby-core:41821]

Description

[ruby-dev:39421] describes exceptions thrown by open-uri, and raise a question why net/http raises EOFError.

net/http sometimes raises EOFError.
I recently find it is because of Keep-Alive.
On HTTP/1.1, connections are Keep-Alive and a Keep-Alive connection has a timeout.
If a client of such connection doesn't send anything after some communication,
server closes the connection because of Keep-Alive timeout,
and the client's connection shall raise EOFError (sometimes it may be ECONNRESET).

HTTP/1.1 says a client should retry a request if the request is idempotent.
http://tools.ietf.org/html/rfc2616#section-8.1.4
http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-17#section-6.1.5
http://www.studyinghttp.net/connections
So I attached a patch to such retry to net/http.

FYI, this timeout of Keep-Alive, KeepAliveTimeout, is:
Apache in FreeBSD ports or pkgsrc is 5 seconds,
the on in Debian Packages or RPM is 15 seconds.

diff --git a/lib/net/http.rb b/lib/net/http.rb
index 879cfe0..13bd1a7 100644
--- a/lib/net/http.rb
+++ b/lib/net/http.rb
@@ -1332,7 +1332,10 @@ module Net #:nodoc:
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 +1349,16 @@ module Net #:nodoc:
}
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?
    diff --git a/test/net/http/test_http.rb b/test/net/http/test_http.rb
    index 1515854..2e7ab4e 100644
    --- a/test/net/http/test_http.rb
    +++ b/test/net/http/test_http.rb
    @@ -564,3 +564,29 @@ class TestNetHTTPContinue < Test::Unit::TestCase
    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' => 0.1,
  • }
  • include TestNetHTTPUtils
  • def test_keep_alive_get
  • start {|http|
  •  res = http.get('/')
    
  •  assert_kind_of Net::HTTPResponse, res
    
  •  assert_kind_of String, res.body
    
  •  sleep 1
    
  •  assert_nothing_raised {
    
  •    res = http.get('/')
    
  •  }
    
  •  assert_kind_of Net::HTTPResponse, res
    
  •  assert_kind_of String, res.body
    
  • }
  • end
    +end
    diff --git a/test/net/http/utils.rb b/test/net/http/utils.rb
    index 50f616f..07e0b9f 100644
    --- a/test/net/http/utils.rb
    +++ b/test/net/http/utils.rb
    @@ -51,6 +51,7 @@ module TestNetHTTPUtils
    :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,

Related issues 2 (0 open2 closed)

Related to Ruby master - Bug #6001: Retry idempotent HTTP requests for more errorsClosed02/11/2012Actions
Is duplicate of Ruby master - Bug #5790: net/http の EOFError と Keep-AliveClosed12/22/2011Actions
Actions #1

Updated by naruse (Yui NARUSE) over 10 years ago

  • Status changed from Assigned to Closed

This issue was solved with changeset r34341.
Yui, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


Actions

Also available in: Atom PDF