Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions lib/inets/src/http_client/httpc_handler.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1583,7 +1583,7 @@ tls_tunnel_request(#request{headers = Headers,
id = RequestId,
from = From,
address = {Host, Port}= Adress,
ipv6_host_with_brackets = IPV6}) ->
ipv6_host_with_brackets = IPV6, request_options = ReqOptions}) ->

URI = Host ++":" ++ integer_to_list(Port),

Expand All @@ -1605,7 +1605,8 @@ tls_tunnel_request(#request{headers = Headers,
userinfo = "",
headers_as_is = [],
started = http_util:timestamp(),
ipv6_host_with_brackets = IPV6
ipv6_host_with_brackets = IPV6,
request_options = ReqOptions
}.

host_header(#http_request_h{host = Host}, _) ->
Expand Down
104 changes: 95 additions & 9 deletions lib/inets/test/httpc_proxy_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
-compile(export_all).

-define(LOCAL_PROXY_SCRIPT, "server_proxy.sh").
-define(DUMMY_PROXY_SCRIPT, "dummy_proxy.sh").
-define(p(F, A), % Debug printout
begin
io:format(
Expand All @@ -53,18 +54,24 @@ suite() ->

all() ->
[{group,local_proxy},
{group,local_proxy_https}].
{group,local_proxy_https},
{group, remote_proxy},
{group, remote_proxy_https},
{group, dummy_proxy}].

groups() ->
[{local_proxy,[],
[http_emulate_lower_versions
|local_proxy_cases()]},
|proxy_cases()]},
{local_proxy_https,[],
local_proxy_cases() ++ local_proxy_https_cases()}].
proxy_cases() ++ proxy_https_cases()},
{remote_proxy, [], proxy_cases()},
{remote_proxy_https, [], proxy_cases() ++ proxy_https_cases()},
{dummy_proxy, [], [proxy_upgrade_connect_error]}].

%% internal functions

local_proxy_cases() ->
proxy_cases() ->
[http_head,
http_get,
http_options,
Expand All @@ -79,7 +86,7 @@ local_proxy_cases() ->
http_stream,
http_not_modified_otp_6821].

local_proxy_https_cases() ->
proxy_https_cases() ->
[https_connect_error,
http_timeout].

Expand Down Expand Up @@ -108,20 +115,48 @@ suite_apps() ->
init_per_group(local_proxy, Config) ->
init_local_proxy([{protocol,http}|Config]);
init_per_group(local_proxy_https, Config) ->
init_local_proxy([{protocol,https}|Config]).
init_local_proxy([{protocol,https}|Config]);

init_per_group(remote_proxy, Config) ->
Config1 = init_local_proxy([{protocol,http}|Config]),
{local,{{"localhost",Port},[]}} = proplists:get_value(proxy, Config1),
lists:keyreplace(proxy, 1, Config1, {proxy, {local, {{"127.0.0.1", Port}, []}}});
init_per_group(remote_proxy_https, Config) ->
Config1 = init_local_proxy([{protocol,https}|Config]),
{local,{{"localhost",Port},[]}} = proplists:get_value(proxy, Config1),
lists:keyreplace(proxy, 1, Config1, {proxy, {local, {{"127.0.0.1", Port}, []}}});

init_per_group(dummy_proxy, Config) ->
ProxyPort = 8000,
ProxyAddress = "127.0.0.1",
DummyPort = 8080,
DummyServer = "localhost",
[{proxy, {local, {{ProxyAddress, ProxyPort}, []}}}, {http, {DummyServer, DummyPort}} | Config].


end_per_group(Group, Config)
when
Group =:= local_proxy;
Group =:= local_proxy_https ->
Group =:= local_proxy_https;
Group =:= remote_proxy;
Group =:= remote_proxy_https ->
rcmd_local_proxy(["stop"], Config),
Config;
end_per_group(_, Config) ->
Config.

%%--------------------------------------------------------------------

init_per_testcase(Case, Config0) ->
init_per_testcase(proxy_upgrade_connect_error = Case, Config) ->
Response = "HTTP/1.1 500",
init_dummy_proxy(Response, Config),
do_init_per_testcase(Case, Config);
init_per_testcase(Case, Config) ->
do_init_per_testcase(Case, Config).

