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
75 def cached_lookup(hostname)
76   now = Utils.now
77   lookup_synchronize do |lookups, hostnames|
78     lookup(hostname, lookups, hostnames, now)
79   end
80 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     lookups.delete_if { |entry| entry["data"] == ip }
119 
120     if lookups.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
 82 def cached_lookup_set(hostname, family, entries)
 83   lookup_synchronize do |lookups, hostnames|
 84     # lru cleanup
 85     while lookups.size >= MAX_CACHE_SIZE
 86       hs = hostnames.shift
 87       lookups.delete(hs)
 88     end
 89     hostnames << hostname
 90 
 91     case family
 92     when Socket::AF_INET6
 93       lookups[hostname].concat(entries)
 94     when Socket::AF_INET
 95       lookups[hostname].unshift(*entries)
 96     end
 97     entries.each do |entry|
 98       next unless entry["name"] != hostname
 99 
100       case family
101       when Socket::AF_INET6
102         lookups[entry["name"]] << entry
103       when Socket::AF_INET
104         lookups[entry["name"]].unshift(entry)
105       end
106     end
107   end
108 end
decode_dns_answer(payload)
[show source]
    # File lib/httpx/resolver.rb
164 def decode_dns_answer(payload)
165   begin
166     message = Resolv::DNS::Message.decode(payload)
167   rescue Resolv::DNS::DecodeError => e
168     return :decode_error, e
169   end
170 
171   # no domain was found
172   return :no_domain_found if message.rcode == Resolv::DNS::RCode::NXDomain
173 
174   return :message_truncated if message.tc == 1
175 
176   if message.rcode != Resolv::DNS::RCode::NoError
177     case message.rcode
178     when Resolv::DNS::RCode::ServFail
179       return :retriable_error, message.rcode
180     else
181       return :dns_error, message.rcode
182     end
183   end
184 
185   addresses = []
186 
187   now = Utils.now
188   message.each_answer do |question, _, value|
189     case value
190     when Resolv::DNS::Resource::IN::CNAME
191       addresses << {
192         "name" => question.to_s,
193         "TTL" => (now + value.ttl),
194         "alias" => value.name.to_s,
195       }
196     when Resolv::DNS::Resource::IN::A,
197          Resolv::DNS::Resource::IN::AAAA
198       addresses << {
199         "name" => question.to_s,
200         "TTL" => (now + value.ttl),
201         "data" => value.address.to_s,
202       }
203     end
204   end
205 
206   [:ok, addresses]
207 end
encode_dns_query(hostname, type: Resolv::DNS::Resource::IN::A, message_id: generate_id)
[show source]
    # File lib/httpx/resolver.rb
157 def encode_dns_query(hostname, type: Resolv::DNS::Resource::IN::A, message_id: generate_id)
158   Resolv::DNS::Message.new(message_id).tap do |query|
159     query.rd = 1
160     query.add_question(hostname, type)
161   end.encode
162 end
generate_id()
[show source]
    # File lib/httpx/resolver.rb
153 def generate_id
154   id_synchronize { @identifier = (@identifier + 1) & 0xFFFF }
155 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
67 def hosts_resolve(hostname)
68   ips = @hosts_resolver.getaddresses(hostname)
69   return if ips.empty?
70 
71   ips.map { |ip| Entry.new(ip) }
72 rescue IOError
73 end
id_synchronize(&block)
[show source]
    # File lib/httpx/resolver.rb
213 def id_synchronize(&block)
214   @identifier_mutex.synchronize(&block)
215 end
ip_resolve(hostname)

tries to convert hostname into an IPAddr, returns nil otherwise.

[show source]
   # File lib/httpx/resolver.rb
60 def ip_resolve(hostname)
61   [Entry.new(hostname)]
62 rescue ArgumentError
63 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
lookup_synchronize()
[show source]
    # File lib/httpx/resolver.rb
209 def lookup_synchronize
210   @lookup_mutex.synchronize { yield(@lookups, @hostnames) }
211 end
nolookup_resolve(hostname)
[show source]
   # File lib/httpx/resolver.rb
55 def nolookup_resolve(hostname)
56   ip_resolve(hostname) || cached_lookup(hostname) || hosts_resolve(hostname)
57 end
resolver_for(resolver_type, options)
[show source]
   # File lib/httpx/resolver.rb
42 def resolver_for(resolver_type, options)
43   case resolver_type
44   when Symbol
45     meth = :"resolver_#{resolver_type}_class"
46 
47     return options.__send__(meth) if options.respond_to?(meth)
48   when Class
49     return resolver_type if resolver_type < Resolver
50   end
51 
52   raise Error, "unsupported resolver type (#{resolver_type})"
53 end
supported_ip_families()
[show source]
   # File lib/httpx/resolver.rb
28 def supported_ip_families
29   @supported_ip_families ||= begin
30     # https://github.com/ruby/resolv/blob/095f1c003f6073730500f02acbdbc55f83d70987/lib/resolv.rb#L408
31     list = Socket.ip_address_list
32     if list.any? { |a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? }
33       [Socket::AF_INET6, Socket::AF_INET]
34     else
35       [Socket::AF_INET]
36     end
37   rescue NotImplementedError
38     [Socket::AF_INET]
39   end.freeze
40 end