fixing TCP connection inprogress on SSL connection bug

The Errno::INPROGRESS error signals that the TCP handshake has been
signaled to the peer already, by which locally we just have wait for it
to be writable.

For simple plaintext requests, this was working correctly, because the
interest was always writable no matter what. However, when wrapped in
the SSL conn, and with the OS tcp stack under more stress, the interest
could be switched to readable, and by reuse, never reset; if, by
subsequent reconnection, EINPROGRESS would be emitted, the socket would
wait for readable instead, resulting in a loop and subsequent
connectionnn timeout.
This commit is contained in:
HoneyryderChuck 2021-02-16 14:42:42 +00:00
parent d3cc6d2d96
commit d4fe89094e
2 changed files with 9 additions and 11 deletions

View File

@ -21,10 +21,6 @@ module HTTPX
@state = :negotiated if @keep_open
end
def interests
@interests || super
end
def protocol
@io.alpn_protocol || super
rescue StandardError
@ -66,6 +62,7 @@ module HTTPX
@io.connect_nonblock
@io.post_connection_check(@sni_hostname) if @ctx.verify_mode != OpenSSL::SSL::VERIFY_NONE
transition(:negotiated)
@interests = :w
rescue ::IO::WaitReadable
@interests = :r
rescue ::IO::WaitWritable

View File

@ -7,7 +7,7 @@ module HTTPX
class TCP
include Loggable
attr_reader :ip, :port, :addresses, :state
attr_reader :ip, :port, :addresses, :state, :interests
alias_method :host, :ip
@ -18,6 +18,7 @@ module HTTPX
@options = Options.new(options)
@fallback_protocol = @options.fallback_protocol
@port = origin.port
@interests = :w
if @options.io
@io = case @options.io
when Hash
@ -39,10 +40,6 @@ module HTTPX
@io ||= build_socket
end
def interests
:w
end
def to_io
@io.to_io
end
@ -62,6 +59,8 @@ module HTTPX
@io.connect_nonblock(Socket.sockaddr_in(@port, @ip.to_s))
rescue Errno::EISCONN
end
@interests = :w
transition(:connected)
rescue Errno::EHOSTUNREACH => e
raise e if @ip_index <= 0
@ -74,8 +73,10 @@ module HTTPX
@ip_index -= 1
retry
rescue Errno::EINPROGRESS,
Errno::EALREADY,
::IO::WaitReadable
Errno::EALREADY
@interests = :w
rescue ::IO::WaitReadable
@interests = :r
end
if RUBY_VERSION < "2.3"