• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/chromeos/proxy_config_service_impl.h"
6 
7 #include <vector>
8 
9 #include "base/format_macros.h"
10 #include "base/json/json_writer.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/prefs/testing_pref_service.h"
14 #include "base/strings/stringprintf.h"
15 #include "chrome/browser/chromeos/settings/cros_settings.h"
16 #include "chrome/browser/chromeos/settings/device_settings_service.h"
17 #include "chrome/browser/chromeos/ui_proxy_config.h"
18 #include "chrome/common/pref_names.h"
19 #include "chromeos/dbus/dbus_thread_manager.h"
20 #include "chromeos/dbus/shill_profile_client.h"
21 #include "chromeos/dbus/shill_service_client.h"
22 #include "chromeos/network/network_handler.h"
23 #include "chromeos/network/network_state.h"
24 #include "chromeos/network/network_state_handler.h"
25 #include "content/public/test/test_browser_thread.h"
26 #include "net/proxy/proxy_config_service_common_unittest.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28 #include "third_party/cros_system_api/dbus/service_constants.h"
29 
30 using content::BrowserThread;
31 
32 namespace chromeos {
33 
34 namespace {
35 
36 struct Input {
37   UIProxyConfig::Mode mode;
38   std::string pac_url;
39   std::string server;
40   std::string bypass_rules;
41 };
42 
43 // Builds an identifier for each test in an array.
44 #define TEST_DESC(desc) base::StringPrintf("at line %d <%s>", __LINE__, desc)
45 
46 // Shortcuts to declare enums within chromeos's ProxyConfig.
47 #define MK_MODE(mode) UIProxyConfig::MODE_##mode
48 
49 // Inspired from net/proxy/proxy_config_service_linux_unittest.cc.
50 const struct TestParams {
51   // Short description to identify the test
52   std::string description;
53 
54   Input input;
55 
56   // Expected outputs from fields of net::ProxyConfig (via IO).
57   bool auto_detect;
58   GURL pac_url;
59   net::ProxyRulesExpectation proxy_rules;
60 } tests[] = {
61   {  // 0
62     TEST_DESC("No proxying"),
63 
64     { // Input.
65       MK_MODE(DIRECT),  // mode
66     },
67 
68     // Expected result.
69     false,                                   // auto_detect
70     GURL(),                                  // pac_url
71     net::ProxyRulesExpectation::Empty(),     // proxy_rules
72   },
73 
74   {  // 1
75     TEST_DESC("Auto detect"),
76 
77     { // Input.
78       MK_MODE(AUTO_DETECT),  // mode
79     },
80 
81     // Expected result.
82     true,                                    // auto_detect
83     GURL(),                                  // pac_url
84     net::ProxyRulesExpectation::Empty(),     // proxy_rules
85   },
86 
87   {  // 2
88     TEST_DESC("Valid PAC URL"),
89 
90     { // Input.
91       MK_MODE(PAC_SCRIPT),     // mode
92       "http://wpad/wpad.dat",  // pac_url
93     },
94 
95     // Expected result.
96     false,                                   // auto_detect
97     GURL("http://wpad/wpad.dat"),            // pac_url
98     net::ProxyRulesExpectation::Empty(),     // proxy_rules
99   },
100 
101   {  // 3
102     TEST_DESC("Invalid PAC URL"),
103 
104     { // Input.
105       MK_MODE(PAC_SCRIPT),  // mode
106       "wpad.dat",           // pac_url
107     },
108 
109     // Expected result.
110     false,                                   // auto_detect
111     GURL(),                                  // pac_url
112     net::ProxyRulesExpectation::Empty(),     // proxy_rules
113   },
114 
115   {  // 4
116     TEST_DESC("Single-host in proxy list"),
117 
118     { // Input.
119       MK_MODE(SINGLE_PROXY),  // mode
120       "",                     // pac_url
121       "www.google.com",       // server
122     },
123 
124     // Expected result.
125     false,                                   // auto_detect
126     GURL(),                                  // pac_url
127     net::ProxyRulesExpectation::Single(      // proxy_rules
128         "www.google.com:80",                 // single proxy
129         "<local>"),                          // bypass rules
130   },
131 
132   {  // 5
133     TEST_DESC("Single-host, different port"),
134 
135     { // Input.
136       MK_MODE(SINGLE_PROXY),  // mode
137       "",                     // pac_url
138       "www.google.com:99",    // server
139     },
140 
141     // Expected result.
142     false,                                   // auto_detect
143     GURL(),                                  // pac_url
144     net::ProxyRulesExpectation::Single(      // proxy_rules
145         "www.google.com:99",                 // single
146         "<local>"),                          // bypass rules
147   },
148 
149   {  // 6
150     TEST_DESC("Tolerate a scheme"),
151 
152     { // Input.
153       MK_MODE(SINGLE_PROXY),       // mode
154       "",                          // pac_url
155       "http://www.google.com:99",  // server
156     },
157 
158     // Expected result.
159     false,                                   // auto_detect
160     GURL(),                                  // pac_url
161     net::ProxyRulesExpectation::Single(      // proxy_rules
162         "www.google.com:99",                 // single proxy
163         "<local>"),                          // bypass rules
164   },
165 
166   {  // 7
167     TEST_DESC("Per-scheme proxy rules"),
168 
169     { // Input.
170       MK_MODE(PROXY_PER_SCHEME),  // mode
171       "",                         // pac_url
172       "http=www.google.com:80;https=https://www.foo.com:110;"
173       "ftp=ftp.foo.com:121;socks=socks5://socks.com:888",  // server
174     },
175 
176     // Expected result.
177     false,                          // auto_detect
178     GURL(),                         // pac_url
179     net::ProxyRulesExpectation::PerSchemeWithSocks(  // proxy_rules
180         "www.google.com:80",        // http
181         "https://www.foo.com:110",  // https
182         "ftp.foo.com:121",          // ftp
183         "socks5://socks.com:888",   // fallback proxy
184         "<local>"),                 // bypass rules
185   },
186 
187   {  // 8
188     TEST_DESC("Bypass rules"),
189 
190     { // Input.
191       MK_MODE(SINGLE_PROXY),      // mode
192       "",                         // pac_url
193       "www.google.com",           // server
194       "*.google.com, *foo.com:99, 1.2.3.4:22, 127.0.0.1/8",  // bypass_rules
195     },
196 
197     // Expected result.
198     false,                          // auto_detect
199     GURL(),                         // pac_url
200     net::ProxyRulesExpectation::Single(  // proxy_rules
201         "www.google.com:80",             // single proxy
202         // bypass_rules
203         "*.google.com,*foo.com:99,1.2.3.4:22,127.0.0.1/8,<local>"),
204   },
205 };  // tests
206 
207 const char* kUserProfilePath = "user_profile";
208 
209 }  // namespace
210 
211 class ProxyConfigServiceImplTest : public testing::Test {
212  protected:
ProxyConfigServiceImplTest()213   ProxyConfigServiceImplTest()
214       : ui_thread_(BrowserThread::UI, &loop_),
215         io_thread_(BrowserThread::IO, &loop_) {}
216 
SetUp()217   virtual void SetUp() {
218     DBusThreadManager::Initialize();
219     NetworkHandler::Initialize();
220 
221     SetUpNetwork();
222 
223     PrefProxyConfigTrackerImpl::RegisterPrefs(pref_service_.registry());
224 
225     // Create a ProxyConfigServiceImpl like for the system request context.
226     config_service_impl_.reset(
227         new ProxyConfigServiceImpl(NULL,  // no profile prefs
228                                    &pref_service_));
229     proxy_config_service_ =
230         config_service_impl_->CreateTrackingProxyConfigService(
231             scoped_ptr<net::ProxyConfigService>());
232 
233     // CreateTrackingProxyConfigService triggers update of initial prefs proxy
234     // config by tracker to chrome proxy config service, so flush all pending
235     // tasks so that tests start fresh.
236     loop_.RunUntilIdle();
237   }
238 
SetUpNetwork()239   void SetUpNetwork() {
240     ShillProfileClient::TestInterface* profile_test =
241         DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
242     ShillServiceClient::TestInterface* service_test =
243         DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
244 
245     // Process any pending notifications before clearing services.
246     loop_.RunUntilIdle();
247     service_test->ClearServices();
248 
249     // Sends a notification about the added profile.
250     profile_test->AddProfile(kUserProfilePath, "user_hash");
251 
252     service_test->AddService("/service/stub_wifi2",
253                              "stub_wifi2" /* guid */,
254                              "wifi2_PSK",
255                              shill::kTypeWifi, shill::kStateOnline,
256                              true /* visible */);
257     profile_test->AddService(kUserProfilePath, "/service/stub_wifi2");
258 
259     loop_.RunUntilIdle();
260   }
261 
TearDown()262   virtual void TearDown() {
263     config_service_impl_->DetachFromPrefService();
264     loop_.RunUntilIdle();
265     config_service_impl_.reset();
266     proxy_config_service_.reset();
267     NetworkHandler::Shutdown();
268     DBusThreadManager::Shutdown();
269   }
270 
InitConfigWithTestInput(const Input & input,base::DictionaryValue * result)271   void InitConfigWithTestInput(const Input& input,
272                                base::DictionaryValue* result) {
273     base::DictionaryValue* new_config = NULL;
274     switch (input.mode) {
275       case MK_MODE(DIRECT):
276         new_config = ProxyConfigDictionary::CreateDirect();
277         break;
278       case MK_MODE(AUTO_DETECT):
279         new_config = ProxyConfigDictionary::CreateAutoDetect();
280         break;
281       case MK_MODE(PAC_SCRIPT):
282         new_config =
283             ProxyConfigDictionary::CreatePacScript(input.pac_url, false);
284         break;
285       case MK_MODE(SINGLE_PROXY):
286       case MK_MODE(PROXY_PER_SCHEME):
287         new_config =
288           ProxyConfigDictionary::CreateFixedServers(input.server,
289                                                     input.bypass_rules);
290         break;
291     }
292     result->Swap(new_config);
293     delete new_config;
294   }
295 
SetConfig(base::DictionaryValue * pref_proxy_config_dict)296   void SetConfig(base::DictionaryValue* pref_proxy_config_dict) {
297     std::string proxy_config;
298     if (pref_proxy_config_dict)
299       base::JSONWriter::Write(pref_proxy_config_dict, &proxy_config);
300 
301     NetworkStateHandler* network_state_handler =
302         NetworkHandler::Get()->network_state_handler();
303     const NetworkState* network = network_state_handler->DefaultNetwork();
304     ASSERT_TRUE(network);
305     DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface()->
306         SetServiceProperty(network->path(),
307                            shill::kProxyConfigProperty,
308                            base::StringValue(proxy_config));
309   }
310 
311   // Synchronously gets the latest proxy config.
SyncGetLatestProxyConfig(net::ProxyConfig * config)312   void SyncGetLatestProxyConfig(net::ProxyConfig* config) {
313     *config = net::ProxyConfig();
314     // Let message loop process all messages. This will run
315     // ChromeProxyConfigService::UpdateProxyConfig, which is posted on IO from
316     // PrefProxyConfigTrackerImpl::OnProxyConfigChanged.
317     loop_.RunUntilIdle();
318     net::ProxyConfigService::ConfigAvailability availability =
319         proxy_config_service_->GetLatestProxyConfig(config);
320 
321     EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID, availability);
322   }
323 
324   base::MessageLoop loop_;
325   scoped_ptr<net::ProxyConfigService> proxy_config_service_;
326   scoped_ptr<ProxyConfigServiceImpl> config_service_impl_;
327   TestingPrefServiceSimple pref_service_;
328 
329  private:
330   ScopedTestDeviceSettingsService test_device_settings_service_;
331   ScopedTestCrosSettings test_cros_settings_;
332   content::TestBrowserThread ui_thread_;
333   content::TestBrowserThread io_thread_;
334 };
335 
TEST_F(ProxyConfigServiceImplTest,NetworkProxy)336 TEST_F(ProxyConfigServiceImplTest, NetworkProxy) {
337   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
338     SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i,
339                                     tests[i].description.c_str()));
340 
341     base::DictionaryValue test_config;
342     InitConfigWithTestInput(tests[i].input, &test_config);
343     SetConfig(&test_config);
344 
345     net::ProxyConfig config;
346     SyncGetLatestProxyConfig(&config);
347 
348     EXPECT_EQ(tests[i].auto_detect, config.auto_detect());
349     EXPECT_EQ(tests[i].pac_url, config.pac_url());
350     EXPECT_TRUE(tests[i].proxy_rules.Matches(config.proxy_rules()));
351   }
352 }
353 
TEST_F(ProxyConfigServiceImplTest,DynamicPrefsOverride)354 TEST_F(ProxyConfigServiceImplTest, DynamicPrefsOverride) {
355   // Groupings of 3 test inputs to use for managed, recommended and network
356   // proxies respectively.  Only valid and non-direct test inputs are used.
357   const size_t proxies[][3] = {
358     { 1, 2, 4, },
359     { 1, 4, 2, },
360     { 4, 2, 1, },
361     { 2, 1, 4, },
362     { 2, 4, 5, },
363     { 2, 5, 4, },
364     { 5, 4, 2, },
365     { 4, 2, 5, },
366     { 4, 5, 6, },
367     { 4, 6, 5, },
368     { 6, 5, 4, },
369     { 5, 4, 6, },
370     { 5, 6, 7, },
371     { 5, 7, 6, },
372     { 7, 6, 5, },
373     { 6, 5, 7, },
374     { 6, 7, 8, },
375     { 6, 8, 7, },
376     { 8, 7, 6, },
377     { 7, 6, 8, },
378   };
379   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(proxies); ++i) {
380     const TestParams& managed_params = tests[proxies[i][0]];
381     const TestParams& recommended_params = tests[proxies[i][1]];
382     const TestParams& network_params = tests[proxies[i][2]];
383 
384     SCOPED_TRACE(base::StringPrintf(
385         "Test[%" PRIuS "] managed=[%s], recommended=[%s], network=[%s]", i,
386         managed_params.description.c_str(),
387         recommended_params.description.c_str(),
388         network_params.description.c_str()));
389 
390     base::DictionaryValue managed_config;
391     InitConfigWithTestInput(managed_params.input, &managed_config);
392     base::DictionaryValue recommended_config;
393     InitConfigWithTestInput(recommended_params.input, &recommended_config);
394     base::DictionaryValue network_config;
395     InitConfigWithTestInput(network_params.input, &network_config);
396 
397     // Managed proxy pref should take effect over recommended proxy and
398     // non-existent network proxy.
399     SetConfig(NULL);
400     pref_service_.SetManagedPref(prefs::kProxy, managed_config.DeepCopy());
401     pref_service_.SetRecommendedPref(prefs::kProxy,
402                                      recommended_config.DeepCopy());
403     net::ProxyConfig actual_config;
404     SyncGetLatestProxyConfig(&actual_config);
405     EXPECT_EQ(managed_params.auto_detect, actual_config.auto_detect());
406     EXPECT_EQ(managed_params.pac_url, actual_config.pac_url());
407     EXPECT_TRUE(managed_params.proxy_rules.Matches(
408         actual_config.proxy_rules()));
409 
410     // Recommended proxy pref should take effect when managed proxy pref is
411     // removed.
412     pref_service_.RemoveManagedPref(prefs::kProxy);
413     SyncGetLatestProxyConfig(&actual_config);
414     EXPECT_EQ(recommended_params.auto_detect, actual_config.auto_detect());
415     EXPECT_EQ(recommended_params.pac_url, actual_config.pac_url());
416     EXPECT_TRUE(recommended_params.proxy_rules.Matches(
417         actual_config.proxy_rules()));
418 
419     // Network proxy should take take effect over recommended proxy pref.
420     SetConfig(&network_config);
421     SyncGetLatestProxyConfig(&actual_config);
422     EXPECT_EQ(network_params.auto_detect, actual_config.auto_detect());
423     EXPECT_EQ(network_params.pac_url, actual_config.pac_url());
424     EXPECT_TRUE(network_params.proxy_rules.Matches(
425         actual_config.proxy_rules()));
426 
427     // Managed proxy pref should take effect over network proxy.
428     pref_service_.SetManagedPref(prefs::kProxy, managed_config.DeepCopy());
429     SyncGetLatestProxyConfig(&actual_config);
430     EXPECT_EQ(managed_params.auto_detect, actual_config.auto_detect());
431     EXPECT_EQ(managed_params.pac_url, actual_config.pac_url());
432     EXPECT_TRUE(managed_params.proxy_rules.Matches(
433         actual_config.proxy_rules()));
434 
435     // Network proxy should take effect over recommended proxy pref when managed
436     // proxy pref is removed.
437     pref_service_.RemoveManagedPref(prefs::kProxy);
438     SyncGetLatestProxyConfig(&actual_config);
439     EXPECT_EQ(network_params.auto_detect, actual_config.auto_detect());
440     EXPECT_EQ(network_params.pac_url, actual_config.pac_url());
441     EXPECT_TRUE(network_params.proxy_rules.Matches(
442         actual_config.proxy_rules()));
443 
444     // Removing recommended proxy pref should have no effect on network proxy.
445     pref_service_.RemoveRecommendedPref(prefs::kProxy);
446     SyncGetLatestProxyConfig(&actual_config);
447     EXPECT_EQ(network_params.auto_detect, actual_config.auto_detect());
448     EXPECT_EQ(network_params.pac_url, actual_config.pac_url());
449     EXPECT_TRUE(network_params.proxy_rules.Matches(
450         actual_config.proxy_rules()));
451   }
452 }
453 
454 }  // namespace chromeos
455