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/file_path.h"
14 #include "base/file_util.h"
15 #include "base/format_macros.h"
16 #include "base/logging.h"
17 #include "base/string_util.h"
18 #include "base/stringprintf.h"
19 #include "base/synchronization/waitable_event.h"
20 #include "base/threading/thread.h"
21 #include "net/proxy/proxy_config.h"
22 #include "net/proxy/proxy_config_service_common_unittest.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "testing/platform_test.h"
29 // Set of values for all environment variables that we might
30 // query. NULL represents an unset variable.
32 // The strange capitalization is so that the field matches the
33 // environment variable name exactly.
34 const char *DESKTOP_SESSION
, *HOME
,
35 *KDEHOME
, *KDE_SESSION_VERSION
,
36 *auto_proxy
, *all_proxy
,
37 *http_proxy
, *https_proxy
, *ftp_proxy
,
38 *SOCKS_SERVER
, *SOCKS_VERSION
,
42 // Undo macro pollution from GDK includes (from message_loop.h).
46 // So as to distinguish between an unset gconf boolean variable and
48 enum BoolSettingValue
{
49 UNSET
= 0, TRUE
, FALSE
52 // Set of values for all gconf settings that we might query.
55 const char *mode
, *autoconfig_url
,
56 *http_host
, *secure_host
, *ftp_host
, *socks_host
;
58 int http_port
, secure_port
, ftp_port
, socks_port
;
60 BoolSettingValue use_proxy
, same_proxy
, use_auth
;
62 std::vector
<std::string
> ignore_hosts
;
65 // Mapping from a setting name to the location of the corresponding
66 // value (inside a EnvVarValues or GConfValues struct).
67 template<typename key_type
, typename value_type
>
68 struct SettingsTable
{
69 typedef std::map
<key_type
, value_type
*> map_type
;
71 // Gets the value from its location
72 value_type
Get(key_type key
) {
73 typename
map_type::const_iterator it
= settings
.find(key
);
74 // In case there's a typo or the unittest becomes out of sync.
75 CHECK(it
!= settings
.end()) << "key " << key
<< " not found";
76 value_type
* value_ptr
= it
->second
;
83 class MockEnvironment
: public base::Environment
{
86 #define ENTRY(x) table[#x] = &values.x
87 ENTRY(DESKTOP_SESSION
);
90 ENTRY(KDE_SESSION_VERSION
);
103 // Zeroes all environment values.
105 EnvVarValues zero_values
= { 0 };
106 values
= zero_values
;
109 // Begin base::Environment implementation.
110 virtual bool GetVar(const char* variable_name
, std::string
* result
) OVERRIDE
{
111 std::map
<std::string
, const char**>::iterator it
=
112 table
.find(variable_name
);
113 if (it
!= table
.end() && *(it
->second
) != NULL
) {
114 // Note that the variable may be defined but empty.
115 *result
= *(it
->second
);
121 virtual bool SetVar(const char* variable_name
, const std::string
& new_value
)
127 virtual bool UnSetVar(const char* variable_name
) OVERRIDE
{
131 // End base::Environment implementation.
133 // Intentionally public, for convenience when setting up a test.
137 std::map
<std::string
, const char**> table
;
140 class MockSettingGetter
141 : public ProxyConfigServiceLinux::SettingGetter
{
143 typedef ProxyConfigServiceLinux::SettingGetter SettingGetter
;
144 MockSettingGetter() {
145 #define ENTRY(key, field) \
146 strings_table.settings[SettingGetter::key] = &values.field
147 ENTRY(PROXY_MODE
, mode
);
148 ENTRY(PROXY_AUTOCONF_URL
, autoconfig_url
);
149 ENTRY(PROXY_HTTP_HOST
, http_host
);
150 ENTRY(PROXY_HTTPS_HOST
, secure_host
);
151 ENTRY(PROXY_FTP_HOST
, ftp_host
);
152 ENTRY(PROXY_SOCKS_HOST
, socks_host
);
154 #define ENTRY(key, field) \
155 ints_table.settings[SettingGetter::key] = &values.field
156 ENTRY(PROXY_HTTP_PORT
, http_port
);
157 ENTRY(PROXY_HTTPS_PORT
, secure_port
);
158 ENTRY(PROXY_FTP_PORT
, ftp_port
);
159 ENTRY(PROXY_SOCKS_PORT
, socks_port
);
161 #define ENTRY(key, field) \
162 bools_table.settings[SettingGetter::key] = &values.field
163 ENTRY(PROXY_USE_HTTP_PROXY
, use_proxy
);
164 ENTRY(PROXY_USE_SAME_PROXY
, same_proxy
);
165 ENTRY(PROXY_USE_AUTHENTICATION
, use_auth
);
167 string_lists_table
.settings
[SettingGetter::PROXY_IGNORE_HOSTS
] =
168 &values
.ignore_hosts
;
172 // Zeros all environment values.
174 GConfValues zero_values
= { 0 };
175 values
= zero_values
;
178 virtual bool Init(base::SingleThreadTaskRunner
* glib_thread_task_runner
,
179 MessageLoopForIO
* file_loop
) OVERRIDE
{
183 virtual void ShutDown() OVERRIDE
{}
185 virtual bool SetUpNotifications(ProxyConfigServiceLinux::Delegate
* delegate
)
190 virtual base::SingleThreadTaskRunner
* GetNotificationTaskRunner() OVERRIDE
{
194 virtual ProxyConfigSource
GetConfigSource() OVERRIDE
{
195 return PROXY_CONFIG_SOURCE_TEST
;
198 virtual bool GetString(StringSetting key
, std::string
* result
) OVERRIDE
{
199 const char* value
= strings_table
.Get(key
);
207 virtual bool GetBool(BoolSetting key
, bool* result
) OVERRIDE
{
208 BoolSettingValue value
= bools_table
.Get(key
);
221 virtual bool GetInt(IntSetting key
, int* result
) OVERRIDE
{
222 // We don't bother to distinguish unset keys from 0 values.
223 *result
= ints_table
.Get(key
);
227 virtual bool GetStringList(StringListSetting key
,
228 std::vector
<std::string
>* result
) OVERRIDE
{
229 *result
= string_lists_table
.Get(key
);
230 // We don't bother to distinguish unset keys from empty lists.
231 return !result
->empty();
234 virtual bool BypassListIsReversed() OVERRIDE
{
238 virtual bool MatchHostsUsingSuffixMatching() OVERRIDE
{
242 // Intentionally public, for convenience when setting up a test.
246 SettingsTable
<StringSetting
, const char*> strings_table
;
247 SettingsTable
<BoolSetting
, BoolSettingValue
> bools_table
;
248 SettingsTable
<IntSetting
, int> ints_table
;
249 SettingsTable
<StringListSetting
,
250 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(net::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
= MessageLoop::TYPE_IO
;
269 io_thread_
.StartWithOptions(options
);
271 // Make sure the thread started.
272 io_thread_
.message_loop()->PostTask(FROM_HERE
,
273 base::Bind(&SynchConfigGetter::Init
, base::Unretained(this)));
277 ~SynchConfigGetter() {
278 // Let the config service post a destroy message to the IO thread
279 // before cleaning up that thread.
280 delete config_service_
;
281 // Clean up the IO thread.
282 io_thread_
.message_loop()->PostTask(FROM_HERE
,
283 base::Bind(&SynchConfigGetter::CleanUp
, base::Unretained(this)));
287 // Does gconf setup and initial fetch of the proxy config,
288 // all on the calling thread (meant to be the thread with the
289 // default glib main loop, which is the UI thread).
290 void SetupAndInitialFetch() {
291 MessageLoop
* file_loop
= io_thread_
.message_loop();
292 DCHECK_EQ(MessageLoop::TYPE_IO
, file_loop
->type());
293 // We pass the mock IO thread as both the IO and file threads.
294 config_service_
->SetupAndFetchInitialConfig(
295 base::MessageLoopProxy::current(), io_thread_
.message_loop_proxy(),
296 static_cast<MessageLoopForIO
*>(file_loop
));
298 // Synchronously gets the proxy config.
299 net::ProxyConfigService::ConfigAvailability
SyncGetLatestProxyConfig(
300 net::ProxyConfig
* config
) {
301 io_thread_
.message_loop()->PostTask(FROM_HERE
,
302 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 MessageLoop::current()->RunUntilIdle();
334 base::WaitableEvent event_
;
335 base::Thread io_thread_
;
337 net::ProxyConfigServiceLinux
* config_service_
;
339 // The config obtained by |io_thread_| and read back by the main
341 net::ProxyConfig proxy_config_
;
343 // Return value from GetLatestProxyConfig().
344 net::ProxyConfigService::ConfigAvailability get_latest_config_result_
;
349 // This test fixture is only really needed for the KDEConfigParser test case,
350 // but all the test cases with the same prefix ("ProxyConfigServiceLinuxTest")
351 // must use the same test fixture class (also "ProxyConfigServiceLinuxTest").
352 class ProxyConfigServiceLinuxTest
: public PlatformTest
{
354 virtual void SetUp() OVERRIDE
{
355 PlatformTest::SetUp();
356 // Set up a temporary KDE home directory.
357 std::string
prefix("ProxyConfigServiceLinuxTest_user_home");
358 file_util::CreateNewTempDirectory(prefix
, &user_home_
);
359 kde_home_
= user_home_
.Append(FILE_PATH_LITERAL(".kde"));
360 FilePath path
= kde_home_
.Append(FILE_PATH_LITERAL("share"));
361 path
= path
.Append(FILE_PATH_LITERAL("config"));
362 file_util::CreateDirectory(path
);
363 kioslaverc_
= path
.Append(FILE_PATH_LITERAL("kioslaverc"));
364 // Set up paths but do not create the directory for .kde4.
365 kde4_home_
= user_home_
.Append(FILE_PATH_LITERAL(".kde4"));
366 path
= kde4_home_
.Append(FILE_PATH_LITERAL("share"));
367 kde4_config_
= path
.Append(FILE_PATH_LITERAL("config"));
368 kioslaverc4_
= kde4_config_
.Append(FILE_PATH_LITERAL("kioslaverc"));
371 virtual void TearDown() OVERRIDE
{
372 // Delete the temporary KDE home directory.
373 file_util::Delete(user_home_
, true);
374 PlatformTest::TearDown();
380 FilePath kioslaverc_
;
383 FilePath kde4_config_
;
384 FilePath kioslaverc4_
;
387 // Builds an identifier for each test in an array.
388 #define TEST_DESC(desc) base::StringPrintf("at line %d <%s>", __LINE__, desc)
390 TEST_F(ProxyConfigServiceLinuxTest
, BasicGConfTest
) {
391 std::vector
<std::string
> empty_ignores
;
393 std::vector
<std::string
> google_ignores
;
394 google_ignores
.push_back("*.google.com");
396 // Inspired from proxy_config_service_win_unittest.cc.
397 // Very neat, but harder to track down failures though.
399 // Short description to identify the test
400 std::string description
;
405 // Expected outputs (availability and fields of ProxyConfig).
406 ProxyConfigService::ConfigAvailability availability
;
409 ProxyRulesExpectation proxy_rules
;
412 TEST_DESC("No proxying"),
415 "", // autoconfig_url
416 "", "", "", "", // hosts
418 FALSE
, FALSE
, FALSE
, // use, same, auth
419 empty_ignores
, // ignore_hosts
423 ProxyConfigService::CONFIG_VALID
,
424 false, // auto_detect
426 ProxyRulesExpectation::Empty(),
430 TEST_DESC("Auto detect"),
433 "", // autoconfig_url
434 "", "", "", "", // hosts
436 FALSE
, FALSE
, FALSE
, // use, same, auth
437 empty_ignores
, // ignore_hosts
441 ProxyConfigService::CONFIG_VALID
,
444 ProxyRulesExpectation::Empty(),
448 TEST_DESC("Valid PAC URL"),
451 "http://wpad/wpad.dat", // autoconfig_url
452 "", "", "", "", // hosts
454 FALSE
, FALSE
, FALSE
, // use, same, auth
455 empty_ignores
, // ignore_hosts
459 ProxyConfigService::CONFIG_VALID
,
460 false, // auto_detect
461 GURL("http://wpad/wpad.dat"), // pac_url
462 ProxyRulesExpectation::Empty(),
466 TEST_DESC("Invalid PAC URL"),
469 "wpad.dat", // autoconfig_url
470 "", "", "", "", // hosts
472 FALSE
, FALSE
, FALSE
, // use, same, auth
473 empty_ignores
, // ignore_hosts
477 ProxyConfigService::CONFIG_VALID
,
478 false, // auto_detect
480 ProxyRulesExpectation::Empty(),
484 TEST_DESC("Single-host in proxy list"),
487 "", // autoconfig_url
488 "www.google.com", "", "", "", // hosts
489 80, 0, 0, 0, // ports
490 TRUE
, TRUE
, FALSE
, // use, same, auth
491 empty_ignores
, // ignore_hosts
495 ProxyConfigService::CONFIG_VALID
,
496 false, // auto_detect
498 ProxyRulesExpectation::Single(
499 "www.google.com:80", // single proxy
504 TEST_DESC("use_http_proxy is honored"),
507 "", // autoconfig_url
508 "www.google.com", "", "", "", // hosts
509 80, 0, 0, 0, // ports
510 FALSE
, TRUE
, FALSE
, // use, same, auth
511 empty_ignores
, // ignore_hosts
515 ProxyConfigService::CONFIG_VALID
,
516 false, // auto_detect
518 ProxyRulesExpectation::Empty(),
522 TEST_DESC("use_http_proxy and use_same_proxy are optional"),
525 "", // autoconfig_url
526 "www.google.com", "", "", "", // hosts
527 80, 0, 0, 0, // ports
528 UNSET
, UNSET
, FALSE
, // use, same, auth
529 empty_ignores
, // ignore_hosts
533 ProxyConfigService::CONFIG_VALID
,
534 false, // auto_detect
536 ProxyRulesExpectation::PerScheme(
537 "www.google.com:80", // http
544 TEST_DESC("Single-host, different port"),
547 "", // autoconfig_url
548 "www.google.com", "", "", "", // hosts
549 88, 0, 0, 0, // ports
550 TRUE
, TRUE
, FALSE
, // use, same, auth
551 empty_ignores
, // ignore_hosts
555 ProxyConfigService::CONFIG_VALID
,
556 false, // auto_detect
558 ProxyRulesExpectation::Single(
559 "www.google.com:88", // single proxy
564 TEST_DESC("Per-scheme proxy rules"),
567 "", // autoconfig_url
568 "www.google.com", // http_host
569 "www.foo.com", // secure_host
570 "ftp.foo.com", // ftp
572 88, 110, 121, 0, // ports
573 TRUE
, FALSE
, FALSE
, // use, same, auth
574 empty_ignores
, // ignore_hosts
578 ProxyConfigService::CONFIG_VALID
,
579 false, // auto_detect
581 ProxyRulesExpectation::PerScheme(
582 "www.google.com:88", // http
583 "www.foo.com:110", // https
584 "ftp.foo.com:121", // ftp
592 "", // autoconfig_url
593 "", "", "", "socks.com", // hosts
594 0, 0, 0, 99, // ports
595 TRUE
, FALSE
, FALSE
, // use, same, auth
596 empty_ignores
, // ignore_hosts
600 ProxyConfigService::CONFIG_VALID
,
601 false, // auto_detect
603 ProxyRulesExpectation::Single(
604 "socks5://socks.com:99", // single proxy
609 TEST_DESC("Per-scheme proxy rules with fallback to SOCKS"),
612 "", // autoconfig_url
613 "www.google.com", // http_host
614 "www.foo.com", // secure_host
615 "ftp.foo.com", // ftp
616 "foobar.net", // socks
617 88, 110, 121, 99, // ports
618 TRUE
, FALSE
, FALSE
, // use, same, auth
619 empty_ignores
, // ignore_hosts
623 ProxyConfigService::CONFIG_VALID
,
624 false, // auto_detect
626 ProxyRulesExpectation::PerSchemeWithSocks(
627 "www.google.com:88", // http
628 "www.foo.com:110", // https
629 "ftp.foo.com:121", // ftp
630 "socks5://foobar.net:99", // socks
635 TEST_DESC("Per-scheme proxy rules (just HTTP) with fallback to SOCKS"),
638 "", // autoconfig_url
639 "www.google.com", // http_host
642 "foobar.net", // socks
643 88, 0, 0, 99, // ports
644 TRUE
, FALSE
, FALSE
, // use, same, auth
645 empty_ignores
, // ignore_hosts
649 ProxyConfigService::CONFIG_VALID
,
650 false, // auto_detect
652 ProxyRulesExpectation::PerSchemeWithSocks(
653 "www.google.com:88", // http
656 "socks5://foobar.net:99", // socks
661 TEST_DESC("Bypass *.google.com"),
664 "", // autoconfig_url
665 "www.google.com", "", "", "", // hosts
666 80, 0, 0, 0, // ports
667 TRUE
, TRUE
, FALSE
, // use, same, auth
668 google_ignores
, // ignore_hosts
671 ProxyConfigService::CONFIG_VALID
,
672 false, // auto_detect
674 ProxyRulesExpectation::Single(
675 "www.google.com:80", // single proxy
676 "*.google.com"), // bypass rules
680 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
681 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"] %s", i
,
682 tests
[i
].description
.c_str()));
683 MockEnvironment
* env
= new MockEnvironment
;
684 MockSettingGetter
* setting_getter
= new MockSettingGetter
;
685 SynchConfigGetter
sync_config_getter(
686 new ProxyConfigServiceLinux(env
, setting_getter
));
688 setting_getter
->values
= tests
[i
].values
;
689 sync_config_getter
.SetupAndInitialFetch();
690 ProxyConfigService::ConfigAvailability availability
=
691 sync_config_getter
.SyncGetLatestProxyConfig(&config
);
692 EXPECT_EQ(tests
[i
].availability
, availability
);
694 if (availability
== ProxyConfigService::CONFIG_VALID
) {
695 EXPECT_EQ(tests
[i
].auto_detect
, config
.auto_detect());
696 EXPECT_EQ(tests
[i
].pac_url
, config
.pac_url());
697 EXPECT_TRUE(tests
[i
].proxy_rules
.Matches(config
.proxy_rules()));
702 TEST_F(ProxyConfigServiceLinuxTest
, BasicEnvTest
) {
703 // Inspired from proxy_config_service_win_unittest.cc.
705 // Short description to identify the test
706 std::string description
;
711 // Expected outputs (availability and fields of ProxyConfig).
712 ProxyConfigService::ConfigAvailability availability
;
715 ProxyRulesExpectation proxy_rules
;
718 TEST_DESC("No proxying"),
720 NULL
, // DESKTOP_SESSION
723 NULL
, // KDE_SESSION_VERSION
726 NULL
, NULL
, NULL
, // per-proto proxies
732 ProxyConfigService::CONFIG_VALID
,
733 false, // auto_detect
735 ProxyRulesExpectation::Empty(),
739 TEST_DESC("Auto detect"),
741 NULL
, // DESKTOP_SESSION
744 NULL
, // KDE_SESSION_VERSION
747 NULL
, NULL
, NULL
, // per-proto proxies
753 ProxyConfigService::CONFIG_VALID
,
756 ProxyRulesExpectation::Empty(),
760 TEST_DESC("Valid PAC URL"),
762 NULL
, // DESKTOP_SESSION
765 NULL
, // KDE_SESSION_VERSION
766 "http://wpad/wpad.dat", // auto_proxy
768 NULL
, NULL
, NULL
, // per-proto proxies
774 ProxyConfigService::CONFIG_VALID
,
775 false, // auto_detect
776 GURL("http://wpad/wpad.dat"), // pac_url
777 ProxyRulesExpectation::Empty(),
781 TEST_DESC("Invalid PAC URL"),
783 NULL
, // DESKTOP_SESSION
786 NULL
, // KDE_SESSION_VERSION
787 "wpad.dat", // auto_proxy
789 NULL
, NULL
, NULL
, // per-proto proxies
795 ProxyConfigService::CONFIG_VALID
,
796 false, // auto_detect
798 ProxyRulesExpectation::Empty(),
802 TEST_DESC("Single-host in proxy list"),
804 NULL
, // DESKTOP_SESSION
807 NULL
, // KDE_SESSION_VERSION
809 "www.google.com", // all_proxy
810 NULL
, NULL
, NULL
, // per-proto proxies
816 ProxyConfigService::CONFIG_VALID
,
817 false, // auto_detect
819 ProxyRulesExpectation::Single(
820 "www.google.com:80", // single proxy
825 TEST_DESC("Single-host, different port"),
827 NULL
, // DESKTOP_SESSION
830 NULL
, // KDE_SESSION_VERSION
832 "www.google.com:99", // all_proxy
833 NULL
, NULL
, NULL
, // per-proto proxies
839 ProxyConfigService::CONFIG_VALID
,
840 false, // auto_detect
842 ProxyRulesExpectation::Single(
843 "www.google.com:99", // single
848 TEST_DESC("Tolerate a scheme"),
850 NULL
, // DESKTOP_SESSION
853 NULL
, // KDE_SESSION_VERSION
855 "http://www.google.com:99", // all_proxy
856 NULL
, NULL
, NULL
, // per-proto proxies
862 ProxyConfigService::CONFIG_VALID
,
863 false, // auto_detect
865 ProxyRulesExpectation::Single(
866 "www.google.com:99", // single proxy
871 TEST_DESC("Per-scheme proxy rules"),
873 NULL
, // DESKTOP_SESSION
876 NULL
, // KDE_SESSION_VERSION
879 "www.google.com:80", "www.foo.com:110", "ftp.foo.com:121", // per-proto
885 ProxyConfigService::CONFIG_VALID
,
886 false, // auto_detect
888 ProxyRulesExpectation::PerScheme(
889 "www.google.com:80", // http
890 "www.foo.com:110", // https
891 "ftp.foo.com:121", // ftp
898 NULL
, // DESKTOP_SESSION
901 NULL
, // KDE_SESSION_VERSION
904 NULL
, NULL
, NULL
, // per-proto proxies
905 "socks.com:888", NULL
, // SOCKS
910 ProxyConfigService::CONFIG_VALID
,
911 false, // auto_detect
913 ProxyRulesExpectation::Single(
914 "socks5://socks.com:888", // single proxy
921 NULL
, // DESKTOP_SESSION
924 NULL
, // KDE_SESSION_VERSION
927 NULL
, NULL
, NULL
, // per-proto proxies
928 "socks.com:888", "4", // SOCKS
933 ProxyConfigService::CONFIG_VALID
,
934 false, // auto_detect
936 ProxyRulesExpectation::Single(
937 "socks4://socks.com:888", // single proxy
942 TEST_DESC("socks default port"),
944 NULL
, // DESKTOP_SESSION
947 NULL
, // KDE_SESSION_VERSION
950 NULL
, NULL
, NULL
, // per-proto proxies
951 "socks.com", NULL
, // SOCKS
956 ProxyConfigService::CONFIG_VALID
,
957 false, // auto_detect
959 ProxyRulesExpectation::Single(
960 "socks5://socks.com:1080", // single proxy
967 NULL
, // DESKTOP_SESSION
970 NULL
, // KDE_SESSION_VERSION
972 "www.google.com", // all_proxy
973 NULL
, NULL
, NULL
, // per-proto
975 ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8", // no_proxy
979 ProxyConfigService::CONFIG_VALID
,
980 false, // auto_detect
982 ProxyRulesExpectation::Single(
984 "*.google.com,*foo.com:99,1.2.3.4:22,127.0.0.1/8"),
988 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
989 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"] %s", i
,
990 tests
[i
].description
.c_str()));
991 MockEnvironment
* env
= new MockEnvironment
;
992 MockSettingGetter
* setting_getter
= new MockSettingGetter
;
993 SynchConfigGetter
sync_config_getter(
994 new ProxyConfigServiceLinux(env
, setting_getter
));
996 env
->values
= tests
[i
].values
;
997 sync_config_getter
.SetupAndInitialFetch();
998 ProxyConfigService::ConfigAvailability availability
=
999 sync_config_getter
.SyncGetLatestProxyConfig(&config
);
1000 EXPECT_EQ(tests
[i
].availability
, availability
);
1002 if (availability
== ProxyConfigService::CONFIG_VALID
) {
1003 EXPECT_EQ(tests
[i
].auto_detect
, config
.auto_detect());
1004 EXPECT_EQ(tests
[i
].pac_url
, config
.pac_url());
1005 EXPECT_TRUE(tests
[i
].proxy_rules
.Matches(config
.proxy_rules()));
1010 TEST_F(ProxyConfigServiceLinuxTest
, GconfNotification
) {
1011 MockEnvironment
* env
= new MockEnvironment
;
1012 MockSettingGetter
* setting_getter
= new MockSettingGetter
;
1013 ProxyConfigServiceLinux
* service
=
1014 new ProxyConfigServiceLinux(env
, setting_getter
);
1015 SynchConfigGetter
sync_config_getter(service
);
1018 // Start with no proxy.
1019 setting_getter
->values
.mode
= "none";
1020 sync_config_getter
.SetupAndInitialFetch();
1021 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1022 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1023 EXPECT_FALSE(config
.auto_detect());
1025 // Now set to auto-detect.
1026 setting_getter
->values
.mode
= "auto";
1027 // Simulate setting change notification callback.
1028 service
->OnCheckProxyConfigSettings();
1029 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1030 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1031 EXPECT_TRUE(config
.auto_detect());
1034 TEST_F(ProxyConfigServiceLinuxTest
, KDEConfigParser
) {
1035 // One of the tests below needs a worst-case long line prefix. We build it
1036 // programmatically so that it will always be the right size.
1037 std::string long_line
;
1038 size_t limit
= ProxyConfigServiceLinux::SettingGetter::BUFFER_SIZE
- 1;
1039 for (size_t i
= 0; i
< limit
; ++i
)
1042 // Inspired from proxy_config_service_win_unittest.cc.
1044 // Short description to identify the test
1045 std::string description
;
1048 std::string kioslaverc
;
1049 EnvVarValues env_values
;
1051 // Expected outputs (availability and fields of ProxyConfig).
1052 ProxyConfigService::ConfigAvailability availability
;
1055 ProxyRulesExpectation proxy_rules
;
1058 TEST_DESC("No proxying"),
1061 "[Proxy Settings]\nProxyType=0\n",
1065 ProxyConfigService::CONFIG_VALID
,
1066 false, // auto_detect
1068 ProxyRulesExpectation::Empty(),
1072 TEST_DESC("Auto detect"),
1075 "[Proxy Settings]\nProxyType=3\n",
1079 ProxyConfigService::CONFIG_VALID
,
1080 true, // auto_detect
1082 ProxyRulesExpectation::Empty(),
1086 TEST_DESC("Valid PAC URL"),
1089 "[Proxy Settings]\nProxyType=2\n"
1090 "Proxy Config Script=http://wpad/wpad.dat\n",
1094 ProxyConfigService::CONFIG_VALID
,
1095 false, // auto_detect
1096 GURL("http://wpad/wpad.dat"), // pac_url
1097 ProxyRulesExpectation::Empty(),
1101 TEST_DESC("Valid PAC file without file://"),
1104 "[Proxy Settings]\nProxyType=2\n"
1105 "Proxy Config Script=/wpad/wpad.dat\n",
1109 ProxyConfigService::CONFIG_VALID
,
1110 false, // auto_detect
1111 GURL("file:///wpad/wpad.dat"), // pac_url
1112 ProxyRulesExpectation::Empty(),
1116 TEST_DESC("Per-scheme proxy rules"),
1119 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1120 "httpsProxy=www.foo.com\nftpProxy=ftp.foo.com\n",
1124 ProxyConfigService::CONFIG_VALID
,
1125 false, // auto_detect
1127 ProxyRulesExpectation::PerScheme(
1128 "www.google.com:80", // http
1129 "www.foo.com:80", // https
1130 "ftp.foo.com:80", // http
1131 ""), // bypass rules
1135 TEST_DESC("Only HTTP proxy specified"),
1138 "[Proxy Settings]\nProxyType=1\n"
1139 "httpProxy=www.google.com\n",
1143 ProxyConfigService::CONFIG_VALID
,
1144 false, // auto_detect
1146 ProxyRulesExpectation::PerScheme(
1147 "www.google.com:80", // http
1150 ""), // bypass rules
1154 TEST_DESC("Only HTTP proxy specified, different port"),
1157 "[Proxy Settings]\nProxyType=1\n"
1158 "httpProxy=www.google.com:88\n",
1162 ProxyConfigService::CONFIG_VALID
,
1163 false, // auto_detect
1165 ProxyRulesExpectation::PerScheme(
1166 "www.google.com:88", // http
1169 ""), // bypass rules
1173 TEST_DESC("Only HTTP proxy specified, different port, space-delimited"),
1176 "[Proxy Settings]\nProxyType=1\n"
1177 "httpProxy=www.google.com 88\n",
1181 ProxyConfigService::CONFIG_VALID
,
1182 false, // auto_detect
1184 ProxyRulesExpectation::PerScheme(
1185 "www.google.com:88", // http
1188 ""), // bypass rules
1192 TEST_DESC("Bypass *.google.com"),
1195 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1196 "NoProxyFor=.google.com\n",
1200 ProxyConfigService::CONFIG_VALID
,
1201 false, // auto_detect
1203 ProxyRulesExpectation::PerScheme(
1204 "www.google.com:80", // http
1207 "*.google.com"), // bypass rules
1211 TEST_DESC("Bypass *.google.com and *.kde.org"),
1214 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1215 "NoProxyFor=.google.com,.kde.org\n",
1219 ProxyConfigService::CONFIG_VALID
,
1220 false, // auto_detect
1222 ProxyRulesExpectation::PerScheme(
1223 "www.google.com:80", // http
1226 "*.google.com,*.kde.org"), // bypass rules
1230 TEST_DESC("Correctly parse bypass list with ReversedException"),
1233 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1234 "NoProxyFor=.google.com\nReversedException=true\n",
1238 ProxyConfigService::CONFIG_VALID
,
1239 false, // auto_detect
1241 ProxyRulesExpectation::PerSchemeWithBypassReversed(
1242 "www.google.com:80", // http
1245 "*.google.com"), // bypass rules
1252 "[Proxy Settings]\nProxyType=1\nsocksProxy=socks.com 888\n",
1256 ProxyConfigService::CONFIG_VALID
,
1257 false, // auto_detect
1259 ProxyRulesExpectation::Single(
1260 "socks5://socks.com:888", // single proxy
1261 ""), // bypass rules
1265 TEST_DESC("socks4"),
1268 "[Proxy Settings]\nProxyType=1\nsocksProxy=socks4://socks.com 888\n",
1272 ProxyConfigService::CONFIG_VALID
,
1273 false, // auto_detect
1275 ProxyRulesExpectation::Single(
1276 "socks4://socks.com:888", // single proxy
1277 ""), // bypass rules
1281 TEST_DESC("Treat all hostname patterns as wildcard patterns"),
1284 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1285 "NoProxyFor=google.com,kde.org,<local>\n",
1289 ProxyConfigService::CONFIG_VALID
,
1290 false, // auto_detect
1292 ProxyRulesExpectation::PerScheme(
1293 "www.google.com:80", // http
1296 "*google.com,*kde.org,<local>"), // bypass rules
1300 TEST_DESC("Allow trailing whitespace after boolean value"),
1303 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1304 "NoProxyFor=.google.com\nReversedException=true \n",
1308 ProxyConfigService::CONFIG_VALID
,
1309 false, // auto_detect
1311 ProxyRulesExpectation::PerSchemeWithBypassReversed(
1312 "www.google.com:80", // http
1315 "*.google.com"), // bypass rules
1319 TEST_DESC("Ignore settings outside [Proxy Settings]"),
1322 "httpsProxy=www.foo.com\n[Proxy Settings]\nProxyType=1\n"
1323 "httpProxy=www.google.com\n[Other Section]\nftpProxy=ftp.foo.com\n",
1327 ProxyConfigService::CONFIG_VALID
,
1328 false, // auto_detect
1330 ProxyRulesExpectation::PerScheme(
1331 "www.google.com:80", // http
1334 ""), // bypass rules
1338 TEST_DESC("Handle CRLF line endings"),
1341 "[Proxy Settings]\r\nProxyType=1\r\nhttpProxy=www.google.com\r\n",
1345 ProxyConfigService::CONFIG_VALID
,
1346 false, // auto_detect
1348 ProxyRulesExpectation::PerScheme(
1349 "www.google.com:80", // http
1352 ""), // bypass rules
1356 TEST_DESC("Handle blank lines and mixed line endings"),
1359 "[Proxy Settings]\r\n\nProxyType=1\n\r\nhttpProxy=www.google.com\n\n",
1363 ProxyConfigService::CONFIG_VALID
,
1364 false, // auto_detect
1366 ProxyRulesExpectation::PerScheme(
1367 "www.google.com:80", // http
1370 ""), // bypass rules
1374 TEST_DESC("Handle localized settings"),
1377 "[Proxy Settings]\nProxyType[$e]=1\nhttpProxy[$e]=www.google.com\n",
1381 ProxyConfigService::CONFIG_VALID
,
1382 false, // auto_detect
1384 ProxyRulesExpectation::PerScheme(
1385 "www.google.com:80", // http
1388 ""), // bypass rules
1392 TEST_DESC("Ignore malformed localized settings"),
1395 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1396 "httpsProxy$e]=www.foo.com\nftpProxy=ftp.foo.com\n",
1400 ProxyConfigService::CONFIG_VALID
,
1401 false, // auto_detect
1403 ProxyRulesExpectation::PerScheme(
1404 "www.google.com:80", // http
1406 "ftp.foo.com:80", // ftp
1407 ""), // bypass rules
1411 TEST_DESC("Handle strange whitespace"),
1414 "[Proxy Settings]\nProxyType [$e] =2\n"
1415 " Proxy Config Script = http:// foo\n",
1419 ProxyConfigService::CONFIG_VALID
,
1420 false, // auto_detect
1421 GURL("http:// foo"), // pac_url
1422 ProxyRulesExpectation::Empty(),
1426 TEST_DESC("Ignore all of a line which is too long"),
1429 std::string("[Proxy Settings]\nProxyType=1\nftpProxy=ftp.foo.com\n") +
1430 long_line
+ "httpsProxy=www.foo.com\nhttpProxy=www.google.com\n",
1434 ProxyConfigService::CONFIG_VALID
,
1435 false, // auto_detect
1437 ProxyRulesExpectation::PerScheme(
1438 "www.google.com:80", // http
1440 "ftp.foo.com:80", // ftp
1441 ""), // bypass rules
1445 TEST_DESC("Indirect Proxy - no env vars set"),
1448 "[Proxy Settings]\nProxyType=4\nhttpProxy=http_proxy\n"
1449 "httpsProxy=https_proxy\nftpProxy=ftp_proxy\nNoProxyFor=no_proxy\n",
1453 ProxyConfigService::CONFIG_VALID
,
1454 false, // auto_detect
1456 ProxyRulesExpectation::Empty(),
1460 TEST_DESC("Indirect Proxy - with env vars set"),
1463 "[Proxy Settings]\nProxyType=4\nhttpProxy=http_proxy\n"
1464 "httpsProxy=https_proxy\nftpProxy=ftp_proxy\nNoProxyFor=no_proxy\n",
1466 NULL
, // DESKTOP_SESSION
1469 NULL
, // KDE_SESSION_VERSION
1472 "www.normal.com", // http_proxy
1473 "www.secure.com", // https_proxy
1474 "ftp.foo.com", // ftp_proxy
1475 NULL
, NULL
, // SOCKS
1476 ".google.com, .kde.org", // no_proxy
1480 ProxyConfigService::CONFIG_VALID
,
1481 false, // auto_detect
1483 ProxyRulesExpectation::PerScheme(
1484 "www.normal.com:80", // http
1485 "www.secure.com:80", // https
1486 "ftp.foo.com:80", // ftp
1487 "*.google.com,*.kde.org"), // bypass rules
1492 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
1493 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"] %s", i
,
1494 tests
[i
].description
.c_str()));
1495 MockEnvironment
* env
= new MockEnvironment
;
1496 env
->values
= tests
[i
].env_values
;
1497 // Force the KDE getter to be used and tell it where the test is.
1498 env
->values
.DESKTOP_SESSION
= "kde4";
1499 env
->values
.KDEHOME
= kde_home_
.value().c_str();
1500 SynchConfigGetter
sync_config_getter(
1501 new ProxyConfigServiceLinux(env
));
1503 // Overwrite the kioslaverc file.
1504 file_util::WriteFile(kioslaverc_
, tests
[i
].kioslaverc
.c_str(),
1505 tests
[i
].kioslaverc
.length());
1506 sync_config_getter
.SetupAndInitialFetch();
1507 ProxyConfigService::ConfigAvailability availability
=
1508 sync_config_getter
.SyncGetLatestProxyConfig(&config
);
1509 EXPECT_EQ(tests
[i
].availability
, availability
);
1511 if (availability
== ProxyConfigService::CONFIG_VALID
) {
1512 EXPECT_EQ(tests
[i
].auto_detect
, config
.auto_detect());
1513 EXPECT_EQ(tests
[i
].pac_url
, config
.pac_url());
1514 EXPECT_TRUE(tests
[i
].proxy_rules
.Matches(config
.proxy_rules()));
1519 TEST_F(ProxyConfigServiceLinuxTest
, KDEHomePicker
) {
1520 // Auto detect proxy settings.
1521 std::string slaverc3
= "[Proxy Settings]\nProxyType=3\n";
1523 std::string slaverc4
= "[Proxy Settings]\nProxyType=2\n"
1524 "Proxy Config Script=http://wpad/wpad.dat\n";
1525 GURL
slaverc4_pac_url("http://wpad/wpad.dat");
1527 // Overwrite the .kde kioslaverc file.
1528 file_util::WriteFile(kioslaverc_
, slaverc3
.c_str(), slaverc3
.length());
1530 // If .kde4 exists it will mess up the first test. It should not, as
1531 // we created the directory for $HOME in the test setup.
1532 CHECK(!file_util::DirectoryExists(kde4_home_
));
1534 { SCOPED_TRACE("KDE4, no .kde4 directory, verify fallback");
1535 MockEnvironment
* env
= new MockEnvironment
;
1536 env
->values
.DESKTOP_SESSION
= "kde4";
1537 env
->values
.HOME
= user_home_
.value().c_str();
1538 SynchConfigGetter
sync_config_getter(
1539 new ProxyConfigServiceLinux(env
));
1541 sync_config_getter
.SetupAndInitialFetch();
1542 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1543 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1544 EXPECT_TRUE(config
.auto_detect());
1545 EXPECT_EQ(GURL(), config
.pac_url());
1548 // Now create .kde4 and put a kioslaverc in the config directory.
1549 // Note that its timestamp will be at least as new as the .kde one.
1550 file_util::CreateDirectory(kde4_config_
);
1551 file_util::WriteFile(kioslaverc4_
, slaverc4
.c_str(), slaverc4
.length());
1552 CHECK(file_util::PathExists(kioslaverc4_
));
1554 { SCOPED_TRACE("KDE4, .kde4 directory present, use it");
1555 MockEnvironment
* env
= new MockEnvironment
;
1556 env
->values
.DESKTOP_SESSION
= "kde4";
1557 env
->values
.HOME
= user_home_
.value().c_str();
1558 SynchConfigGetter
sync_config_getter(
1559 new ProxyConfigServiceLinux(env
));
1561 sync_config_getter
.SetupAndInitialFetch();
1562 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1563 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1564 EXPECT_FALSE(config
.auto_detect());
1565 EXPECT_EQ(slaverc4_pac_url
, config
.pac_url());
1568 { SCOPED_TRACE("KDE3, .kde4 directory present, ignore it");
1569 MockEnvironment
* env
= new MockEnvironment
;
1570 env
->values
.DESKTOP_SESSION
= "kde";
1571 env
->values
.HOME
= user_home_
.value().c_str();
1572 SynchConfigGetter
sync_config_getter(
1573 new ProxyConfigServiceLinux(env
));
1575 sync_config_getter
.SetupAndInitialFetch();
1576 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1577 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1578 EXPECT_TRUE(config
.auto_detect());
1579 EXPECT_EQ(GURL(), config
.pac_url());
1582 { SCOPED_TRACE("KDE4, .kde4 directory present, KDEHOME set to .kde");
1583 MockEnvironment
* env
= new MockEnvironment
;
1584 env
->values
.DESKTOP_SESSION
= "kde4";
1585 env
->values
.HOME
= user_home_
.value().c_str();
1586 env
->values
.KDEHOME
= kde_home_
.value().c_str();
1587 SynchConfigGetter
sync_config_getter(
1588 new ProxyConfigServiceLinux(env
));
1590 sync_config_getter
.SetupAndInitialFetch();
1591 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1592 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1593 EXPECT_TRUE(config
.auto_detect());
1594 EXPECT_EQ(GURL(), config
.pac_url());
1597 // Finally, make the .kde4 config directory older than the .kde directory
1598 // and make sure we then use .kde instead of .kde4 since it's newer.
1599 file_util::SetLastModifiedTime(kde4_config_
, base::Time());
1601 { SCOPED_TRACE("KDE4, very old .kde4 directory present, use .kde");
1602 MockEnvironment
* env
= new MockEnvironment
;
1603 env
->values
.DESKTOP_SESSION
= "kde4";
1604 env
->values
.HOME
= user_home_
.value().c_str();
1605 SynchConfigGetter
sync_config_getter(
1606 new ProxyConfigServiceLinux(env
));
1608 sync_config_getter
.SetupAndInitialFetch();
1609 EXPECT_EQ(ProxyConfigService::CONFIG_VALID
,
1610 sync_config_getter
.SyncGetLatestProxyConfig(&config
));
1611 EXPECT_TRUE(config
.auto_detect());
1612 EXPECT_EQ(GURL(), config
.pac_url());