Fixed issue when IO was passed as an option, but a DNS query was still

issued to the request host, which doesn't make sense.

This also fixed an inconsistency when passing an hash of IOs. The key of
that hash MUST match the request authority for the channel to properly
assign it.
This commit is contained in:
HoneyryderChuck 2018-12-23 02:22:16 +00:00
parent 2051aef665
commit cf7b4bff94
4 changed files with 41 additions and 9 deletions

View File

@ -77,11 +77,26 @@ module HTTPX
@write_buffer = Buffer.new(BUFFER_SIZE)
@pending = []
on(:error) { |ex| on_error(ex) }
transition(:idle)
if @options.io
# if there's an already open IO, get its
# peer address, and force-initiate the parser
transition(:already_open)
@io = IO.registry(@type).new(@uri, nil, @options)
parser
else
transition(:idle)
end
end
# this is a semi-private method, to be used by the resolver
# to initiate the io object.
def addresses=(addrs)
@io = IO.registry(@type).new(@uri, addrs, @options)
@io ||= IO.registry(@type).new(@uri, addrs, @options) # rubocop:disable Naming/MemoizedInstanceVariableName
end
def addresses
return unless @io
@io.addresses
end
def mergeable?(addresses)
@ -342,6 +357,11 @@ module HTTPX
@io.close
@read_buffer.clear
when :already_open
nextstate = :open
send_pending
@timeout_threshold = @options.timeout.operation_timeout
@timeout = @timeout_threshold
end
@state = nextstate
rescue Errno::EHOSTUNREACH

View File

@ -120,12 +120,20 @@ module HTTPX
end
def register_channel(channel)
@timeout.transition(:idle)
monitor = @selector.register(channel, :w)
monitor = if channel.state == :open
# if open, an IO was passed upstream, therefore
# consider it connected already.
@connected_channels += 1
@selector.register(channel, :rw)
else
@selector.register(channel, :w)
end
monitor.value = channel
channel.on(:close) do
unregister_channel(channel)
end
return if channel.state == :open
@timeout.transition(:idle)
end
def unregister_channel(channel)

View File

@ -17,24 +17,25 @@ module HTTPX
@state = :idle
@hostname = uri.host
@addresses = addresses
@ip_index = @addresses.size - 1
@options = Options.new(options)
@fallback_protocol = @options.fallback_protocol
@port = uri.port
if @options.io
@io = case @options.io
when Hash
@ip = @addresses[@ip_index]
@options.io[@ip] || @options.io["#{@ip}:#{@port}"]
@options.io[uri.authority]
else
@ip = @hostname
@options.io
end
_, _, _, @ip = @io.addr
@addresses ||= [@ip]
@ip_index = @addresses.size - 1
unless @io.nil?
@keep_open = true
@state = :connected
end
else
@ip_index = @addresses.size - 1
@ip = @addresses[@ip_index]
end
@io ||= build_socket

View File

@ -36,7 +36,10 @@ module HTTPX
end
def early_resolve(channel, hostname: channel.uri.host)
addresses = ip_resolve(hostname) || Resolver.cached_lookup(hostname) || system_resolve(hostname)
addresses = channel.addresses ||
ip_resolve(hostname) ||
Resolver.cached_lookup(hostname) ||
system_resolve(hostname)
return unless addresses
emit_addresses(channel, addresses)