mirror of
https://github.com/HoneyryderChuck/httpx.git
synced 2025-10-04 00:00:37 -04:00
Merge branch 'gh-52' into 'master'
native resolver: moved timeouts reset out of idle transition, retry alias See merge request os85/httpx!342
This commit is contained in:
commit
7062b3c49b
@ -65,6 +65,7 @@ module HTTPX
|
|||||||
if nameserver && @ns_index < nameserver.size
|
if nameserver && @ns_index < nameserver.size
|
||||||
log { "resolver: failed resolving on nameserver #{@nameserver[@ns_index - 1]} (#{e.message})" }
|
log { "resolver: failed resolving on nameserver #{@nameserver[@ns_index - 1]} (#{e.message})" }
|
||||||
transition(:idle)
|
transition(:idle)
|
||||||
|
@timeouts.clear
|
||||||
else
|
else
|
||||||
handle_error(e)
|
handle_error(e)
|
||||||
end
|
end
|
||||||
@ -143,13 +144,16 @@ module HTTPX
|
|||||||
|
|
||||||
if !@timeouts[host].empty?
|
if !@timeouts[host].empty?
|
||||||
log { "resolver: timeout after #{timeout}s, retry(#{@timeouts[host].first}) #{host}..." }
|
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
|
elsif @ns_index + 1 < @nameserver.size
|
||||||
# try on the next nameserver
|
# try on the next nameserver
|
||||||
@ns_index += 1
|
@ns_index += 1
|
||||||
log { "resolver: failed resolving #{host} on nameserver #{@nameserver[@ns_index - 1]} (timeout error)" }
|
log { "resolver: failed resolving #{host} on nameserver #{@nameserver[@ns_index - 1]} (timeout error)" }
|
||||||
transition(:idle)
|
transition(:idle)
|
||||||
resolve(connection)
|
@timeouts.clear
|
||||||
|
resolve(connection, h)
|
||||||
else
|
else
|
||||||
|
|
||||||
@timeouts.delete(host)
|
@timeouts.delete(host)
|
||||||
@ -187,10 +191,9 @@ module HTTPX
|
|||||||
next unless @large_packet.full?
|
next unless @large_packet.full?
|
||||||
|
|
||||||
parse(@large_packet.to_s)
|
parse(@large_packet.to_s)
|
||||||
@socket_type = @resolver_options.fetch(:socket_type, :udp)
|
|
||||||
@large_packet = nil
|
@large_packet = nil
|
||||||
transition(:idle)
|
# downgrade to udp again
|
||||||
transition(:open)
|
downgrade_socket
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
size = @read_buffer[0, 2].unpack1("n")
|
size = @read_buffer[0, 2].unpack1("n")
|
||||||
@ -304,13 +307,21 @@ module HTTPX
|
|||||||
end
|
end
|
||||||
|
|
||||||
if address.key?("alias") # CNAME
|
if address.key?("alias") # CNAME
|
||||||
|
hostname_alias = address["alias"]
|
||||||
# clean up intermediate queries
|
# clean up intermediate queries
|
||||||
@timeouts.delete(name) unless connection.origin.host == name
|
@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)
|
@connections.delete(connection)
|
||||||
else
|
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
|
return
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -386,6 +397,14 @@ module HTTPX
|
|||||||
end
|
end
|
||||||
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)
|
def transition(nextstate)
|
||||||
case nextstate
|
case nextstate
|
||||||
when :idle
|
when :idle
|
||||||
@ -393,7 +412,6 @@ module HTTPX
|
|||||||
@io.close
|
@io.close
|
||||||
@io = nil
|
@io = nil
|
||||||
end
|
end
|
||||||
@timeouts.clear
|
|
||||||
when :open
|
when :open
|
||||||
return unless @state == :idle
|
return unless @state == :idle
|
||||||
|
|
||||||
|
@ -59,6 +59,8 @@ module HTTPX
|
|||||||
|
|
||||||
def build_socket: () -> (UDP | TCP)
|
def build_socket: () -> (UDP | TCP)
|
||||||
|
|
||||||
|
def downgrade_socket: () -> void
|
||||||
|
|
||||||
def transition: (Symbol nextstate) -> void
|
def transition: (Symbol nextstate) -> void
|
||||||
|
|
||||||
def handle_error: (NativeResolveError | StandardError) -> void
|
def handle_error: (NativeResolveError | StandardError) -> void
|
||||||
|
@ -99,8 +99,8 @@ module ResponseHelpers
|
|||||||
File.join("test", "support", "fixtures", fixture_file_name)
|
File.join("test", "support", "fixtures", fixture_file_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
def start_test_servlet(servlet_class, *args)
|
def start_test_servlet(servlet_class, *args, **kwargs)
|
||||||
server = servlet_class.new(*args)
|
server = servlet_class.new(*args, **kwargs)
|
||||||
th = Thread.new { server.start }
|
th = Thread.new { server.start }
|
||||||
begin
|
begin
|
||||||
yield server
|
yield server
|
||||||
|
@ -131,7 +131,7 @@ module Requests
|
|||||||
uri = build_uri("/get")
|
uri = build_uri("/get")
|
||||||
|
|
||||||
before_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second)
|
before_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second)
|
||||||
response = session.get(uri, resolver_class: resolver_type, resolver_options: resolver_opts)
|
response = session.get(uri, resolver_class: resolver_type, resolver_options: options.merge(resolver_opts))
|
||||||
after_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second)
|
after_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second)
|
||||||
total_time = after_time - before_time
|
total_time = after_time - before_time
|
||||||
|
|
||||||
@ -160,7 +160,7 @@ module Requests
|
|||||||
HTTPX.plugin(SessionWithPool).wrap do |session|
|
HTTPX.plugin(SessionWithPool).wrap do |session|
|
||||||
uri = build_uri("/get")
|
uri = build_uri("/get")
|
||||||
|
|
||||||
response = session.get(uri, resolver_class: resolver_type, resolver_options: resolver_opts)
|
response = session.get(uri, resolver_class: resolver_type, resolver_options: options.merge(resolver_opts))
|
||||||
verify_status(response, 200)
|
verify_status(response, 200)
|
||||||
|
|
||||||
resolver = session.pool.resolver.resolvers[0]
|
resolver = session.pool.resolver.resolvers[0]
|
||||||
@ -180,7 +180,7 @@ module Requests
|
|||||||
HTTPX.plugin(SessionWithPool).wrap do |session|
|
HTTPX.plugin(SessionWithPool).wrap do |session|
|
||||||
uri = build_uri("/get")
|
uri = build_uri("/get")
|
||||||
|
|
||||||
response = session.get(uri, resolver_class: resolver_type, resolver_options: resolver_opts)
|
response = session.get(uri, resolver_class: resolver_type, resolver_options: options.merge(resolver_opts))
|
||||||
verify_error_response(response, /unknown DNS error/)
|
verify_error_response(response, /unknown DNS error/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -231,6 +231,8 @@ module Requests
|
|||||||
attr_reader :ios
|
attr_reader :ios
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
def build_socket
|
def build_socket
|
||||||
io = super
|
io = super
|
||||||
self.class.ios << io
|
self.class.ios << io
|
||||||
|
@ -6,15 +6,30 @@ require_relative "test"
|
|||||||
# from https://gist.github.com/peterc/1425383
|
# from https://gist.github.com/peterc/1425383
|
||||||
|
|
||||||
class SlowDNSServer < TestDNSResolver
|
class SlowDNSServer < TestDNSResolver
|
||||||
def initialize(timeout)
|
def initialize(timeout, *args, hostname: nil, als: nil)
|
||||||
@timeout = timeout
|
@timeout = timeout
|
||||||
super()
|
@hostname = hostname
|
||||||
|
@alias = als
|
||||||
|
super(*args)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def dns_response(*)
|
def dns_response(query)
|
||||||
sleep(@timeout)
|
if @alias
|
||||||
|
domain = extract_domain(query)
|
||||||
|
sleep(@timeout) if domain == @alias
|
||||||
|
else
|
||||||
|
sleep(@timeout)
|
||||||
|
end
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def resolve(domain)
|
||||||
|
if domain == "#{@hostname}."
|
||||||
|
@alias
|
||||||
|
else
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -116,11 +116,12 @@ end
|
|||||||
class TestDNSResolver
|
class TestDNSResolver
|
||||||
attr_reader :queries, :answers
|
attr_reader :queries, :answers
|
||||||
|
|
||||||
def initialize
|
def initialize(port = next_available_port, socket_type = :udp)
|
||||||
@port = next_available_port
|
@port = port
|
||||||
@can_log = ENV.key?("HTTPX_DEBUG")
|
@can_log = ENV.key?("HTTPX_DEBUG")
|
||||||
@queries = 0
|
@queries = 0
|
||||||
@answers = 0
|
@answers = 0
|
||||||
|
@socket_type = socket_type
|
||||||
end
|
end
|
||||||
|
|
||||||
def nameserver
|
def nameserver
|
||||||
@ -128,10 +129,31 @@ class TestDNSResolver
|
|||||||
end
|
end
|
||||||
|
|
||||||
def start
|
def start
|
||||||
Socket.udp_server_loop(@port) do |query, src|
|
if @socket_type == :udp
|
||||||
@queries += 1
|
Socket.udp_server_loop(@port) do |query, src|
|
||||||
src.reply(dns_response(query))
|
puts "bang bang"
|
||||||
@answers += 1
|
@queries += 1
|
||||||
|
src.reply(dns_response(query))
|
||||||
|
@answers += 1
|
||||||
|
end
|
||||||
|
elsif @socket_type == :tcp
|
||||||
|
Socket.tcp_server_loop(@port) do |sock, _addrinfo|
|
||||||
|
begin
|
||||||
|
loop do
|
||||||
|
query = sock.readpartial(2048)
|
||||||
|
size = query[0, 2].unpack1("n")
|
||||||
|
query = query.byteslice(2..-1)
|
||||||
|
query << sock.readpartial(size - query.size) while query.size < size
|
||||||
|
@queries += 1
|
||||||
|
answer = dns_response(query)
|
||||||
|
|
||||||
|
answer.prepend([answer.size].pack("n"))
|
||||||
|
sock.write(answer)
|
||||||
|
@answers += 1
|
||||||
|
end
|
||||||
|
rescue EOFError
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user