1 // Copyright (c) 2011 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 "chrome/browser/net/pref_proxy_config_tracker_impl.h"
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/prefs/pref_registry_simple.h"
13 #include "base/prefs/testing_pref_service.h"
14 #include "chrome/browser/prefs/pref_service_mock_factory.h"
15 #include "chrome/browser/prefs/proxy_config_dictionary.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "chrome/common/pref_names.h"
18 #include "content/public/test/test_browser_thread.h"
19 #include "net/proxy/proxy_config_service_common_unittest.h"
20 #include "net/proxy/proxy_info.h"
21 #include "net/proxy/proxy_list.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 using content::BrowserThread
;
31 const char kFixedPacUrl
[] = "http://chromium.org/fixed_pac_url";
33 // Testing proxy config service that allows us to fire notifications at will.
34 class TestProxyConfigService
: public net::ProxyConfigService
{
36 TestProxyConfigService(const net::ProxyConfig
& config
,
37 ConfigAvailability availability
)
39 availability_(availability
) {}
41 void SetProxyConfig(const net::ProxyConfig config
,
42 ConfigAvailability availability
) {
44 availability_
= availability
;
45 FOR_EACH_OBSERVER(net::ProxyConfigService::Observer
, observers_
,
46 OnProxyConfigChanged(config
, availability
));
50 void AddObserver(net::ProxyConfigService::Observer
* observer
) override
{
51 observers_
.AddObserver(observer
);
54 void RemoveObserver(net::ProxyConfigService::Observer
* observer
) override
{
55 observers_
.RemoveObserver(observer
);
58 net::ProxyConfigService::ConfigAvailability
GetLatestProxyConfig(
59 net::ProxyConfig
* config
) override
{
64 net::ProxyConfig config_
;
65 ConfigAvailability availability_
;
66 ObserverList
<net::ProxyConfigService::Observer
, true> observers_
;
69 // A mock observer for capturing callbacks.
70 class MockObserver
: public net::ProxyConfigService::Observer
{
72 MOCK_METHOD2(OnProxyConfigChanged
,
73 void(const net::ProxyConfig
&,
74 net::ProxyConfigService::ConfigAvailability
));
77 template<typename TESTBASE
>
78 class PrefProxyConfigTrackerImplTestBase
: public TESTBASE
{
80 PrefProxyConfigTrackerImplTestBase()
81 : ui_thread_(BrowserThread::UI
, &loop_
),
82 io_thread_(BrowserThread::IO
, &loop_
) {}
84 virtual void Init(PrefService
* pref_service
, PrefRegistrySimple
* registry
) {
85 ASSERT_TRUE(pref_service
);
86 PrefProxyConfigTrackerImpl::RegisterPrefs(registry
);
87 fixed_config_
.set_pac_url(GURL(kFixedPacUrl
));
89 new TestProxyConfigService(fixed_config_
,
90 net::ProxyConfigService::CONFIG_VALID
);
91 proxy_config_tracker_
.reset(new PrefProxyConfigTrackerImpl(pref_service
));
92 proxy_config_service_
=
93 proxy_config_tracker_
->CreateTrackingProxyConfigService(
94 scoped_ptr
<net::ProxyConfigService
>(delegate_service_
));
95 // SetChromeProxyConfigService triggers update of initial prefs proxy
96 // config by tracker to chrome proxy config service, so flush all pending
97 // tasks so that tests start fresh.
101 virtual void TearDown() {
102 proxy_config_tracker_
->DetachFromPrefService();
103 loop_
.RunUntilIdle();
104 proxy_config_tracker_
.reset();
105 proxy_config_service_
.reset();
108 base::MessageLoop loop_
;
109 TestProxyConfigService
* delegate_service_
; // weak
110 scoped_ptr
<net::ProxyConfigService
> proxy_config_service_
;
111 net::ProxyConfig fixed_config_
;
114 scoped_ptr
<PrefProxyConfigTrackerImpl
> proxy_config_tracker_
;
115 content::TestBrowserThread ui_thread_
;
116 content::TestBrowserThread io_thread_
;
119 class PrefProxyConfigTrackerImplTest
120 : public PrefProxyConfigTrackerImplTestBase
<testing::Test
> {
122 void SetUp() override
{
123 pref_service_
.reset(new TestingPrefServiceSimple());
124 Init(pref_service_
.get(), pref_service_
->registry());
127 scoped_ptr
<TestingPrefServiceSimple
> pref_service_
;
130 TEST_F(PrefProxyConfigTrackerImplTest
, BaseConfiguration
) {
131 net::ProxyConfig actual_config
;
132 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
133 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
134 EXPECT_EQ(GURL(kFixedPacUrl
), actual_config
.pac_url());
137 TEST_F(PrefProxyConfigTrackerImplTest
, DynamicPrefOverrides
) {
138 pref_service_
->SetManagedPref(prefs::kProxy
,
139 ProxyConfigDictionary::CreateFixedServers(
140 "http://example.com:3128", std::string()));
141 loop_
.RunUntilIdle();
143 net::ProxyConfig actual_config
;
144 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
145 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
146 EXPECT_FALSE(actual_config
.auto_detect());
147 EXPECT_EQ(net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY
,
148 actual_config
.proxy_rules().type
);
149 EXPECT_EQ(actual_config
.proxy_rules().single_proxies
.Get(),
150 net::ProxyServer::FromURI("http://example.com:3128",
151 net::ProxyServer::SCHEME_HTTP
));
153 pref_service_
->SetManagedPref(prefs::kProxy
,
154 ProxyConfigDictionary::CreateAutoDetect());
155 loop_
.RunUntilIdle();
157 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
158 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
159 EXPECT_TRUE(actual_config
.auto_detect());
162 // Compares proxy configurations, but allows different identifiers.
163 MATCHER_P(ProxyConfigMatches
, config
, "") {
164 net::ProxyConfig
reference(config
);
165 reference
.set_id(arg
.id());
166 return reference
.Equals(arg
);
169 TEST_F(PrefProxyConfigTrackerImplTest
, Observers
) {
170 const net::ProxyConfigService::ConfigAvailability CONFIG_VALID
=
171 net::ProxyConfigService::CONFIG_VALID
;
172 MockObserver observer
;
173 proxy_config_service_
->AddObserver(&observer
);
175 // Firing the observers in the delegate should trigger a notification.
176 net::ProxyConfig config2
;
177 config2
.set_auto_detect(true);
178 EXPECT_CALL(observer
, OnProxyConfigChanged(ProxyConfigMatches(config2
),
179 CONFIG_VALID
)).Times(1);
180 delegate_service_
->SetProxyConfig(config2
, CONFIG_VALID
);
181 loop_
.RunUntilIdle();
182 Mock::VerifyAndClearExpectations(&observer
);
184 // Override configuration, this should trigger a notification.
185 net::ProxyConfig pref_config
;
186 pref_config
.set_pac_url(GURL(kFixedPacUrl
));
188 EXPECT_CALL(observer
, OnProxyConfigChanged(ProxyConfigMatches(pref_config
),
189 CONFIG_VALID
)).Times(1);
190 pref_service_
->SetManagedPref(
192 ProxyConfigDictionary::CreatePacScript(kFixedPacUrl
, false));
193 loop_
.RunUntilIdle();
194 Mock::VerifyAndClearExpectations(&observer
);
196 // Since there are pref overrides, delegate changes should be ignored.
197 net::ProxyConfig config3
;
198 config3
.proxy_rules().ParseFromString("http=config3:80");
199 EXPECT_CALL(observer
, OnProxyConfigChanged(_
, _
)).Times(0);
200 fixed_config_
.set_auto_detect(true);
201 delegate_service_
->SetProxyConfig(config3
, CONFIG_VALID
);
202 loop_
.RunUntilIdle();
203 Mock::VerifyAndClearExpectations(&observer
);
205 // Clear the override should switch back to the fixed configuration.
206 EXPECT_CALL(observer
, OnProxyConfigChanged(ProxyConfigMatches(config3
),
207 CONFIG_VALID
)).Times(1);
208 pref_service_
->RemoveManagedPref(prefs::kProxy
);
209 loop_
.RunUntilIdle();
210 Mock::VerifyAndClearExpectations(&observer
);
212 // Delegate service notifications should show up again.
213 net::ProxyConfig config4
;
214 config4
.proxy_rules().ParseFromString("socks:config4");
215 EXPECT_CALL(observer
, OnProxyConfigChanged(ProxyConfigMatches(config4
),
216 CONFIG_VALID
)).Times(1);
217 delegate_service_
->SetProxyConfig(config4
, CONFIG_VALID
);
218 loop_
.RunUntilIdle();
219 Mock::VerifyAndClearExpectations(&observer
);
221 proxy_config_service_
->RemoveObserver(&observer
);
224 TEST_F(PrefProxyConfigTrackerImplTest
, Fallback
) {
225 const net::ProxyConfigService::ConfigAvailability CONFIG_VALID
=
226 net::ProxyConfigService::CONFIG_VALID
;
227 MockObserver observer
;
228 net::ProxyConfig actual_config
;
229 delegate_service_
->SetProxyConfig(net::ProxyConfig::CreateDirect(),
230 net::ProxyConfigService::CONFIG_UNSET
);
231 proxy_config_service_
->AddObserver(&observer
);
233 // Prepare test data.
234 net::ProxyConfig recommended_config
= net::ProxyConfig::CreateAutoDetect();
235 net::ProxyConfig user_config
=
236 net::ProxyConfig::CreateFromCustomPacURL(GURL(kFixedPacUrl
));
238 // Set a recommended pref.
239 EXPECT_CALL(observer
,
240 OnProxyConfigChanged(ProxyConfigMatches(recommended_config
),
241 CONFIG_VALID
)).Times(1);
242 pref_service_
->SetRecommendedPref(
244 ProxyConfigDictionary::CreateAutoDetect());
245 loop_
.RunUntilIdle();
246 Mock::VerifyAndClearExpectations(&observer
);
247 EXPECT_EQ(CONFIG_VALID
,
248 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
249 EXPECT_TRUE(actual_config
.Equals(recommended_config
));
251 // Override in user prefs.
252 EXPECT_CALL(observer
,
253 OnProxyConfigChanged(ProxyConfigMatches(user_config
),
254 CONFIG_VALID
)).Times(1);
255 pref_service_
->SetManagedPref(
257 ProxyConfigDictionary::CreatePacScript(kFixedPacUrl
, false));
258 loop_
.RunUntilIdle();
259 Mock::VerifyAndClearExpectations(&observer
);
260 EXPECT_EQ(CONFIG_VALID
,
261 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
262 EXPECT_TRUE(actual_config
.Equals(user_config
));
264 // Go back to recommended pref.
265 EXPECT_CALL(observer
,
266 OnProxyConfigChanged(ProxyConfigMatches(recommended_config
),
267 CONFIG_VALID
)).Times(1);
268 pref_service_
->RemoveManagedPref(prefs::kProxy
);
269 loop_
.RunUntilIdle();
270 Mock::VerifyAndClearExpectations(&observer
);
271 EXPECT_EQ(CONFIG_VALID
,
272 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
273 EXPECT_TRUE(actual_config
.Equals(recommended_config
));
275 proxy_config_service_
->RemoveObserver(&observer
);
278 TEST_F(PrefProxyConfigTrackerImplTest
, ExplicitSystemSettings
) {
279 pref_service_
->SetRecommendedPref(
281 ProxyConfigDictionary::CreateAutoDetect());
282 pref_service_
->SetUserPref(
284 ProxyConfigDictionary::CreateSystem());
285 loop_
.RunUntilIdle();
287 // Test if we actually use the system setting, which is |kFixedPacUrl|.
288 net::ProxyConfig actual_config
;
289 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
290 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
291 EXPECT_EQ(GURL(kFixedPacUrl
), actual_config
.pac_url());
294 void CheckResolvedProxyMatches(net::ProxyConfig
* config
,
296 const std::string
& result_string
) {
297 net::ProxyInfo expected_result
;
298 expected_result
.UseNamedProxy(result_string
);
300 net::ProxyInfo result
;
301 config
->proxy_rules().Apply(url
, &result
);
303 EXPECT_TRUE(expected_result
.proxy_list().Equals(result
.proxy_list()))
304 << "expected: " << expected_result
.proxy_list().ToPacString()
305 << "\nactual: " << result
.proxy_list().ToPacString();
308 TEST_F(PrefProxyConfigTrackerImplTest
, ExcludeGooglezipDataReductionProxies
) {
309 const std::string kDataReductionProxies
=
310 "https://proxy.googlezip.net:443,compress.googlezip.net,"
311 "https://proxy-dev.googlezip.net:443,proxy-dev.googlezip.net,"
312 "quic://proxy.googlezip.net";
315 std::string initial_proxy_rules
;
316 const char* http_proxy_info
;
317 const char* https_proxy_info
;
318 const char* ftp_proxy_info
;
320 {"http=foopyhttp," + kDataReductionProxies
+
321 ",direct://;https=foopyhttps," + kDataReductionProxies
+
322 ",direct://;ftp=foopyftp," + kDataReductionProxies
+ ",direct://",
323 "foopyhttp;direct://",
324 "foopyhttps;direct://",
325 "foopyftp;direct://"},
327 {"foopy," + kDataReductionProxies
+ ",direct://",
332 {"http=" + kDataReductionProxies
+ ";https=" + kDataReductionProxies
+
333 ";ftp=" + kDataReductionProxies
,
338 {"http=" + kDataReductionProxies
+ ",foopy,direct://",
344 // Test setting the proxy from a user pref.
345 for (const auto& test
: test_cases
) {
346 pref_service_
->SetUserPref(prefs::kProxy
,
347 ProxyConfigDictionary::CreateFixedServers(
348 test
.initial_proxy_rules
, std::string()));
349 loop_
.RunUntilIdle();
351 net::ProxyConfig config
;
352 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
353 proxy_config_service_
->GetLatestProxyConfig(&config
));
355 CheckResolvedProxyMatches(&config
, GURL("http://google.com"),
356 test
.http_proxy_info
);
357 CheckResolvedProxyMatches(&config
, GURL("https://google.com"),
358 test
.https_proxy_info
);
359 CheckResolvedProxyMatches(&config
, GURL("ftp://google.com"),
360 test
.ftp_proxy_info
);
364 // Test parameter object for testing command line proxy configuration.
365 struct CommandLineTestParams
{
366 // Explicit assignment operator, so testing::TestWithParam works with MSVC.
367 CommandLineTestParams
& operator=(const CommandLineTestParams
& other
) {
368 description
= other
.description
;
369 for (unsigned int i
= 0; i
< arraysize(switches
); i
++)
370 switches
[i
] = other
.switches
[i
];
371 is_null
= other
.is_null
;
372 auto_detect
= other
.auto_detect
;
373 pac_url
= other
.pac_url
;
374 proxy_rules
= other
.proxy_rules
;
378 // Short description to identify the test.
379 const char* description
;
381 // The command line to build a ProxyConfig from.
387 // Expected outputs (fields of the ProxyConfig).
391 net::ProxyRulesExpectation proxy_rules
;
394 void PrintTo(const CommandLineTestParams
& params
, std::ostream
* os
) {
395 *os
<< params
.description
;
398 class PrefProxyConfigTrackerImplCommandLineTest
399 : public PrefProxyConfigTrackerImplTestBase
<
400 testing::TestWithParam
<CommandLineTestParams
> > {
402 PrefProxyConfigTrackerImplCommandLineTest()
403 : command_line_(base::CommandLine::NO_PROGRAM
) {}
405 void SetUp() override
{
406 for (size_t i
= 0; i
< arraysize(GetParam().switches
); i
++) {
407 const char* name
= GetParam().switches
[i
].name
;
408 const char* value
= GetParam().switches
[i
].value
;
410 command_line_
.AppendSwitchASCII(name
, value
);
412 command_line_
.AppendSwitch(name
);
414 scoped_refptr
<PrefRegistrySimple
> registry
= new PrefRegistrySimple
;
415 PrefServiceMockFactory factory
;
416 factory
.SetCommandLine(&command_line_
);
417 pref_service_
= factory
.Create(registry
.get()).Pass();
418 Init(pref_service_
.get(), registry
.get());
422 base::CommandLine command_line_
;
423 scoped_ptr
<PrefService
> pref_service_
;
426 TEST_P(PrefProxyConfigTrackerImplCommandLineTest
, CommandLine
) {
427 net::ProxyConfig config
;
428 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
429 proxy_config_service_
->GetLatestProxyConfig(&config
));
431 if (GetParam().is_null
) {
432 EXPECT_EQ(GURL(kFixedPacUrl
), config
.pac_url());
434 EXPECT_NE(GURL(kFixedPacUrl
), config
.pac_url());
435 EXPECT_EQ(GetParam().auto_detect
, config
.auto_detect());
436 EXPECT_EQ(GetParam().pac_url
, config
.pac_url());
437 EXPECT_TRUE(GetParam().proxy_rules
.Matches(config
.proxy_rules()));
441 static const CommandLineTestParams kCommandLineTestParams
[] = {
443 "Empty command line",
448 false, // auto_detect
450 net::ProxyRulesExpectation::Empty(),
456 { switches::kNoProxyServer
, NULL
},
460 false, // auto_detect
462 net::ProxyRulesExpectation::Empty(),
465 "No proxy with extra parameters.",
468 { switches::kNoProxyServer
, NULL
},
469 { switches::kProxyServer
, "http://proxy:8888" },
473 false, // auto_detect
475 net::ProxyRulesExpectation::Empty(),
481 { switches::kProxyServer
, "http://proxy:8888" },
485 false, // auto_detect
487 net::ProxyRulesExpectation::Single(
488 "proxy:8888", // single proxy
495 { switches::kProxyServer
, "http=httpproxy:8888;ftp=ftpproxy:8889" },
499 false, // auto_detect
501 net::ProxyRulesExpectation::PerScheme(
502 "httpproxy:8888", // http
504 "ftpproxy:8889", // ftp
508 "Per scheme proxy with bypass URLs.",
511 { switches::kProxyServer
, "http=httpproxy:8888;ftp=ftpproxy:8889" },
512 { switches::kProxyBypassList
,
513 ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8" },
517 false, // auto_detect
519 net::ProxyRulesExpectation::PerScheme(
520 "httpproxy:8888", // http
522 "ftpproxy:8889", // ftp
523 "*.google.com,foo.com:99,1.2.3.4:22,127.0.0.1/8"),
529 { switches::kProxyPacUrl
, "http://wpad/wpad.dat" },
533 false, // auto_detect
534 GURL("http://wpad/wpad.dat"), // pac_url
535 net::ProxyRulesExpectation::Empty(),
541 { switches::kProxyAutoDetect
, NULL
},
547 net::ProxyRulesExpectation::Empty(),
551 INSTANTIATE_TEST_CASE_P(
552 PrefProxyConfigTrackerImplCommandLineTestInstance
,
553 PrefProxyConfigTrackerImplCommandLineTest
,
554 testing::ValuesIn(kCommandLineTestParams
));