Skip to content

Commit 45dbfa4

Browse files
committed
Merge branch 'whaileee/inets/httpc/tls-request-options/PR-10369/OTP-19875' into maint
* whaileee/inets/httpc/tls-request-options/PR-10369/OTP-19875: Add tests for remote proxy Copy request options during tls connection change
2 parents 2826a12 + 74a94a9 commit 45dbfa4

File tree

3 files changed

+127
-11
lines changed

3 files changed

+127
-11
lines changed

lib/inets/src/http_client/httpc_handler.erl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,7 +1585,7 @@ tls_tunnel_request(#request{headers = Headers,
15851585
id = RequestId,
15861586
from = From,
15871587
address = {Host, Port}= Adress,
1588-
ipv6_host_with_brackets = IPV6}) ->
1588+
ipv6_host_with_brackets = IPV6, request_options = ReqOptions}) ->
15891589

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

@@ -1606,7 +1606,8 @@ tls_tunnel_request(#request{headers = Headers,
16061606
userinfo = "",
16071607
headers_as_is = [],
16081608
started = http_util:timestamp(),
1609-
ipv6_host_with_brackets = IPV6
1609+
ipv6_host_with_brackets = IPV6,
1610+
request_options = ReqOptions
16101611
}.
16111612

16121613
host_header(#http_request_h{host = Host}, _) ->

lib/inets/test/httpc_proxy_SUITE.erl

Lines changed: 103 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
-compile(export_all).
3838

3939
-define(LOCAL_PROXY_SCRIPT, "server_proxy.sh").
40+
-define(DUMMY_PROXY_SCRIPT, "dummy_proxy.sh").
4041
-define(p(F, A), % Debug printout
4142
begin
4243
io:format(
@@ -55,18 +56,24 @@ suite() ->
5556

5657
all() ->
5758
[{group,local_proxy},
58-
{group,local_proxy_https}].
59+
{group,local_proxy_https},
60+
{group, remote_proxy},
61+
{group, remote_proxy_https},
62+
{group, dummy_proxy}].
5963

6064
groups() ->
6165
[{local_proxy,[],
6266
[http_emulate_lower_versions
63-
|local_proxy_cases()]},
67+
|proxy_cases()]},
6468
{local_proxy_https,[],
65-
local_proxy_cases() ++ local_proxy_https_cases()}].
69+
proxy_cases() ++ proxy_https_cases()},
70+
{remote_proxy, [], proxy_cases()},
71+
{remote_proxy_https, [], proxy_cases() ++ proxy_https_cases()},
72+
{dummy_proxy, [], [proxy_upgrade_connect_error]}].
6673

6774
%% internal functions
6875

69-
local_proxy_cases() ->
76+
proxy_cases() ->
7077
[http_head,
7178
http_get,
7279
http_options,
@@ -81,7 +88,7 @@ local_proxy_cases() ->
8188
http_stream,
8289
http_not_modified_otp_6821].
8390

84-
local_proxy_https_cases() ->
91+
proxy_https_cases() ->
8592
[https_connect_error,
8693
http_timeout].
8794

@@ -110,20 +117,56 @@ suite_apps() ->
110117
init_per_group(local_proxy, Config) ->
111118
init_local_proxy([{protocol,http}|Config]);
112119
init_per_group(local_proxy_https, Config) ->
113-
init_local_proxy([{protocol,https}|Config]).
120+
init_local_proxy([{protocol,https}|Config]);
121+
122+
init_per_group(remote_proxy, Config) ->
123+
Config1 = init_local_proxy([{protocol,http}|Config]),
124+
case Config1 of
125+
{skip, _} -> Config1;
126+
_ ->
127+
{local,{{"localhost",Port},[]}} = proplists:get_value(proxy, Config1),
128+
lists:keyreplace(proxy, 1, Config1, {proxy, {local, {{"127.0.0.1", Port}, []}}})
129+
end;
130+
init_per_group(remote_proxy_https, Config) ->
131+
Config1 = init_local_proxy([{protocol,https}|Config]),
132+
case Config1 of
133+
{skip, _} -> Config1;
134+
_ ->
135+
{local,{{"localhost",Port},[]}} = proplists:get_value(proxy, Config1),
136+
lists:keyreplace(proxy, 1, Config1, {proxy, {local, {{"127.0.0.1", Port}, []}}})
137+
end;
138+
139+
init_per_group(dummy_proxy, Config) ->
140+
ProxyPort = 8000,
141+
ProxyAddress = "127.0.0.1",
142+
DummyPort = 8080,
143+
DummyServer = "localhost",
144+
[{proxy, {local, {{ProxyAddress, ProxyPort}, []}}}, {http, {DummyServer, DummyPort}} | Config].
145+
114146

115147
end_per_group(Group, Config)
116148
when
117149
Group =:= local_proxy;
118-
Group =:= local_proxy_https ->
150+
Group =:= local_proxy_https;
151+
Group =:= remote_proxy;
152+
Group =:= remote_proxy_https ->
119153
rcmd_local_proxy(["stop"], Config),
120154
Config;
121155
end_per_group(_, Config) ->
122156
Config.
123157

124158
%%--------------------------------------------------------------------
125159

