Configure the default Linux SSL context once instead of per handshake

Merged
KL
7h ago
+53-12

Closes #1252.

On Linux, truststore.SSLContext calls set_default_verify_paths() on its shared inner context before every handshake. OpenSSL < 3.4 appends a duplicate CApath lookup on each call, so issuer lookups grow quadratically and CPU climbs over the lifetime of a reused client (sethmlarson/truststore#212).

On Linux, the default context is now a stdlib ssl.SSLContext configured once, with the same logic truststore uses there (its Linux backend delegates verification to OpenSSL anyway). Windows and macOS still use truststore. httpx2.create_ssl_context() now uses httpcore2.default_ssl_context() instead of duplicating it, passing trust_env through a private _trust_env keyword. With trust_env=False, SSL_CERT_FILE/SSL_CERT_DIR are ignored. The private keyword goes away together with the Linux branch.

Measured on Debian bookworm (OpenSSL 3.0.22), against a server with an intermediate chain:

beforeafter
CPU per request, 4 batches of 10023 → 27 → 32 → 36 ms1.4 ms, flat
/usr/lib/ssl/certs opens for 5 / 20 / 50 requests20 / 230 / 13256 / 21 / 51

Verification is still enforced: an untrusted chain fails with CERTIFICATE_VERIFY_FAILED, and system CAs still validate public hosts.

This can be reverted once sethmlarson/truststore#213 is released.

AI Disclaimer

This PR was developed with the assistance of either Claude or Codex. I've reviewed and verified the changes.