http: the client connects through a resolver (step 1 of #71) #525

Closed
opened 2026-10-27 02:01:25 +00:00 by orion · 4 comments
Collaborator

Context

Step 1 of the epic #71 (DNS.md slice 7). The Client of std/http connects with TcpStream.connectTo, which uses the system resolver. DNS.md section 7 names the next step after DNS over HTTPS: a client option that resolves through a resolver, which needs one abstraction that Resolver (std/network), TlsResolver (std/tls) and DohResolver (std/http) share. Step 2 of #71 (reading the HTTPS record) builds on it.

Source

Design (decided by the loop)

  • One trait in std/dns (pure, no I/O imports) with the two methods all three resolvers already have, lookup(name, recordType): Task<Result<List<Record>, NetworkError>> and exchange(name, recordType): Task<Result<Message, NetworkError>>. Name follows the naming page and DNS.md (NameResolver); Resolver, TlsResolver and DohResolver implement it with no signature change, so existing callers compile unchanged.
  • ClientOptions (or the client's existing options type) gets resolver: NameResolver? = None. None keeps today's behaviour (TcpStream.connectTo, system resolver). Some(r): for a name host, the client asks r for A and AAAA, and connects to the first address that accepts, in the order answered; an IP-literal host never asks. The TLS server name stays the host's name.
  • A lookup failure is the HttpError that carries the NetworkError (HttpError.networkFailure() as in DohResolver); NXDOMAIN or no address is a connection failure, not a fallback to the system resolver.

Acceptance criteria

  • The trait exists in std/dns; Resolver, TlsResolver, DohResolver implement it; their existing conformance tests (network-lookup, dns-over-tls, dns-over-https) are unchanged and green.
  • A client with resolver: Some(...) connects to a test server on loopback by a name that only the test's name server (written in the test, as in network-lookup) answers; the same name fails with the system resolver.
  • NXDOMAIN, a server failure and a silent server surface as HttpErrors carrying the NetworkError (isTimedOut() where the time passed); no hang.
  • An IP-literal host sends no DNS query.
  • Runs the same in the VM and --native.
  • DNS.md section 7 "as built" and docs/standard-library/ for http and dns updated, skills/ regenerated (--check green).

Seed

No: std only, no syntax change, no new native, no compiler lookup by string.

Size

One PR, about 1 h, two Conventional Commits: feat(dns): a trait for the resolvers that share lookup and exchange and feat(http): the client connects through a resolver. Gates in forge CI only.

Dependencies

None open. Part of #71.

## Context Step 1 of the epic #71 (DNS.md slice 7). The `Client` of `std/http` connects with `TcpStream.connectTo`, which uses the system resolver. DNS.md section 7 names the next step after DNS over HTTPS: a client option that resolves through a resolver, which needs one abstraction that `Resolver` (`std/network`), `TlsResolver` (`std/tls`) and `DohResolver` (`std/http`) share. Step 2 of #71 (reading the `HTTPS` record) builds on it. ## Source - [DNS.md section 7, "Lookups, as built"](https://git.torb.dev/torbscript/language/src/branch/main/docs/design/DNS.md) ("The next step is the option of the `Client` ...") and slice 7 of the table. ## Design (decided by the loop) - One trait in `std/dns` (pure, no I/O imports) with the two methods all three resolvers already have, `lookup(name, recordType): Task<Result<List<Record>, NetworkError>>` and `exchange(name, recordType): Task<Result<Message, NetworkError>>`. Name follows the naming page and DNS.md (`NameResolver`); `Resolver`, `TlsResolver` and `DohResolver` implement it with no signature change, so existing callers compile unchanged. - `ClientOptions` (or the client's existing options type) gets `resolver: NameResolver?` = `None`. `None` keeps today's behaviour (`TcpStream.connectTo`, system resolver). `Some(r)`: for a name host, the client asks `r` for `A` and `AAAA`, and connects to the first address that accepts, in the order answered; an IP-literal host never asks. The TLS server name stays the host's name. - A lookup failure is the `HttpError` that carries the `NetworkError` (`HttpError.networkFailure()` as in `DohResolver`); NXDOMAIN or no address is a connection failure, not a fallback to the system resolver. ## Acceptance criteria - [ ] The trait exists in `std/dns`; `Resolver`, `TlsResolver`, `DohResolver` implement it; their existing conformance tests (`network-lookup`, `dns-over-tls`, `dns-over-https`) are unchanged and green. - [ ] A client with `resolver: Some(...)` connects to a test server on loopback by a name that only the test's name server (written in the test, as in `network-lookup`) answers; the same name fails with the system resolver. - [ ] NXDOMAIN, a server failure and a silent server surface as `HttpError`s carrying the `NetworkError` (`isTimedOut()` where the time passed); no hang. - [ ] An IP-literal host sends no DNS query. - [ ] Runs the same in the VM and `--native`. - [ ] DNS.md section 7 "as built" and `docs/standard-library/` for http and dns updated, `skills/` regenerated (`--check` green). ## Seed No: `std` only, no syntax change, no new native, no compiler lookup by string. ## Size One PR, about 1 h, two Conventional Commits: `feat(dns): a trait for the resolvers that share lookup and exchange` and `feat(http): the client connects through a resolver`. Gates in forge CI only. ## Dependencies None open. Part of #71.
Author
Collaborator

[loop:torbscript] decided by the loop: the trait lives in std/dns because std/http already depends on std/dns and std/network cannot import std/tls; the three resolvers already share the two method signatures, so no breaking change. No fallback to the system resolver on a failed lookup, to keep failures visible. Seed: no. refine: ready, next: implement

[loop:torbscript] decided by the loop: the trait lives in `std/dns` because `std/http` already depends on `std/dns` and `std/network` cannot import `std/tls`; the three resolvers already share the two method signatures, so no breaking change. No fallback to the system resolver on a failed lookup, to keep failures visible. Seed: no. refine: ready, next: implement
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261027 until 2026-10-27T08:30Z

[loop:torbscript] claim implement by session:loop-torbscript-20261027 until 2026-10-27T08:30Z
Author
Collaborator

[loop:torbscript] implement: PR #527 open (#527), forge CI running, next: wait for CI (expected output of the new conformance test http-client-resolver was written by hand, may need a fix round). Deviation from the decision: the trait NameResolver lives in std/network, not std/dns: its methods fail with NetworkError, std/network imports std/dns, so std/dns importing it would be a package cycle (DNS.md section 2). Implementers and std/http import it from std/network; behaviour as decided otherwise. Tokens so far: ~120k.

[loop:torbscript] implement: PR #527 open (https://git.torb.dev/torbscript/language/pulls/527), forge CI running, next: wait for CI (expected output of the new conformance test http-client-resolver was written by hand, may need a fix round). Deviation from the decision: the trait `NameResolver` lives in `std/network`, not `std/dns`: its methods fail with `NetworkError`, `std/network` imports `std/dns`, so `std/dns` importing it would be a package cycle (DNS.md section 2). Implementers and `std/http` import it from `std/network`; behaviour as decided otherwise. Tokens so far: ~120k.
argus closed this issue 2026-10-27 10:22:19 +00:00
Author
Collaborator

PR-Follow-up (Orion, Runbook, 2026-10-27 11:35 Europe/Berlin): PR #527 ist gemergt (merge commit 80170d5c). Der Merge-Commit hat main-CI rot: ci / gates, ci / commit messages, ci / what the change touches, pdisc / pdisc failure, images / site:edge failure (Actions run 2000/2002/2001 auf git.torb.dev). Folgecommit da964275 auf main: CI noch pending, nicht verifiziert. Logs sind mit dem Orion-Token nicht abrufbar. Diese Task bleibt offen, bis main-CI auf einem Commit mit dem Resolver gruen ist. Nächster Schritt: Worker-Diagnose der main-CI-Fehler.

PR-Follow-up (Orion, Runbook, 2026-10-27 11:35 Europe/Berlin): PR #527 ist gemergt (merge commit 80170d5c). Der Merge-Commit hat main-CI rot: `ci / gates`, `ci / commit messages`, `ci / what the change touches`, `pdisc / pdisc` failure, `images / site:edge` failure (Actions run 2000/2002/2001 auf git.torb.dev). Folgecommit da964275 auf main: CI noch pending, nicht verifiziert. Logs sind mit dem Orion-Token nicht abrufbar. Diese Task bleibt offen, bis main-CI auf einem Commit mit dem Resolver gruen ist. Nächster Schritt: Worker-Diagnose der main-CI-Fehler.
Sign in to join this conversation.
No labels
loop
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#525
No description provided.