diff --git a/.travis.yml b/.travis.yml
index 3d2f5ff..be3eb2f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,16 +9,15 @@ notifications:
   email:
   - drbrain@segment7.net
 rvm:
-- 2.1
-- 2.2
 - 2.3
 - 2.4
 - 2.5
 - 2.6
+- 2.7
 script: rake travis
 install: "" # avoid running default bundler install
 
 matrix:
   include:
-  - rvm: "2.6"
+  - rvm: "2.7"
     env: TRAVIS_MATRIX=pipeline
diff --git a/History.txt b/History.txt
index 6e0987b..36743ba 100644
--- a/History.txt
+++ b/History.txt
@@ -1,4 +1,49 @@
-=== 3.1.0 2019-07-24
+=== 4.0.1 / 2021-01-12
+
+Bug fixes:
+
+* Loosen Ruby version requirement so Ruby 3.0 will work.
+
+=== 4.0.0 / 2020-04-30
+
+Breaking changes:
+
+* Removed built-in support for retrying failed requests as Net::HTTP has this
+  built-in for all supported versions.  Pull request #100 by Michael Grosser.
+* Dropped support for EoL ruby versions (< 2.4).  Future feature releases may
+  drop support for ruby versions that are at end-of-life or in security-only
+  maintenance mode with any release.  Pull request #113 by David Rodríguez
+
+New features:
+
+* Added Net::HTTP::Persistent#max_retries= to configure the number of retries
+  performed on a request for ruby versions that support it (2.5+).
+* URI-ness is determined through #respond_to? to allow compatibility with
+  Addressable::URI.  Pull request #67 by Ryan McKern.
+* Use require_relative to reduce patch burden for vendored versions.  Pull
+  Request #106 by David Rodríguez
+
+Bug fixes:
+
+* Stop wasting a connection when the keep-alive timeout is less than the idle
+  timeout.  Pull request #115 by Yap Sok Ann.
+* Improved use of URI#hostname for IPv6 connections.  Pull request #76 by
+  Tomas Koutsky.
+* Improved check for Process::RLIMIT_NOFILE support.  Pull request #109 by Vít
+  Ondruch.
+* Fix namespace in comments for escape/unescape wrappers.  Pull request #114
+  by David Rodríguez.
+* Fix History.txt timestamp for 3.0.0 release.  Pull request #107 by Joe Van
+  Dyk.
+* Fix link to PR #98 in 3.1.0 release notes.  Pull request #110 by Justin
+  Reid.
+
+Other:
+
+* Updated Net::HTTP::Persistent#reconnect documentation to indicate that all
+  connections are reset.  Issue #117 by Taisuke Miyazaki.
+
+=== 3.1.0 / 2019-07-24
 
 New features:
 * Support ruby 2.6 Net::HTTP#write_timeout=.  Pull request #99 by Víctor
@@ -23,7 +68,7 @@ Bug fixes:
   Kauppila.
 * Fix missing +name:+ argument in documentation.  Pull requests #85 by T.J.
   Schuck, #84 by James White.
-* Fix memory leak from connection pooling.  Pull request #97 by Aaron
+* Fix memory leak from connection pooling.  Pull request #98 by Aaron
   Patterson.
 * Update tests for minitest assert_equal deprecation.  Pull request #92 by
   Olle Jonsson.
@@ -35,7 +80,7 @@ Other:
 * Updated ruby versions in Travis CI.  Pull request #93 by Olle Jonsson.  Pull
   request #103 by Michael Grosser.
 
-=== 3.0 2016-10-05
+=== 3.0 / 2016-10-05
 
 Breaking changes:
 
diff --git a/README.rdoc b/README.rdoc
index 82c4861..4f95ad3 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -1,27 +1,27 @@
 = net-http-persistent
 
-* http://docs.seattlerb.org/net-http-persistent
-* https://github.com/drbrain/net-http-persistent
+home :: https://github.com/drbrain/net-http-persistent
+rdoc :: http://docs.seattlerb.org/net-http-persistent
 
 == DESCRIPTION:
 
-Manages persistent connections using Net::HTTP plus a speed fix for Ruby 1.8.
-It's thread-safe too!
+Manages persistent connections using Net::HTTP including a thread pool for
+connecting to multiple hosts.
 
 Using persistent HTTP connections can dramatically increase the speed of HTTP.
 Creating a new HTTP connection for every request involves an extra TCP
 round-trip and causes TCP congestion avoidance negotiation to start over.
 
 Net::HTTP supports persistent connections with some API methods but does not
-handle reconnection gracefully.  Net::HTTP::Persistent supports reconnection
-and retry according to RFC 2616.
+make setting up a single persistent connection or managing multiple
+connections easy.  Net::HTTP::Persistent wraps Net::HTTP and allows you to
+focus on how to make HTTP requests.
 
 == FEATURES/PROBLEMS:
 
-* Supports SSL
+* Supports TLS with secure defaults
 * Thread-safe
 * Pure ruby
-* Timeout-less speed boost for Ruby 1.8 (by Aaron Patterson)
 
 == SYNOPSIS
 
@@ -60,7 +60,7 @@ including SSL connection verification, header handling and tunable options.
 
 (The MIT License)
 
-Copyright (c) 2010 Eric Hodel, Aaron Patterson
+Copyright (c) Eric Hodel, Aaron Patterson
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
diff --git a/Rakefile b/Rakefile
index 7df2ad2..e3d78c3 100644
--- a/Rakefile
+++ b/Rakefile
@@ -13,12 +13,12 @@ Hoe.spec 'net-http-persistent' do
   self.readme_file      = 'README.rdoc'
   self.extra_rdoc_files += Dir['*.rdoc']
 
-  self.require_ruby_version '~> 2.1'
+  self.require_ruby_version '>= 2.3'
 
   license 'MIT'
 
   rdoc_locations <<
