Skip to content

Add support for HTTPS proxies for HTTPS connections#492

Open
ericmj wants to merge 1 commit into
mainfrom
https-tunnel-proxies
Open

Add support for HTTPS proxies for HTTPS connections#492
ericmj wants to merge 1 commit into
mainfrom
https-tunnel-proxies

Conversation

@ericmj

@ericmj ericmj commented Jul 18, 2026

Copy link
Copy Markdown
Member

Adds TLS-in-TLS tunneling: Mint.HTTP.connect(:https, host, port, proxy: {:https, proxy_host, proxy_port, opts}) now establishes a CONNECT tunnel over a TLS connection to the proxy, with the TLS session to the host nested inside it. Previously this combination raised "nested SSL sessions are not supported".

The nesting uses OTP's documented cb_info transport option: the established :ssl socket to the proxy acts as the transport for the inner :ssl.connect/3, with the new Mint.Core.Transport.SSL.Tunnel module (delegating to :ssl) as the gen_tcp-shaped callback. No intermediary process is needed, so this fits Mint's process-less design. The inner handshake goes through the same ssl_opts/2 pipeline as direct connections, so verify_peer, CA trust, SNI, hostname verification, and ALPN (HTTP/2 negotiation) all apply through the tunnel. cb_info is forced after merging user transport options so it cannot be overridden. Works on all supported OTP versions (the upgrade form of :ssl.connect/3 accepts a non-port socket with cb_info since at least OTP 24; verified empirically on 27/28 and by source inspection on 24.3).

Two adjacent fixes are included: the proxy connection is now closed when the tunnel upgrade fails (previously the socket leaked, for :http proxies too), and Mint.Negotiate.connect_upgrade/6 no longer double-wraps %TransportError{} returned by transport upgrades.

Tests come in two layers. An offline suite (test/mint/https_proxy_test.exs, runs on the whole CI matrix including OTP 24.3) drives the public API through a local TLS-terminating CONNECT proxy: HTTP/1 and HTTP/2 (both ALPN-negotiated and forced), certificate verification through the tunnel using runtime-generated chains via :public_key.pkix_test_data/1 (including a rejection test), inner-handshake failure surfacing clean error tuples plus tunnel teardown, and a guard that user-supplied cb_info cannot displace the tunnel transport. A docker-based integration layer adds a real TLS-terminating Squid proxy (test/docker/squid-https, bound to loopback since it is an open proxy) and exercises HTTP/1 and HTTP/2 through Squid to the Caddy-fronted httpbin with real certificate verification on the inner hop; these run under the existing --include proxy CI step with no workflow changes.

The permanently-skipped nested-HTTPS test against tinyproxy (which cannot terminate TLS) and the test asserting the old raise are removed, superseded by the above.

Establish CONNECT tunnels through TLS proxies by nesting the TLS session
to the host inside the TLS session to the proxy. The established :ssl
socket acts as the transport for the nested connection through the
:cb_info option, with Mint.Core.Transport.SSL.Tunnel as the callback
module. The proxy connection is now also closed when the tunnel upgrade
fails, and transport errors returned from upgrades are no longer wrapped
twice.
@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 0

Coverage increased (+0.08%) to 87.621%

Details

  • Coverage increased (+0.08%) from the base build.
  • Patch coverage: 6 uncovered changes across 1 file (15 of 21 lines covered, 71.43%).
  • 1 coverage regression across 1 file.

Uncovered Changes

File Changed Covered %
lib/mint/core/transport/ssl/tunnel.ex 12 6 50.0%
Total (4 files) 21 15 71.43%

Coverage Regressions

1 previously-covered line in 1 file lost coverage.

File Lines Losing Coverage Coverage
lib/mint/negotiate.ex 1 84.85%

Coverage Stats

Coverage Status
Relevant Lines: 1656
Covered Lines: 1451
Line Coverage: 87.62%
Coverage Strength: 490.22 hits per line

💛 - Coveralls

@ericmj
ericmj marked this pull request as ready for review July 18, 2026 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants