This is an automated email from the ASF dual-hosted git repository. willholley pushed a commit to branch wh/connect_to in repository https://gitbox.apache.org/repos/asf/couchdb-ibrowse.git
commit 2c20f471d58ca0fd4997e362858b85997196de29 Author: Will Holley <[email protected]> AuthorDate: Mon Apr 27 12:06:11 2026 +0100 feat: add connect_to option Add a `connect_to` request option that lets ibrowse connect to a different network target while preserving the original URL host for Host handling, cookies, and TLS SNI. The use case for this is when connecting through a transparent SNI proxy for egress control. --- src/ibrowse_http_client.erl | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/ibrowse_http_client.erl b/src/ibrowse_http_client.erl index bee6a70..f79130c 100644 --- a/src/ibrowse_http_client.erl +++ b/src/ibrowse_http_client.erl @@ -618,13 +618,18 @@ do_connect(Host, Port, Options, #state{is_ssl = true, use_proxy = false, ssl_options = SSLOptions}, Timeout) -> + %% Check for connect_to override and remove from options + Host1 = get_value(connect_to, Options, Host), + Options1 = proplists:delete(connect_to, Options), + %% if a socks5 proxy is configured, open the socket separately %% before upgrading the socket to a TLS connection. - case get_value(socks5_host, Options, undefined) of + case get_value(socks5_host, Options1, undefined) of %% no socks5 proxy is configured, connect directly with TLS: undefined -> - Sock_options = get_sock_options(Host, Options, SSLOptions), - ssl:connect(Host, Port, Sock_options, Timeout); + Sock_options = get_sock_options(Host, Options1, SSLOptions), + Sock_options1 = ensure_sni(Sock_options, Host), + ssl:connect(Host1, Port, Sock_options1, Timeout); %% proxy configuration is present: first establish a socket %% and then upgrade: @@ -641,13 +646,17 @@ do_connect(Host, Port, Options, #state{is_ssl = true, end; do_connect(Host, Port, Options, _State, Timeout) -> - Socks5Host = get_value(socks5_host, Options, undefined), - Sock_options = get_sock_options(Host, Options, []), + %% Check for connect_to override and remove from options + Host1 = get_value(connect_to, Options, Host), + Options1 = proplists:delete(connect_to, Options), + + Socks5Host = get_value(socks5_host, Options1, undefined), + Sock_options = get_sock_options(Host, Options1, []), case Socks5Host of undefined -> - gen_tcp:connect(Host, Port, Sock_options, Timeout); + gen_tcp:connect(Host1, Port, Sock_options, Timeout); _ -> - catch ibrowse_socks5:connect(Host, Port, Options, Sock_options, Timeout) + catch ibrowse_socks5:connect(Host1, Port, Options1, Sock_options, Timeout) end. get_sock_options(Host, Options, SSLOptions) -> @@ -695,10 +704,20 @@ filter_sock_options(Opts) -> false; (list) -> false; + (_) -> true end, Opts). +%% Ensure SNI is set for SSL connections when using connect_to override +ensure_sni(Opts, Host) -> + case lists:keyfind(server_name_indication, 1, Opts) of + false -> + [{server_name_indication, Host} | Opts]; + _ -> + Opts + end. + do_send(Req, #state{socket = Sock, is_ssl = true, use_proxy = true,
