1+ % %% -*- erlang -*-
2+ % %%
3+ % %% This file is part of hackney released under the Apache 2 license.
4+ % %% See the NOTICE for more information.
5+ % %%
6+ % %% Copyright (c) 2025 Benoît Chesneau <[email protected] >7+ % %%
8+
9+ -module (hackney_proxy_tests ).
10+ -include_lib (" eunit/include/eunit.hrl" ).
11+
12+ % % Test empty proxy environment variables handling
13+ empty_proxy_env_test_ () ->
14+ {setup ,
15+ fun setup /0 ,
16+ fun teardown /1 ,
17+ fun (State ) ->
18+ [
19+ {" Empty http_proxy" , fun () -> test_empty_proxy_env (" http_proxy" , State ) end },
20+ {" Empty HTTP_PROXY" , fun () -> test_empty_proxy_env (" HTTP_PROXY" , State ) end },
21+ {" Empty https_proxy" , fun () -> test_empty_proxy_env (" https_proxy" , State ) end },
22+ {" Empty HTTPS_PROXY" , fun () -> test_empty_proxy_env (" HTTPS_PROXY" , State ) end },
23+ {" Whitespace http_proxy" , fun () -> test_whitespace_proxy_env (" http_proxy" , State ) end },
24+ {" Whitespace HTTPS_PROXY" , fun () -> test_whitespace_proxy_env (" HTTPS_PROXY" , State ) end },
25+ {" Multiple spaces proxy" , fun () -> test_multiple_spaces_proxy_env (" http_proxy" , State ) end },
26+ {" Valid proxy URL" , fun () -> test_valid_proxy_env (" http_proxy" , State ) end },
27+ {" Valid proxy with spaces" , fun () -> test_valid_proxy_with_spaces (" HTTP_PROXY" , State ) end }
28+ ]
29+ end }.
30+
31+ setup () ->
32+ % % Save current environment variables
33+ SavedEnv = [{Var , os :getenv (Var )} || Var <- [" http_proxy" , " HTTP_PROXY" ,
34+ " https_proxy" , " HTTPS_PROXY" ,
35+ " all_proxy" , " ALL_PROXY" ]],
36+ % % Clear all proxy environment variables
37+ [os :unsetenv (Var ) || {Var , _ } <- SavedEnv ],
38+ % % Clear hackney's cached proxy settings
39+ application :unset_env (hackney , http_proxy ),
40+ application :unset_env (hackney , https_proxy ),
41+ SavedEnv .
42+
43+ teardown (SavedEnv ) ->
44+ % % Restore original environment variables
45+ lists :foreach (fun
46+ ({Var , false }) -> os :unsetenv (Var );
47+ ({Var , Value }) -> os :putenv (Var , Value )
48+ end , SavedEnv ),
49+ % % Clear hackney's cached proxy settings
50+ application :unset_env (hackney , http_proxy ),
51+ application :unset_env (hackney , https_proxy ).
52+
53+ test_empty_proxy_env (Var , _State ) ->
54+ os :putenv (Var , " " ),
55+ % % Clear cached values first
56+ application :unset_env (hackney , http_proxy ),
57+ application :unset_env (hackney , https_proxy ),
58+ % % This should not crash and should return false (no proxy)
59+ Result = hackney :get_proxy_env (http ),
60+ ? assertEqual (false , Result ),
61+ os :unsetenv (Var ).
62+
63+ test_whitespace_proxy_env (Var , _State ) ->
64+ os :putenv (Var , " " ),
65+ % % Clear cached values first
66+ application :unset_env (hackney , http_proxy ),
67+ application :unset_env (hackney , https_proxy ),
68+ % % This should not crash and should return false (no proxy)
69+ Result = hackney :get_proxy_env (http ),
70+ ? assertEqual (false , Result ),
71+ os :unsetenv (Var ).
72+
73+ test_multiple_spaces_proxy_env (Var , _State ) ->
74+ os :putenv (Var , " \t \n " ),
75+ % % Clear cached values first
76+ application :unset_env (hackney , http_proxy ),
77+ application :unset_env (hackney , https_proxy ),
78+ % % This should not crash and should return false (no proxy)
79+ Result = hackney :get_proxy_env (http ),
80+ ? assertEqual (false , Result ),
81+ os :unsetenv (Var ).
82+
83+ test_valid_proxy_env (Var , _State ) ->
84+ ProxyUrl = " http://proxy.example.com:8080" ,
85+ os :putenv (Var , ProxyUrl ),
86+ % % Clear cached values first
87+ application :unset_env (hackney , http_proxy ),
88+ application :unset_env (hackney , https_proxy ),
89+ % % This should return the proxy URL
90+ Result = hackney :get_proxy_env (http ),
91+ ? assertEqual ({ok , ProxyUrl }, Result ),
92+ os :unsetenv (Var ).
93+
94+ test_valid_proxy_with_spaces (Var , _State ) ->
95+ ProxyUrl = " http://proxy.example.com:8080 " ,
96+ ExpectedUrl = " http://proxy.example.com:8080" ,
97+ os :putenv (Var , ProxyUrl ),
98+ % % Clear cached values first
99+ application :unset_env (hackney , http_proxy ),
100+ application :unset_env (hackney , https_proxy ),
101+ % % This should return the proxy URL with stripped spaces
102+ Result = hackney :get_proxy_env (http ),
103+ ? assertEqual ({ok , ExpectedUrl }, Result ),
104+ os :unsetenv (Var ).
105+
106+ % % Test that empty proxy doesn't cause crash in actual request
107+ integration_empty_proxy_test_ () ->
108+ {setup ,
109+ fun () ->
110+ setup (),
111+ {ok , _ } = application :ensure_all_started (hackney )
112+ end ,
113+ fun (State ) ->
114+ teardown (State ),
115+ application :stop (hackney )
116+ end ,
117+ fun (_ ) ->
118+ [
119+ {" Request with empty http_proxy" , fun test_request_with_empty_proxy /0 },
120+ {" Request with whitespace https_proxy" , fun test_request_with_whitespace_proxy /0 }
121+ ]
122+ end }.
123+
124+ test_request_with_empty_proxy () ->
125+ os :putenv (" http_proxy" , " " ),
126+ % % This request should not crash
127+ {ok , StatusCode , _Headers , Ref } = hackney :request (get , " http://httpbin.org/status/200" ),
128+ ? assertEqual (200 , StatusCode ),
129+ hackney :close (Ref ),
130+ os :unsetenv (" http_proxy" ).
131+
132+ test_request_with_whitespace_proxy () ->
133+ os :putenv (" https_proxy" , " " ),
134+ % % This request should not crash
135+ {ok , StatusCode , _Headers , Ref } = hackney :request (get , " https://httpbin.org/status/200" ),
136+ ? assertEqual (200 , StatusCode ),
137+ hackney :close (Ref ),
138+ os :unsetenv (" https_proxy" ).
0 commit comments