lib/httpx/resolver/native.rb in httpx-0.18.7 vs lib/httpx/resolver/native.rb in httpx-0.19.0
- old
+ new
@@ -2,34 +2,26 @@
require "forwardable"
require "resolv"
module HTTPX
- class Resolver::Native
+ class Resolver::Native < Resolver::Resolver
extend Forwardable
- include Resolver::ResolverMixin
using URIExtensions
- RECORD_TYPES = {
- "A" => Resolv::DNS::Resource::IN::A,
- "AAAA" => Resolv::DNS::Resource::IN::AAAA,
- }.freeze
-
DEFAULTS = if RUBY_VERSION < "2.2"
{
**Resolv::DNS::Config.default_config_hash,
packet_size: 512,
timeouts: Resolver::RESOLVE_TIMEOUT,
- record_types: RECORD_TYPES.keys,
}.freeze
else
{
nameserver: nil,
**Resolv::DNS::Config.default_config_hash,
packet_size: 512,
timeouts: Resolver::RESOLVE_TIMEOUT,
- record_types: RECORD_TYPES.keys,
}.freeze
end
# nameservers for ipv6 are misconfigured in certain systems;
# this can use an unexpected endless loop
@@ -47,18 +39,17 @@
def_delegator :@connections, :empty?
attr_reader :state
- def initialize(options)
- @options = HTTPX::Options.new(options)
+ def initialize(_, options)
+ super
@ns_index = 0
@resolver_options = DEFAULTS.merge(@options.resolver_options)
@nameserver = @resolver_options[:nameserver]
@_timeouts = Array(@resolver_options[:timeouts])
@timeouts = Hash.new { |timeouts, host| timeouts[host] = @_timeouts.dup }
- @_record_types = Hash.new { |types, host| types[host] = @resolver_options[:record_types].dup }
@connections = []
@queries = {}
@read_buffer = "".b
@write_buffer = Buffer.new(@resolver_options[:packet_size])
@state = :idle
@@ -105,12 +96,10 @@
calculate_interests
end
def <<(connection)
- return if early_resolve(connection)
-
if @nameserver.nil?
ex = ResolveError.new("No available nameserver")
ex.set_backtrace(caller)
throw(:resolve_error, ex)
else
@@ -138,11 +127,11 @@
do_retry
dwrite if calculate_interests == :w
end
def do_retry
- return if @queries.empty?
+ return if @queries.empty? || !@start_timeout
loop_time = Utils.elapsed_time(@start_timeout)
connections = []
queries = {}
while (query = @queries.shift)
@@ -158,11 +147,11 @@
if @timeouts[host].empty?
@timeouts.delete(host)
@connections.delete(connection)
# This loop_time passed to the exception is bogus. Ideally we would pass the total
# resolve timeout, including from the previous retries.
- raise ResolveTimeoutError.new(loop_time, "Timed out")
+ raise ResolveTimeoutError.new(loop_time, "Timed out while resolving #{host}")
# raise NativeResolveError.new(connection, host)
else
log { "resolver: timeout after #{timeout}s, retry(#{@timeouts[host].first}) #{host}..." }
connections << connection
queries[h] = connection
@@ -196,31 +185,25 @@
def parse(buffer)
begin
addresses = Resolver.decode_dns_answer(buffer)
rescue Resolv::DNS::DecodeError => e
hostname, connection = @queries.first
- if @_record_types[hostname].empty?
- @queries.delete(hostname)
- @timeouts.delete(hostname)
- @connections.delete(connection)
- ex = NativeResolveError.new(connection, hostname, e.message)
- ex.set_backtrace(e.backtrace)
- raise ex
- end
+ @queries.delete(hostname)
+ @timeouts.delete(hostname)
+ @connections.delete(connection)
+ ex = NativeResolveError.new(connection, hostname, e.message)
+ ex.set_backtrace(e.backtrace)
+ raise ex
end
if addresses.nil? || addresses.empty?
hostname, connection = @queries.first
- @_record_types[hostname].shift
- if @_record_types[hostname].empty?
- @queries.delete(hostname)
- @_record_types.delete(hostname)
- @timeouts.delete(hostname)
- @connections.delete(connection)
+ @queries.delete(hostname)
+ @timeouts.delete(hostname)
+ @connections.delete(connection)
- raise NativeResolveError.new(connection, hostname)
- end
+ raise NativeResolveError.new(connection, hostname)
else
address = addresses.first
name = address["name"]
connection = @queries.delete(name)
@@ -237,24 +220,24 @@
connection = @queries.delete(name)
end
if address.key?("alias") # CNAME
# clean up intermediate queries
- @timeouts.delete(address["name"]) unless connection.origin.host == address["name"]
+ @timeouts.delete(name) unless connection.origin.host == name
if catch(:coalesced) { early_resolve(connection, hostname: address["alias"]) }
- @timeouts.delete(connection.origin.host)
@connections.delete(connection)
else
resolve(connection, address["alias"])
return
end
else
+ @timeouts.delete(name)
@timeouts.delete(connection.origin.host)
@connections.delete(connection)
- Resolver.cached_lookup_set(connection.origin.host, addresses) if @resolver_options[:cache]
- emit_addresses(connection, addresses.map { |addr| addr["data"] })
+ Resolver.cached_lookup_set(connection.origin.host, @family, addresses) if @resolver_options[:cache]
+ emit_addresses(connection, @family, addresses.map { |addr| addr["data"] })
end
end
return emit(:close) if @connections.empty?
resolve
@@ -269,14 +252,13 @@
if hostname.nil?
hostname = connection.origin.host
log { "resolver: resolve IDN #{connection.origin.non_ascii_hostname} as #{hostname}" } if connection.origin.non_ascii_hostname
end
@queries[hostname] = connection
- type = @_record_types[hostname].first || "A"
- log { "resolver: query #{type} for #{hostname}" }
+ log { "resolver: query #{@record_type.name.split("::").last} for #{hostname}" }
begin
- @write_buffer << Resolver.encode_dns_query(hostname, type: RECORD_TYPES[type])
+ @write_buffer << Resolver.encode_dns_query(hostname, type: @record_type)
rescue Resolv::DNS::EncodeError => e
emit_resolve_error(connection, hostname, e)
end
end
@@ -311,9 +293,12 @@
resolve if @queries.empty? && !@connections.empty?
when :closed
return unless @state == :open
@io.close if @io
+ @start_timeout = nil
+ @write_buffer.clear
+ @read_buffer.clear
end
@state = nextstate
end
def handle_error(error)