1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/proxy/proxy_config_service_linux.h"
11 #include "base/bind.h"
12 #include "base/compiler_specific.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_util.h"
15 #include "base/format_macros.h"
16 #include "base/logging.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/synchronization/waitable_event.h"
20 #include "base/thread_task_runner_handle.h"
21 #include "base/threading/thread.h"
22 #include "net/proxy/proxy_config.h"
23 #include "net/proxy/proxy_config_service_common_unittest.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "testing/platform_test.h"
30 // Set of values for all environment variables that we might
31 // query. NULL represents an unset variable.
33 // The strange capitalization is so that the field matches the
34 // environment variable name exactly.
35 const char *DESKTOP_SESSION
, *HOME
,
36 *KDEHOME
, *KDE_SESSION_VERSION
,
37 *auto_proxy
, *all_proxy
,
38 *http_proxy
, *https_proxy
, *ftp_proxy
,
39 *SOCKS_SERVER
, *SOCKS_VERSION
,
43 // Undo macro pollution from GDK includes (from message_loop.h).
47 // So as to distinguish between an unset gconf boolean variable and
49 enum BoolSettingValue
{
50 UNSET
= 0, TRUE
, FALSE
53 // Set of values for all gconf settings that we might query.
56 const char *mode
, *autoconfig_url
,
57 *http_host
, *secure_host
, *ftp_host
, *socks_host
;
59 int http_port
, secure_port
, ftp_port
, socks_port
;
61 BoolSettingValue use_proxy
, same_proxy
, use_auth
;
63 std::vector
<std::string
> ignore_hosts
;
66 // Mapping from a setting name to the location of the corresponding
67 // value (inside a EnvVarValues or GConfValues struct).
68 template<typename key_type
, typename value_type
>
69 struct SettingsTable
{
70 typedef std::map
<key_type
, value_type
*> map_type
;
72 // Gets the value from its location
73 value_type
Get(key_type key
) {
74 typename
map_type::const_iterator it
= settings
.find(key
);
75 // In case there's a typo or the unittest becomes out of sync.
76 CHECK(it
!= settings
.end()) << "key " << key
<< " not found";
77 value_type
* value_ptr
= it
->second
;
84 class MockEnvironment
: public base::Environment
{
87 #define ENTRY(x) table[#x] = &values.x
88 ENTRY(DESKTOP_SESSION
);
91 ENTRY(KDE_SESSION_VERSION
);
104 // Zeroes all environment values.
106 EnvVarValues zero_values
= { 0 };
107 values
= zero_values
;
110 // Begin base::Environment implementation.
111 bool GetVar(const char* variable_name
, std::string
* result
) override
{
112 std::map
<std::string
, const char**>::iterator it
=
113 table
.find(variable_name
);
114 if (it
!= table
.end() && *(it
->second
) != NULL
) {
115 // Note that the variable may be defined but empty.
116 *result
= *(it
->second
);
122 bool SetVar(const char* variable_name
,
123 const std::string
& new_value
) override
{
128 bool UnSetVar(const char* variable_name
) override
{
132 // End base::Environment implementation.
134 // Intentionally public, for convenience when setting up a test.
138 std::map
<std::string
, const char**> table
;
141 class MockSettingGetter
142 : public ProxyConfigServiceLinux::SettingGetter
{
144 typedef ProxyConfigServiceLinux::SettingGetter SettingGetter
;
145 MockSettingGetter() {
146 #define ENTRY(key, field) \
147 strings_table.settings[SettingGetter::key] = &values.field
148 ENTRY(PROXY_MODE
, mode
);
149 ENTRY(PROXY_AUTOCONF_URL
, autoconfig_url
);
150 ENTRY(PROXY_HTTP_HOST
, http_host
);
151 ENTRY(PROXY_HTTPS_HOST
, secure_host
);
152 ENTRY(PROXY_FTP_HOST
, ftp_host
);
153 ENTRY(PROXY_SOCKS_HOST
, socks_host
);
155 #define ENTRY(key, field) \
156 ints_table.settings[SettingGetter::key] = &values.field
157 ENTRY(PROXY_HTTP_PORT
, http_port
);
158 ENTRY(PROXY_HTTPS_PORT
, secure_port
);
159 ENTRY(PROXY_FTP_PORT
, ftp_port
);
160 ENTRY(PROXY_SOCKS_PORT
, socks_port
);
162 #define ENTRY(key, field) \
163 bools_table.settings[SettingGetter::key] = &values.field
164 ENTRY(PROXY_USE_HTTP_PROXY
, use_proxy
);
165 ENTRY(PROXY_USE_SAME_PROXY
, same_proxy
);
166 ENTRY(PROXY_USE_AUTHENTICATION
, use_auth
);
168 string_lists_table
.settings
[SettingGetter::PROXY_IGNORE_HOSTS
] =
169 &values
.ignore_hosts
;
173 // Zeros all environment values.
175 GConfValues zero_values
= { 0 };
176 values
= zero_values
;
179 bool Init(const scoped_refptr
<base::SingleThreadTaskRunner
>& glib_task_runner
,
180 const scoped_refptr
<base::SingleThreadTaskRunner
>& file_task_runner
)
182 task_runner_
= glib_task_runner
;
186 void ShutDown() override
{}
188 bool SetUpNotifications(
189 ProxyConfigServiceLinux::Delegate
* delegate
) override
{
193 const scoped_refptr
<base::SingleThreadTaskRunner
>& GetNotificationTaskRunner()
198 ProxyConfigSource
GetConfigSource() override
{
199 return PROXY_CONFIG_SOURCE_TEST
;
202 bool GetString(StringSetting key
, std::string
* result
) override
{
203 const char* value
= strings_table
.Get(key
);
211 bool GetBool(BoolSetting key
, bool* result
) override
{
212 BoolSettingValue value
= bools_table
.Get(key
);
225 bool GetInt(IntSetting key
, int* result
) override
{
226 // We don't bother to distinguish unset keys from 0 values.
227 *result
= ints_table
.Get(key
);
231 bool GetStringList(StringListSetting key
,
232 std::vector
<std::string
>* result
) override
{
233 *result
= string_lists_table
.Get(key
);
234 // We don't bother to distinguish unset keys from empty lists.
235 return !result
->empty();
238 bool BypassListIsReversed() override
{ return false; }
240 bool MatchHostsUsingSuffixMatching() override
{ return false; }
242 // Intentionally public, for convenience when setting up a test.
246 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
247 SettingsTable
<StringSetting
, const char*> strings_table
;
248 SettingsTable
<BoolSetting
, BoolSettingValue
> bools_table
;
249 SettingsTable
<IntSetting
, int> ints_table
;
250 SettingsTable
<StringListSetting
,
251 std::vector
<std::string
> > string_lists_table
;
254 // This helper class runs ProxyConfigServiceLinux::GetLatestProxyConfig() on
255 // the IO thread and synchronously waits for the result.
256 // Some code duplicated from proxy_script_fetcher_unittest.cc.
257 class SynchConfigGetter
{
259 // Takes ownership of |config_service|.
260 explicit SynchConfigGetter(ProxyConfigServiceLinux
* config_service
)
261 : event_(false, false),
262 io_thread_("IO_Thread"),
263 config_service_(config_service
) {
264 // Start an IO thread.
265 base::Thread::Options options
;
266 options
.message_loop_type
= base::MessageLoop::TYPE_IO
;
267 io_thread_
.StartWithOptions(options
);
269 // Make sure the thread started.
270 io_thread_
.message_loop()->PostTask(FROM_HERE
,
271 base::Bind(&SynchConfigGetter::Init
, base::Unretained(this)));
275 ~SynchConfigGetter() {
276 // Let the config service post a destroy message to the IO thread
277 // before cleaning up that thread.
278 delete config_service_
;
279 // Clean up the IO thread.
280 io_thread_
.message_loop()->PostTask(FROM_HERE
,
281 base::Bind(&SynchConfigGetter::CleanUp
, base::Unretained(this)));
285 // Does gconf setup and initial fetch of the proxy config,
286 // all on the calling thread (meant to be the thread with the
287 // default glib main loop, which is the UI thread).
288 void SetupAndInitialFetch() {
289 // We pass the mock IO thread as both the IO and file threads.
290 config_service_
->SetupAndFetchInitialConfig(
291 base::ThreadTaskRunnerHandle::Get(), io_thread_
.message_loop_proxy(),
292 io_thread_
.message_loop_proxy());
294 // Synchronously gets the proxy config.
295 ProxyConfigService::ConfigAvailability
SyncGetLatestProxyConfig(
296 ProxyConfig
* config
) {
297 io_thread_
.message_loop()->PostTask(FROM_HERE
,
298 base::Bind(&SynchConfigGetter::GetLatestConfigOnIOThread
,
299 base::Unretained(this)));
301 *config
= proxy_config_
;
302 return get_latest_config_result_
;
306 // [Runs on |io_thread_|]
311 // Calls GetLatestProxyConfig, running on |io_thread_| Signals |event_|
313 void GetLatestConfigOnIOThread() {
314 get_latest_config_result_
=
315 config_service_
->GetLatestProxyConfig(&proxy_config_
);
319 // [Runs on |io_thread_|] Signals |event_| on cleanup completion.
321 base::MessageLoop::current()->RunUntilIdle();
330 base::WaitableEvent event_
;
331 base::Thread io_thread_
;
333 ProxyConfigServiceLinux
* config_service_
;
335 // The config obtained by |io_thread_| and read back by the main
337 ProxyConfig proxy_config_
;
339 // Return value from GetLatestProxyConfig().
340 ProxyConfigService::ConfigAvailability get_latest_config_result_
;
343 // This test fixture is only really needed for the KDEConfigParser test case,
344 // but all the test cases with the same prefix ("ProxyConfigServiceLinuxTest")
345 // must use the same test fixture class (also "ProxyConfigServiceLinuxTest").
346 class ProxyConfigServiceLinuxTest
: public PlatformTest
{
348 void SetUp() override
{
349 PlatformTest::SetUp();
350 // Set up a temporary KDE home directory.
351 std::string
prefix("ProxyConfigServiceLinuxTest_user_home");
352 base::CreateNewTempDirectory(prefix
, &user_home_
);
353 kde_home_
= user_home_
.Append(FILE_PATH_LITERAL(".kde"));
354 base::FilePath path
= kde_home_
.Append(FILE_PATH_LITERAL("share"));
355 path
= path
.Append(FILE_PATH_LITERAL("config"));
356 base::CreateDirectory(path
);
357 kioslaverc_
= path
.Append(FILE_PATH_LITERAL("kioslaverc"));
358 // Set up paths but do not create the directory for .kde4.
359 kde4_home_
= user_home_
.Append(FILE_PATH_LITERAL(".kde4"));
360 path
= kde4_home_
.Append(FILE_PATH_LITERAL("share"));
361 kde4_config_
= path
.Append(FILE_PATH_LITERAL("config"));
362 kioslaverc4_
= kde4_config_
.Append(FILE_PATH_LITERAL("kioslaverc"));
365 void TearDown() override
{
366 // Delete the temporary KDE home directory.
367 base::DeleteFile(user_home_
, true);
368 PlatformTest::TearDown();
371 base::FilePath user_home_
;
373 base::FilePath kde_home_
;
374 base::FilePath kioslaverc_
;
376 base::FilePath kde4_home_
;
377 base::FilePath kde4_config_
;
378 base::FilePath kioslaverc4_
;
381 // Builds an identifier for each test in an array.
382 #define TEST_DESC(desc) base::StringPrintf("at line %d <%s>", __LINE__, desc)
384 TEST_F(ProxyConfigServiceLinuxTest
, BasicGConfTest
) {
385 std::vector
<std::string
> empty_ignores
;
387 std::vector
<std::string
> google_ignores
;
388 google_ignores
.push_back("*.google.com");
390 // Inspired from proxy_config_service_win_unittest.cc.
391 // Very neat, but harder to track down failures though.
393 // Short description to identify the test
394 std::string description
;
399 // Expected outputs (availability and fields of ProxyConfig).
400 ProxyConfigService::ConfigAvailability availability
;
403 ProxyRulesExpectation proxy_rules
;
406 TEST_DESC("No proxying"),
409 "", // autoconfig_url
410 "", "", "", "", // hosts
412 FALSE
, FALSE
, FALSE
, // use, same, auth
413 empty_ignores
, // ignore_hosts
417 ProxyConfigService::CONFIG_VALID
,
418 false, // auto_detect
420 ProxyRulesExpectation::Empty(),
424 TEST_DESC("Auto detect"),
427 "", // autoconfig_url
428 "", "", "", "", // hosts
430 FALSE
, FALSE
, FALSE
, // use, same, auth
431 empty_ignores
, // ignore_hosts
435 ProxyConfigService::CONFIG_VALID
,
438 ProxyRulesExpectation::Empty(),
442 TEST_DESC("Valid PAC URL"),
445 "http://wpad/wpad.dat", // autoconfig_url
446 "", "", "", "", // hosts
448 FALSE
, FALSE
, FALSE
, // use, same, auth
449 empty_ignores
, // ignore_hosts
453 ProxyConfigService::CONFIG_VALID
,
454 false, // auto_detect
455 GURL("http://wpad/wpad.dat"), // pac_url
456 ProxyRulesExpectation::Empty(),
460 TEST_DESC("Invalid PAC URL"),
463 "wpad.dat", // autoconfig_url
464 "", "", "", "", // hosts
466 FALSE
, FALSE
, FALSE
, // use, same, auth
467 empty_ignores
, // ignore_hosts
471 ProxyConfigService::CONFIG_VALID
,
472 false, // auto_detect
474 ProxyRulesExpectation::Empty(),
478 TEST_DESC("Single-host in proxy list"),
481 "", // autoconfig_url
482 "www.google.com", "", "", "", // hosts
483 80, 0, 0, 0, // ports
484 TRUE
, TRUE
, FALSE
, // use, same, auth
485 empty_ignores
, // ignore_hosts
489 ProxyConfigService::CONFIG_VALID
,
490 false, // auto_detect
492 ProxyRulesExpectation::Single(
493 "www.google.com:80", // single proxy
498 TEST_DESC("use_http_proxy is honored"),
501 "", // autoconfig_url
502 "www.google.com", "", "", "", // hosts
503 80, 0, 0, 0, // ports
504 FALSE
, TRUE
, FALSE
, // use, same, auth
505 empty_ignores
, // ignore_hosts
509 ProxyConfigService::CONFIG_VALID
,
510 false, // auto_detect
512 ProxyRulesExpectation::Empty(),
516 TEST_DESC("use_http_proxy and use_same_proxy are optional"),
519 "", // autoconfig_url
520 "www.google.com", "", "", "", // hosts
521 80, 0, 0, 0, // ports
522 UNSET
, UNSET
, FALSE
, // use, same, auth
523 empty_ignores
, // ignore_hosts
527 ProxyConfigService::CONFIG_VALID
,
528 false, // auto_detect
530 ProxyRulesExpectation::PerScheme(
531 "www.google.com:80", // http
538 TEST_DESC("Single-host, different port"),
541 "", // autoconfig_url
542 "www.google.com", "", "", "", // hosts
543 88, 0, 0, 0, // ports
544 TRUE
, TRUE
, FALSE
, // use, same, auth
545 empty_ignores
, // ignore_hosts
549 ProxyConfigService::CONFIG_VALID
,
550 false, // auto_detect
552 ProxyRulesExpectation::Single(
553 "www.google.com:88", // single proxy
558 TEST_DESC("Per-scheme proxy rules"),
561 "", // autoconfig_url
562 "www.google.com", // http_host
563 "www.foo.com", // secure_host
564 "ftp.foo.com", // ftp
566 88, 110, 121, 0, // ports
567 TRUE
, FALSE
, FALSE
, // use, same, auth
568 empty_ignores
, // ignore_hosts
572 ProxyConfigService::CONFIG_VALID
,
573 false, // auto_detect
575 ProxyRulesExpectation::PerScheme(
576 "www.google.com:88", // http
577 "www.foo.com:110", // https
578 "ftp.foo.com:121", // ftp
586 "", // autoconfig_url
587 "", "", "", "socks.com", // hosts
588 0, 0, 0, 99, // ports
589 TRUE
, FALSE
, FALSE
, // use, same, auth
590 empty_ignores
, // ignore_hosts
594 ProxyConfigService::CONFIG_VALID
,
595 false, // auto_detect
597 ProxyRulesExpectation::Single(
598 "socks5://socks.com:99", // single proxy
603 TEST_DESC("Per-scheme proxy rules with fallback to SOCKS"),
606 "", // autoconfig_url
607 "www.google.com", // http_host
608 "www.foo.com", // secure_host
609 "ftp.foo.com", // ftp
610 "foobar.net", // socks
611 88, 110, 121, 99, // ports
612 TRUE
, FALSE
, FALSE
, // use, same, auth
613 empty_ignores
, // ignore_hosts
617 ProxyConfigService::CONFIG_VALID
,
618 false, // auto_detect
620 ProxyRulesExpectation::PerSchemeWithSocks(
621 "www.google.com:88", // http
622 "www.foo.com:110", // https
623 "ftp.foo.com:121", // ftp
624 "socks5://foobar.net:99", // socks
629 TEST_DESC("Per-scheme proxy rules (just HTTP) with fallback to SOCKS"),
632 "", // autoconfig_url
633 "www.google.com", // http_host
636 "foobar.net", // socks
637 88, 0, 0, 99, // ports
638 TRUE
, FALSE
, FALSE
, // use, same, auth
639 empty_ignores
, // ignore_hosts
643 ProxyConfigService::CONFIG_VALID
,
644 false, // auto_detect
646 ProxyRulesExpectation::PerSchemeWithSocks(
647 "www.google.com:88", // http
650 "socks5://foobar.net:99", // socks
655 TEST_DESC("Bypass *.google.com"),
658 "", // autoconfig_url
659 "www.google.com", "", "", "", // hosts
660 80, 0, 0, 0, // ports
661 TRUE
, TRUE
, FALSE
, // use, same, auth
662 google_ignores
, // ignore_hosts
665 ProxyConfigService::CONFIG_VALID
,
666 false, // auto_detect
668 ProxyRulesExpectation::Single(
669 "www.google.com:80", // single proxy
670 "*.google.com"), // bypass rules
674 for (size_t i
= 0; i
< arraysize(tests
); ++i
) {
675 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"] %s", i
,
676 tests
[i
].description
.c_str()));
677 MockEnvironment
* env
= new MockEnvironment
;
678 MockSettingGetter
* setting_getter
= new MockSettingGetter
;
679 SynchConfigGetter
sync_config_getter(
680 new ProxyConfigServiceLinux(env
, setting_getter
));
682 setting_getter
->values
= tests
[i
].values
;
683 sync_config_getter
.SetupAndInitialFetch();
684 ProxyConfigService::ConfigAvailability availability
=
685 sync_config_getter
.SyncGetLatestProxyConfig(&config
);
686 EXPECT_EQ(tests
[i
].availability
, availability
);
688 if (availability
== ProxyConfigService::CONFIG_VALID
) {
689 EXPECT_EQ(tests
[i
].auto_detect
, config
.auto_detect());
690 EXPECT_EQ(tests
[i
].pac_url
, config
.pac_url());
691 EXPECT_TRUE(tests
[i
].proxy_rules
.Matches(config
.proxy_rules()));
696 TEST_F(ProxyConfigServiceLinuxTest
, BasicEnvTest
) {
697 // Inspired from proxy_config_service_win_unittest.cc.
699 // Short description to identify the test
700 std::string description
;
705 // Expected outputs (availability and fields of ProxyConfig).
706 ProxyConfigService::ConfigAvailability availability
;
709 ProxyRulesExpectation proxy_rules
;
712 TEST_DESC("No proxying"),
714 NULL
, // DESKTOP_SESSION
717 NULL
, // KDE_SESSION_VERSION
720 NULL
, NULL
, NULL
, // per-proto proxies
726 ProxyConfigService::CONFIG_VALID
,
727 false, // auto_detect
729 ProxyRulesExpectation::Empty(),
733 TEST_DESC("Auto detect"),
735 NULL
, // DESKTOP_SESSION
738 NULL
, // KDE_SESSION_VERSION
741 NULL
, NULL
, NULL
, // per-proto proxies
747 ProxyConfigService::CONFIG_VALID
,
750 ProxyRulesExpectation::Empty(),
754 TEST_DESC("Valid PAC URL"),
756 NULL
, // DESKTOP_SESSION
759 NULL
, // KDE_SESSION_VERSION
760 "http://wpad/wpad.dat", // auto_proxy
762 NULL
, NULL
, NULL
, // per-proto proxies
768 ProxyConfigService::CONFIG_VALID
,
769 false, // auto_detect
770 GURL("http://wpad/wpad.dat"), // pac_url
771 ProxyRulesExpectation::Empty(),
775 TEST_DESC("Invalid PAC URL"),
777 NULL
, // DESKTOP_SESSION
780 NULL
, // KDE_SESSION_VERSION
781 "wpad.dat", // auto_proxy
783 NULL
, NULL
, NULL
, // per-proto proxies
789 ProxyConfigService::CONFIG_VALID
,
790 false, // auto_detect
792 ProxyRulesExpectation::Empty(),
796 TEST_DESC("Single-host in proxy list"),
798 NULL
, // DESKTOP_SESSION
801 NULL
, // KDE_SESSION_VERSION
803 "www.google.com", // all_proxy
804 NULL
, NULL
, NULL
, // per-proto proxies
810 ProxyConfigService::CONFIG_VALID
,
811 false, // auto_detect
813 ProxyRulesExpectation::Single(
814 "www.google.com:80", // single proxy
819 TEST_DESC("Single-host, different port"),
821 NULL
, // DESKTOP_SESSION
824 NULL
, // KDE_SESSION_VERSION
826 "www.google.com:99", // all_proxy
827 NULL
, NULL
, NULL
, // per-proto proxies
833 ProxyConfigService::CONFIG_VALID
,
834 false, // auto_detect
836 ProxyRulesExpectation::Single(
837 "www.google.com:99", // single
842 TEST_DESC("Tolerate a scheme"),
844 NULL
, // DESKTOP_SESSION
847 NULL
, // KDE_SESSION_VERSION
849 "http://www.google.com:99", // all_proxy
850 NULL
, NULL
, NULL
, // per-proto proxies
856 ProxyConfigService::CONFIG_VALID
,
857 false, // auto_detect
859 ProxyRulesExpectation::Single(
860 "www.google.com:99", // single proxy
865 TEST_DESC("Per-scheme proxy rules"),
867 NULL
, // DESKTOP_SESSION
870 NULL
, // KDE_SESSION_VERSION
873 "www.google.com:80", "www.foo.com:110", "ftp.foo.com:121", // per-proto
879 ProxyConfigService::CONFIG_VALID
,
880 false, // auto_detect
882 ProxyRulesExpectation::PerScheme(
883 "www.google.com:80", // http
884 "www.foo.com:110", // https
885 "ftp.foo.com:121", // ftp
892 NULL
, // DESKTOP_SESSION
895 NULL
, // KDE_SESSION_VERSION
898 NULL
, NULL
, NULL
, // per-proto proxies
899 "socks.com:888", NULL
, // SOCKS
904 ProxyConfigService::CONFIG_VALID
,
905 false, // auto_detect
907 ProxyRulesExpectation::Single(
908 "socks5://socks.com:888", // single proxy
915 NULL
, // DESKTOP_SESSION
918 NULL
, // KDE_SESSION_VERSION
921 NULL
, NULL
, NULL
, // per-proto proxies
922 "socks.com:888", "4", // SOCKS
927 ProxyConfigService::CONFIG_VALID
,
928 false, // auto_detect
930 ProxyRulesExpectation::Single(
931 "socks4://socks.com:888", // single proxy
936 TEST_DESC("socks default port"),
938 NULL
, // DESKTOP_SESSION
941 NULL
, // KDE_SESSION_VERSION
944 NULL
, NULL
, NULL
, // per-proto proxies
945 "socks.com", NULL
, // SOCKS
950 ProxyConfigService::CONFIG_VALID
,
951 false, // auto_detect
953 ProxyRulesExpectation::Single(
954 "socks5://socks.com:1080", // single proxy
961 NULL
, // DESKTOP_SESSION
964 NULL
, // KDE_SESSION_VERSION
966 "www.google.com", // all_proxy
967 NULL
, NULL
, NULL
, // per-proto
969 ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8", // no_proxy
973 ProxyConfigService::CONFIG_VALID
,
974 false, // auto_detect
976 ProxyRulesExpectation::Single(
978 "*.google.com,*foo.com:99,1.2.3.4:22,127.0.0.1/8"),
982 for (size_t i
= 0; i
< arraysize(tests
); ++i
) {
983 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"] %s", i
,
984 tests
[i
].description
.c_str()));
985 MockEnvironment
* env
= new MockEnvironment
;
986 MockSettingGetter
* setting_getter
= new MockSettingGetter
;
987 SynchConfigGetter
sync_config_getter(
988 new ProxyConfigServiceLinux(env
, setting_getter
));
990 env
->values
= tests
[i
].values
;
991 sync_config_getter
.SetupAndInitialFetch();
992 ProxyConfigService::ConfigAvailability availability
=
993 sync_config_getter
.SyncGetLatestProxyConfig(&config
);
994 EXPECT_EQ(tests
[i
].availability
, availability
);
996 if (availability
== ProxyConfigService::CONFIG_VALID
) {
997 EXPECT_EQ(tests
[i
].auto_detect
, config
.auto_detect());
998 EXPECT_EQ(tests
[i
].pac_url
, config
.pac_url());
999 EXPECT_TRUE(tests
[i
].proxy_rules
.Matches(config
.proxy_rules()));
1004 TEST_F(ProxyConfigServiceLinuxTest
, GconfNotification
) {
1005 MockEnvironment
* env
= new MockEnvironment
;
1006 MockSettingGetter
* setting_getter
= new MockSettingGetter
;
1007 ProxyConfigServiceLinux
* service
=
1008 new ProxyConfigServiceLinux(env
, setting_getter
);
1009 SynchConfigGetter
sync_config_getter(service
);
1012 // Start with no proxy.
1013 setting_getter
->values
.mode
= "none";
1014 sync_config_getter
.SetupAndInitialFetch();
1015 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1016 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1017 EXPECT_FALSE(config
.auto_detect());
1019 // Now set to auto-detect.
1020 setting_getter
->values
.mode
= "auto";
1021 // Simulate setting change notification callback.
1022 service
->OnCheckProxyConfigSettings();
1023 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1024 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1025 EXPECT_TRUE(config
.auto_detect());
1028 TEST_F(ProxyConfigServiceLinuxTest
, KDEConfigParser
) {
1029 // One of the tests below needs a worst-case long line prefix. We build it
1030 // programmatically so that it will always be the right size.
1031 std::string long_line
;
1032 size_t limit
= ProxyConfigServiceLinux::SettingGetter::BUFFER_SIZE
- 1;
1033 for (size_t i
= 0; i
< limit
; ++i
)
1036 // Inspired from proxy_config_service_win_unittest.cc.
1038 // Short description to identify the test
1039 std::string description
;
1042 std::string kioslaverc
;
1043 EnvVarValues env_values
;
1045 // Expected outputs (availability and fields of ProxyConfig).
1046 ProxyConfigService::ConfigAvailability availability
;
1049 ProxyRulesExpectation proxy_rules
;
1052 TEST_DESC("No proxying"),
1055 "[Proxy Settings]\nProxyType=0\n",
1059 ProxyConfigService::CONFIG_VALID
,
1060 false, // auto_detect
1062 ProxyRulesExpectation::Empty(),
1066 TEST_DESC("Auto detect"),
1069 "[Proxy Settings]\nProxyType=3\n",
1073 ProxyConfigService::CONFIG_VALID
,
1074 true, // auto_detect
1076 ProxyRulesExpectation::Empty(),
1080 TEST_DESC("Valid PAC URL"),
1083 "[Proxy Settings]\nProxyType=2\n"
1084 "Proxy Config Script=http://wpad/wpad.dat\n",
1088 ProxyConfigService::CONFIG_VALID
,
1089 false, // auto_detect
1090 GURL("http://wpad/wpad.dat"), // pac_url
1091 ProxyRulesExpectation::Empty(),
1095 TEST_DESC("Valid PAC file without file://"),
1098 "[Proxy Settings]\nProxyType=2\n"
1099 "Proxy Config Script=/wpad/wpad.dat\n",
1103 ProxyConfigService::CONFIG_VALID
,
1104 false, // auto_detect
1105 GURL("file:///wpad/wpad.dat"), // pac_url
1106 ProxyRulesExpectation::Empty(),
1110 TEST_DESC("Per-scheme proxy rules"),
1113 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1114 "httpsProxy=www.foo.com\nftpProxy=ftp.foo.com\n",
1118 ProxyConfigService::CONFIG_VALID
,
1119 false, // auto_detect
1121 ProxyRulesExpectation::PerScheme(
1122 "www.google.com:80", // http
1123 "www.foo.com:80", // https
1124 "ftp.foo.com:80", // http
1125 ""), // bypass rules
1129 TEST_DESC("Only HTTP proxy specified"),
1132 "[Proxy Settings]\nProxyType=1\n"
1133 "httpProxy=www.google.com\n",
1137 ProxyConfigService::CONFIG_VALID
,
1138 false, // auto_detect
1140 ProxyRulesExpectation::PerScheme(
1141 "www.google.com:80", // http
1144 ""), // bypass rules
1148 TEST_DESC("Only HTTP proxy specified, different port"),
1151 "[Proxy Settings]\nProxyType=1\n"
1152 "httpProxy=www.google.com:88\n",
1156 ProxyConfigService::CONFIG_VALID
,
1157 false, // auto_detect
1159 ProxyRulesExpectation::PerScheme(
1160 "www.google.com:88", // http
1163 ""), // bypass rules
1167 TEST_DESC("Only HTTP proxy specified, different port, space-delimited"),
1170 "[Proxy Settings]\nProxyType=1\n"
1171 "httpProxy=www.google.com 88\n",
1175 ProxyConfigService::CONFIG_VALID
,
1176 false, // auto_detect
1178 ProxyRulesExpectation::PerScheme(
1179 "www.google.com:88", // http
1182 ""), // bypass rules
1186 TEST_DESC("Bypass *.google.com"),
1189 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1190 "NoProxyFor=.google.com\n",
1194 ProxyConfigService::CONFIG_VALID
,
1195 false, // auto_detect
1197 ProxyRulesExpectation::PerScheme(
1198 "www.google.com:80", // http
1201 "*.google.com"), // bypass rules
1205 TEST_DESC("Bypass *.google.com and *.kde.org"),
1208 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1209 "NoProxyFor=.google.com,.kde.org\n",
1213 ProxyConfigService::CONFIG_VALID
,
1214 false, // auto_detect
1216 ProxyRulesExpectation::PerScheme(
1217 "www.google.com:80", // http
1220 "*.google.com,*.kde.org"), // bypass rules
1224 TEST_DESC("Correctly parse bypass list with ReversedException"),
1227 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1228 "NoProxyFor=.google.com\nReversedException=true\n",
1232 ProxyConfigService::CONFIG_VALID
,
1233 false, // auto_detect
1235 ProxyRulesExpectation::PerSchemeWithBypassReversed(
1236 "www.google.com:80", // http
1239 "*.google.com"), // bypass rules
1246 "[Proxy Settings]\nProxyType=1\nsocksProxy=socks.com 888\n",
1250 ProxyConfigService::CONFIG_VALID
,
1251 false, // auto_detect
1253 ProxyRulesExpectation::Single(
1254 "socks5://socks.com:888", // single proxy
1255 ""), // bypass rules
1259 TEST_DESC("socks4"),
1262 "[Proxy Settings]\nProxyType=1\nsocksProxy=socks4://socks.com 888\n",
1266 ProxyConfigService::CONFIG_VALID
,
1267 false, // auto_detect
1269 ProxyRulesExpectation::Single(
1270 "socks4://socks.com:888", // single proxy
1271 ""), // bypass rules
1275 TEST_DESC("Treat all hostname patterns as wildcard patterns"),
1278 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1279 "NoProxyFor=google.com,kde.org,<local>\n",
1283 ProxyConfigService::CONFIG_VALID
,
1284 false, // auto_detect
1286 ProxyRulesExpectation::PerScheme(
1287 "www.google.com:80", // http
1290 "*google.com,*kde.org,<local>"), // bypass rules
1294 TEST_DESC("Allow trailing whitespace after boolean value"),
1297 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1298 "NoProxyFor=.google.com\nReversedException=true \n",
1302 ProxyConfigService::CONFIG_VALID
,
1303 false, // auto_detect
1305 ProxyRulesExpectation::PerSchemeWithBypassReversed(
1306 "www.google.com:80", // http
1309 "*.google.com"), // bypass rules
1313 TEST_DESC("Ignore settings outside [Proxy Settings]"),
1316 "httpsProxy=www.foo.com\n[Proxy Settings]\nProxyType=1\n"
1317 "httpProxy=www.google.com\n[Other Section]\nftpProxy=ftp.foo.com\n",
1321 ProxyConfigService::CONFIG_VALID
,
1322 false, // auto_detect
1324 ProxyRulesExpectation::PerScheme(
1325 "www.google.com:80", // http
1328 ""), // bypass rules
1332 TEST_DESC("Handle CRLF line endings"),
1335 "[Proxy Settings]\r\nProxyType=1\r\nhttpProxy=www.google.com\r\n",
1339 ProxyConfigService::CONFIG_VALID
,
1340 false, // auto_detect
1342 ProxyRulesExpectation::PerScheme(
1343 "www.google.com:80", // http
1346 ""), // bypass rules
1350 TEST_DESC("Handle blank lines and mixed line endings"),
1353 "[Proxy Settings]\r\n\nProxyType=1\n\r\nhttpProxy=www.google.com\n\n",
1357 ProxyConfigService::CONFIG_VALID
,
1358 false, // auto_detect
1360 ProxyRulesExpectation::PerScheme(
1361 "www.google.com:80", // http
1364 ""), // bypass rules
1368 TEST_DESC("Handle localized settings"),
1371 "[Proxy Settings]\nProxyType[$e]=1\nhttpProxy[$e]=www.google.com\n",
1375 ProxyConfigService::CONFIG_VALID
,
1376 false, // auto_detect
1378 ProxyRulesExpectation::PerScheme(
1379 "www.google.com:80", // http
1382 ""), // bypass rules
1386 TEST_DESC("Ignore malformed localized settings"),
1389 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1390 "httpsProxy$e]=www.foo.com\nftpProxy=ftp.foo.com\n",
1394 ProxyConfigService::CONFIG_VALID
,
1395 false, // auto_detect
1397 ProxyRulesExpectation::PerScheme(
1398 "www.google.com:80", // http
1400 "ftp.foo.com:80", // ftp
1401 ""), // bypass rules
1405 TEST_DESC("Handle strange whitespace"),
1408 "[Proxy Settings]\nProxyType [$e] =2\n"
1409 " Proxy Config Script = http:// foo\n",
1413 ProxyConfigService::CONFIG_VALID
,
1414 false, // auto_detect
1415 GURL("http:// foo"), // pac_url
1416 ProxyRulesExpectation::Empty(),
1420 TEST_DESC("Ignore all of a line which is too long"),
1423 std::string("[Proxy Settings]\nProxyType=1\nftpProxy=ftp.foo.com\n") +
1424 long_line
+ "httpsProxy=www.foo.com\nhttpProxy=www.google.com\n",
1428 ProxyConfigService::CONFIG_VALID
,
1429 false, // auto_detect
1431 ProxyRulesExpectation::PerScheme(
1432 "www.google.com:80", // http
1434 "ftp.foo.com:80", // ftp
1435 ""), // bypass rules
1439 TEST_DESC("Indirect Proxy - no env vars set"),
1442 "[Proxy Settings]\nProxyType=4\nhttpProxy=http_proxy\n"
1443 "httpsProxy=https_proxy\nftpProxy=ftp_proxy\nNoProxyFor=no_proxy\n",
1447 ProxyConfigService::CONFIG_VALID
,
1448 false, // auto_detect
1450 ProxyRulesExpectation::Empty(),
1454 TEST_DESC("Indirect Proxy - with env vars set"),
1457 "[Proxy Settings]\nProxyType=4\nhttpProxy=http_proxy\n"
1458 "httpsProxy=https_proxy\nftpProxy=ftp_proxy\nNoProxyFor=no_proxy\n",
1460 NULL
, // DESKTOP_SESSION
1463 NULL
, // KDE_SESSION_VERSION
1466 "www.normal.com", // http_proxy
1467 "www.secure.com", // https_proxy
1468 "ftp.foo.com", // ftp_proxy
1469 NULL
, NULL
, // SOCKS
1470 ".google.com, .kde.org", // no_proxy
1474 ProxyConfigService::CONFIG_VALID
,
1475 false, // auto_detect
1477 ProxyRulesExpectation::PerScheme(
1478 "www.normal.com:80", // http
1479 "www.secure.com:80", // https
1480 "ftp.foo.com:80", // ftp
1481 "*.google.com,*.kde.org"), // bypass rules
1486 for (size_t i
= 0; i
< arraysize(tests
); ++i
) {
1487 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"] %s", i
,
1488 tests
[i
].description
.c_str()));
1489 MockEnvironment
* env
= new MockEnvironment
;
1490 env
->values
= tests
[i
].env_values
;
1491 // Force the KDE getter to be used and tell it where the test is.
1492 env
->values
.DESKTOP_SESSION
= "kde4";
1493 env
->values
.KDEHOME
= kde_home_
.value().c_str();
1494 SynchConfigGetter
sync_config_getter(
1495 new ProxyConfigServiceLinux(env
));
1497 // Overwrite the kioslaverc file.
1498 base::WriteFile(kioslaverc_
, tests
[i
].kioslaverc
.c_str(),
1499 tests
[i
].kioslaverc
.length());
1500 sync_config_getter
.SetupAndInitialFetch();
1501 ProxyConfigService::ConfigAvailability availability
=
1502 sync_config_getter
.SyncGetLatestProxyConfig(&config
);
1503 EXPECT_EQ(tests
[i
].availability
, availability
);
1505 if (availability
== ProxyConfigService::CONFIG_VALID
) {
1506 EXPECT_EQ(tests
[i
].auto_detect
, config
.auto_detect());
1507 EXPECT_EQ(tests
[i
].pac_url
, config
.pac_url());
1508 EXPECT_TRUE(tests
[i
].proxy_rules
.Matches(config
.proxy_rules()));
1513 TEST_F(ProxyConfigServiceLinuxTest
, KDEHomePicker
) {
1514 // Auto detect proxy settings.
1515 std::string slaverc3
= "[Proxy Settings]\nProxyType=3\n";
1517 std::string slaverc4
= "[Proxy Settings]\nProxyType=2\n"
1518 "Proxy Config Script=http://wpad/wpad.dat\n";
1519 GURL
slaverc4_pac_url("http://wpad/wpad.dat");
1521 // Overwrite the .kde kioslaverc file.
1522 base::WriteFile(kioslaverc_
, slaverc3
.c_str(), slaverc3
.length());
1524 // If .kde4 exists it will mess up the first test. It should not, as
1525 // we created the directory for $HOME in the test setup.
1526 CHECK(!base::DirectoryExists(kde4_home_
));
1528 { SCOPED_TRACE("KDE4, no .kde4 directory, verify fallback");
1529 MockEnvironment
* env
= new MockEnvironment
;
1530 env
->values
.DESKTOP_SESSION
= "kde4";
1531 env
->values
.HOME
= user_home_
.value().c_str();
1532 SynchConfigGetter
sync_config_getter(
1533 new ProxyConfigServiceLinux(env
));
1535 sync_config_getter
.SetupAndInitialFetch();
1536 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1537 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1538 EXPECT_TRUE(config
.auto_detect());
1539 EXPECT_EQ(GURL(), config
.pac_url());
1542 // Now create .kde4 and put a kioslaverc in the config directory.
1543 // Note that its timestamp will be at least as new as the .kde one.
1544 base::CreateDirectory(kde4_config_
);
1545 base::WriteFile(kioslaverc4_
, slaverc4
.c_str(), slaverc4
.length());
1546 CHECK(base::PathExists(kioslaverc4_
));
1548 { SCOPED_TRACE("KDE4, .kde4 directory present, use it");
1549 MockEnvironment
* env
= new MockEnvironment
;
1550 env
->values
.DESKTOP_SESSION
= "kde4";
1551 env
->values
.HOME
= user_home_
.value().c_str();
1552 SynchConfigGetter
sync_config_getter(
1553 new ProxyConfigServiceLinux(env
));
1555 sync_config_getter
.SetupAndInitialFetch();
1556 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1557 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1558 EXPECT_FALSE(config
.auto_detect());
1559 EXPECT_EQ(slaverc4_pac_url
, config
.pac_url());
1562 { SCOPED_TRACE("KDE3, .kde4 directory present, ignore it");
1563 MockEnvironment
* env
= new MockEnvironment
;
1564 env
->values
.DESKTOP_SESSION
= "kde";
1565 env
->values
.HOME
= user_home_
.value().c_str();
1566 SynchConfigGetter
sync_config_getter(
1567 new ProxyConfigServiceLinux(env
));
1569 sync_config_getter
.SetupAndInitialFetch();
1570 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1571 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1572 EXPECT_TRUE(config
.auto_detect());
1573 EXPECT_EQ(GURL(), config
.pac_url());
1576 { SCOPED_TRACE("KDE4, .kde4 directory present, KDEHOME set to .kde");
1577 MockEnvironment
* env
= new MockEnvironment
;
1578 env
->values
.DESKTOP_SESSION
= "kde4";
1579 env
->values
.HOME
= user_home_
.value().c_str();
1580 env
->values
.KDEHOME
= kde_home_
.value().c_str();
1581 SynchConfigGetter
sync_config_getter(
1582 new ProxyConfigServiceLinux(env
));
1584 sync_config_getter
.SetupAndInitialFetch();
1585 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1586 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1587 EXPECT_TRUE(config
.auto_detect());
1588 EXPECT_EQ(GURL(), config
.pac_url());
1591 // Finally, make the .kde4 config directory older than the .kde directory
1592 // and make sure we then use .kde instead of .kde4 since it's newer.
1593 base::TouchFile(kde4_config_
, base::Time(), base::Time());
1595 { SCOPED_TRACE("KDE4, very old .kde4 directory present, use .kde");
1596 MockEnvironment
* env
= new MockEnvironment
;
1597 env
->values
.DESKTOP_SESSION
= "kde4";
1598 env
->values
.HOME
= user_home_
.value().c_str();
1599 SynchConfigGetter
sync_config_getter(
1600 new ProxyConfigServiceLinux(env
));
1602 sync_config_getter
.SetupAndInitialFetch();
1603 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1604 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1605 EXPECT_TRUE(config
.auto_detect());
1606 EXPECT_EQ(GURL(), config
.pac_url());