mirror of
https://github.com/HoneyryderChuck/httpx.git
synced 2025-12-15 00:01:02 -05:00
fix for loop on resolution and retry on new connection
A certain behaviour was observed, when performing some tests using the hackernews script, where after a failed request on a non-initiated connection, a new DNS resolution would be emitted, although the connection still had other IPs to try on. This led to a cascading behaviour where the DNS response would fill up the connection with the same repeated IPs and trigger coalescing, which would loop indefinitely after emitting the resolve event. This was fixed by not allowing DNS resolution on already resolved names, to propagate to connections which already contain the advertised IPs. This seems to address the github issue 5, which description matches the observed behaviour.
This commit is contained in:
parent
534b3eb91b
commit
b0777c61e5
@ -83,22 +83,41 @@ module HTTPX
|
||||
end
|
||||
|
||||
module ArrayExtensions
|
||||
refine Array do
|
||||
module FilterMap
|
||||
refine Array do
|
||||
|
||||
def filter_map
|
||||
return to_enum(:filter_map) unless block_given?
|
||||
def filter_map
|
||||
return to_enum(:filter_map) unless block_given?
|
||||
|
||||
each_with_object([]) do |item, res|
|
||||
processed = yield(item)
|
||||
res << processed if processed
|
||||
each_with_object([]) do |item, res|
|
||||
processed = yield(item)
|
||||
res << processed if processed
|
||||
end
|
||||
end
|
||||
end unless Array.method_defined?(:filter_map)
|
||||
end
|
||||
|
||||
def sum(accumulator = 0, &block)
|
||||
values = block_given? ? map(&block) : self
|
||||
values.inject(accumulator, :+)
|
||||
module Sum
|
||||
refine Array do
|
||||
def sum(accumulator = 0, &block)
|
||||
values = block_given? ? map(&block) : self
|
||||
values.inject(accumulator, :+)
|
||||
end
|
||||
end unless Array.method_defined?(:sum)
|
||||
end
|
||||
|
||||
module Intersect
|
||||
refine Array do
|
||||
def intersect?(arr)
|
||||
if size < arr.size
|
||||
smaller = self
|
||||
else
|
||||
smaller, arr = arr, self
|
||||
end
|
||||
(array & smaller).size > 0
|
||||
end
|
||||
end unless Array.method_defined?(:intersect?)
|
||||
end
|
||||
end
|
||||
|
||||
module IOExtensions
|
||||
|
||||
@ -72,7 +72,7 @@ module HTTPX
|
||||
end
|
||||
|
||||
module ResponseBodyMethods
|
||||
using ArrayExtensions
|
||||
using ArrayExtensions::FilterMap
|
||||
|
||||
attr_reader :encodings
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ require "httpx/resolver"
|
||||
|
||||
module HTTPX
|
||||
class Pool
|
||||
using ArrayExtensions
|
||||
using ArrayExtensions::FilterMap
|
||||
extend Forwardable
|
||||
|
||||
def_delegator :@timers, :after
|
||||
|
||||
@ -6,7 +6,7 @@ require "resolv"
|
||||
module HTTPX
|
||||
class Resolver::Multi
|
||||
include Callbacks
|
||||
using ArrayExtensions
|
||||
using ArrayExtensions::FilterMap
|
||||
|
||||
attr_reader :resolvers
|
||||
|
||||
|
||||
@ -8,6 +8,8 @@ module HTTPX
|
||||
include Callbacks
|
||||
include Loggable
|
||||
|
||||
using ArrayExtensions::Intersect
|
||||
|
||||
RECORD_TYPES = {
|
||||
Socket::AF_INET6 => Resolv::DNS::Resource::IN::AAAA,
|
||||
Socket::AF_INET => Resolv::DNS::Resource::IN::A,
|
||||
@ -48,6 +50,10 @@ module HTTPX
|
||||
addresses.map! do |address|
|
||||
address.is_a?(IPAddr) ? address : IPAddr.new(address.to_s)
|
||||
end
|
||||
|
||||
# double emission check
|
||||
return if connection.addresses && !addresses.intersect?(connection.addresses)
|
||||
|
||||
log { "resolver: answer #{connection.origin.host}: #{addresses.inspect}" }
|
||||
if @pool && # if triggered by early resolve, pool may not be here yet
|
||||
!connection.io &&
|
||||
@ -56,8 +62,12 @@ module HTTPX
|
||||
addresses.first.to_s != connection.origin.host.to_s
|
||||
log { "resolver: A response, applying resolution delay..." }
|
||||
@pool.after(0.05) do
|
||||
connection.addresses = addresses
|
||||
emit(:resolve, connection)
|
||||
# double emission check
|
||||
unless connection.addresses && addresses.intersect?(connection.addresses)
|
||||
|
||||
connection.addresses = addresses
|
||||
emit(:resolve, connection)
|
||||
end
|
||||
end
|
||||
else
|
||||
connection.addresses = addresses
|
||||
|
||||
@ -310,9 +310,12 @@ module HTTPX
|
||||
|
||||
class ErrorResponse
|
||||
include Loggable
|
||||
extend Forwardable
|
||||
|
||||
attr_reader :request, :error
|
||||
|
||||
def_delegator :@request, :uri
|
||||
|
||||
def initialize(request, error, options)
|
||||
@request = request
|
||||
@error = error
|
||||
|
||||
@ -9,7 +9,7 @@ module HTTPX::Transcoder
|
||||
module_function
|
||||
|
||||
class Encoder
|
||||
using HTTPX::ArrayExtensions
|
||||
using HTTPX::ArrayExtensions::Sum
|
||||
extend Forwardable
|
||||
|
||||
def_delegator :@raw, :to_s
|
||||
|
||||
@ -96,6 +96,7 @@ module HTTPX
|
||||
class ErrorResponse
|
||||
include _Response
|
||||
include Loggable
|
||||
extend Forwardable
|
||||
|
||||
@options: Options
|
||||
@error: Exception
|
||||
@ -104,6 +105,8 @@ module HTTPX
|
||||
|
||||
def status: () -> (Integer | _ToS)
|
||||
|
||||
def uri: () -> URI::Generic
|
||||
|
||||
private
|
||||
|
||||
def initialize: (Request, Exception, options) -> untyped
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user