do_init_per_testcase(_, {skip, _} = Config) ->
Config;
do_init_per_testcase(Case, Config0) ->
ct:timetrap({seconds,30}),
Apps = apps(Case, Config0),
case init_apps(Apps, Config0) of
Expand All @@ -137,6 +172,12 @@ init_per_testcase(Case, Config0) ->
E3
end.

end_per_testcase(proxy_upgrade_connect_error, Config) ->
DataDir = proplists:get_value(data_dir, Config),
PrivDir = proplists:get_value(priv_dir, Config),
Script = filename:join(DataDir, ?DUMMY_PROXY_SCRIPT),
rcmd(Script, ["stop"], [{cd, PrivDir}]),
Config;
end_per_testcase(_Case, Config) ->
app_stop(inets),
Config.
Expand Down Expand Up @@ -447,6 +488,26 @@ https_connect_error(Config) when is_list(Config) ->
{error,{failed_connect,[_,{tls,_,_}]}} =
httpc:request(Method, Request, HttpOpts, Opts).

%%--------------------------------------------------------------------
proxy_upgrade_connect_error(doc) ->
["This targets verification of upgrade process
when proxy sends back response code that is not 200"];
proxy_upgrade_connect_error(Config) when is_list(Config) ->
{HttpServer,HttpPort} = proplists:get_value(http, Config),
Method = get,
%% using HTTPS scheme to test upgrade connection
URL = "https://" ++ HttpServer ++ ":" ++
integer_to_list(HttpPort) ++ "/index.html",
Opts = [],
HttpOpts = [?SSL_NO_VERIFY],
Request = {URL,[]},
%% This is a dummy proxy so no further connection will be established
%% We are only interested in testing parsing of the proxy response
{error,{failed_connect,[_,{_,_,econnrefused}]}} =
httpc:request(Method, Request, HttpOpts, Opts).



%%--------------------------------------------------------------------
http_timeout(doc) ->
["Test http/https connect and upgrade timeouts."];
Expand All @@ -455,10 +516,11 @@ http_timeout(Config) when is_list(Config) ->
URL = url("/index.html", Config),
Request = {URL,[]},
Timeout = timer:seconds(1),
{_,{{ProxyAddr, ProxyPort}, []}} = proplists:get_value(proxy, Config),
HttpOpts1 = [{timeout, Timeout}, {connect_timeout, 0}, ?SSL_NO_VERIFY],
{error,
{failed_connect,
[{to_address,{"localhost",8000}},
[{to_address,{ProxyAddr, ProxyPort}},
{inet,[inet],timeout}]}}
= httpc:request(Method, Request, HttpOpts1, []),
ok.
Expand Down Expand Up @@ -538,6 +600,30 @@ url(AbsPath, Config) ->

%%--------------------------------------------------------------------

init_dummy_proxy(Response, Config) ->
case os:type() of
{unix, _} ->
case os:cmd("which ncat") of
[] ->
{skip, "Ncat not available on the system"};
_ ->
Proxy = proplists:get_value(proxy, Config),
{_, {{ProxyAddress, ProxyPort}, _}} = Proxy,

DataDir = proplists:get_value(data_dir, Config),
PrivDir = proplists:get_value(priv_dir, Config),
Script = filename:join(DataDir, ?DUMMY_PROXY_SCRIPT),

spawn(fun() -> rcmd(Script, ["start",
ProxyAddress,
integer_to_list(ProxyPort),
Response], [{cd, PrivDir}])
end)
end;
_ ->
{skip, "Platform cannot run dummy proxy script"}
end.

init_local_proxy(Config) ->
case os:type() of
{unix,_} ->
Expand Down
18 changes: 18 additions & 0 deletions lib/inets/test/httpc_proxy_SUITE_data/dummy_proxy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/sh

# %CopyrightBegin%
#
# SPDX-License-Identifier: Apache-2.0
#
# Copyright Ericsson AB 2025. All Rights Reserved.
#
# %CopyrightEnd%

case :"${1:?}" in
:start)
/bin/echo -ne "${4}\r\n\r\n" | ncat -l ${2} ${3} & echo $! > dummy_proxy.pid
;;
:stop)
kill $(cat dummy_proxy.pid) || true
;;
esac
Loading