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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! Serving over TLS, including client certificates, SNI and protocol tuning.
//!
//! Run it without the macros or the JSON codec — the transport is the subject
//! here, not the API:
//!
//! ```text
//! cargo run -p kynos --example tls --no-default-features \
//! --features openapi31,server,http1,http2,tls
//! ```
//!
//! The certificates are minted at startup with `rcgen`, so this runs with
//! nothing prepared and nothing committed. A real deployment reads PEM from
//! disk, a secret manager or an ACME client; `from_pem` takes bytes and does
//! not care where they came from.
//!
//! Four things are worth noticing:
//!
//! * **rustls is the only TLS backend, and that is a decision rather than a
//! default.** There is no `native-tls` feature and no runtime selection, so
//! there is one code path to audit and one set of failure modes to
//! understand. See `docs/architecture.md`.
//! * **SNI is a list of certificates, not a list of servers.** One listener
//! serves several names by choosing a certificate during the handshake, which
//! is why the names are attached to the certificate rather than to the bind
//! address.
//! * **Client certificates are `require_`, not `allow_`.** Optional mutual TLS
//! is a configuration that looks secure and is not: a request that arrives
//! without a certificate would be served anyway. The scheme to *describe* it
//! is `#[security(mutual_tls)]` — see [`security_schemes.rs`](security_schemes.rs).
//! * **`handshake_timeout` is fallible.** Zero is rejected rather than accepted
//! as "no timeout", because a handshake that never completes is the cheapest
//! way to hold a connection open forever.
//! * **Both protocol configs are set here because ALPN is where the choice is
//! made.** Under TLS the client and server negotiate `h2` or `http/1.1`
//! during the handshake, so a server offering both needs both configured.
//! Without TLS there is no negotiation: `Server::http2` alone serves
//! cleartext HTTP/2 — h2c — which clients reach only by prior knowledge.
//!
//! `prepare` splits binding from serving, which is what lets a test learn the
//! port before any request is sent — `local_addrs` is meaningless before the
//! bind and unavailable after `serve` takes ownership.
use ;
use ;
/// A certificate and its private key, both PEM-encoded.
/// Mints a self-signed certificate for `names`.
///
/// A real service does not do this. It is here so the example runs with nothing
/// prepared, which matters more for a transport example than for any other:
/// the thing worth seeing is the handshake succeeding.
/// Assembles the TLS configuration.
///
/// Its own function because the builder is a chain: every step takes `self` and
/// returns `Result<Self, TlsError>`, so the whole thing is one expression and
/// wants one place to be. `main` could `?` each step directly — `kynos::Error`
/// converts from a `TlsError` — but it would read as five statements instead of
/// the single configuration it is.
async