module HTTPX::Resolver

  1. lib/httpx/resolver.rb
  2. lib/httpx/resolver/entry.rb
  3. lib/httpx/resolver/https.rb
  4. lib/httpx/resolver/multi.rb
  5. lib/httpx/resolver/native.rb
  6. lib/httpx/resolver/resolver.rb
  7. lib/httpx/resolver/system.rb
  8. lib/httpx/selector.rb
  9. show all

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