test(https): cover the TLS transport from three angles

ShouldSendRecieveHTTPS1 replays the plaintext round-trip over TLS, so a
regression in the transport shows up as an HTTP failure rather than
nothing at all, and adds what only exists under TLS: ALPN, scheme=https
reaching handlers, a body spanning many records, and the two ways
verification must fail — an untrusted self-signed certificate, and a
trusted certificate presented for the wrong name. A plaintext peer
knocking on the TLS port is asserted to be counted and shrugged off.

ShouldInteropCurlHTTPS1 puts real implementations on the other end, since
two OpenSSL peers can agree on a mistake. curl verifies our certificate
with --cacert rather than --insecure, and an h2-only curl is asserted to
be refused rather than mis-served. python3's http.server behind
ssl.wrap_socket answers HTTP/1.0 with Connection: close, which frames the
body by close_notify — the path a reader is most likely to get wrong.

ShouldRequireClientCertificateHTTPS1 covers mutual TLS both ways, and
drives TLSStream directly with hand-written HTTP/1.1 to keep the :TLS
layer honest as something usable without :ClientHTTP1 on top.

Also fix a delegation that `{}` no longer disambiguates now that a
three-argument TLS constructor exists alongside the fallback one.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
catbot 2026-07-28 20:17:07 +00:00
commit 39ff5806ed
5 changed files with 656 additions and 2 deletions

View file

@ -235,7 +235,9 @@ struct ListenerHTTP1::Impl {
ListenerHTTP1::ListenerHTTP1(std::uint16_t port,
std::unordered_map<std::string, std::function<HTTPResponse(const HTTPRequest&)>> routes)
: ListenerHTTP1(port, std::move(routes), {})
// Spelled out rather than `{}`: with a TLS overload also taking a third
// argument, a braced empty initialiser no longer names one constructor.
: ListenerHTTP1(port, std::move(routes), std::function<HTTPResponse(const HTTPRequest&)>{})
{}
ListenerHTTP1::ListenerHTTP1(std::uint16_t port,
@ -255,7 +257,8 @@ ListenerHTTP1::ListenerHTTP1(std::uint16_t port,
ListenerHTTP1::ListenerHTTP1(std::uint16_t port,
std::unordered_map<std::string, std::function<HTTPResponse(const HTTPRequest&)>> routes,
TLSServerCredentials credentials)
: ListenerHTTP1(port, std::move(routes), {}, std::move(credentials))
: ListenerHTTP1(port, std::move(routes),
std::function<HTTPResponse(const HTTPRequest&)>{}, std::move(credentials))
{}
ListenerHTTP1::ListenerHTTP1(std::uint16_t port,