using the same strategy when exiting early from unexpected dns errors

there was a :resolve_error already in place for this. this extends the
same strategy for https and native resolvers, thereby fixing potential
bugs.
This commit is contained in:
HoneyryderChuck 2020-12-01 00:05:26 +00:00
parent c98d568e07
commit 7a5eaa3795
4 changed files with 54 additions and 41 deletions

View File

@ -44,7 +44,11 @@ module HTTPX
@uri_addresses ||= Resolv.getaddresses(@uri.host)
raise ResolveError, "Can't resolve DNS server #{@uri.host}" if @uri_addresses.empty?
if @uri_addresses.empty?
ex = ResolveError.new("Can't resolve DNS server #{@uri.host}")
ex.set_backtrace(caller)
throw(:resolve_error, ex)
end
early_resolve(connection) || resolve(connection)
end

View File

@ -15,7 +15,6 @@ module HTTPX
"AAAA" => Resolv::DNS::Resource::IN::AAAA,
}.freeze
# :nocov:
DEFAULTS = if RUBY_VERSION < "2.2"
{
**Resolv::DNS::Config.default_config_hash,
@ -44,7 +43,6 @@ module HTTPX
false
end
end if DEFAULTS[:nameserver]
# :nocov:
DNS_PORT = 53
@ -111,9 +109,9 @@ module HTTPX
return if early_resolve(connection)
if @nameserver.nil?
ex = ResolveError.new("Can't resolve #{connection.origin.host}: no nameserver")
ex = ResolveError.new("No available nameserver")
ex.set_backtrace(caller)
emit(:error, connection, ex)
throw(:resolve_error, ex)
else
@connections << connection
resolve

View File

@ -57,7 +57,7 @@ module HTTPX
ips.map { |ip| IPAddr.new(ip) }
end
def emit_resolve_error(connection, hostname, ex = nil)
def emit_resolve_error(connection, hostname = connection.origin.host, ex = nil)
emit(:error, connection, resolve_error(hostname, ex))
end

View File

@ -25,49 +25,60 @@ module Requests
response.close
end
next unless resolver == :https
case resolver
when :https
define_method :"test_resolver_#{resolver}_get_request" do
session = HTTPX.plugin(SessionWithPool)
uri = build_uri("/get")
response = session.head(uri, resolver_class: resolver, resolver_options: options.merge(use_get: true))
verify_status(response, 200)
response.close
end
define_method :"test_resolver_#{resolver}_unresolvable_servername" do
session = HTTPX.plugin(SessionWithPool)
uri = build_uri("/get")
ex = assert_raises(HTTPX::ResolveError) do
session.head(uri, resolver_class: resolver, resolver_options: options.merge(uri: "https://unexisting-doh/dns-query"))
define_method :"test_resolver_#{resolver}_get_request" do
session = HTTPX.plugin(SessionWithPool)
uri = build_uri("/get")
response = session.head(uri, resolver_class: resolver, resolver_options: options.merge(use_get: true))
verify_status(response, 200)
response.close
end
assert ex.message =~ /Can't resolve DNS server/
end
define_method :"test_resolver_#{resolver}_server_error" do
session = HTTPX.plugin(SessionWithPool)
uri = URI(build_uri("/get"))
resolver_class = Class.new(HTTPX::Resolver::HTTPS) do
def build_request(_hostname, _type)
@options.request_class.new("POST", @uri)
define_method :"test_resolver_#{resolver}_unresolvable_servername" do
session = HTTPX.plugin(SessionWithPool)
uri = build_uri("/get")
response = session.head(uri, resolver_class: resolver, resolver_options: options.merge(uri: "https://unexisting-doh/dns-query"))
assert response.is_a?(HTTPX::ErrorResponse), "should be a response error"
assert response.error.is_a?(HTTPX::ResolveError), "should be a resolving error"
end
define_method :"test_resolver_#{resolver}_server_error" do
session = HTTPX.plugin(SessionWithPool)
uri = URI(build_uri("/get"))
resolver_class = Class.new(HTTPX::Resolver::HTTPS) do
def build_request(_hostname, _type)
@options.request_class.new("POST", @uri)
end
end
response = session.head(uri, resolver_class: resolver_class, resolver_options: options)
assert response.is_a?(HTTPX::ErrorResponse), "should be a response error"
assert response.error.is_a?(HTTPX::ResolveError), "should be a resolving error"
end
response = session.head(uri, resolver_class: resolver_class, resolver_options: options)
assert response.is_a?(HTTPX::ErrorResponse), "should be a response error"
assert response.error.is_a?(HTTPX::ResolveError), "should be a resolving error"
end
define_method :"test_resolver_#{resolver}_decoding_error" do
session = HTTPX.plugin(SessionWithPool)
uri = URI(build_uri("/get"))
resolver_class = Class.new(HTTPX::Resolver::HTTPS) do
def decode_response_body(_response)
raise Resolv::DNS::DecodeError
define_method :"test_resolver_#{resolver}_decoding_error" do
session = HTTPX.plugin(SessionWithPool)
uri = URI(build_uri("/get"))
resolver_class = Class.new(HTTPX::Resolver::HTTPS) do
def decode_response_body(_response)
raise Resolv::DNS::DecodeError
end
end
response = session.head(uri, resolver_class: resolver_class, resolver_options: options.merge(record_types: %w[A]))
assert response.is_a?(HTTPX::ErrorResponse), "should be a response error"
assert response.error.is_a?(HTTPX::ResolveError), "should be a resolving error"
end
when :native
define_method :"test_resolver_#{resolver}_no_nameserver" do
session = HTTPX.plugin(SessionWithPool)
uri = build_uri("/get")
response = session.head(uri, resolver_class: resolver, resolver_options: options.merge(nameserver: nil))
assert response.is_a?(HTTPX::ErrorResponse), "should be a response error"
assert response.error.is_a?(HTTPX::ResolveError), "should be a resolving error"
end
response = session.head(uri, resolver_class: resolver_class, resolver_options: options.merge(record_types: %w[A]))
assert response.is_a?(HTTPX::ErrorResponse), "should be a response error"
assert response.error.is_a?(HTTPX::ResolveError), "should be a resolving error"
end
end
end