mirror of
https://github.com/HoneyryderChuck/httpx.git
synced 2025-10-04 00:00:37 -04:00
Merge branch 'gh-103' into 'master'
fix: do not check if multi-homed network at boot time, instead do it a runtime See merge request os85/httpx!408
This commit is contained in:
commit
267bbea7f9
@ -1,7 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "socket"
|
||||
|
||||
module HTTPX
|
||||
# Contains a set of options which are passed and shared across from session to its requests or
|
||||
# responses.
|
||||
@ -414,18 +412,6 @@ module HTTPX
|
||||
end
|
||||
end
|
||||
|
||||
# https://github.com/ruby/resolv/blob/095f1c003f6073730500f02acbdbc55f83d70987/lib/resolv.rb#L408
|
||||
ip_address_families = begin
|
||||
list = Socket.ip_address_list
|
||||
if list.any? { |a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? }
|
||||
[Socket::AF_INET6, Socket::AF_INET]
|
||||
else
|
||||
[Socket::AF_INET]
|
||||
end
|
||||
rescue NotImplementedError
|
||||
[Socket::AF_INET]
|
||||
end.freeze
|
||||
|
||||
DEFAULT_OPTIONS = {
|
||||
:max_requests => Float::INFINITY,
|
||||
:debug => nil,
|
||||
@ -470,7 +456,7 @@ module HTTPX
|
||||
:resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym,
|
||||
:resolver_options => { cache: true }.freeze,
|
||||
:pool_options => EMPTY_HASH,
|
||||
:ip_families => ip_address_families,
|
||||
:ip_families => nil,
|
||||
:close_on_fork => false,
|
||||
}.freeze
|
||||
end
|
||||
|
@ -1,5 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "socket"
|
||||
require "resolv"
|
||||
|
||||
module HTTPX
|
||||
@ -22,6 +23,20 @@ module HTTPX
|
||||
|
||||
module_function
|
||||
|
||||
def supported_ip_families
|
||||
@supported_ip_families ||= begin
|
||||
# https://github.com/ruby/resolv/blob/095f1c003f6073730500f02acbdbc55f83d70987/lib/resolv.rb#L408
|
||||
list = Socket.ip_address_list
|
||||
if list.any? { |a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? }
|
||||
[Socket::AF_INET6, Socket::AF_INET]
|
||||
else
|
||||
[Socket::AF_INET]
|
||||
end
|
||||
rescue NotImplementedError
|
||||
[Socket::AF_INET]
|
||||
end.freeze
|
||||
end
|
||||
|
||||
def resolver_for(resolver_type, options)
|
||||
case resolver_type
|
||||
when Symbol
|
||||
|
@ -15,7 +15,9 @@ module HTTPX
|
||||
@options = options
|
||||
@resolver_options = @options.resolver_options
|
||||
|
||||
@resolvers = options.ip_families.map do |ip_family|
|
||||
ip_families = options.ip_families || Resolver.supported_ip_families
|
||||
|
||||
@resolvers = ip_families.map do |ip_family|
|
||||
resolver = resolver_type.new(ip_family, options)
|
||||
resolver.multi = self
|
||||
resolver
|
||||
@ -67,8 +69,12 @@ module HTTPX
|
||||
addresses = @resolver_options[:cache] && (connection.addresses || HTTPX::Resolver.nolookup_resolve(hostname))
|
||||
return false unless addresses
|
||||
|
||||
ip_families = connection.options.ip_families || Resolver.supported_ip_families
|
||||
|
||||
resolved = false
|
||||
addresses.group_by(&:family).sort { |(f1, _), (f2, _)| f2 <=> f1 }.each do |family, addrs|
|
||||
next unless ip_families.include?(family)
|
||||
|
||||
# try to match the resolver by family. However, there are cases where that's not possible, as when
|
||||
# the system does not have IPv6 connectivity, but it does support IPv6 via loopback/link-local.
|
||||
resolver = @resolvers.find { |r| r.family == family } || @resolvers.first
|
||||
@ -85,7 +91,11 @@ module HTTPX
|
||||
end
|
||||
|
||||
def lazy_resolve(connection)
|
||||
ip_families = connection.options.ip_families || Resolver.supported_ip_families
|
||||
|
||||
@resolvers.each do |resolver|
|
||||
next unless ip_families.include?(resolver.family)
|
||||
|
||||
resolver << @current_session.try_clone_connection(connection, @current_selector, resolver.family)
|
||||
next if resolver.empty?
|
||||
|
||||
|
@ -79,12 +79,18 @@ module HTTPX
|
||||
"answer #{connection.peer.host}: #{addresses.inspect} (early resolve: #{early_resolve})"
|
||||
end
|
||||
|
||||
if !early_resolve && # do not apply resolution delay for non-dns name resolution
|
||||
@current_selector && # just in case...
|
||||
family == Socket::AF_INET && # resolution delay only applies to IPv4
|
||||
!connection.io && # connection already has addresses and initiated/ended handshake
|
||||
connection.options.ip_families.size > 1 && # no need to delay if not supporting dual stack IP
|
||||
addresses.first.to_s != connection.peer.host.to_s # connection URL host is already the IP (early resolve included perhaps?)
|
||||
# do not apply resolution delay for non-dns name resolution
|
||||
if !early_resolve &&
|
||||
# just in case...
|
||||
@current_selector &&
|
||||
# resolution delay only applies to IPv4
|
||||
family == Socket::AF_INET &&
|
||||
# connection already has addresses and initiated/ended handshake
|
||||
!connection.io &&
|
||||
# no need to delay if not supporting dual stack / multi-homed IP
|
||||
(connection.options.ip_families || Resolver.supported_ip_families).size > 1 &&
|
||||
# connection URL host is already the IP (early resolve included perhaps?)
|
||||
addresses.first.to_s != connection.peer.host.to_s
|
||||
log { "resolver #{FAMILY_TYPES[RECORD_TYPES[family]]}: applying resolution delay..." }
|
||||
|
||||
@current_selector.after(0.05) do
|
||||
|
@ -187,7 +187,9 @@ module HTTPX
|
||||
|
||||
transition(:open)
|
||||
|
||||
connection.options.ip_families.each do |family|
|
||||
ip_families = connection.options.ip_families || Resolver.supported_ip_families
|
||||
|
||||
ip_families.each do |family|
|
||||
@queries << [family, connection]
|
||||
end
|
||||
async_resolve(connection, hostname, scheme)
|
||||
@ -195,7 +197,7 @@ module HTTPX
|
||||
end
|
||||
|
||||
def async_resolve(connection, hostname, scheme)
|
||||
families = connection.options.ip_families
|
||||
families = connection.options.ip_families || Resolver.supported_ip_families
|
||||
log { "resolver: query for #{hostname}" }
|
||||
timeouts = @timeouts[connection.peer.host]
|
||||
resolve_timeout = timeouts.first
|
||||
|
@ -130,7 +130,7 @@ module HTTPX
|
||||
attr_reader pool_options: pool_options
|
||||
|
||||
# ip_families
|
||||
attr_reader ip_families: Array[ip_family]
|
||||
attr_reader ip_families: Array[ip_family]?
|
||||
|
||||
def ==: (Options other) -> bool
|
||||
|
||||
@ -195,7 +195,7 @@ module HTTPX
|
||||
|
||||
def option_addresses: (ipaddr | _ToAry[ipaddr] value) -> Array[ipaddr]
|
||||
|
||||
def option_ip_families: (Integer | _ToAry[Integer] value) -> Array[Integer]
|
||||
def option_ip_families: (ip_family | _ToAry[ip_family] value) -> Array[ip_family]
|
||||
end
|
||||
|
||||
type options = Options | Hash[Symbol, untyped]
|
||||
|
@ -23,6 +23,8 @@ module HTTPX
|
||||
|
||||
def self?.hosts_resolve: (String hostname) -> Array[Entry]?
|
||||
|
||||
def self?.supported_ip_families: () -> Array[ip_family]
|
||||
|
||||
def self?.resolver_for: (Symbol | singleton(Resolver) resolver_type, Options options) -> singleton(Resolver)
|
||||
|
||||
def self?.cached_lookup: (String hostname) -> Array[Entry]?
|
||||
|
@ -3,14 +3,13 @@
|
||||
require_relative "test"
|
||||
|
||||
class ByIpCertServer < TestServer
|
||||
USE_IPV6 = HTTPX::Options::DEFAULT_OPTIONS[:ip_families].size > 1
|
||||
CERTS_DIR = File.expand_path("../ci/certs", __dir__)
|
||||
|
||||
def initialize
|
||||
cert = OpenSSL::X509::Certificate.new(File.read(File.join(CERTS_DIR, "localhost-server.crt")))
|
||||
key = OpenSSL::PKey.read(File.read(File.join(CERTS_DIR, "localhost-server.key")))
|
||||
super(
|
||||
:BindAddress => USE_IPV6 ? "::1" : "127.0.0.1",
|
||||
:BindAddress => HTTPX::Resolver.supported_ip_families.size > 1 ? "::1" : "127.0.0.1",
|
||||
:SSLEnable => true,
|
||||
:SSLCertificate => cert,
|
||||
:SSLPrivateKey => key,
|
||||
|
Loading…
x
Reference in New Issue
Block a user