126-
init_per_testcase(Case, Config0) ->
160+
init_per_testcase(proxy_upgrade_connect_error = Case, Config) ->
161+
Response = "HTTP/1.1 500",
162+
init_dummy_proxy(Response, Config),
163+
do_init_per_testcase(Case, Config);
164+
init_per_testcase(Case, Config) ->
165+
do_init_per_testcase(Case, Config).
166+
167+
do_init_per_testcase(_, {skip, _} = Config) ->
168+
Config;
169+
do_init_per_testcase(Case, Config0) ->
127170
ct:timetrap({seconds,30}),
128171
Apps = apps(Case, Config0),
129172
case init_apps(Apps, Config0) of
@@ -139,6 +182,12 @@ init_per_testcase(Case, Config0) ->
139182
E3
140183
end.
141184

185+
end_per_testcase(proxy_upgrade_connect_error, Config) ->
186+
DataDir = proplists:get_value(data_dir, Config),
187+
PrivDir = proplists:get_value(priv_dir, Config),
188+
Script = filename:join(DataDir, ?DUMMY_PROXY_SCRIPT),
189+
rcmd(Script, ["stop"], [{cd, PrivDir}]),
190+
Config;
142191
end_per_testcase(_Case, Config) ->
143192
app_stop(inets),
144193
Config.
@@ -449,6 +498,26 @@ https_connect_error(Config) when is_list(Config) ->
449498
{error,{failed_connect,[_,{tls,_,_}]}} =
450499
httpc:request(Method, Request, HttpOpts, Opts).
451500

501+
%%--------------------------------------------------------------------
502+
proxy_upgrade_connect_error(doc) ->
503+
["This targets verification of upgrade process
504+
when proxy sends back response code that is not 200"];
505+
proxy_upgrade_connect_error(Config) when is_list(Config) ->
506+
{HttpServer,HttpPort} = proplists:get_value(http, Config),
507+
Method = get,
508+
%% using HTTPS scheme to test upgrade connection
509+
URL = "https://" ++ HttpServer ++ ":" ++
510+
integer_to_list(HttpPort) ++ "/index.html",
511+
Opts = [],
512+
HttpOpts = [?SSL_NO_VERIFY],
513+
Request = {URL,[]},
514+
%% This is a dummy proxy so no further connection will be established
515+
%% We are only interested in testing parsing of the proxy response
516+
{error,{failed_connect,[_,{_,_,econnrefused}]}} =
517+
httpc:request(Method, Request, HttpOpts, Opts).
518+
519+
520+
452521
%%--------------------------------------------------------------------
453522
http_timeout(doc) ->
454523
["Test http/https connect and upgrade timeouts."];
@@ -457,10 +526,11 @@ http_timeout(Config) when is_list(Config) ->
457526
URL = url("/index.html", Config),
458527
Request = {URL,[]},
459528
Timeout = timer:seconds(1),
529+
{_,{{ProxyAddr, ProxyPort}, []}} = proplists:get_value(proxy, Config),
460530
HttpOpts1 = [{timeout, Timeout}, {connect_timeout, 0}, ?SSL_NO_VERIFY],
461531
{error,
462532
{failed_connect,
463-
[{to_address,{"localhost",8000}},
533+
[{to_address,{ProxyAddr, ProxyPort}},
464534
{inet,[inet],timeout}]}}
465535
= httpc:request(Method, Request, HttpOpts1, []),
466536
ok.
@@ -540,6 +610,30 @@ url(AbsPath, Config) ->
540610

541611
%%--------------------------------------------------------------------
542612

613+
init_dummy_proxy(Response, Config) ->
614+
case os:type() of
615+
{unix, _} ->
616+
case os:cmd("which ncat") of
617+
[] ->
618+
{skip, "Ncat not available on the system"};
619+
_ ->
620+
Proxy = proplists:get_value(proxy, Config),
621+
{_, {{ProxyAddress, ProxyPort}, _}} = Proxy,
622+
623+
DataDir = proplists:get_value(data_dir, Config),
624+
PrivDir = proplists:get_value(priv_dir, Config),
625+
Script = filename:join(DataDir, ?DUMMY_PROXY_SCRIPT),
626+
627+
spawn(fun() -> rcmd(Script, ["start",
628+
ProxyAddress,
629+
integer_to_list(ProxyPort),
630+
Response], [{cd, PrivDir}])
631+
end)
632+
end;
633+
_ ->
634+
{skip, "Platform cannot run dummy proxy script"}
635+
end.
636+
543637
init_local_proxy(Config) ->
544638
case os:type() of
545639
{unix,_} ->
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/bin/sh
2+
3+
# %CopyrightBegin%
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
#
7+
# Copyright Ericsson AB 2025. All Rights Reserved.
8+
#
9+
# %CopyrightEnd%
10+
11+
case :"${1:?}" in
12+
:start)
13+
/bin/echo -ne "${4}\r\n\r\n" | ncat -l ${2} ${3} & echo $! > dummy_proxy.pid
14+
;;
15+
:stop)
16+
Pid=`pgrep -F dummy_proxy.pid`
17+
if [ ! "$Pid" = "" ]; then
18+
kill "$Pid" || true
19+
fi
20+
;;
21+
esac

0 commit comments

Comments
 (0)