1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//! Where a URI's authority stops being URI syntax.
/// The host a URI names, with an IPv6 literal's brackets removed.
///
/// `[2001:db8::1]` becomes `2001:db8::1`; every other host — a name, an
/// IPv4 literal, an already-bare v6 address — comes back untouched.
///
/// # Why this exists at all, and why in this crate
///
/// `http::Uri::host()` returns an IPv6 literal **with its brackets**,
/// because that is what the URI says: RFC 3986 §3.2.2 puts `IP-literal =
/// "[" ( IPv6address / IPvFuture ) "]"` in the *authority*'s grammar, not
/// in the host's. Nothing outside a URI wants them, and everything outside
/// a URI is where this workspace kept meeting the same failure:
///
/// * `str::parse::<IpAddr>()` rejects `[::1]`, so a resolver's literal
/// shortcut falls through and asks DNS about a string no zone contains.
/// * `rustls_pki_types::ServerName::try_from` rejects `[::1]` as **both** a
/// DNS name and an address, so a TLS or QUIC handshake fails with
/// `invalid dns name` before a byte of the exchange happens.
///
/// The duty is the **caller's**, not the backend's — see
/// `hclient_tls::TlsRequest::server_name`, whose doc says so at the seam
/// where it matters. A backend that stripped defensively would be the
/// second place normalising, and two places normalising is how they drift;
/// worse, it would have to guess, since a backend cannot tell a host that
/// came from a URI from one a caller built by hand.
///
/// This crate is the home because it is the only one every consumer
/// already has. `hclient-native` and `hclient-h3` both hold a `Uri` and
/// both feed a TLS seam; `hclient-dns` and `hclient-dns-doh` both parse
/// literals; `hclient-tls`, whose doc has to name the duty, depends on
/// this crate and not on any of them. Putting it in `hclient-dns` would
/// make a TLS server name reach through a resolver crate for a fact about
/// URI syntax, and putting it in `hclient-tls` would do the mirror image
/// to a resolver.
///
/// # What it does not do
///
/// It is not a validator and not a parser. `[` alone is not a bracketed
/// host and comes back as `[`; `[]` is a bracketed *empty* host and comes
/// back as the empty string, which every consumer downstream then refuses
/// — `ServerName::try_from("")` and `"".parse::<IpAddr>()` both fail —
/// rather than being quietly patched up here. Percent-encoding, ports and
/// userinfo are `http::Uri`'s business and have already been removed by
/// the time `Uri::host()` has answered.
///
/// # What must NOT be stripped
///
/// The `Host` header and HTTP/2's `:authority` are authority syntax, so
/// they keep their brackets (RFC 9110 §7.2 — `Host = uri-host [ ":" port
/// ]`). Only the step out of URI-land takes them off.