lib/httpx/resolver/https.rb in httpx-0.22.5 vs lib/httpx/resolver/https.rb in httpx-0.23.0

- old
+ new

@@ -102,20 +102,20 @@ request.on(:promise, &method(:on_promise)) @requests[request] = hostname resolver_connection.send(request) @connections << connection rescue ResolveError, Resolv::DNS::EncodeError => e - @queries.delete(hostname) + reset_hostname(hostname) emit_resolve_error(connection, connection.origin.host, e) end end def on_response(request, response) response.raise_for_status rescue StandardError => e hostname = @requests.delete(request) - connection = @queries.delete(hostname) + connection = reset_hostname(hostname) emit_resolve_error(connection, connection.origin.host, e) else # @type var response: HTTPX::Response parse(request, response) ensure @@ -126,45 +126,50 @@ log(level: 2) { "#{stream.id}: refusing stream!" } stream.refuse end def parse(request, response) - begin - answers = decode_response_body(response) - rescue Resolv::DNS::DecodeError => e - host, connection = @queries.first - @queries.delete(host) - emit_resolve_error(connection, connection.origin.host, e) - return - end + code, result = decode_response_body(response) - if answers.nil? + case code + when :ok + parse_addresses(result) + when :no_domain_found # Indicates no such domain was found. host = @requests.delete(request) - connection = @queries.delete(host) + connection = reset_hostname(host) - emit_resolve_error(connection) unless @queries.value?(connection) - elsif answers.empty? - # no address found, eliminate candidates + emit_resolve_error(connection) + when :dns_error host = @requests.delete(request) - connection = @queries.delete(host) + connection = reset_hostname(host) - # eliminate other candidates - @queries.delete_if { |_, conn| connection == conn } + emit_resolve_error(connection) + when :decode_error + host, connection = @queries.first + reset_hostname(host) + emit_resolve_error(connection, connection.origin.host, result) + end + end + def parse_addresses(answers) + if answers.empty? + # no address found, eliminate candidates + host = @requests.delete(request) + connection = reset_hostname(host) emit_resolve_error(connection) return else answers = answers.group_by { |answer| answer["name"] } answers.each do |hostname, addresses| addresses = addresses.flat_map do |address| if address.key?("alias") alias_address = answers[address["alias"]] if alias_address.nil? - @queries.delete(address["name"]) + reset_hostname(address["name"]) if catch(:coalesced) { early_resolve(connection, hostname: address["alias"]) } @connections.delete(connection) else resolve(connection, address["alias"]) return # rubocop:disable Lint/NonLocalExitFromIterator @@ -177,11 +182,11 @@ end end.compact next if addresses.empty? hostname.delete_suffix!(".") if hostname.end_with?(".") - connection = @queries.delete(hostname) + connection = reset_hostname(hostname, reset_candidates: false) next unless connection # probably a retried query for which there's an answer @connections.delete(connection) # eliminate other candidates @@ -221,8 +226,20 @@ "application/dns-message" Resolver.decode_dns_answer(response.to_s) else raise Error, "unsupported DNS mime-type (#{response.headers["content-type"]})" end + end + + def reset_hostname(hostname, reset_candidates: true) + connection = @queries.delete(hostname) + + return connection unless connection && reset_candidates + + # eliminate other candidates + candidates = @queries.select { |_, conn| connection == conn }.keys + @queries.delete_if { |h, _| candidates.include?(h) } + + connection end end end