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/location.h"
17 #include "base/logging.h"
18 #include "base/single_thread_task_runner.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/synchronization/waitable_event.h"
22 #include "base/thread_task_runner_handle.h"
23 #include "base/threading/thread.h"
24 #include "net/proxy/proxy_config.h"
25 #include "net/proxy/proxy_config_service_common_unittest.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "testing/platform_test.h"
32 // Set of values for all environment variables that we might
33 // query. NULL represents an unset variable.
35 // The strange capitalization is so that the field matches the
36 // environment variable name exactly.
37 const char *DESKTOP_SESSION
, *HOME
,
38 *KDEHOME
, *KDE_SESSION_VERSION
,
39 *auto_proxy
, *all_proxy
,
40 *http_proxy
, *https_proxy
, *ftp_proxy
,
41 *SOCKS_SERVER
, *SOCKS_VERSION
,
45 // Undo macro pollution from GDK includes (from message_loop.h).
49 // So as to distinguish between an unset gconf boolean variable and
51 enum BoolSettingValue
{
52 UNSET
= 0, TRUE
, FALSE
55 // Set of values for all gconf settings that we might query.
58 const char *mode
, *autoconfig_url
,
59 *http_host
, *secure_host
, *ftp_host
, *socks_host
;
61 int http_port
, secure_port
, ftp_port
, socks_port
;
63 BoolSettingValue use_proxy
, same_proxy
, use_auth
;
65 std::vector
<std::string
> ignore_hosts
;
68 // Mapping from a setting name to the location of the corresponding
69 // value (inside a EnvVarValues or GConfValues struct).
70 template<typename key_type
, typename value_type
>
71 struct SettingsTable
{
72 typedef std::map
<key_type
, value_type
*> map_type
;
74 // Gets the value from its location
75 value_type
Get(key_type key
) {
76 typename
map_type::const_iterator it
= settings
.find(key
);
77 // In case there's a typo or the unittest becomes out of sync.
78 CHECK(it
!= settings
.end()) << "key " << key
<< " not found";
79 value_type
* value_ptr
= it
->second
;
86 class MockEnvironment
: public base::Environment
{
89 #define ENTRY(x) table[#x] = &values.x
90 ENTRY(DESKTOP_SESSION
);
93 ENTRY(KDE_SESSION_VERSION
);
101 ENTRY(SOCKS_VERSION
);
106 // Zeroes all environment values.
108 EnvVarValues zero_values
= { 0 };
109 values
= zero_values
;
112 // Begin base::Environment implementation.
113 bool GetVar(const char* variable_name
, std::string
* result
) override
{
114 std::map
<std::string
, const char**>::iterator it
=
115 table
.find(variable_name
);
116 if (it
!= table
.end() && *(it
->second
) != NULL
) {
117 // Note that the variable may be defined but empty.
118 *result
= *(it
->second
);
124 bool SetVar(const char* variable_name
,
125 const std::string
& new_value
) override
{
130 bool UnSetVar(const char* variable_name
) override
{
134 // End base::Environment implementation.
136 // Intentionally public, for convenience when setting up a test.
140 std::map
<std::string
, const char**> table
;
143 class MockSettingGetter
144 : public ProxyConfigServiceLinux::SettingGetter
{
146 typedef ProxyConfigServiceLinux::SettingGetter SettingGetter
;
147 MockSettingGetter() {
148 #define ENTRY(key, field) \
149 strings_table.settings[SettingGetter::key] = &values.field
150 ENTRY(PROXY_MODE
, mode
);
151 ENTRY(PROXY_AUTOCONF_URL
, autoconfig_url
);
152 ENTRY(PROXY_HTTP_HOST
, http_host
);
153 ENTRY(PROXY_HTTPS_HOST
, secure_host
);
154 ENTRY(PROXY_FTP_HOST
, ftp_host
);
155 ENTRY(PROXY_SOCKS_HOST
, socks_host
);
157 #define ENTRY(key, field) \
158 ints_table.settings[SettingGetter::key] = &values.field
159 ENTRY(PROXY_HTTP_PORT
, http_port
);
160 ENTRY(PROXY_HTTPS_PORT
, secure_port
);
161 ENTRY(PROXY_FTP_PORT
, ftp_port
);
162 ENTRY(PROXY_SOCKS_PORT
, socks_port
);
164 #define ENTRY(key, field) \
165 bools_table.settings[SettingGetter::key] = &values.field
166 ENTRY(PROXY_USE_HTTP_PROXY
, use_proxy
);
167 ENTRY(PROXY_USE_SAME_PROXY
, same_proxy
);
168 ENTRY(PROXY_USE_AUTHENTICATION
, use_auth
);
170 string_lists_table
.settings
[SettingGetter::PROXY_IGNORE_HOSTS
] =
171 &values
.ignore_hosts
;
175 // Zeros all environment values.
177 GConfValues zero_values
= { 0 };
178 values
= zero_values
;
181 bool Init(const scoped_refptr
<base::SingleThreadTaskRunner
>& glib_task_runner
,
182 const scoped_refptr
<base::SingleThreadTaskRunner
>& file_task_runner
)
184 task_runner_
= glib_task_runner
;
188 void ShutDown() override
{}
190 bool SetUpNotifications(
191 ProxyConfigServiceLinux::Delegate
* delegate
) override
{
195 const scoped_refptr
<base::SingleThreadTaskRunner
>& GetNotificationTaskRunner()
200 ProxyConfigSource
GetConfigSource() override
{
201 return PROXY_CONFIG_SOURCE_TEST
;
204 bool GetString(StringSetting key
, std::string
* result
) override
{
205 const char* value
= strings_table
.Get(key
);
213 bool GetBool(BoolSetting key
, bool* result
) override
{
214 BoolSettingValue value
= bools_table
.Get(key
);
227 bool GetInt(IntSetting key
, int* result
) override
{
228 // We don't bother to distinguish unset keys from 0 values.
229 *result
= ints_table
.Get(key
);
233 bool GetStringList(StringListSetting key
,
234 std::vector
<std::string
>* result
) override
{
235 *result
= string_lists_table
.Get(key
);
236 // We don't bother to distinguish unset keys from empty lists.
237 return !result
->empty();
240 bool BypassListIsReversed() override
{ return false; }
242 bool MatchHostsUsingSuffixMatching() override
{ return false; }
244 // Intentionally public, for convenience when setting up a test.
248 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
249 SettingsTable
<StringSetting
, const char*> strings_table
;
250 SettingsTable
<BoolSetting
, BoolSettingValue
> bools_table
;
251 SettingsTable
<IntSetting
, int> ints_table
;
252 SettingsTable
<StringListSetting
,
253 std::vector
<std::string
> > string_lists_table
;
256 // This helper class runs ProxyConfigServiceLinux::GetLatestProxyConfig() on
257 // the IO thread and synchronously waits for the result.
258 // Some code duplicated from proxy_script_fetcher_unittest.cc.
259 class SynchConfigGetter
{
261 // Takes ownership of |config_service|.
262 explicit SynchConfigGetter(ProxyConfigServiceLinux
* config_service
)
263 : event_(false, false),
264 io_thread_("IO_Thread"),
265 config_service_(config_service
) {
266 // Start an IO thread.
267 base::Thread::Options options
;
268 options
.message_loop_type
= base::MessageLoop::TYPE_IO
;
269 io_thread_
.StartWithOptions(options
);
271 // Make sure the thread started.
272 io_thread_
.task_runner()->PostTask(
274 base::Bind(&SynchConfigGetter::Init
, base::Unretained(this)));
278 ~SynchConfigGetter() {
279 // Let the config service post a destroy message to the IO thread
280 // before cleaning up that thread.
281 delete config_service_
;
282 // Clean up the IO thread.
283 io_thread_
.task_runner()->PostTask(
285 base::Bind(&SynchConfigGetter::CleanUp
, base::Unretained(this)));
289 // Does gconf setup and initial fetch of the proxy config,
290 // all on the calling thread (meant to be the thread with the
291 // default glib main loop, which is the UI thread).
292 void SetupAndInitialFetch() {
293 // We pass the mock IO thread as both the IO and file threads.
294 config_service_
->SetupAndFetchInitialConfig(
295 base::ThreadTaskRunnerHandle::Get(), io_thread_
.task_runner(),
296 io_thread_
.task_runner());
298 // Synchronously gets the proxy config.
299 ProxyConfigService::ConfigAvailability
SyncGetLatestProxyConfig(
300 ProxyConfig
* config
) {
301 io_thread_
.task_runner()->PostTask(
302 FROM_HERE
, base::Bind(&SynchConfigGetter::GetLatestConfigOnIOThread
,
303 base::Unretained(this)));
305 *config
= proxy_config_
;
306 return get_latest_config_result_
;
310 // [Runs on |io_thread_|]
315 // Calls GetLatestProxyConfig, running on |io_thread_| Signals |event_|
317 void GetLatestConfigOnIOThread() {
318 get_latest_config_result_
=
319 config_service_
->GetLatestProxyConfig(&proxy_config_
);
323 // [Runs on |io_thread_|] Signals |event_| on cleanup completion.
325 base::MessageLoop::current()->RunUntilIdle();
334 base::WaitableEvent event_
;
335 base::Thread io_thread_
;
337 ProxyConfigServiceLinux
* config_service_
;
339 // The config obtained by |io_thread_| and read back by the main
341 ProxyConfig proxy_config_
;
343 // Return value from GetLatestProxyConfig().
344 ProxyConfigService::ConfigAvailability get_latest_config_result_
;
347 // This test fixture is only really needed for the KDEConfigParser test case,
348 // but all the test cases with the same prefix ("ProxyConfigServiceLinuxTest")
349 // must use the same test fixture class (also "ProxyConfigServiceLinuxTest").
350 class ProxyConfigServiceLinuxTest
: public PlatformTest
{
352 void SetUp() override
{
353 PlatformTest::SetUp();
354 // Set up a temporary KDE home directory.
355 std::string
prefix("ProxyConfigServiceLinuxTest_user_home");
356 base::CreateNewTempDirectory(prefix
, &user_home_
);
357 kde_home_
= user_home_
.Append(FILE_PATH_LITERAL(".kde"));
358 base::FilePath path
= kde_home_
.Append(FILE_PATH_LITERAL("share"));
359 path
= path
.Append(FILE_PATH_LITERAL("config"));
360 base::CreateDirectory(path
);
361 kioslaverc_
= path
.Append(FILE_PATH_LITERAL("kioslaverc"));
362 // Set up paths but do not create the directory for .kde4.
363 kde4_home_
= user_home_
.Append(FILE_PATH_LITERAL(".kde4"));
364 path
= kde4_home_
.Append(FILE_PATH_LITERAL("share"));
365 kde4_config_
= path
.Append(FILE_PATH_LITERAL("config"));
366 kioslaverc4_
= kde4_config_
.Append(FILE_PATH_LITERAL("kioslaverc"));
369 void TearDown() override
{
370 // Delete the temporary KDE home directory.
371 base::DeleteFile(user_home_
, true);
372 PlatformTest::TearDown();
375 base::FilePath user_home_
;
377 base::FilePath kde_home_
;
378 base::FilePath kioslaverc_
;
380 base::FilePath kde4_home_
;
381 base::FilePath kde4_config_
;
382 base::FilePath kioslaverc4_
;
385 // Builds an identifier for each test in an array.
386 #define TEST_DESC(desc) base::StringPrintf("at line %d <%s>", __LINE__, desc)
388 TEST_F(ProxyConfigServiceLinuxTest
, BasicGConfTest
) {
389 std::vector
<std::string
> empty_ignores
;
391 std::vector
<std::string
> google_ignores
;
392 google_ignores
.push_back("*.google.com");
394 // Inspired from proxy_config_service_win_unittest.cc.
395 // Very neat, but harder to track down failures though.
397 // Short description to identify the test
398 std::string description
;
403 // Expected outputs (availability and fields of ProxyConfig).
404 ProxyConfigService::ConfigAvailability availability
;
407 ProxyRulesExpectation proxy_rules
;
410 TEST_DESC("No proxying"),
413 "", // autoconfig_url
414 "", "", "", "", // hosts
416 FALSE
, FALSE
, FALSE
, // use, same, auth
417 empty_ignores
, // ignore_hosts
421 ProxyConfigService::CONFIG_VALID
,
422 false, // auto_detect
424 ProxyRulesExpectation::Empty(),
428 TEST_DESC("Auto detect"),
431 "", // autoconfig_url
432 "", "", "", "", // hosts
434 FALSE
, FALSE
, FALSE
, // use, same, auth
435 empty_ignores
, // ignore_hosts
439 ProxyConfigService::CONFIG_VALID
,
442 ProxyRulesExpectation::Empty(),
446 TEST_DESC("Valid PAC URL"),
449 "http://wpad/wpad.dat", // autoconfig_url
450 "", "", "", "", // hosts
452 FALSE
, FALSE
, FALSE
, // use, same, auth
453 empty_ignores
, // ignore_hosts
457 ProxyConfigService::CONFIG_VALID
,
458 false, // auto_detect
459 GURL("http://wpad/wpad.dat"), // pac_url
460 ProxyRulesExpectation::Empty(),
464 TEST_DESC("Invalid PAC URL"),
467 "wpad.dat", // autoconfig_url
468 "", "", "", "", // hosts
470 FALSE
, FALSE
, FALSE
, // use, same, auth
471 empty_ignores
, // ignore_hosts
475 ProxyConfigService::CONFIG_VALID
,
476 false, // auto_detect
478 ProxyRulesExpectation::Empty(),
482 TEST_DESC("Single-host in proxy list"),
485 "", // autoconfig_url
486 "www.google.com", "", "", "", // hosts
487 80, 0, 0, 0, // ports
488 TRUE
, TRUE
, FALSE
, // use, same, auth
489 empty_ignores
, // ignore_hosts
493 ProxyConfigService::CONFIG_VALID
,
494 false, // auto_detect
496 ProxyRulesExpectation::Single(
497 "www.google.com:80", // single proxy
502 TEST_DESC("use_http_proxy is honored"),
505 "", // autoconfig_url
506 "www.google.com", "", "", "", // hosts
507 80, 0, 0, 0, // ports
508 FALSE
, TRUE
, FALSE
, // use, same, auth
509 empty_ignores
, // ignore_hosts
513 ProxyConfigService::CONFIG_VALID
,
514 false, // auto_detect
516 ProxyRulesExpectation::Empty(),
520 TEST_DESC("use_http_proxy and use_same_proxy are optional"),
523 "", // autoconfig_url
524 "www.google.com", "", "", "", // hosts
525 80, 0, 0, 0, // ports
526 UNSET
, UNSET
, FALSE
, // use, same, auth
527 empty_ignores
, // ignore_hosts
531 ProxyConfigService::CONFIG_VALID
,
532 false, // auto_detect
534 ProxyRulesExpectation::PerScheme(
535 "www.google.com:80", // http
542 TEST_DESC("Single-host, different port"),
545 "", // autoconfig_url
546 "www.google.com", "", "", "", // hosts
547 88, 0, 0, 0, // ports
548 TRUE
, TRUE
, FALSE
, // use, same, auth
549 empty_ignores
, // ignore_hosts
553 ProxyConfigService::CONFIG_VALID
,
554 false, // auto_detect
556 ProxyRulesExpectation::Single(
557 "www.google.com:88", // single proxy
562 TEST_DESC("Per-scheme proxy rules"),
565 "", // autoconfig_url
566 "www.google.com", // http_host
567 "www.foo.com", // secure_host
568 "ftp.foo.com", // ftp
570 88, 110, 121, 0, // ports
571 TRUE
, FALSE
, FALSE
, // use, same, auth
572 empty_ignores
, // ignore_hosts
576 ProxyConfigService::CONFIG_VALID
,
577 false, // auto_detect
579 ProxyRulesExpectation::PerScheme(
580 "www.google.com:88", // http
581 "www.foo.com:110", // https
582 "ftp.foo.com:121", // ftp
590 "", // autoconfig_url
591 "", "", "", "socks.com", // hosts
592 0, 0, 0, 99, // ports
593 TRUE
, FALSE
, FALSE
, // use, same, auth
594 empty_ignores
, // ignore_hosts
598 ProxyConfigService::CONFIG_VALID
,
599 false, // auto_detect
601 ProxyRulesExpectation::Single(
602 "socks5://socks.com:99", // single proxy
607 TEST_DESC("Per-scheme proxy rules with fallback to SOCKS"),
610 "", // autoconfig_url
611 "www.google.com", // http_host
612 "www.foo.com", // secure_host
613 "ftp.foo.com", // ftp
614 "foobar.net", // socks
615 88, 110, 121, 99, // ports
616 TRUE
, FALSE
, FALSE
, // use, same, auth
617 empty_ignores
, // ignore_hosts
621 ProxyConfigService::CONFIG_VALID
,
622 false, // auto_detect
624 ProxyRulesExpectation::PerSchemeWithSocks(
625 "www.google.com:88", // http
626 "www.foo.com:110", // https
627 "ftp.foo.com:121", // ftp
628 "socks5://foobar.net:99", // socks
633 TEST_DESC("Per-scheme proxy rules (just HTTP) with fallback to SOCKS"),
636 "", // autoconfig_url
637 "www.google.com", // http_host
640 "foobar.net", // socks
641 88, 0, 0, 99, // ports
642 TRUE
, FALSE
, FALSE
, // use, same, auth
643 empty_ignores
, // ignore_hosts
647 ProxyConfigService::CONFIG_VALID
,
648 false, // auto_detect
650 ProxyRulesExpectation::PerSchemeWithSocks(
651 "www.google.com:88", // http
654 "socks5://foobar.net:99", // socks
659 TEST_DESC("Bypass *.google.com"),
662 "", // autoconfig_url
663 "www.google.com", "", "", "", // hosts
664 80, 0, 0, 0, // ports
665 TRUE
, TRUE
, FALSE
, // use, same, auth
666 google_ignores
, // ignore_hosts
669 ProxyConfigService::CONFIG_VALID
,
670 false, // auto_detect
672 ProxyRulesExpectation::Single(
673 "www.google.com:80", // single proxy
674 "*.google.com"), // bypass rules
678 for (size_t i
= 0; i
< arraysize(tests
); ++i
) {
679 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"] %s", i
,
680 tests
[i
].description
.c_str()));
681 MockEnvironment
* env
= new MockEnvironment
;
682 MockSettingGetter
* setting_getter
= new MockSettingGetter
;
683 SynchConfigGetter
sync_config_getter(
684 new ProxyConfigServiceLinux(env
, setting_getter
));
686 setting_getter
->values
= tests
[i
].values
;
687 sync_config_getter
.SetupAndInitialFetch();
688 ProxyConfigService::ConfigAvailability availability
=
689 sync_config_getter
.SyncGetLatestProxyConfig(&config
);
690 EXPECT_EQ(tests
[i
].availability
, availability
);
692 if (availability
== ProxyConfigService::CONFIG_VALID
) {
693 EXPECT_EQ(tests
[i
].auto_detect
, config
.auto_detect());
694 EXPECT_EQ(tests
[i
].pac_url
, config
.pac_url());
695 EXPECT_TRUE(tests
[i
].proxy_rules
.Matches(config
.proxy_rules()));
700 TEST_F(ProxyConfigServiceLinuxTest
, BasicEnvTest
) {
701 // Inspired from proxy_config_service_win_unittest.cc.
703 // Short description to identify the test
704 std::string description
;
709 // Expected outputs (availability and fields of ProxyConfig).
710 ProxyConfigService::ConfigAvailability availability
;
713 ProxyRulesExpectation proxy_rules
;
716 TEST_DESC("No proxying"),
718 NULL
, // DESKTOP_SESSION
721 NULL
, // KDE_SESSION_VERSION
724 NULL
, NULL
, NULL
, // per-proto proxies
730 ProxyConfigService::CONFIG_VALID
,
731 false, // auto_detect
733 ProxyRulesExpectation::Empty(),
737 TEST_DESC("Auto detect"),
739 NULL
, // DESKTOP_SESSION
742 NULL
, // KDE_SESSION_VERSION
745 NULL
, NULL
, NULL
, // per-proto proxies
751 ProxyConfigService::CONFIG_VALID
,
754 ProxyRulesExpectation::Empty(),
758 TEST_DESC("Valid PAC URL"),
760 NULL
, // DESKTOP_SESSION
763 NULL
, // KDE_SESSION_VERSION
764 "http://wpad/wpad.dat", // auto_proxy
766 NULL
, NULL
, NULL
, // per-proto proxies
772 ProxyConfigService::CONFIG_VALID
,
773 false, // auto_detect
774 GURL("http://wpad/wpad.dat"), // pac_url
775 ProxyRulesExpectation::Empty(),
779 TEST_DESC("Invalid PAC URL"),
781 NULL
, // DESKTOP_SESSION
784 NULL
, // KDE_SESSION_VERSION
785 "wpad.dat", // auto_proxy
787 NULL
, NULL
, NULL
, // per-proto proxies
793 ProxyConfigService::CONFIG_VALID
,
794 false, // auto_detect
796 ProxyRulesExpectation::Empty(),
800 TEST_DESC("Single-host in proxy list"),
802 NULL
, // DESKTOP_SESSION
805 NULL
, // KDE_SESSION_VERSION
807 "www.google.com", // all_proxy
808 NULL
, NULL
, NULL
, // per-proto proxies
814 ProxyConfigService::CONFIG_VALID
,
815 false, // auto_detect
817 ProxyRulesExpectation::Single(
818 "www.google.com:80", // single proxy
823 TEST_DESC("Single-host, different port"),
825 NULL
, // DESKTOP_SESSION
828 NULL
, // KDE_SESSION_VERSION
830 "www.google.com:99", // all_proxy
831 NULL
, NULL
, NULL
, // per-proto proxies
837 ProxyConfigService::CONFIG_VALID
,
838 false, // auto_detect
840 ProxyRulesExpectation::Single(
841 "www.google.com:99", // single
846 TEST_DESC("Tolerate a scheme"),
848 NULL
, // DESKTOP_SESSION
851 NULL
, // KDE_SESSION_VERSION
853 "http://www.google.com:99", // all_proxy
854 NULL
, NULL
, NULL
, // per-proto proxies
860 ProxyConfigService::CONFIG_VALID
,
861 false, // auto_detect
863 ProxyRulesExpectation::Single(
864 "www.google.com:99", // single proxy
869 TEST_DESC("Per-scheme proxy rules"),
871 NULL
, // DESKTOP_SESSION
874 NULL
, // KDE_SESSION_VERSION
877 "www.google.com:80", "www.foo.com:110", "ftp.foo.com:121", // per-proto
883 ProxyConfigService::CONFIG_VALID
,
884 false, // auto_detect
886 ProxyRulesExpectation::PerScheme(
887 "www.google.com:80", // http
888 "www.foo.com:110", // https
889 "ftp.foo.com:121", // ftp
896 NULL
, // DESKTOP_SESSION
899 NULL
, // KDE_SESSION_VERSION
902 NULL
, NULL
, NULL
, // per-proto proxies
903 "socks.com:888", NULL
, // SOCKS
908 ProxyConfigService::CONFIG_VALID
,
909 false, // auto_detect
911 ProxyRulesExpectation::Single(
912 "socks5://socks.com:888", // single proxy
919 NULL
, // DESKTOP_SESSION
922 NULL
, // KDE_SESSION_VERSION
925 NULL
, NULL
, NULL
, // per-proto proxies
926 "socks.com:888", "4", // SOCKS
931 ProxyConfigService::CONFIG_VALID
,
932 false, // auto_detect
934 ProxyRulesExpectation::Single(
935 "socks4://socks.com:888", // single proxy
940 TEST_DESC("socks default port"),
942 NULL
, // DESKTOP_SESSION
945 NULL
, // KDE_SESSION_VERSION
948 NULL
, NULL
, NULL
, // per-proto proxies
949 "socks.com", NULL
, // SOCKS
954 ProxyConfigService::CONFIG_VALID
,
955 false, // auto_detect
957 ProxyRulesExpectation::Single(
958 "socks5://socks.com:1080", // single proxy
965 NULL
, // DESKTOP_SESSION
968 NULL
, // KDE_SESSION_VERSION
970 "www.google.com", // all_proxy
971 NULL
, NULL
, NULL
, // per-proto
973 ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8", // no_proxy
977 ProxyConfigService::CONFIG_VALID
,
978 false, // auto_detect
980 ProxyRulesExpectation::Single(
982 "*.google.com,*foo.com:99,1.2.3.4:22,127.0.0.1/8"),
986 for (size_t i
= 0; i
< arraysize(tests
); ++i
) {
987 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"] %s", i
,
988 tests
[i
].description
.c_str()));
989 MockEnvironment
* env
= new MockEnvironment
;
990 MockSettingGetter
* setting_getter
= new MockSettingGetter
;
991 SynchConfigGetter
sync_config_getter(
992 new ProxyConfigServiceLinux(env
, setting_getter
));
994 env
->values
= tests
[i
].values
;
995 sync_config_getter
.SetupAndInitialFetch();
996 ProxyConfigService::ConfigAvailability availability
=
997 sync_config_getter
.SyncGetLatestProxyConfig(&config
);
998 EXPECT_EQ(tests
[i
].availability
, availability
);
1000 if (availability
== ProxyConfigService::CONFIG_VALID
) {
1001 EXPECT_EQ(tests
[i
].auto_detect
, config
.auto_detect());
1002 EXPECT_EQ(tests
[i
].pac_url
, config
.pac_url());
1003 EXPECT_TRUE(tests
[i
].proxy_rules
.Matches(config
.proxy_rules()));
1008 TEST_F(ProxyConfigServiceLinuxTest
, GconfNotification
) {
1009 MockEnvironment
* env
= new MockEnvironment
;
1010 MockSettingGetter
* setting_getter
= new MockSettingGetter
;
1011 ProxyConfigServiceLinux
* service
=
1012 new ProxyConfigServiceLinux(env
, setting_getter
);
1013 SynchConfigGetter
sync_config_getter(service
);
1016 // Start with no proxy.
1017 setting_getter
->values
.mode
= "none";
1018 sync_config_getter
.SetupAndInitialFetch();
1019 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1020 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1021 EXPECT_FALSE(config
.auto_detect());
1023 // Now set to auto-detect.
1024 setting_getter
->values
.mode
= "auto";
1025 // Simulate setting change notification callback.
1026 service
->OnCheckProxyConfigSettings();
1027 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1028 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1029 EXPECT_TRUE(config
.auto_detect());
1032 TEST_F(ProxyConfigServiceLinuxTest
, KDEConfigParser
) {
1033 // One of the tests below needs a worst-case long line prefix. We build it
1034 // programmatically so that it will always be the right size.
1035 std::string long_line
;
1036 size_t limit
= ProxyConfigServiceLinux::SettingGetter::BUFFER_SIZE
- 1;
1037 for (size_t i
= 0; i
< limit
; ++i
)
1040 // Inspired from proxy_config_service_win_unittest.cc.
1042 // Short description to identify the test
1043 std::string description
;
1046 std::string kioslaverc
;
1047 EnvVarValues env_values
;
1049 // Expected outputs (availability and fields of ProxyConfig).
1050 ProxyConfigService::ConfigAvailability availability
;
1053 ProxyRulesExpectation proxy_rules
;
1056 TEST_DESC("No proxying"),
1059 "[Proxy Settings]\nProxyType=0\n",
1063 ProxyConfigService::CONFIG_VALID
,
1064 false, // auto_detect
1066 ProxyRulesExpectation::Empty(),
1070 TEST_DESC("Auto detect"),
1073 "[Proxy Settings]\nProxyType=3\n",
1077 ProxyConfigService::CONFIG_VALID
,
1078 true, // auto_detect
1080 ProxyRulesExpectation::Empty(),
1084 TEST_DESC("Valid PAC URL"),
1087 "[Proxy Settings]\nProxyType=2\n"
1088 "Proxy Config Script=http://wpad/wpad.dat\n",
1092 ProxyConfigService::CONFIG_VALID
,
1093 false, // auto_detect
1094 GURL("http://wpad/wpad.dat"), // pac_url
1095 ProxyRulesExpectation::Empty(),
1099 TEST_DESC("Valid PAC file without file://"),
1102 "[Proxy Settings]\nProxyType=2\n"
1103 "Proxy Config Script=/wpad/wpad.dat\n",
1107 ProxyConfigService::CONFIG_VALID
,
1108 false, // auto_detect
1109 GURL("file:///wpad/wpad.dat"), // pac_url
1110 ProxyRulesExpectation::Empty(),
1114 TEST_DESC("Per-scheme proxy rules"),
1117 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1118 "httpsProxy=www.foo.com\nftpProxy=ftp.foo.com\n",
1122 ProxyConfigService::CONFIG_VALID
,
1123 false, // auto_detect
1125 ProxyRulesExpectation::PerScheme(
1126 "www.google.com:80", // http
1127 "www.foo.com:80", // https
1128 "ftp.foo.com:80", // http
1129 ""), // bypass rules
1133 TEST_DESC("Only HTTP proxy specified"),
1136 "[Proxy Settings]\nProxyType=1\n"
1137 "httpProxy=www.google.com\n",
1141 ProxyConfigService::CONFIG_VALID
,
1142 false, // auto_detect
1144 ProxyRulesExpectation::PerScheme(
1145 "www.google.com:80", // http
1148 ""), // bypass rules
1152 TEST_DESC("Only HTTP proxy specified, different port"),
1155 "[Proxy Settings]\nProxyType=1\n"
1156 "httpProxy=www.google.com:88\n",
1160 ProxyConfigService::CONFIG_VALID
,
1161 false, // auto_detect
1163 ProxyRulesExpectation::PerScheme(
1164 "www.google.com:88", // http
1167 ""), // bypass rules
1171 TEST_DESC("Only HTTP proxy specified, different port, space-delimited"),
1174 "[Proxy Settings]\nProxyType=1\n"
1175 "httpProxy=www.google.com 88\n",
1179 ProxyConfigService::CONFIG_VALID
,
1180 false, // auto_detect
1182 ProxyRulesExpectation::PerScheme(
1183 "www.google.com:88", // http
1186 ""), // bypass rules
1190 TEST_DESC("Bypass *.google.com"),
1193 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1194 "NoProxyFor=.google.com\n",
1198 ProxyConfigService::CONFIG_VALID
,
1199 false, // auto_detect
1201 ProxyRulesExpectation::PerScheme(
1202 "www.google.com:80", // http
1205 "*.google.com"), // bypass rules
1209 TEST_DESC("Bypass *.google.com and *.kde.org"),
1212 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1213 "NoProxyFor=.google.com,.kde.org\n",
1217 ProxyConfigService::CONFIG_VALID
,
1218 false, // auto_detect
1220 ProxyRulesExpectation::PerScheme(
1221 "www.google.com:80", // http
1224 "*.google.com,*.kde.org"), // bypass rules
1228 TEST_DESC("Correctly parse bypass list with ReversedException"),
1231 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1232 "NoProxyFor=.google.com\nReversedException=true\n",
1236 ProxyConfigService::CONFIG_VALID
,
1237 false, // auto_detect
1239 ProxyRulesExpectation::PerSchemeWithBypassReversed(
1240 "www.google.com:80", // http
1243 "*.google.com"), // bypass rules
1250 "[Proxy Settings]\nProxyType=1\nsocksProxy=socks.com 888\n",
1254 ProxyConfigService::CONFIG_VALID
,
1255 false, // auto_detect
1257 ProxyRulesExpectation::Single(
1258 "socks5://socks.com:888", // single proxy
1259 ""), // bypass rules
1263 TEST_DESC("socks4"),
1266 "[Proxy Settings]\nProxyType=1\nsocksProxy=socks4://socks.com 888\n",
1270 ProxyConfigService::CONFIG_VALID
,
1271 false, // auto_detect
1273 ProxyRulesExpectation::Single(
1274 "socks4://socks.com:888", // single proxy
1275 ""), // bypass rules
1279 TEST_DESC("Treat all hostname patterns as wildcard patterns"),
1282 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1283 "NoProxyFor=google.com,kde.org,<local>\n",
1287 ProxyConfigService::CONFIG_VALID
,
1288 false, // auto_detect
1290 ProxyRulesExpectation::PerScheme(
1291 "www.google.com:80", // http
1294 "*google.com,*kde.org,<local>"), // bypass rules
1298 TEST_DESC("Allow trailing whitespace after boolean value"),
1301 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1302 "NoProxyFor=.google.com\nReversedException=true \n",
1306 ProxyConfigService::CONFIG_VALID
,
1307 false, // auto_detect
1309 ProxyRulesExpectation::PerSchemeWithBypassReversed(
1310 "www.google.com:80", // http
1313 "*.google.com"), // bypass rules
1317 TEST_DESC("Ignore settings outside [Proxy Settings]"),
1320 "httpsProxy=www.foo.com\n[Proxy Settings]\nProxyType=1\n"
1321 "httpProxy=www.google.com\n[Other Section]\nftpProxy=ftp.foo.com\n",
1325 ProxyConfigService::CONFIG_VALID
,
1326 false, // auto_detect
1328 ProxyRulesExpectation::PerScheme(
1329 "www.google.com:80", // http
1332 ""), // bypass rules
1336 TEST_DESC("Handle CRLF line endings"),
1339 "[Proxy Settings]\r\nProxyType=1\r\nhttpProxy=www.google.com\r\n",
1343 ProxyConfigService::CONFIG_VALID
,
1344 false, // auto_detect
1346 ProxyRulesExpectation::PerScheme(
1347 "www.google.com:80", // http
1350 ""), // bypass rules
1354 TEST_DESC("Handle blank lines and mixed line endings"),
1357 "[Proxy Settings]\r\n\nProxyType=1\n\r\nhttpProxy=www.google.com\n\n",
1361 ProxyConfigService::CONFIG_VALID
,
1362 false, // auto_detect
1364 ProxyRulesExpectation::PerScheme(
1365 "www.google.com:80", // http
1368 ""), // bypass rules
1372 TEST_DESC("Handle localized settings"),
1375 "[Proxy Settings]\nProxyType[$e]=1\nhttpProxy[$e]=www.google.com\n",
1379 ProxyConfigService::CONFIG_VALID
,
1380 false, // auto_detect
1382 ProxyRulesExpectation::PerScheme(
1383 "www.google.com:80", // http
1386 ""), // bypass rules
1390 TEST_DESC("Ignore malformed localized settings"),
1393 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1394 "httpsProxy$e]=www.foo.com\nftpProxy=ftp.foo.com\n",
1398 ProxyConfigService::CONFIG_VALID
,
1399 false, // auto_detect
1401 ProxyRulesExpectation::PerScheme(
1402 "www.google.com:80", // http
1404 "ftp.foo.com:80", // ftp
1405 ""), // bypass rules
1409 TEST_DESC("Handle strange whitespace"),
1412 "[Proxy Settings]\nProxyType [$e] =2\n"
1413 " Proxy Config Script = http:// foo\n",
1417 ProxyConfigService::CONFIG_VALID
,
1418 false, // auto_detect
1419 GURL("http:// foo"), // pac_url
1420 ProxyRulesExpectation::Empty(),
1424 TEST_DESC("Ignore all of a line which is too long"),
1427 std::string("[Proxy Settings]\nProxyType=1\nftpProxy=ftp.foo.com\n") +
1428 long_line
+ "httpsProxy=www.foo.com\nhttpProxy=www.google.com\n",
1432 ProxyConfigService::CONFIG_VALID
,
1433 false, // auto_detect
1435 ProxyRulesExpectation::PerScheme(
1436 "www.google.com:80", // http
1438 "ftp.foo.com:80", // ftp
1439 ""), // bypass rules
1443 TEST_DESC("Indirect Proxy - no env vars set"),
1446 "[Proxy Settings]\nProxyType=4\nhttpProxy=http_proxy\n"
1447 "httpsProxy=https_proxy\nftpProxy=ftp_proxy\nNoProxyFor=no_proxy\n",
1451 ProxyConfigService::CONFIG_VALID
,
1452 false, // auto_detect
1454 ProxyRulesExpectation::Empty(),
1458 TEST_DESC("Indirect Proxy - with env vars set"),
1461 "[Proxy Settings]\nProxyType=4\nhttpProxy=http_proxy\n"
1462 "httpsProxy=https_proxy\nftpProxy=ftp_proxy\nNoProxyFor=no_proxy\n",
1464 NULL
, // DESKTOP_SESSION
1467 NULL
, // KDE_SESSION_VERSION
1470 "www.normal.com", // http_proxy
1471 "www.secure.com", // https_proxy
1472 "ftp.foo.com", // ftp_proxy
1473 NULL
, NULL
, // SOCKS
1474 ".google.com, .kde.org", // no_proxy
1478 ProxyConfigService::CONFIG_VALID
,
1479 false, // auto_detect
1481 ProxyRulesExpectation::PerScheme(
1482 "www.normal.com:80", // http
1483 "www.secure.com:80", // https
1484 "ftp.foo.com:80", // ftp
1485 "*.google.com,*.kde.org"), // bypass rules
1490 for (size_t i
= 0; i
< arraysize(tests
); ++i
) {
1491 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"] %s", i
,
1492 tests
[i
].description
.c_str()));
1493 MockEnvironment
* env
= new MockEnvironment
;
1494 env
->values
= tests
[i
].env_values
;
1495 // Force the KDE getter to be used and tell it where the test is.
1496 env
->values
.DESKTOP_SESSION
= "kde4";
1497 env
->values
.KDEHOME
= kde_home_
.value().c_str();
1498 SynchConfigGetter
sync_config_getter(
1499 new ProxyConfigServiceLinux(env
));
1501 // Overwrite the kioslaverc file.
1502 base::WriteFile(kioslaverc_
, tests
[i
].kioslaverc
.c_str(),
1503 tests
[i
].kioslaverc
.length());
1504 sync_config_getter
.SetupAndInitialFetch();
1505 ProxyConfigService::ConfigAvailability availability
=
1506 sync_config_getter
.SyncGetLatestProxyConfig(&config
);
1507 EXPECT_EQ(tests
[i
].availability
, availability
);
1509 if (availability
== ProxyConfigService::CONFIG_VALID
) {
1510 EXPECT_EQ(tests
[i
].auto_detect
, config
.auto_detect());
1511 EXPECT_EQ(tests
[i
].pac_url
, config
.pac_url());
1512 EXPECT_TRUE(tests
[i
].proxy_rules
.Matches(config
.proxy_rules()));
1517 TEST_F(ProxyConfigServiceLinuxTest
, KDEHomePicker
) {
1518 // Auto detect proxy settings.
1519 std::string slaverc3
= "[Proxy Settings]\nProxyType=3\n";
1521 std::string slaverc4
= "[Proxy Settings]\nProxyType=2\n"
1522 "Proxy Config Script=http://wpad/wpad.dat\n";
1523 GURL
slaverc4_pac_url("http://wpad/wpad.dat");
1525 // Overwrite the .kde kioslaverc file.
1526 base::WriteFile(kioslaverc_
, slaverc3
.c_str(), slaverc3
.length());
1528 // If .kde4 exists it will mess up the first test. It should not, as
1529 // we created the directory for $HOME in the test setup.
1530 CHECK(!base::DirectoryExists(kde4_home_
));
1532 { SCOPED_TRACE("KDE4, no .kde4 directory, verify fallback");
1533 MockEnvironment
* env
= new MockEnvironment
;
1534 env
->values
.DESKTOP_SESSION
= "kde4";
1535 env
->values
.HOME
= user_home_
.value().c_str();
1536 SynchConfigGetter
sync_config_getter(
1537 new ProxyConfigServiceLinux(env
));
1539 sync_config_getter
.SetupAndInitialFetch();
1540 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1541 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1542 EXPECT_TRUE(config
.auto_detect());
1543 EXPECT_EQ(GURL(), config
.pac_url());
1546 // Now create .kde4 and put a kioslaverc in the config directory.
1547 // Note that its timestamp will be at least as new as the .kde one.
1548 base::CreateDirectory(kde4_config_
);
1549 base::WriteFile(kioslaverc4_
, slaverc4
.c_str(), slaverc4
.length());
1550 CHECK(base::PathExists(kioslaverc4_
));
1552 { SCOPED_TRACE("KDE4, .kde4 directory present, use it");
1553 MockEnvironment
* env
= new MockEnvironment
;
1554 env
->values
.DESKTOP_SESSION
= "kde4";
1555 env
->values
.HOME
= user_home_
.value().c_str();
1556 SynchConfigGetter
sync_config_getter(
1557 new ProxyConfigServiceLinux(env
));
1559 sync_config_getter
.SetupAndInitialFetch();
1560 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1561 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1562 EXPECT_FALSE(config
.auto_detect());
1563 EXPECT_EQ(slaverc4_pac_url
, config
.pac_url());
1566 { SCOPED_TRACE("KDE3, .kde4 directory present, ignore it");
1567 MockEnvironment
* env
= new MockEnvironment
;
1568 env
->values
.DESKTOP_SESSION
= "kde";
1569 env
->values
.HOME
= user_home_
.value().c_str();
1570 SynchConfigGetter
sync_config_getter(
1571 new ProxyConfigServiceLinux(env
));
1573 sync_config_getter
.SetupAndInitialFetch();
1574 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1575 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1576 EXPECT_TRUE(config
.auto_detect());
1577 EXPECT_EQ(GURL(), config
.pac_url());
1580 { SCOPED_TRACE("KDE4, .kde4 directory present, KDEHOME set to .kde");
1581 MockEnvironment
* env
= new MockEnvironment
;
1582 env
->values
.DESKTOP_SESSION
= "kde4";
1583 env
->values
.HOME
= user_home_
.value().c_str();
1584 env
->values
.KDEHOME
= kde_home_
.value().c_str();
1585 SynchConfigGetter
sync_config_getter(
1586 new ProxyConfigServiceLinux(env
));
1588 sync_config_getter
.SetupAndInitialFetch();
1589 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1590 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1591 EXPECT_TRUE(config
.auto_detect());
1592 EXPECT_EQ(GURL(), config
.pac_url());
1595 // Finally, make the .kde4 config directory older than the .kde directory
1596 // and make sure we then use .kde instead of .kde4 since it's newer.
1597 base::TouchFile(kde4_config_
, base::Time(), base::Time());
1599 { SCOPED_TRACE("KDE4, very old .kde4 directory present, use .kde");
1600 MockEnvironment
* env
= new MockEnvironment
;
1601 env
->values
.DESKTOP_SESSION
= "kde4";
1602 env
->values
.HOME
= user_home_
.value().c_str();
1603 SynchConfigGetter
sync_config_getter(
1604 new ProxyConfigServiceLinux(env
));
1606 sync_config_getter
.SetupAndInitialFetch();
1607 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1608 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1609 EXPECT_TRUE(config
.auto_detect());
1610 EXPECT_EQ(GURL(), config
.pac_url());