OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <map> | 5 #include <map> |
6 #include <string> | 6 #include <string> |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "net/proxy/proxy_config_service_linux.h" | 9 #include "net/proxy/proxy_config_service_linux.h" |
10 | 10 |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 13 #include "base/task.h" |
| 14 #include "base/thread.h" |
| 15 #include "base/waitable_event.h" |
13 #include "net/proxy/proxy_config.h" | 16 #include "net/proxy/proxy_config.h" |
14 #include "net/proxy/proxy_config_service_common_unittest.h" | 17 #include "net/proxy/proxy_config_service_common_unittest.h" |
15 | 18 |
16 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
17 | 20 |
18 namespace net { | 21 namespace net { |
19 | |
20 namespace { | 22 namespace { |
21 | 23 |
22 // Set of values for all environment variables that we might | 24 // Set of values for all environment variables that we might |
23 // query. NULL represents an unset variable. | 25 // query. NULL represents an unset variable. |
24 struct EnvVarValues { | 26 struct EnvVarValues { |
25 // The strange capitalization is so that the field matches the | 27 // The strange capitalization is so that the field matches the |
26 // environment variable name exactly. | 28 // environment variable name exactly. |
27 const char *GNOME_DESKTOP_SESSION_ID, *DESKTOP_SESSION, | 29 const char *GNOME_DESKTOP_SESSION_ID, *DESKTOP_SESSION, |
28 *auto_proxy, *all_proxy, | 30 *auto_proxy, *all_proxy, |
29 *http_proxy, *https_proxy, *ftp_proxy, | 31 *http_proxy, *https_proxy, *ftp_proxy, |
30 *SOCKS_SERVER, *SOCKS_VERSION, | 32 *SOCKS_SERVER, *SOCKS_VERSION, |
31 *no_proxy; | 33 *no_proxy; |
32 }; | 34 }; |
33 | 35 |
| 36 // Undo macro pollution from GDK includes (from message_loop.h). |
| 37 #undef TRUE |
| 38 #undef FALSE |
| 39 |
34 // So as to distinguish between an unset gconf boolean variable and | 40 // So as to distinguish between an unset gconf boolean variable and |
35 // one that is false. | 41 // one that is false. |
36 enum BoolSettingValue { | 42 enum BoolSettingValue { |
37 UNSET = 0, TRUE, FALSE | 43 UNSET = 0, TRUE, FALSE |
38 }; | 44 }; |
39 | 45 |
40 // Set of values for all gconf settings that we might query. | 46 // Set of values for all gconf settings that we might query. |
41 struct GConfValues { | 47 struct GConfValues { |
42 // strings | 48 // strings |
43 const char *mode, *autoconfig_url, | 49 const char *mode, *autoconfig_url, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 ENTRY(DESKTOP_SESSION); | 83 ENTRY(DESKTOP_SESSION); |
78 ENTRY(auto_proxy); | 84 ENTRY(auto_proxy); |
79 ENTRY(all_proxy); | 85 ENTRY(all_proxy); |
80 ENTRY(http_proxy); | 86 ENTRY(http_proxy); |
81 ENTRY(https_proxy); | 87 ENTRY(https_proxy); |
82 ENTRY(ftp_proxy); | 88 ENTRY(ftp_proxy); |
83 ENTRY(no_proxy); | 89 ENTRY(no_proxy); |
84 ENTRY(SOCKS_SERVER); | 90 ENTRY(SOCKS_SERVER); |
85 ENTRY(SOCKS_VERSION); | 91 ENTRY(SOCKS_VERSION); |
86 #undef ENTRY | 92 #undef ENTRY |
87 reset(); | 93 Reset(); |
88 } | 94 } |
89 | 95 |
90 // Zeros all environment values. | 96 // Zeros all environment values. |
91 void reset() { | 97 void Reset() { |
92 EnvVarValues zero_values = { 0 }; | 98 EnvVarValues zero_values = { 0 }; |
93 values = zero_values; | 99 values = zero_values; |
94 } | 100 } |
95 | 101 |
96 virtual bool Getenv(const char* variable_name, std::string* result) { | 102 virtual bool Getenv(const char* variable_name, std::string* result) { |
97 const char* env_value = table.Get(variable_name); | 103 const char* env_value = table.Get(variable_name); |
98 if (env_value) { | 104 if (env_value) { |
99 // Note that the variable may be defined but empty. | 105 // Note that the variable may be defined but empty. |
100 *result = env_value; | 106 *result = env_value; |
101 return true; | 107 return true; |
(...skipping 29 matching lines...) Expand all Loading... |
131 ENTRY("proxy/socks_port", socks_port); | 137 ENTRY("proxy/socks_port", socks_port); |
132 #undef ENTRY | 138 #undef ENTRY |
133 #define ENTRY(key, field) \ | 139 #define ENTRY(key, field) \ |
134 bools_table.settings["/system/" key] = &values.field | 140 bools_table.settings["/system/" key] = &values.field |
135 ENTRY("http_proxy/use_http_proxy", use_proxy); | 141 ENTRY("http_proxy/use_http_proxy", use_proxy); |
136 ENTRY("http_proxy/use_same_proxy", same_proxy); | 142 ENTRY("http_proxy/use_same_proxy", same_proxy); |
137 ENTRY("http_proxy/use_authentication", use_auth); | 143 ENTRY("http_proxy/use_authentication", use_auth); |
138 #undef ENTRY | 144 #undef ENTRY |
139 string_lists_table.settings["/system/http_proxy/ignore_hosts"] = | 145 string_lists_table.settings["/system/http_proxy/ignore_hosts"] = |
140 &values.ignore_hosts; | 146 &values.ignore_hosts; |
141 reset(); | 147 Reset(); |
142 } | 148 } |
143 | 149 |
144 // Zeros all environment values. | 150 // Zeros all environment values. |
145 void reset() { | 151 void Reset() { |
146 GConfValues zero_values; | 152 GConfValues zero_values = { 0 }; |
147 values = zero_values; | 153 values = zero_values; |
148 } | 154 } |
149 | 155 |
150 virtual void Enter() {} | 156 virtual bool Init() { |
151 virtual void Leave() {} | |
152 | |
153 virtual bool InitIfNeeded() { | |
154 return true; | 157 return true; |
155 } | 158 } |
156 | 159 |
| 160 virtual void Release() {} |
| 161 |
| 162 virtual bool SetupNotification(void* callback_user_data) { |
| 163 return true; |
| 164 } |
| 165 |
157 virtual bool GetString(const char* key, std::string* result) { | 166 virtual bool GetString(const char* key, std::string* result) { |
158 const char* value = strings_table.Get(key); | 167 const char* value = strings_table.Get(key); |
159 if (value) { | 168 if (value) { |
160 *result = value; | 169 *result = value; |
161 return true; | 170 return true; |
162 } | 171 } |
163 return false; | 172 return false; |
164 } | 173 } |
165 | 174 |
166 virtual bool GetInt(const char* key, int* result) { | 175 virtual bool GetInt(const char* key, int* result) { |
(...skipping 27 matching lines...) Expand all Loading... |
194 GConfValues values; | 203 GConfValues values; |
195 | 204 |
196 private: | 205 private: |
197 SettingsTable<const char*> strings_table; | 206 SettingsTable<const char*> strings_table; |
198 SettingsTable<int> ints_table; | 207 SettingsTable<int> ints_table; |
199 SettingsTable<BoolSettingValue> bools_table; | 208 SettingsTable<BoolSettingValue> bools_table; |
200 SettingsTable<std::vector<std::string> > string_lists_table; | 209 SettingsTable<std::vector<std::string> > string_lists_table; |
201 }; | 210 }; |
202 | 211 |
203 } // namespace | 212 } // namespace |
| 213 } // namespace net |
| 214 |
| 215 // This helper class runs ProxyConfigServiceLinux::GetProxyConfig() on |
| 216 // the IO thread and synchronously waits for the result. |
| 217 // Some code duplicated from proxy_script_fetcher_unittest.cc. |
| 218 class SynchConfigGetter { |
| 219 public: |
| 220 explicit SynchConfigGetter(net::ProxyConfigServiceLinux* config_service) |
| 221 : event_(false, false), |
| 222 io_thread_("IO_Thread"), |
| 223 config_service_(config_service) { |
| 224 // Start an IO thread. |
| 225 base::Thread::Options options; |
| 226 options.message_loop_type = MessageLoop::TYPE_IO; |
| 227 io_thread_.StartWithOptions(options); |
| 228 |
| 229 // Make sure the thread started. |
| 230 io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( |
| 231 this, &SynchConfigGetter::Init)); |
| 232 Wait(); |
| 233 } |
| 234 |
| 235 ~SynchConfigGetter() { |
| 236 // Cleanup the IO thread. |
| 237 io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( |
| 238 this, &SynchConfigGetter::Cleanup)); |
| 239 Wait(); |
| 240 } |
| 241 |
| 242 // Does a reset, gconf setup and initial fetch of the proxy config, |
| 243 // all on the calling thread (meant to be the thread with the |
| 244 // default glib main loop, which is the UI thread). |
| 245 void SetupAndInitialFetch() { |
| 246 config_service_->Reset(); |
| 247 config_service_->SetupAndFetchInitialConfig( |
| 248 MessageLoop::current(), io_thread_.message_loop()); |
| 249 } |
| 250 // Synchronously gets the proxy config. |
| 251 int SyncGetProxyConfig(net::ProxyConfig* config) { |
| 252 io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( |
| 253 this, &SynchConfigGetter::GetConfigOnIOThread)); |
| 254 Wait(); |
| 255 *config = proxy_config_; |
| 256 return get_config_result_; |
| 257 } |
| 258 |
| 259 private: |
| 260 // [Runs on |io_thread_|] |
| 261 void Init() { |
| 262 event_.Signal(); |
| 263 } |
| 264 |
| 265 // Calls GetProxyConfig, running on |io_thread_|] Signals |event_| |
| 266 // on completion. |
| 267 void GetConfigOnIOThread() { |
| 268 get_config_result_ = config_service_->GetProxyConfig(&proxy_config_); |
| 269 event_.Signal(); |
| 270 } |
| 271 |
| 272 // [Runs on |io_thread_|] Signals |event_| on cleanup completion. |
| 273 void Cleanup() { |
| 274 MessageLoop::current()->RunAllPending(); |
| 275 event_.Signal(); |
| 276 } |
| 277 |
| 278 void Wait() { |
| 279 event_.Wait(); |
| 280 event_.Reset(); |
| 281 } |
| 282 |
| 283 base::WaitableEvent event_; |
| 284 base::Thread io_thread_; |
| 285 |
| 286 net::ProxyConfigServiceLinux* config_service_; |
| 287 |
| 288 // The config obtained by |io_thread_| and read back by the main |
| 289 // thread. |
| 290 net::ProxyConfig proxy_config_; |
| 291 int get_config_result_; // Return value from GetProxyConfig(). |
| 292 }; |
| 293 |
| 294 template<> |
| 295 void RunnableMethodTraits<SynchConfigGetter>::RetainCallee( |
| 296 SynchConfigGetter* remover) {} |
| 297 template<> |
| 298 void RunnableMethodTraits<SynchConfigGetter>::ReleaseCallee( |
| 299 SynchConfigGetter* remover) {} |
| 300 |
| 301 namespace net { |
204 | 302 |
205 // Builds an identifier for each test in an array. | 303 // Builds an identifier for each test in an array. |
206 #define TEST_DESC(desc) StringPrintf("at line %d <%s>", __LINE__, desc) | 304 #define TEST_DESC(desc) StringPrintf("at line %d <%s>", __LINE__, desc) |
207 | 305 |
208 #if 0 // gconf temporarily disabled. | |
209 TEST(ProxyConfigServiceLinuxTest, BasicGConfTest) { | 306 TEST(ProxyConfigServiceLinuxTest, BasicGConfTest) { |
210 MockEnvironmentVariableGetter* env_getter = | 307 MockEnvironmentVariableGetter* env_getter = |
211 new MockEnvironmentVariableGetter; | 308 new MockEnvironmentVariableGetter; |
212 MockGConfSettingGetter* gconf_getter = new MockGConfSettingGetter; | 309 MockGConfSettingGetter* gconf_getter = new MockGConfSettingGetter; |
213 ProxyConfigServiceLinux service(env_getter, gconf_getter); | 310 ProxyConfigServiceLinux service(env_getter, gconf_getter); |
214 // This env var indicates we are running Gnome and should consult gconf. | 311 // This env var indicates we are running Gnome and should consult gconf. |
215 env_getter->values.GNOME_DESKTOP_SESSION_ID = "defined"; | 312 env_getter->values.GNOME_DESKTOP_SESSION_ID = "defined"; |
216 | 313 |
217 std::vector<std::string> empty_ignores; | 314 std::vector<std::string> empty_ignores; |
218 | 315 |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 }, | 540 }, |
444 | 541 |
445 false, // auto_detect | 542 false, // auto_detect |
446 GURL(), // pac_url | 543 GURL(), // pac_url |
447 MakeSingleProxyRules("www.google.com"), // proxy_rules | 544 MakeSingleProxyRules("www.google.com"), // proxy_rules |
448 "*.google.com\n", // proxy_bypass_list | 545 "*.google.com\n", // proxy_bypass_list |
449 false, // bypass_local_names | 546 false, // bypass_local_names |
450 }, | 547 }, |
451 }; | 548 }; |
452 | 549 |
| 550 SynchConfigGetter sync_config_getter(&service); |
| 551 |
453 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { | 552 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { |
454 SCOPED_TRACE(StringPrintf("Test[%d] %s", i, tests[i].description.c_str())); | 553 SCOPED_TRACE(StringPrintf("Test[%d] %s", i, tests[i].description.c_str())); |
455 ProxyConfig config; | 554 ProxyConfig config; |
456 gconf_getter->values = tests[i].values; | 555 gconf_getter->values = tests[i].values; |
457 service.GetProxyConfig(&config); | 556 sync_config_getter.SetupAndInitialFetch(); |
| 557 sync_config_getter.SyncGetProxyConfig(&config); |
458 | 558 |
459 // TODO(sdoyon): Add a description field to each test, and a | |
460 // corresponding message to the EXPECT statements, so that it is | |
461 // possible to identify which one of the tests failed. | |
462 EXPECT_EQ(tests[i].auto_detect, config.auto_detect); | 559 EXPECT_EQ(tests[i].auto_detect, config.auto_detect); |
463 EXPECT_EQ(tests[i].pac_url, config.pac_url); | 560 EXPECT_EQ(tests[i].pac_url, config.pac_url); |
464 EXPECT_EQ(tests[i].proxy_bypass_list, | 561 EXPECT_EQ(tests[i].proxy_bypass_list, |
465 FlattenProxyBypass(config.proxy_bypass)); | 562 FlattenProxyBypass(config.proxy_bypass)); |
466 EXPECT_EQ(tests[i].bypass_local_names, config.proxy_bypass_local_names); | 563 EXPECT_EQ(tests[i].bypass_local_names, config.proxy_bypass_local_names); |
467 EXPECT_EQ(tests[i].proxy_rules, config.proxy_rules); | 564 EXPECT_EQ(tests[i].proxy_rules, config.proxy_rules); |
468 } | 565 } |
469 } | 566 } |
470 #endif // 0 (gconf disabled) | |
471 | 567 |
472 TEST(ProxyConfigServiceLinuxTest, BasicEnvTest) { | 568 TEST(ProxyConfigServiceLinuxTest, BasicEnvTest) { |
473 MockEnvironmentVariableGetter* env_getter = | 569 MockEnvironmentVariableGetter* env_getter = |
474 new MockEnvironmentVariableGetter; | 570 new MockEnvironmentVariableGetter; |
475 MockGConfSettingGetter* gconf_getter = new MockGConfSettingGetter; | 571 MockGConfSettingGetter* gconf_getter = new MockGConfSettingGetter; |
476 ProxyConfigServiceLinux service(env_getter, gconf_getter); | 572 ProxyConfigServiceLinux service(env_getter, gconf_getter); |
477 | 573 |
478 // Inspired from proxy_config_service_win_unittest.cc. | 574 // Inspired from proxy_config_service_win_unittest.cc. |
479 const struct { | 575 const struct { |
480 // Short description to identify the test | 576 // Short description to identify the test |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
713 | 809 |
714 false, // auto_detect | 810 false, // auto_detect |
715 GURL(), // pac_url | 811 GURL(), // pac_url |
716 MakeSingleProxyRules("www.google.com"), // proxy_rules | 812 MakeSingleProxyRules("www.google.com"), // proxy_rules |
717 // proxy_bypass_list | 813 // proxy_bypass_list |
718 "*.google.com\n*foo.com:99\n1.2.3.4:22\n127.0.0.1/8\n", | 814 "*.google.com\n*foo.com:99\n1.2.3.4:22\n127.0.0.1/8\n", |
719 false, // bypass_local_names | 815 false, // bypass_local_names |
720 }, | 816 }, |
721 }; | 817 }; |
722 | 818 |
| 819 SynchConfigGetter sync_config_getter(&service); |
| 820 |
723 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { | 821 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { |
724 SCOPED_TRACE(StringPrintf("Test[%d] %s", i, tests[i].description.c_str())); | 822 SCOPED_TRACE(StringPrintf("Test[%d] %s", i, tests[i].description.c_str())); |
725 ProxyConfig config; | 823 ProxyConfig config; |
726 env_getter->values = tests[i].values; | 824 env_getter->values = tests[i].values; |
727 service.GetProxyConfig(&config); | 825 sync_config_getter.SetupAndInitialFetch(); |
| 826 sync_config_getter.SyncGetProxyConfig(&config); |
728 | 827 |
729 EXPECT_EQ(tests[i].auto_detect, config.auto_detect); | 828 EXPECT_EQ(tests[i].auto_detect, config.auto_detect); |
730 EXPECT_EQ(tests[i].pac_url, config.pac_url); | 829 EXPECT_EQ(tests[i].pac_url, config.pac_url); |
731 EXPECT_EQ(tests[i].proxy_bypass_list, | 830 EXPECT_EQ(tests[i].proxy_bypass_list, |
732 FlattenProxyBypass(config.proxy_bypass)); | 831 FlattenProxyBypass(config.proxy_bypass)); |
733 EXPECT_EQ(tests[i].bypass_local_names, config.proxy_bypass_local_names); | 832 EXPECT_EQ(tests[i].bypass_local_names, config.proxy_bypass_local_names); |
734 EXPECT_EQ(tests[i].proxy_rules, config.proxy_rules); | 833 EXPECT_EQ(tests[i].proxy_rules, config.proxy_rules); |
735 } | 834 } |
736 } | 835 } |
737 | 836 |
738 // Verify that we fall back on consulting the environment when | 837 // Verify that we fall back on consulting the environment when |
739 // GNOME-specific environment variables aren't available. | 838 // GNOME-specific environment variables aren't available. |
740 TEST(ProxyConfigServiceLinuxTest, FallbackOnEnv) { | 839 TEST(ProxyConfigServiceLinuxTest, FallbackOnEnv) { |
741 MockEnvironmentVariableGetter* env_getter = | 840 MockEnvironmentVariableGetter* env_getter = |
742 new MockEnvironmentVariableGetter; | 841 new MockEnvironmentVariableGetter; |
743 MockGConfSettingGetter* gconf_getter = new MockGConfSettingGetter; | 842 MockGConfSettingGetter* gconf_getter = new MockGConfSettingGetter; |
744 ProxyConfigServiceLinux service(env_getter, gconf_getter); | 843 ProxyConfigServiceLinux service(env_getter, gconf_getter); |
745 | 844 |
746 // Imagine we're: | 845 // Imagine we're: |
747 // 1) Running a non-GNOME desktop session: | 846 // 1) Running a non-GNOME desktop session: |
748 env_getter->values.DESKTOP_SESSION = "default"; | 847 env_getter->values.DESKTOP_SESSION = "default"; |
749 // 2) Have settings in gconf. | 848 // 2) Have settings in gconf. |
750 gconf_getter->values.mode = "auto"; | 849 gconf_getter->values.mode = "auto"; |
751 gconf_getter->values.autoconfig_url = "http://incorrect/wpad.dat"; | 850 gconf_getter->values.autoconfig_url = "http://incorrect/wpad.dat"; |
752 // 3) But we have a proxy-specifying environment variable set: | 851 // 3) But we have a proxy-specifying environment variable set: |
753 env_getter->values.auto_proxy = "http://correct/wpad.dat"; | 852 env_getter->values.auto_proxy = "http://correct/wpad.dat"; |
754 | 853 |
755 ProxyConfig config; | 854 ProxyConfig config; |
756 service.GetProxyConfig(&config); | 855 |
| 856 SynchConfigGetter sync_config_getter(&service); |
| 857 sync_config_getter.SetupAndInitialFetch(); |
| 858 sync_config_getter.SyncGetProxyConfig(&config); |
757 | 859 |
758 // Then we expect the environment variable to win. | 860 // Then we expect the environment variable to win. |
759 EXPECT_EQ(GURL(env_getter->values.auto_proxy), config.pac_url); | 861 EXPECT_EQ(GURL(env_getter->values.auto_proxy), config.pac_url); |
760 } | 862 } |
761 | 863 |
| 864 TEST(ProxyConfigServiceLinuxTest, GconfNotification) { |
| 865 MockEnvironmentVariableGetter* env_getter = |
| 866 new MockEnvironmentVariableGetter; |
| 867 MockGConfSettingGetter* gconf_getter = new MockGConfSettingGetter; |
| 868 ProxyConfigServiceLinux service(env_getter, gconf_getter); |
| 869 ProxyConfig config; |
| 870 SynchConfigGetter sync_config_getter(&service); |
| 871 |
| 872 // Use gconf configuration. |
| 873 env_getter->values.GNOME_DESKTOP_SESSION_ID = "defined"; |
| 874 |
| 875 // Start with no proxy. |
| 876 gconf_getter->values.mode = "none"; |
| 877 sync_config_getter.SetupAndInitialFetch(); |
| 878 sync_config_getter.SyncGetProxyConfig(&config); |
| 879 EXPECT_FALSE(config.auto_detect); |
| 880 |
| 881 // Now set to auto-detect. |
| 882 gconf_getter->values.mode = "auto"; |
| 883 // Simulate gconf notification callback. |
| 884 service.OnCheckProxyConfigSettings(); |
| 885 sync_config_getter.SyncGetProxyConfig(&config); |
| 886 EXPECT_TRUE(config.auto_detect); |
| 887 } |
| 888 |
762 } // namespace net | 889 } // namespace net |
OLD | NEW |