Methods
Public Instance
Classes and Modules
Constants
| MAX_CACHE_SIZE | = | 512 | ||
| RESOLVE_TIMEOUT | = | [2, 3].freeze |
Public Instance methods
cached_lookup(hostname)
[show source]
# File lib/httpx/resolver.rb 74 def cached_lookup(hostname) 75 now = Utils.now 76 lookup_synchronize do |lookups, hostnames| 77 lookup(hostname, lookups, hostnames, now) 78 end 79 end
cached_lookup_evict(hostname, ip)
[show source]
# File lib/httpx/resolver.rb 110 def cached_lookup_evict(hostname, ip) 111 ip = ip.to_s 112 113 lookup_synchronize do |lookups, hostnames| 114 entries = lookups[hostname] 115 116 return unless entries 117 118 entries.delete_if { |entry| entry["data"] == ip } 119 120 if entries.empty? 121 lookups.delete(hostname) 122 hostnames.delete(hostname) 123 end 124 end 125 end
cached_lookup_set(hostname, family, entries)
[show source]
# File lib/httpx/resolver.rb 81 def cached_lookup_set(hostname, family, entries) 82 lookup_synchronize do |lookups, hostnames| 83 # lru cleanup 84 while lookups.size >= MAX_CACHE_SIZE 85 hs = hostnames.shift 86 lookups.delete(hs) 87 end 88 hostnames << hostname 89 90 case family 91 when Socket::AF_INET6 92 lookups[hostname].concat(entries) 93 when Socket::AF_INET 94 lookups[hostname].unshift(*entries) 95 end 96 entries.each do |entry| 97 name = entry["name"] 98 next unless name != hostname 99 100 case family 101 when Socket::AF_INET6 102 lookups[name] << entry 103 when Socket::AF_INET 104 lookups[name].unshift(entry) 105 end 106 end 107 end 108 end
decode_dns_answer(payload)
[show source]
# File lib/httpx/resolver.rb 169 def decode_dns_answer(payload) 170 begin 171 message = Resolv::DNS::Message.decode(payload) 172 rescue Resolv::DNS::DecodeError => e 173 return :decode_error, e 174 end 175 176 # no domain was found 177 return :no_domain_found if message.rcode == Resolv::DNS::RCode::NXDomain 178 179 return :message_truncated if message.tc == 1 180 181 if message.rcode != Resolv::DNS::RCode::NoError 182 case message.rcode 183 when Resolv::DNS::RCode::ServFail 184 return :retriable_error, message.rcode 185 else 186 return :dns_error, message.rcode 187 end 188 end 189 190 addresses = [] 191 192 now = Utils.now 193 message.each_answer do |question, _, value| 194 case value 195 when Resolv::DNS::Resource::IN::CNAME 196 addresses << { 197 "name" => question.to_s, 198 "TTL" => (now + value.ttl), 199 "alias" => value.name.to_s, 200 } 201 when Resolv::DNS::Resource::IN::A, 202 Resolv::DNS::Resource::IN::AAAA 203 addresses << { 204 "name" => question.to_s, 205 "TTL" => (now + value.ttl), 206 "data" => value.address.to_s, 207 } 208 end 209 end 210 211 [:ok, addresses] 212 end
encode_dns_query(hostname, type: Resolv::DNS::Resource::IN::A, message_id: generate_id)
[show source]
# File lib/httpx/resolver.rb 162 def encode_dns_query(hostname, type: Resolv::DNS::Resource::IN::A, message_id: generate_id) 163 Resolv::DNS::Message.new(message_id).tap do |query| 164 query.rd = 1 165 query.add_question(hostname, type) 166 end.encode 167 end
generate_id()
[show source]
# File lib/httpx/resolver.rb 153 def generate_id 154 if in_ractor? 155 identifier = Ractor.store_if_absent(:httpx_resolver_identifier) { -1 } 156 Ractor.current[:httpx_resolver_identifier] = (identifier + 1) & 0xFFFF 157 else 158 id_synchronize { @identifier = (@identifier + 1) & 0xFFFF } 159 end 160 end
hosts_resolve(hostname)
matches hostname to entries in the hosts file, returns <tt>nil</nil> if none is found, or there is no hosts file.
[show source]
# File lib/httpx/resolver.rb 61 def hosts_resolve(hostname) 62 ips = if in_ractor? 63 Ractor.store_if_absent(:httpx_hosts_resolver) { Resolv::Hosts.new } 64 else 65 @hosts_resolver 66 end.getaddresses(hostname) 67 68 return if ips.empty? 69 70 ips.map { |ip| Entry.new(ip) } 71 rescue IOError 72 end
ip_resolve(hostname)
tries to convert hostname into an IPAddr, returns nil otherwise.
[show source]
# File lib/httpx/resolver.rb 54 def ip_resolve(hostname) 55 [Entry.new(hostname)] 56 rescue ArgumentError 57 end
lookup(hostname, lookups, hostnames, ttl)
do not use directly!
[show source]
# File lib/httpx/resolver.rb 128 def lookup(hostname, lookups, hostnames, ttl) 129 return unless lookups.key?(hostname) 130 131 entries = lookups[hostname] 132 133 entries.delete_if do |address| 134 address["TTL"] < ttl 135 end 136 137 if entries.empty? 138 lookups.delete(hostname) 139 hostnames.delete(hostname) 140 end 141 142 ips = entries.flat_map do |address| 143 if (als = address["alias"]) 144 lookup(als, lookups, hostnames, ttl) 145 else 146 Entry.new(address["data"], address["TTL"]) 147 end 148 end.compact 149 150 ips unless ips.empty? 151 end
nolookup_resolve(hostname)
[show source]
# File lib/httpx/resolver.rb 49 def nolookup_resolve(hostname) 50 ip_resolve(hostname) || cached_lookup(hostname) || hosts_resolve(hostname) 51 end
resolver_for(resolver_type, options)
[show source]
# File lib/httpx/resolver.rb 36 def resolver_for(resolver_type, options) 37 case resolver_type 38 when Symbol 39 meth = :"resolver_#{resolver_type}_class" 40 41 return options.__send__(meth) if options.respond_to?(meth) 42 when Class 43 return resolver_type if resolver_type < Resolver 44 end 45 46 raise Error, "unsupported resolver type (#{resolver_type})" 47 end
supported_ip_families()
[show source]
# File lib/httpx/resolver.rb 28 def supported_ip_families 29 if in_ractor? 30 Ractor.store_if_absent(:httpx_supported_ip_families) { find_supported_ip_families } 31 else 32 @supported_ip_families ||= find_supported_ip_families 33 end 34 end