Skip to content

Add per-request DNS override API (curl --resolve / OkHttp Dns-style) #866

Description

@caogaoshuai

Could you please add support for a per-request DNS override that behaves like curl’s --resolve, or similar to OkHttp’s pluggable Dns interface (which lets you override host→IP
resolution on a per-request basis)? At the moment HTTPClient.Configuration.dnsOverride is the only entry-point, so the mapping is effectively static for the lifetime of a client. In
our workloads the host→IP mapping can change every minute, and paying the cost of creating and shutting down separate HTTPClient instances (each with its own connection pool) just to
apply a new override is prohibitively expensive.

The capability we are looking for is:

  • Let a single request supply a temporary host→IP mapping (or a resolver callback).
  • Keep using the original host for SNI/certificate validation and logging.
  • Route the actual TCP/TLS connection to the overridden address.

If the existing execute APIs exposed an optional per-request override, or allowed callers to provide a resolver closure (akin to overriding OkHttp’s Dns.resolve), we could keep the
default behavior while enabling dynamic overrides. We’d greatly appreciate this enhancement.

Activity

  1. Lukasa commented on Oct 30, 2025

    @Lukasa
    Collaborator

    This feels like a totally reasonable feature request. Right now it's not likely to be high enough up our priority list for us to tackle it immediately, but we'd welcome a contribution and I'd make sure we got it merged and across the line.

  2. thliu21 commented on Aug 6, 2026

    @thliu21

    Thanks for confirming that a contribution would be welcome. I explored a minimal additive API based on the existing Configuration.dnsOverride behavior and the request-level localAddress precedent:

    public var dnsOverride: [String: String]?

    In the local prototype, nil uses the client configuration, while a non-nil mapping replaces it for that request; an empty mapping explicitly disables client-level overrides. The mapping is preserved across redirects. The overridden connection target participates in the pool key, while the original host remains unchanged for the Host header, SNI, certificate validation, and request URL/tracing. The full local test suite passes.

    Before opening a PR, could you clarify a few contract and lifecycle choices?

    1. Given the client-level Configuration.DNSResolver introduced in Add randomized DNS resolver option for load balancing #907, would you prefer a per-request mapping, or an extension of that resolver model for per-request/custom resolution?
    2. Should request entries replace the client mapping, or merge over it? What should an empty mapping mean?
    3. Should the still-public HTTPClient.Request API be supported as well?
    4. Each distinct overridden target currently creates a distinct pool key, and the pool manager retains those pools until client shutdown. For mappings that change frequently over a long-lived client, should the target set be treated as bounded, or is empty-pool eviction/another pool-identity design expected?

    I also noticed #914 touches the same request/preparation files for local-port binding, but it does not appear to overlap functionally with this work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions