lib/httpx/resolver/native.rb in httpx-1.2.4 vs lib/httpx/resolver/native.rb in httpx-1.2.6

- old
+ new

@@ -63,10 +63,11 @@ @ns_index += 1 nameserver = @nameserver if nameserver && @ns_index < nameserver.size log { "resolver: failed resolving on nameserver #{@nameserver[@ns_index - 1]} (#{e.message})" } transition(:idle) + @timeouts.clear else handle_error(e) end rescue NativeResolveError => e handle_error(e) @@ -141,17 +142,20 @@ @timeouts[host].shift if !@timeouts[host].empty? log { "resolver: timeout after #{timeout}s, retry(#{@timeouts[host].first}) #{host}..." } - resolve(connection) + # must downgrade to tcp AND retry on same host as last + downgrade_socket + resolve(connection, h) elsif @ns_index + 1 < @nameserver.size # try on the next nameserver @ns_index += 1 log { "resolver: failed resolving #{host} on nameserver #{@nameserver[@ns_index - 1]} (timeout error)" } transition(:idle) - resolve(connection) + @timeouts.clear + resolve(connection, h) else @timeouts.delete(host) reset_hostname(h, reset_candidates: false) @@ -185,14 +189,13 @@ @large_packet << @read_buffer next unless @large_packet.full? parse(@large_packet.to_s) - @socket_type = @resolver_options.fetch(:socket_type, :udp) @large_packet = nil - transition(:idle) - transition(:open) + # downgrade to udp again + downgrade_socket return else size = @read_buffer[0, 2].unpack1("n") buffer = @read_buffer.byteslice(2..-1) @@ -302,17 +305,25 @@ address["name"] = name connection = @queries.delete(name) end if address.key?("alias") # CNAME + hostname_alias = address["alias"] # clean up intermediate queries @timeouts.delete(name) unless connection.origin.host == name - if catch(:coalesced) { early_resolve(connection, hostname: address["alias"]) } + if catch(:coalesced) { early_resolve(connection, hostname: hostname_alias) } @connections.delete(connection) else - resolve(connection, address["alias"]) + if @socket_type == :tcp + # must downgrade to udp if tcp + @socket_type = @resolver_options.fetch(:socket_type, :udp) + transition(:idle) + transition(:open) + end + log { "resolver: ALIAS #{hostname_alias} for #{name}" } + resolve(connection, hostname_alias) return end else reset_hostname(name, connection: connection) @timeouts.delete(connection.origin.host) @@ -384,17 +395,24 @@ origin = URI("tcp://#{ip}:#{port}") TCP.new(origin, [ip], @options) end end + def downgrade_socket + return unless @socket_type == :tcp + + @socket_type = @resolver_options.fetch(:socket_type, :udp) + transition(:idle) + transition(:open) + end + def transition(nextstate) case nextstate when :idle if @io @io.close @io = nil end - @timeouts.clear when :open return unless @state == :idle @io ||= build_socket