Bug #5813

net/http's EOFError and Keep-Alive

Added by Yui NARUSE over 2 years ago. Updated about 2 years ago.

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

Description

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

  • IDEMPOTENTMETHODS = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc: + def transport_request(req)
  • count = 0 begintransport req res = catch(:response) { req.exec @socket, @currhttpversion, editpath(req.path) @@ -1346,6 +1349,16 @@ module Net #:nodoc: } end_transport req, res res
  • rescue EOFError, Errno::ECONNRESET => exception
  • if count == 0 && IDEMPOTENTMETHODS.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/testhttp.rb b/test/net/http/testhttp.rb index 1515854..2e7ab4e 100644 --- a/test/net/http/testhttp.rb +++ b/test/net/http/testhttp.rb @@ -564,3 +564,29 @@ class TestNetHTTPContinue < Test::Unit::TestCase assertnotmatch(/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 testkeepalive_get
  • start {|http|
  • res = http.get('/')
  • assertkindof Net::HTTPResponse, res
  • assertkindof String, res.body
  • sleep 1
  • assertnothingraised {
  • res = http.get('/')
  • }
  • assertkindof Net::HTTPResponse, res
  • assertkindof 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')
  • serverconfig[:RequestTimeout] = config('RequestTimeout') if config('RequestTimeout') if defined?(OpenSSL) and config('sslenable') server_config.update({ :SSLEnable => true,

Related issues

Related to ruby-trunk - Bug #6001: Retry idempotent HTTP requests for more errors Closed 02/11/2012
Duplicates ruby-trunk - Bug #5790: net/http の EOFError と Keep-Alive Closed 12/22/2011

Associated revisions

Revision 34341
Added by Yui NARUSE about 2 years ago

  • lib/net/http.rb (Net::HTTP#transport_request): retry a idempotent
    request automatically. [Bug #5790]
    [Bug #5813]

  • lib/net/http.rb (Net::HTTP#keepalivetimeout=): 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.

History

#1 Updated by Yui NARUSE about 2 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.


  • lib/net/http.rb (Net::HTTP#transport_request): retry a idempotent
    request automatically. [Bug #5790]
    [Bug #5813]

  • lib/net/http.rb (Net::HTTP#keepalivetimeout=): 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.

Also available in: Atom PDF