The DNS resolver is a building block which the user can switch.
httpx ships with the following resolvers:
:native: pure ruby resolver (default).:system: uses Addrinfo.getaddrinfo to perform DNS queries.:https: DNS over HTTPS (DoH) resolver.You can switch DNS resolvers by passing it as an option:
HTTPX.with(resolver_class: :https).get("https://example.com")
or set the default via the HTTPX_RESOLVER environment variable (ex: HTTPX_RESOLVER=https).
You can also pass additional DNS resolver options by using :resolver_options:
HTTPX.with(resolver_class: :https, resolver_options: { uri: "https://cloudflare-dns.com/dns-query" })
The :native resolver is a custom pure ruby DNS resolver implementation deeply integrated with httpx. It essentially delivers practically the same functionality as getaddrinfo without the drawbacks (examples of which are, no socket handler for IO operations, no support for timeouts, sorting applied by default…)
As extra :resolver_options, you can pass the same ones used for the ruby Resolv::DNS initializer (hint: check the options available for your ruby version), along with:
:socket_type: (:udp by default) type of socket used to send DNS queries to the nameservers (also accepts :tcp, which it automatically falls back to in the large request TCP fallback scenario).This system resolver uses Addrinfo.getaddrinfo to perform the DNS queries. It integrates with the IO loop by running the resolution call in a background thread and notifying the loop asynchronously.
getaddrinfo is a notoriously hard-to-integrate API for the kind of scenarios httpx supports. However, it’s a stable and widely available API, and easy to fall back to.
The :https resolver uses the same internal httpx HTTP stack as the requests to perform DNS resolution following the DoH spec.
As extra :resolver_options, you can pass the following:
uri: the DoH-enabled URI where to send the query (default: https://1.1.1.1/dns-query);use_get: whether to use GET instead of POST for DoH requests (default: false);All options above are supported in the happy eyeballs v2 algorithm in multi-homed dual-stack (IPv6 / IPv4) networks. This means that, preference will be given to the fastest option to query and connect to (with a slight preference to IPv6 connections).
A DNS resolution caching layer, which keeps DNS results around for reuse for the duration of the advertised “time-to-live”, is built-in for the :native and :https resolvers.
This is enabled by default, and can be disabled by setting it to false:
session = HTTPX.with(resolver_options: { cache: false })
The cache type can also be switch by using the :resolver_cache option.
:memory (default)By default, DNS cache lives in memory, in a thread-safe / ractor-safe data structure, which is reused and manipulated across.
:fileWith the :file resolver cache, DNS results are stored in a file in a known location (in the Dir.tmpdir directory, in a file called httpx-ruby-$VERSION.cache, where VERSION is the httpx version), so that DNS results can be reused across all processes from the machine.
session = HTTPX.with(resolver_cache: :file)
Note: This feature requires the pstore standard gem, make sure you have it installed.
You can set your own resolver cache by passing an object instead:
session = HTTPX.with(resolver_cache: CustomCache)
You’ll have to ensure that the custom object responds to:
#resolve(hostname): main used function, should return an array of Resolver::Entry objects#get(hostname): should return an array of Resolver::Entry objects#set(hostname, ip_family, entries): should store the entries, for the given ip family and hostname.#evict(hostname, ip): should evict the given ip for that hostname.If the custom object inherits from HTTPX::Resolver::Cache::Base, #resolve is already there.
Next: TLS