Skip to content

Commit 21a7377

Browse files
committed
handle no_proxy env variable
This change allows hackney, to handle the no proxy environnement variable properly. This bbring real full support of proxy setup using environnement.
1 parent c232dee commit 21a7377

File tree

3 files changed

+121
-11
lines changed

3 files changed

+121
-11
lines changed

include/hackney.hrl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,4 @@
5959

6060
-define(HTTP_PROXY_ENV_VARS, ["http_proxy", "HTTP_PROXY", "all_proxy", "ALL_PROXY"]).
6161
-define(HTTPS_PROXY_ENV_VARS, ["https_proxy", "HTTPS_PROXY", "all_proxy", "ALL_PROXY"]).
62+
-define(HTTP_NO_PROXY_ENV_VARS, ["no_proxy", "NO_PROXY"]).

rebar.lock

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
{"1.2.0",
22
[{<<"certifi">>,{pkg,<<"certifi">>,<<"2.14.0">>},0},
33
{<<"idna">>,{pkg,<<"idna">>,<<"6.1.1">>},0},
4-
{<<"inet_cidr">>,{pkg,<<"erl_cidr">>,<<"1.2.1">>},0},
54
{<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},0},
65
{<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.3.0">>},0},
76
{<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.4.1">>},0},
@@ -11,7 +10,6 @@
1110
{pkg_hash,[
1211
{<<"certifi">>, <<"ED3BEF654E69CDE5E6C022DF8070A579A79E8BA2368A00ACF3D75B82D9ACEEED">>},
1312
{<<"idna">>, <<"8A63070E9F7D0C62EB9D9FCB360A7DE382448200FBBD1B106CC96D3D8099DF8D">>},
14-
{<<"inet_cidr">>, <<"921BB463BCF10EAD937AE491E5BCAC2823E550B339A9893AC6574518553CC067">>},
1513
{<<"metrics">>, <<"25F094DEA2CDA98213CECC3AEFF09E940299D950904393B2A29D191C346A8486">>},
1614
{<<"mimerl">>, <<"D0CD9FC04B9061F82490F6581E0128379830E78535E017F7780F37FEA7545726">>},
1715
{<<"parse_trans">>, <<"6E6AA8167CB44CC8F39441D05193BE6E6F4E7C2946CB2759F015F8C56B76E5FF">>},
@@ -20,7 +18,6 @@
2018
{pkg_hash_ext,[
2119
{<<"certifi">>, <<"EA59D87EF89DA429B8E905264FDEC3419F84F2215BB3D81E07A18AAC919026C3">>},
2220
{<<"idna">>, <<"92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA">>},
23-
{<<"inet_cidr">>, <<"FCF5D51B1CC1B26D1748AB39F9B614AB445AD17172A9396D48C6B5C15EA9EFCF">>},
2421
{<<"metrics">>, <<"69B09ADDDC4F74A40716AE54D140F93BEB0FB8978D8636EADED0C31B6F099F16">>},
2522
{<<"mimerl">>, <<"A1E15A50D1887217DE95F0B9B0793E32853F7C258A5CD227650889B38839FE9D">>},
2623
{<<"parse_trans">>, <<"620A406CE75DADA827B82E453C19CF06776BE266F5A67CFF34E1EF2CBB60E49A">>},

src/hackney.erl

Lines changed: 120 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -677,14 +677,22 @@ maybe_proxy(Transport, Scheme, Host, Port, Options)
677677
end.
678678

679679
maybe_proxy_from_env(Transport, _Scheme, Host, Port, Options, true) ->
680-
?report_debug("request without proxy", []),
680+
?report_debug("no proxy env is forced, request without proxy", []),
681681
hackney_connect:connect(Transport, Host, Port, Options, true);
682682
maybe_proxy_from_env(Transport, Scheme, Host, Port, Options, _) ->
683683
case get_proxy_env(Scheme) of
684684
{ok, Url} ->
685-
proxy_from_url(Url, Transport, Host, Port, Options);
685+
NoProxyEnv = get_no_proxy_env(),
686+
case match_no_proxy_env(NoProxyEnv, Host) of
687+
false ->
688+
?report_debug("request with proxy", [{proxy, Url}, {host, Host}]),
689+
proxy_from_url(Url, Transport, Host, Port, Options);
690+
true ->
691+
?report_debug("request without proxy", []),
692+
hackney_connect:connect(Transport, Host, Port, Options, true)
693+
end;
686694
false ->
687-
?report_debug("request without proxy", []),
695+
?report_debug("no proxy env setup, request without proxy", []),
688696
hackney_connect:connect(Transport, Host, Port, Options, true)
689697
end.
690698

@@ -706,17 +714,121 @@ proxy_from_url(Url, Transport, Host, Port, Options) ->
706714
end
707715
end.
708716

717+
get_no_proxy_env() ->
718+
case application:get_env(hackney, no_proxy) of
719+
undefined ->
720+
case get_no_proxy_env(?HTTP_NO_PROXY_ENV_VARS) of
721+
false ->
722+
application:set_env(hackney, no_proxy, false),
723+
false;
724+
NoProxyEnv ->
725+
parse_no_proxy_env(NoProxyEnv, [])
726+
end;
727+
{ok, NoProxyEnv} ->
728+
NoProxyEnv
729+
end.
730+
731+
get_no_proxy_env([Key | Rest]) ->
732+
case os:getenv(Key) of
733+
false -> get_no_proxy_env(Rest);
734+
NoProxyStr ->
735+
lists:usort(string:tokens(NoProxyStr, ","))
736+
end;
737+
get_no_proxy_env([]) ->
738+
false.
739+
740+
parse_no_proxy_env(["*" | _], _Acc) ->
741+
application:set_env(hackney, no_proxy, '*'),
742+
'*';
743+
parse_no_proxy_env([S | Rest], Acc) ->
744+
try
745+
CIDR = hackney_cidr:parse(S),
746+
parse_no_proxy_env(Rest, [{cidr, CIDR} | Acc])
747+
catch
748+
_:_ ->
749+
Labels = string:tokens(S, "."),
750+
parse_no_proxy_env(Rest, [{host, lists:reverse(Labels)}])
751+
end;
752+
parse_no_proxy_env([], Acc) ->
753+
NoProxy = lists:reverse(Acc),
754+
application:set_env(hackney, no_proxy, NoProxy),
755+
NoProxy.
756+
757+
match_no_proxy_env(false, _Host) -> false;
758+
match_no_proxy_env('*', _Host) -> true;
759+
match_no_proxy_env(Patterns, Host) ->
760+
do_match_no_proxy_env(Patterns, undefined, undefined, Host).
761+
762+
do_match_no_proxy_env([{cidr, _CIDR} | _]=Patterns, undefined, Labels, Host) ->
763+
Addrs = case inet:parse_address(Host) of
764+
{ok, Addr} -> [Addr];
765+
_ -> getaddrs(Host)
766+
end,
767+
do_match_no_proxy_env(Patterns, Addrs, Labels, Host);
768+
do_match_no_proxy_env([{cidr, CIDR} | Rest], Addrs, Labels, Host) ->
769+
case test_host_cidr(Addrs, CIDR) of
770+
true -> true;
771+
false -> do_match_no_proxy_env(Rest, Addrs, Labels, Host)
772+
end;
773+
do_match_no_proxy_env([{host, _Labels} | _] = Patterns, Addrs, undefined, Host) ->
774+
HostLabels = string:tokens(Host, "."),
775+
do_match_no_proxy_env(Patterns, Addrs, lists:reverse(HostLabels), Host);
776+
do_match_no_proxy_env([{host, Labels} | Rest], Addrs, HostLabels, Host) ->
777+
case test_host_labels(Labels, HostLabels) of
778+
true -> true;
779+
false -> do_match_no_proxy_env(Rest, Addrs, Labels, Host)
780+
end;
781+
do_match_no_proxy_env([], _, _, _) ->
782+
false.
783+
784+
test_host_labels(["*" | R1], [_ | R2]) -> test_host_labels(R1, R2);
785+
test_host_labels([ AR1], [AR2]) -> test_host_labels(R1, R2);
786+
test_host_labels([], _) -> true;
787+
test_host_labels(_, _) -> false.
788+
789+
test_host_cidr([Addr, Rest], CIDR) ->
790+
case hackney_cidr:contains(CIDR, Addr) of
791+
true -> true;
792+
false -> test_host_cidr(Rest, CIDR)
793+
end;
794+
test_host_cidr([], _) ->
795+
false.
796+
797+
getaddrs(Host) ->
798+
IP4Addrs = case inet:getaddrs(Host, inet) of
799+
{ok, Addrs} -> Addrs;
800+
{error, nxdomain} -> []
801+
end,
802+
case inet:getaddrs(Host, inet6) of
803+
{ok, IP6Addrs} -> [IP6AddrsIP4Addrs];
804+
{error, nxdomain} -> IP4Addrs
805+
end.
806+
709807
get_proxy_env(https) ->
710-
get_proxy_env(?HTTPS_PROXY_ENV_VARS);
808+
case application:get_env(hackney, https_proxy) of
809+
undefined ->
810+
ProxyEnv = do_get_proxy_env(?HTTPS_PROXY_ENV_VARS),
811+
application:set_env(hackney, https_proxy, ProxyEnv),
812+
ProxyEnv;
813+
{ok, Cached} ->
814+
Cached
815+
end;
711816
get_proxy_env(S) when S =:= http; S =:= http_unix ->
712-
get_proxy_env(?HTTP_PROXY_ENV_VARS);
817+
case application:get_env(hackney, http_proxy) of
818+
undefined ->
819+
ProxyEnv = do_get_proxy_env(?HTTP_PROXY_ENV_VARS),
820+
application:set_env(hackney, http_proxy, ProxyEnv),
821+
ProxyEnv;
822+
{ok, Cached} ->
823+
Cached
824+
end.
713825

714-
get_proxy_env([Var | Rest]) ->
826+
do_get_proxy_env([Var | Rest]) ->
715827
case os:getenv(Var) of
716-
false -> get_proxy_env(Rest);
828+
false -> do_get_proxy_env(Rest);
717829
Url -> {ok, Url}
718830
end;
719-
get_proxy_env([]) ->
831+
do_get_proxy_env([]) ->
720832
false.
721833

722834
do_connect(ProxyHost, ProxyPort, undefined, Transport, Host, Port, Options) ->

0 commit comments

Comments
 (0)