-    'docs.seattlerb.org:/data/www/docs.seattlerb.org/net-http-persistent/'
+    'docs-push.seattlerb.org:/data/www/docs.seattlerb.org/net-http-persistent/'
 
   dependency 'connection_pool',   '~> 2.2'
   dependency 'minitest',          '~> 5.2', :development
diff --git a/checksums.yaml.gz.sig b/checksums.yaml.gz.sig
deleted file mode 100644
index 7f07877..0000000
--- a/checksums.yaml.gz.sig
+++ /dev/null
@@ -1,2 +0,0 @@
-x"%<���5������?�^_���ru�/]�-��>ʝ�qH�O�R,��0����$W�	N�Xζ~���o�^��Z�7,���0�J�A�8ڽ0�]�m�M����v9�74��m_na���)���'+�o��X6-k���'�_
-h����.��*�R|RU�Ջ��;�o"��X�e0	�k�3�шɑ�p�����wo�ΪK��C�dÈ%aIFD�C�`(.,"[�g���_�+��ŵ�s�Ъ�
\ No newline at end of file
diff --git a/data.tar.gz.sig b/data.tar.gz.sig
deleted file mode 100644
index ed07bfe..0000000
Binary files a/data.tar.gz.sig and /dev/null differ
diff --git a/lib/net/http/persistent.rb b/lib/net/http/persistent.rb
index a54be2a..d5fdeb6 100644
--- a/lib/net/http/persistent.rb
+++ b/lib/net/http/persistent.rb
@@ -17,15 +17,11 @@ autoload :OpenSSL, 'openssl'
 # servers you wish to talk to.  For each host:port you communicate with a
 # single persistent connection is created.
 #
-# Multiple Net::HTTP::Persistent objects will share the same set of
-# connections.
+# Connections will be shared across threads through a connection pool to
+# increase reuse of connections.
 #
-# For each thread you start a new connection will be created.  A
-# Net::HTTP::Persistent connection will not be shared across threads.
-#
-# You can shut down the HTTP connections when done by calling #shutdown.  You
-# should name your Net::HTTP::Persistent object if you intend to call this
-# method.
+# You can shut down any remaining HTTP connections when done by calling
+# #shutdown.
 #
 # Example:
 #
@@ -33,7 +29,7 @@ autoload :OpenSSL, 'openssl'
 #
 #   uri = URI 'http://example.com/awesome/web/service'
 #
-#   http = Net::HTTP::Persistent.new name: 'my_app_name'
+#   http = Net::HTTP::Persistent.new
 #
 #   # perform a GET
 #   response = http.request uri
@@ -55,14 +51,14 @@ autoload :OpenSSL, 'openssl'
 # to use URI#request_uri not URI#path.  The request_uri contains the query
 # params which are sent in the body for other requests.
 #
-# == SSL
+# == TLS/SSL
 #
-# SSL connections are automatically created depending upon the scheme of the
-# URI.  SSL connections are automatically verified against the default
+# TLS connections are automatically created depending upon the scheme of the
+# URI.  TLS connections are automatically verified against the default
 # certificate store for your computer.  You can override this by changing
 # verify_mode or by specifying an alternate cert_store.
 #
-# Here are the SSL settings, see the individual methods for documentation:
+# Here are the TLS settings, see the individual methods for documentation:
 #
 # #certificate        :: This client's certificate
 # #ca_file            :: The certificate-authorities
@@ -72,7 +68,7 @@ autoload :OpenSSL, 'openssl'
 # #private_key        :: The client's SSL private key
 # #reuse_ssl_sessions :: Reuse a previously opened SSL session for a new
 #                        connection
-# #ssl_timeout        :: SSL session lifetime
+# #ssl_timeout        :: Session lifetime
 # #ssl_version        :: Which specific SSL version to use
 # #verify_callback    :: For server certificate verification
 # #verify_depth       :: Depth of certificate verification
@@ -101,14 +97,15 @@ autoload :OpenSSL, 'openssl'
 #
 # === Segregation
 #
-# By providing an application name to ::new you can separate your connections
-# from the connections of other applications.
+# Each Net::HTTP::Persistent instance has its own pool of connections.  There
+# is no sharing with other instances (as was true in earlier versions).
 #
 # === Idle Timeout
 #
-# If a connection hasn't been used for this number of seconds it will automatically be
-# reset upon the next use to avoid attempting to send to a closed connection.
-# The default value is 5 seconds. nil means no timeout. Set through #idle_timeout.
+# If a connection hasn't been used for this number of seconds it will
+# automatically be reset upon the next use to avoid attempting to send to a
+# closed connection.  The default value is 5 seconds. nil means no timeout.
+# Set through #idle_timeout.
 #
 # Reducing this value may help avoid the "too many connection resets" error
 # when sending non-idempotent requests while increasing this value will cause
@@ -123,8 +120,9 @@ autoload :OpenSSL, 'openssl'
 #
 # The number of requests that should be made before opening a new connection.
 # Typically many keep-alive capable servers tune this to 100 or less, so the
-# 101st request will fail with ECONNRESET. If unset (default), this value has no
-# effect, if set, connections will be reset on the request after max_requests.
+# 101st request will fail with ECONNRESET. If unset (default), this value has
+# no effect, if set, connections will be reset on the request after
+# max_requests.
 #
 # === Open Timeout
 #
@@ -136,45 +134,6 @@ autoload :OpenSSL, 'openssl'
 # Socket options may be set on newly-created connections.  See #socket_options
 # for details.
 #
-# === Non-Idempotent Requests
-#
-# By default non-idempotent requests will not be retried per RFC 2616.  By
-# setting retry_change_requests to true requests will automatically be retried
-# once.
-#
-# Only do this when you know that retrying a POST or other non-idempotent
-# request is safe for your application and will not create duplicate
-# resources.
-#
-# The recommended way to handle non-idempotent requests is the following:
-#
-#   require 'net/http/persistent'
-#
-#   uri = URI 'http://example.com/awesome/web/service'
-#   post_uri = uri + 'create'
-#
-#   http = Net::HTTP::Persistent.new name: 'my_app_name'
-#
-#   post = Net::HTTP::Post.new post_uri.path
-#   # ... fill in POST request
-#
-#   begin
-#     response = http.request post_uri, post
-#   rescue Net::HTTP::Persistent::Error
-#
-#     # POST failed, make a new request to verify the server did not process
-#     # the request
-#     exists_uri = uri + '...'
-#     response = http.get exists_uri
-#
-#     # Retry if it failed
-#     retry if response.code == '404'
-#   end
-#
-# The method of determining if the resource was created or not is unique to
-# the particular service you are using.  Of course, you will want to add
-# protection from infinite looping.
-#
 # === Connection Termination
 #
 # If you are done using the Net::HTTP::Persistent instance you may shut down
@@ -200,33 +159,20 @@ class Net::HTTP::Persistent
   HAVE_OPENSSL = defined? OpenSSL::SSL # :nodoc:
 
   ##
-  # The default connection pool size is 1/4 the allowed open files.
+  # The default connection pool size is 1/4 the allowed open files
+  # (<code>ulimit -n</code>) or 256 if your OS does not support file handle
+  # limits (typically windows).
 
-  if Gem.win_platform? then
-    DEFAULT_POOL_SIZE = 256
-  else
+  if Process.const_defined? :RLIMIT_NOFILE
     DEFAULT_POOL_SIZE = Process.getrlimit(Process::RLIMIT_NOFILE).first / 4
+  else
+    DEFAULT_POOL_SIZE = 256
   end
 
   ##
   # The version of Net::HTTP::Persistent you are using
 
-  VERSION = '3.1.0'
-
-  ##
-  # Exceptions rescued for automatic retry on ruby 2.0.0.  This overlaps with
-  # the exception list for ruby 1.x.
-
-  RETRIED_EXCEPTIONS = [ # :nodoc:
-    (Net::ReadTimeout if Net.const_defined? :ReadTimeout),
-    IOError,
-    EOFError,
-    Errno::ECONNRESET,
-    Errno::ECONNABORTED,
-    Errno::EPIPE,
-    (OpenSSL::SSL::SSLError if HAVE_OPENSSL),
-    Timeout::Error,
-  ].compact
+  VERSION = '4.0.1'
 
   ##
   # Error class for errors raised by Net::HTTP::Persistent.  Various
@@ -353,6 +299,13 @@ class Net::HTTP::Persistent
 
   attr_accessor :max_requests
 
+  ##
+  # Number of retries to perform if a request fails.
+  #
+  # See also #max_retries=, Net::HTTP#max_retries=.
+
+  attr_reader :max_retries
+
   ##
   # The value sent in the Keep-Alive header.  Defaults to 30.  Not needed for
   # HTTP/1.1 servers.
@@ -365,8 +318,7 @@ class Net::HTTP::Persistent
   attr_accessor :keep_alive
 
   ##
-  # A name for this connection.  Allows you to keep your connections apart
-  # from everybody else's.
+  # The name for this collection of persistent connections.
 
   attr_reader :name
 
@@ -495,23 +447,11 @@ class Net::HTTP::Persistent
 
   attr_reader :verify_mode
 
-  ##
-  # Enable retries of non-idempotent requests that change data (e.g. POST
-  # requests) when the server has disconnected.
-  #
-  # This will in the worst case lead to multiple requests with the same data,
-  # but it may be useful for some applications.  Take care when enabling
-  # this option to ensure it is safe to POST or perform other non-idempotent
-  # requests to the server.
-
-  attr_accessor :retry_change_requests
-
   ##
   # Creates a new Net::HTTP::Persistent.
   #
-  # Set +name+ to keep your connections apart from everybody else's.  Not
-  # required currently, but highly recommended.  Your library name should be
-  # good enough.  This parameter will be required in a future version.
+  # Set a +name+ for fun.  Your library name should be good enough, but this
+  # otherwise has no purpose.
   #
   # +proxy+ may be set to a URI::HTTP or :ENV to pick up proxy options from
   # the environment.  See proxy_from_env for details.
@@ -524,8 +464,9 @@ class Net::HTTP::Persistent
   #   proxy.password = 'hunter2'
   #
   # Set +pool_size+ to limit the maximum number of connections allowed.
-  # Defaults to 1/4 the number of allowed file handles.  You can have no more
-  # than this many threads with active HTTP transactions.
+  # Defaults to 1/4 the number of allowed file handles or 256 if your OS does
+  # not support a limit on allowed file handles.  You can have no more than
+  # this many threads with active HTTP transactions.
 
   def initialize name: nil, proxy: nil, pool_size: DEFAULT_POOL_SIZE
     @name = name
@@ -542,6 +483,7 @@ class Net::HTTP::Persistent
     @write_timeout    = nil
     @idle_timeout     = 5
     @max_requests     = nil
+    @max_retries      = 1
     @socket_options   = []
     @ssl_generation   = 0 # incremented when SSL session variables change
 
@@ -573,8 +515,6 @@ class Net::HTTP::Persistent
       @reuse_ssl_sessions = OpenSSL::SSL.const_defined? :Session
     end
 
-    @retry_change_requests = false
-
     self.proxy = proxy if proxy
   end
 
@@ -635,7 +575,9 @@ class Net::HTTP::Persistent
 
     net_http_args = [uri.hostname, uri.port]
 
-    if @proxy_uri and not proxy_bypass? uri.hostname, uri.port then
+    # I'm unsure if uri.host or uri.hostname should be checked against
+    # the proxy bypass list.
+    if @proxy_uri and not proxy_bypass? uri.host, uri.port then
       net_http_args.concat @proxy_args
     else
       net_http_args.concat [nil, nil, nil, nil]
@@ -655,9 +597,11 @@ class Net::HTTP::Persistent
       reset connection
     end
 
-    http.read_timeout = @read_timeout if @read_timeout
-    http.write_timeout = @write_timeout if @write_timeout && http.respond_to?(:write_timeout=)
-    http.keep_alive_timeout = @idle_timeout if @idle_timeout
+    http.keep_alive_timeout = @idle_timeout  if @idle_timeout
+    http.max_retries        = @max_retries   if http.respond_to?(:max_retries=)
+    http.read_timeout       = @read_timeout  if @read_timeout
+    http.write_timeout      = @write_timeout if
+      @write_timeout && http.respond_to?(:write_timeout=)
 
     return yield connection
   rescue Errno::ECONNREFUSED
@@ -675,27 +619,14 @@ class Net::HTTP::Persistent
   end
 
   ##
-  # Returns an error message containing the number of requests performed on
-  # this connection
-
-  def error_message connection
-    connection.requests -= 1 # fixup
-
-    age = Time.now - connection.last_use
-
-    "after #{connection.requests} requests on #{connection.http.object_id}, " \
-      "last used #{age} seconds ago"
-  end
-
-  ##
-  # URI::escape wrapper
+  # CGI::escape wrapper
 
   def escape str
     CGI.escape str if str
   end
 
   ##
-  # URI::unescape wrapper
+  # CGI::unescape wrapper
 
   def unescape str
     CGI.unescape str if str
@@ -738,6 +669,7 @@ class Net::HTTP::Persistent
   def finish connection
     connection.finish
 
+    connection.http.instance_variable_set :@last_communicated, nil
     connection.http.instance_variable_set :@ssl_session, nil unless
       @reuse_ssl_sessions
   end
@@ -746,31 +678,31 @@ class Net::HTTP::Persistent
   # Returns the HTTP protocol version for +uri+
 
   def http_version uri
-    @http_versions["#{uri.host}:#{uri.port}"]
+    @http_versions["#{uri.hostname}:#{uri.port}"]
   end
 
   ##
-  # Is +req+ idempotent according to RFC 2616?
+  # Adds "http://" to the String +uri+ if it is missing.
 
-  def idempotent? req
-    case req.method
-    when 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PUT', 'TRACE' then
-      true
-    end
+  def normalize_uri uri
+    (uri =~ /^https?:/) ? uri : "http://#{uri}"
   end
 
   ##
-  # Is the request +req+ idempotent or is retry_change_requests allowed.
+  # Set the maximum number of retries for a request.
+  #
+  # Defaults to one retry.
+  #
+  # Set this to 0 to disable retries.
 
-  def can_retry? req
-    @retry_change_requests && !idempotent?(req)
-  end
+  def max_retries= retries
+    retries = retries.to_int
 
-  ##
-  # Adds "http://" to the String +uri+ if it is missing.
+    raise ArgumentError, "max_retries must be positive" if retries < 0
 
-  def normalize_uri uri
-    (uri =~ /^https?:/) ? uri : "http://#{uri}"
+    @max_retries = retries
+
+    reconnect
   end
 
   ##
@@ -828,7 +760,7 @@ class Net::HTTP::Persistent
 
     if @proxy_uri then
       @proxy_args = [
-        @proxy_uri.host,
+        @proxy_uri.hostname,
         @proxy_uri.port,
         unescape(@proxy_uri.user),
         unescape(@proxy_uri.password),
@@ -903,14 +835,15 @@ class Net::HTTP::Persistent
   end
 
   ##
-  # Forces reconnection of HTTP connections.
+  # Forces reconnection of all HTTP connections, including TLS/SSL
+  # connections.
 
   def reconnect
     @generation += 1
   end
 
   ##
-  # Forces reconnection of SSL connections.
+  # Forces reconnection of only TLS/SSL connections.
 
   def reconnect_ssl
     @ssl_generation += 1
@@ -943,14 +876,8 @@ class Net::HTTP::Persistent
   # the response will not have been read).
   #
   # +req+ must be a Net::HTTPGenericRequest subclass (see Net::HTTP for a list).
-  #
-  # If there is an error and the request is idempotent according to RFC 2616
-  # it will be retried automatically.
 
   def request uri, req = nil, &block
-    retried      = false
-    bad_response = false
-
     uri      = URI uri
     req      = request_setup req || uri
     response = nil
@@ -964,37 +891,12 @@ class Net::HTTP::Persistent
         response = http.request req, &block
 
         if req.connection_close? or
-           (response.http_version <= '1.0' and
+          (response.http_version <= '1.0' and
             not response.connection_keep_alive?) or
-           response.connection_close? then
+            response.connection_close? then
           finish connection
         end
-      rescue Net::HTTPBadResponse => e
-        message = error_message connection
-
-        finish connection
-
-        raise Error, "too many bad responses #{message}" if
-        bad_response or not can_retry? req
-
-        bad_response = true
-        retry
-      rescue *RETRIED_EXCEPTIONS => e
-        request_failed e, req, connection if
-          retried or not can_retry? req
-
-        reset connection
-
-        retried = true
-        retry
-      rescue Errno::EINVAL, Errno::ETIMEDOUT => e # not retried on ruby 2
-        request_failed e, req, connection if retried or not can_retry? req
-
-        reset connection
-
-        retried = true
-        retry
-      rescue Exception => e
+      rescue Exception # make sure to close the connection when it was interrupted
         finish connection
 
         raise
@@ -1003,26 +905,11 @@ class Net::HTTP::Persistent
       end
     end
 
-    @http_versions["#{uri.host}:#{uri.port}"] ||= response.http_version
+    @http_versions["#{uri.hostname}:#{uri.port}"] ||= response.http_version
 
     response
   end
 
-  ##
-  # Raises an Error for +exception+ which resulted from attempting the request
-  # +req+ on the +connection+.
-  #
-  # Finishes the +connection+.
-
-  def request_failed exception, req, connection # :nodoc:
-    due_to = "(due to #{exception.message} - #{exception.class})"
-    message = "too many connection resets #{due_to} #{error_message connection}"
-
-    finish connection
-
-    raise Error, message, exception.backtrace
-  end
-
   ##
   # Creates a GET request if +req_or_uri+ is a URI and adds headers to the
   # request.
@@ -1030,7 +917,7 @@ class Net::HTTP::Persistent
   # Returns the request.
 
   def request_setup req_or_uri # :nodoc:
-    req = if URI === req_or_uri then
+    req = if req_or_uri.respond_to? 'request_uri' then
             Net::HTTP::Get.new req_or_uri.request_uri
           else
             req_or_uri
@@ -1194,9 +1081,8 @@ application:
 
     reconnect_ssl
   end
-
 end
 
-require 'net/http/persistent/connection'
-require 'net/http/persistent/pool'
+require_relative 'persistent/connection'
+require_relative 'persistent/pool'
 
diff --git a/lib/net/http/persistent/pool.rb b/lib/net/http/persistent/pool.rb
index 8990006..21371f5 100644
--- a/lib/net/http/persistent/pool.rb
+++ b/lib/net/http/persistent/pool.rb
@@ -49,5 +49,5 @@ class Net::HTTP::Persistent::Pool < ConnectionPool # :nodoc:
   end
 end
 
-require 'net/http/persistent/timed_stack_multi'
+require_relative 'timed_stack_multi'
 
diff --git a/metadata.gz.sig b/metadata.gz.sig
deleted file mode 100644
index 15d4844..0000000
--- a/metadata.gz.sig
+++ /dev/null
@@ -1,2 +0,0 @@
-x�L��)��0�嫗f[f+K�Ն�ʺ�,&��L6�9�4�m(��hρ�X�O`�w�/���OX��S�#y�j6c(ܜ6�qB��k��_��W;��D�6������*�ϴ��mV_�+��R\���H@
-��O�+)#�tB]�/�����崯���[���1x#w�M׳$�W�>�nb���}8�O�
��%��%v1����y�D�����ft%P��i;@���x*��_�v����C���W��#�)
\ No newline at end of file
diff --git a/net-http-persistent.gemspec b/net-http-persistent.gemspec
index 8a9cc94..b6d3bcc 100644
--- a/net-http-persistent.gemspec
+++ b/net-http-persistent.gemspec
@@ -2,52 +2,52 @@
 # This file has been automatically generated by gem2tgz #
 #########################################################
 # -*- encoding: utf-8 -*-
-# stub: net-http-persistent 3.1.0 ruby lib
+# stub: net-http-persistent 4.0.1 ruby lib
 
 Gem::Specification.new do |s|
   s.name = "net-http-persistent".freeze
-  s.version = "3.1.0"
+  s.version = "4.0.1"
 
   s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
+  s.metadata = { "homepage_uri" => "https://github.com/drbrain/net-http-persistent" } if s.respond_to? :metadata=
   s.require_paths = ["lib".freeze]
   s.authors = ["Eric Hodel".freeze]
-  s.cert_chain = ["-----BEGIN CERTIFICATE-----\nMIIDNjCCAh6gAwIBAgIBBjANBgkqhkiG9w0BAQsFADBBMRAwDgYDVQQDDAdkcmJy\nYWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZFgNu\nZXQwHhcNMTkwNDA4MjEwOTU2WhcNMjAwNDA3MjEwOTU2WjBBMRAwDgYDVQQDDAdk\ncmJyYWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZ\nFgNuZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbbgLrGLGIDE76\nLV/cvxdEzCuYuS3oG9PrSZnuDweySUfdp/so0cDq+j8bqy6OzZSw07gdjwFMSd6J\nU5ddZCVywn5nnAQ+Ui7jMW54CYt5/H6f2US6U0hQOjJR6cpfiymgxGdfyTiVcvTm\nGj/okWrQl0NjYOYBpDi+9PPmaH2RmLJu0dB/NylsDnW5j6yN1BEI8MfJRR+HRKZY\nmUtgzBwF1V4KIZQ8EuL6I/nHVu07i6IkrpAgxpXUfdJQJi0oZAqXurAV3yTxkFwd\ng62YrrW26mDe+pZBzR6bpLE+PmXCzz7UxUq3AE0gPHbiMXie3EFE0oxnsU3lIduh\nsCANiQ8BAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW\nBBS5k4Z75VSpdM0AclG2UvzFA/VW5DANBgkqhkiG9w0BAQsFAAOCAQEAP5FfXeij\n/fkvIZDdN0LV1ES3Thqoz4aQFbJv1Gf3VccYMs7/Rop5oWBOtiHMIVc855bgv5fx\nuzRtuwiuiq1mZ6IZWkFnEw+vi+M6Q5e/8v+dhej1r7rPW71y4I1wH972O8qiuRXZ\nEVu1y+fPhNAu6OTMgVtgkijEuA9d4OQ2xusF/YKWkaVkjrdHcDAEaquxYUKrswxM\nDohqfAYWGDt2dmCWfRWTsBLm3p3R0mwKe8uOy4gSwcvG5SG57oSZoxrAN9CgsJoR\nP+3YOaiDtZ7g4lYXhpJrMooDnoWr4TPbGIVuq0xfPlFinjBH0o1W+LfGS+3aCN6b\njT8g+1iKSQKJYA==\n-----END CERTIFICATE-----\n".freeze]
-  s.date = "2019-07-25"
-  s.description = "Manages persistent connections using Net::HTTP plus a speed fix for Ruby 1.8.\nIt's thread-safe too!\n\nUsing persistent HTTP connections can dramatically increase the speed of HTTP.\nCreating a new HTTP connection for every request involves an extra TCP\nround-trip and causes TCP congestion avoidance negotiation to start over.\n\nNet::HTTP supports persistent connections with some API methods but does not\nhandle reconnection gracefully.  Net::HTTP::Persistent supports reconnection\nand retry according to RFC 2616.".freeze
+  s.date = "2021-01-12"
+  s.description = "Manages persistent connections using Net::HTTP including a thread pool for\nconnecting to multiple hosts.\n\nUsing persistent HTTP connections can dramatically increase the speed of HTTP.\nCreating a new HTTP connection for every request involves an extra TCP\nround-trip and causes TCP congestion avoidance negotiation to start over.\n\nNet::HTTP supports persistent connections with some API methods but does not\nmake setting up a single persistent connection or managing multiple\nconnections easy.  Net::HTTP::Persistent wraps Net::HTTP and allows you to\nfocus on how to make HTTP requests.".freeze
   s.email = ["drbrain@segment7.net".freeze]
   s.extra_rdoc_files = ["History.txt".freeze, "Manifest.txt".freeze, "README.rdoc".freeze]
   s.files = [".autotest".freeze, ".gemtest".freeze, ".travis.yml".freeze, "Gemfile".freeze, "History.txt".freeze, "Manifest.txt".freeze, "README.rdoc".freeze, "Rakefile".freeze, "lib/net/http/persistent.rb".freeze, "lib/net/http/persistent/connection.rb".freeze, "lib/net/http/persistent/pool.rb".freeze, "lib/net/http/persistent/timed_stack_multi.rb".freeze, "test/test_net_http_persistent.rb".freeze, "test/test_net_http_persistent_timed_stack_multi.rb".freeze]
-  s.homepage = "http://docs.seattlerb.org/net-http-persistent".freeze
+  s.homepage = "https://github.com/drbrain/net-http-persistent".freeze
   s.licenses = ["MIT".freeze]
   s.rdoc_options = ["--main".freeze, "README.rdoc".freeze]
-  s.required_ruby_version = Gem::Requirement.new("~> 2.1".freeze)
-  s.rubygems_version = "2.5.2.1".freeze
-  s.summary = "Manages persistent connections using Net::HTTP plus a speed fix for Ruby 1.8".freeze
+  s.required_ruby_version = Gem::Requirement.new(">= 2.3".freeze)
+  s.rubygems_version = "2.7.6.2".freeze
+  s.summary = "Manages persistent connections using Net::HTTP including a thread pool for connecting to multiple hosts".freeze
 
   if s.respond_to? :specification_version then
     s.specification_version = 4
 
     if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
       s.add_runtime_dependency(%q<connection_pool>.freeze, ["~> 2.2"])
-      s.add_development_dependency(%q<hoe>.freeze, ["~> 3.17"])
+      s.add_development_dependency(%q<hoe>.freeze, ["~> 3.22"])
       s.add_development_dependency(%q<hoe-bundler>.freeze, ["~> 1.5"])
       s.add_development_dependency(%q<hoe-travis>.freeze, [">= 1.4.1", "~> 1.4"])
-      s.add_development_dependency(%q<minitest>.freeze, ["~> 5.11"])
+      s.add_development_dependency(%q<minitest>.freeze, ["~> 5.14"])
       s.add_development_dependency(%q<rdoc>.freeze, ["< 7", ">= 4.0"])
     else
       s.add_dependency(%q<connection_pool>.freeze, ["~> 2.2"])
-      s.add_dependency(%q<hoe>.freeze, ["~> 3.17"])
+      s.add_dependency(%q<hoe>.freeze, ["~> 3.22"])
       s.add_dependency(%q<hoe-bundler>.freeze, ["~> 1.5"])
       s.add_dependency(%q<hoe-travis>.freeze, [">= 1.4.1", "~> 1.4"])
-      s.add_dependency(%q<minitest>.freeze, ["~> 5.11"])
+      s.add_dependency(%q<minitest>.freeze, ["~> 5.14"])
       s.add_dependency(%q<rdoc>.freeze, ["< 7", ">= 4.0"])
     end
   else
     s.add_dependency(%q<connection_pool>.freeze, ["~> 2.2"])
-    s.add_dependency(%q<hoe>.freeze, ["~> 3.17"])
+    s.add_dependency(%q<hoe>.freeze, ["~> 3.22"])
     s.add_dependency(%q<hoe-bundler>.freeze, ["~> 1.5"])
     s.add_dependency(%q<hoe-travis>.freeze, [">= 1.4.1", "~> 1.4"])
-    s.add_dependency(%q<minitest>.freeze, ["~> 5.11"])
+    s.add_dependency(%q<minitest>.freeze, ["~> 5.14"])
     s.add_dependency(%q<rdoc>.freeze, ["< 7", ">= 4.0"])
   end
 end
diff --git a/test/test_net_http_persistent.rb b/test/test_net_http_persistent.rb
index 2ced6ae..f393950 100644
--- a/test/test_net_http_persistent.rb
+++ b/test/test_net_http_persistent.rb
@@ -56,7 +56,8 @@ class TestNetHttpPersistent < Minitest::Test
   def setup
     @http = Net::HTTP::Persistent.new
 
-    @uri  = URI.parse 'http://example.com/path'
+    @uri    = URI 'http://example.com/path'
+    @uri_v6 = URI 'http://[2001:db8::1]/path'
 
     ENV.delete 'http_proxy'
     ENV.delete 'HTTP_PROXY'
@@ -120,7 +121,7 @@ class TestNetHttpPersistent < Minitest::Test
   def basic_connection
     raise "#{@uri} is not HTTP" unless @uri.scheme.downcase == 'http'
 
-    net_http_args = [@uri.host, @uri.port, nil, nil, nil, nil]
+    net_http_args = [@uri.hostname, @uri.port, nil, nil, nil, nil]
 
     connection = Net::HTTP::Persistent::Connection.allocate
     connection.ssl_generation = @http.ssl_generation
@@ -132,7 +133,9 @@ class TestNetHttpPersistent < Minitest::Test
     connection
   end
 
-  def connection
+  def connection uri = @uri
+    @uri = uri
+
     connection = basic_connection
     connection.last_use = Time.now
 
@@ -152,7 +155,7 @@ class TestNetHttpPersistent < Minitest::Test
   def ssl_connection
     raise "#{@uri} is not HTTPS" unless @uri.scheme.downcase == 'https'
 
-    net_http_args = [@uri.host, @uri.port, nil, nil, nil, nil]
+    net_http_args = [@uri.hostname, @uri.port, nil, nil, nil, nil]
 
     connection = Net::HTTP::Persistent::Connection.allocate
     connection.ssl_generation = @http.ssl_generation
@@ -220,26 +223,6 @@ class TestNetHttpPersistent < Minitest::Test
     assert_equal 1, @http.ssl_generation
   end
 
-  def test_can_retry_eh_change_requests
-    post = Net::HTTP::Post.new '/'
-
-    refute @http.can_retry? post
-
-    @http.retry_change_requests = true
-
-    assert @http.can_retry? post
-  end
-
-  def test_can_retry_eh_idempotent
-    head = Net::HTTP::Head.new '/'
-
-    refute @http.can_retry? head
-
-    post = Net::HTTP::Post.new '/'
-
-    refute @http.can_retry? post
-  end
-
   def test_cert_store_equals
     @http.cert_store = :cert_store
 
@@ -265,6 +248,7 @@ class TestNetHttpPersistent < Minitest::Test
     @http.open_timeout = 123
     @http.read_timeout = 321
     @http.idle_timeout = 42
+    @http.max_retries  = 5
 
     used = @http.connection_for @uri do |c|
       assert_kind_of Net::HTTP, c.http
@@ -275,6 +259,7 @@ class TestNetHttpPersistent < Minitest::Test
       assert_equal 123, c.http.open_timeout
       assert_equal 321, c.http.read_timeout
       assert_equal 42, c.http.keep_alive_timeout
+      assert_equal 5, c.http.max_retries if c.http.respond_to?(:max_retries)
 
       c
     end
@@ -396,10 +381,8 @@ class TestNetHttpPersistent < Minitest::Test
   end
 
   def test_connection_for_ipv6
-    uri = URI.parse 'https://[::1]/'
-
-    @http.connection_for uri do |c|
-      assert_equal '::1', c.http.address
+    @http.connection_for @uri_v6 do |c|
+      assert_equal '2001:db8::1', c.http.address
     end
   end
 
@@ -635,16 +618,6 @@ class TestNetHttpPersistent < Minitest::Test
     end
   end
 
-  def test_error_message
-    c = basic_connection
-    c.last_use = Time.now - 1
-    c.requests = 5
-
-    message = @http.error_message c
-    assert_match %r%after 4 requests on #{c.http.object_id}%, message
-    assert_match %r%, last used [\d.]+ seconds ago%, message
-  end
-
   def test_escape
     assert_nil @http.escape nil
 
@@ -698,6 +671,7 @@ class TestNetHttpPersistent < Minitest::Test
   def test_finish
     c = basic_connection
     c.requests = 5
+    c.http.instance_variable_set(:@last_communicated, Process.clock_gettime(Process::CLOCK_MONOTONIC))
 
     @http.finish c
 
@@ -706,6 +680,7 @@ class TestNetHttpPersistent < Minitest::Test
 
     assert_equal 0, c.requests
     assert_equal Net::HTTP::Persistent::EPOCH, c.last_use
+    assert_nil c.http.instance_variable_get(:@last_communicated)
   end
 
   def test_finish_io_error
@@ -743,24 +718,21 @@ class TestNetHttpPersistent < Minitest::Test
     assert_equal '1.1', @http.http_version(@uri)
   end
 
-  def test_idempotent_eh
-    assert @http.idempotent? Net::HTTP::Delete.new '/'
-    assert @http.idempotent? Net::HTTP::Get.new '/'
-    assert @http.idempotent? Net::HTTP::Head.new '/'
-    assert @http.idempotent? Net::HTTP::Options.new '/'
-    assert @http.idempotent? Net::HTTP::Put.new '/'
-    assert @http.idempotent? Net::HTTP::Trace.new '/'
+  def test_http_version_IPv6
+    assert_nil @http.http_version @uri_v6
+
+    connection @uri_v6
 
-    assert @http.idempotent? Net::HTTPGenericRequest.new('DELETE', false, true, '/')
-    assert @http.idempotent? Net::HTTPGenericRequest.new('GET', false, true, '/')
-    assert @http.idempotent? Net::HTTPGenericRequest.new('HEAD', false, false, '/')
-    assert @http.idempotent? Net::HTTPGenericRequest.new('OPTIONS', false, false, '/')
-    assert @http.idempotent? Net::HTTPGenericRequest.new('PUT', true, true, '/')
-    assert @http.idempotent? Net::HTTPGenericRequest.new('TRACE', false, true, '/')
+    @http.request @uri_v6
+
+    assert_equal '1.1', @http.http_version(@uri_v6)
+  end
 
-    refute @http.idempotent? Net::HTTP::Post.new '/'
+  def test_max_retries_equals
+    @http.max_retries = 5
 
-    refute @http.idempotent? Net::HTTPGenericRequest.new('POST', true, true, '/')
+    assert_equal 5, @http.max_retries
+    assert_equal 1, @http.generation
   end
 
   def test_normalize_uri
@@ -832,6 +804,14 @@ class TestNetHttpPersistent < Minitest::Test
     assert_equal proxy_uri, @http.proxy_uri
   end
 
+  def test_proxy_equals_uri_IPv6
+    proxy_uri = @uri_v6
+
+    @http.proxy = proxy_uri
+
+    assert_equal proxy_uri, @http.proxy_uri
+  end
+
   def test_proxy_from_env
     ENV['http_proxy']      = 'proxy.example'
     ENV['http_proxy_user'] = 'johndoe'
@@ -977,7 +957,7 @@ class TestNetHttpPersistent < Minitest::Test
     assert_equal Net::HTTP::Persistent::EPOCH, used2.last_use
   end
 
-  def test_request
+  def test_requestx
     @http.override_headers['user-agent'] = 'test ua'
     @http.headers['accept'] = 'text/*'
     c = connection
@@ -1001,62 +981,6 @@ class TestNetHttpPersistent < Minitest::Test
     assert_equal 1, c.requests
   end
 
-  def test_request_ETIMEDOUT
-    c = basic_connection
-    def (c.http).request(*a) raise Errno::ETIMEDOUT, "timed out" end
-
-    e = assert_raises Net::HTTP::Persistent::Error do
-      @http.request @uri
-    end
-
-    assert_equal 0, c.requests
-    assert_match %r%too many connection resets%, e.message
-  end
-
-  def test_request_bad_response
-    c = basic_connection
-    def (c.http).request(*a) raise Net::HTTPBadResponse end
-
-    e = assert_raises Net::HTTP::Persistent::Error do
-      @http.request @uri
-    end
-
-    assert_equal 0, c.requests
-    assert_match %r%too many bad responses%, e.message
-  end
-
-  def test_request_bad_response_retry
-    c = basic_connection
-    def (c.http).request(*a)
-      raise Net::HTTPBadResponse
-    end
-
-    assert_raises Net::HTTP::Persistent::Error do
-      @http.request @uri
-    end
-
-    assert c.http.finished?
-  end
-
-  def test_request_bad_response_unsafe
-    c = basic_connection
-    def (c.http).request(*a)
-      if instance_variable_defined? :@request then
-        raise 'POST must not be retried'
-      else
-        @request = true
-        raise Net::HTTPBadResponse
-      end
-    end
-
-    e = assert_raises Net::HTTP::Persistent::Error do
-      @http.request @uri, Net::HTTP::Post.new(@uri.path)
-    end
-
-    assert_equal 0, c.requests
-    assert_match %r%too many bad responses%, e.message
-  end
-
   def test_request_block
     @http.headers['user-agent'] = 'test ua'
     c = connection
@@ -1182,12 +1106,12 @@ class TestNetHttpPersistent < Minitest::Test
     c = basic_connection
     def (c.http).request(*a) raise Errno::EINVAL, "write" end
 
-    e = assert_raises Net::HTTP::Persistent::Error do
+    e = assert_raises Errno::EINVAL do
       @http.request @uri
     end
 
     assert_equal 0, c.requests
-    assert_match %r%too many connection resets%, e.message
+    assert_match %r%Invalid argument - write%, e.message
   end
 
   def test_request_post
@@ -1201,69 +1125,6 @@ class TestNetHttpPersistent < Minitest::Test
     assert_same post, req
   end
 
-  def test_request_reset
-    c = basic_connection
-    def (c.http).request(*a) raise Errno::ECONNRESET end
-
-    e = assert_raises Net::HTTP::Persistent::Error do
-      @http.request @uri
-    end
-
-    assert_equal 0, c.requests
-    assert_match %r%too many connection resets%, e.message
-  end
-
-  def test_request_reset_retry
-    c = basic_connection
-    c.last_use = Time.now
-
-    def (c.http).request(*a)
-      raise Errno::ECONNRESET
-    end
-
-    assert_raises Net::HTTP::Persistent::Error do
-      @http.request @uri
-    end
-
-    refute (c.http).reset?
-    assert (c.http).finished?
-  end
-
-  def test_request_reset_unsafe
-    c = basic_connection
-    def (c.http).request(*a)
-      if instance_variable_defined? :@request then
-        raise 'POST must not be retried'
-      else
-        @request = true
-        raise Errno::ECONNRESET
-      end
-    end
-
-    e = assert_raises Net::HTTP::Persistent::Error do
-      @http.request @uri, Net::HTTP::Post.new(@uri.path)
-    end
-
-    assert_equal 0, c.requests
-    assert_match %r%too many connection resets%, e.message
-  end
-
-  def test_request_ssl_error
-    skip 'OpenSSL is missing' unless HAVE_OPENSSL
-
-    uri = URI.parse 'https://example.com/path'
-    @http.connection_for uri do |c|
-      def (c.http).request(*)
-        raise OpenSSL::SSL::SSLError, "SSL3_WRITE_PENDING:bad write retry"
-      end
-
-      e = assert_raises Net::HTTP::Persistent::Error do
-        @http.request uri
-      end
-      assert_match %r%bad write retry%, e.message
-    end
-  end
-
   def test_request_setup
     @http.override_headers['user-agent'] = 'test ua'
     @http.headers['accept'] = 'text/*'
@@ -1307,30 +1168,6 @@ class TestNetHttpPersistent < Minitest::Test
     assert_equal '/path?a=b',  req.path
   end
 
-  def test_request_failed
-    c = basic_connection
-    c.requests = 1
-    c.last_use = Time.now
-
-    original = nil
-
-    begin
-      raise 'original'
-    rescue => original
-    end
-
-    req = Net::HTTP::Get.new '/'
-
-    e = assert_raises Net::HTTP::Persistent::Error do
-      @http.request_failed original, req, c
-    end
-
-    assert_match "too many connection resets (due to original - RuntimeError)",
-                 e.message
-
-    assert_equal original.backtrace, e.backtrace
-  end
-
   def test_reset
     c = basic_connection
     c.http.start
@@ -1385,23 +1222,6 @@ class TestNetHttpPersistent < Minitest::Test
     assert_match __FILE__, e.backtrace.first
   end
 
-  def test_retry_change_requests_equals
-    get  = Net::HTTP::Get.new('/')
-    post = Net::HTTP::Post.new('/')
-
-    refute @http.retry_change_requests
-
-    refute @http.can_retry?(get)
-    refute @http.can_retry?(post)
-
-    @http.retry_change_requests = true
-
-    assert @http.retry_change_requests
-
-    refute @http.can_retry?(get)
-    assert @http.can_retry?(post)
-  end
-
   def test_shutdown
     c = connection