1 // Copyright 2012 The Chromium Authors
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 "net/proxy_resolution/proxy_config_service_linux.h"
6
7 #include <map>
8 #include <string>
9 #include <vector>
10
11 #include "base/check.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/functional/bind.h"
17 #include "base/location.h"
18 #include "base/memory/raw_ptr.h"
19 #include "base/message_loop/message_pump_type.h"
20 #include "base/run_loop.h"
21 #include "base/strings/string_util.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/synchronization/lock.h"
24 #include "base/synchronization/waitable_event.h"
25 #include "base/task/sequenced_task_runner.h"
26 #include "base/task/single_thread_task_runner.h"
27 #include "base/task/thread_pool/thread_pool_instance.h"
28 #include "base/threading/thread.h"
29 #include "base/time/time.h"
30 #include "net/proxy_resolution/proxy_config.h"
31 #include "net/proxy_resolution/proxy_config_service_common_unittest.h"
32 #include "net/test/test_with_task_environment.h"
33 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
34 #include "testing/gtest/include/gtest/gtest.h"
35 #include "testing/platform_test.h"
36
37 // TODO(eroman): Convert these to parameterized tests using TEST_P().
38
39 namespace net {
40 namespace {
41
42 // Set of values for all environment variables that we might
43 // query. NULL represents an unset variable.
44 struct EnvVarValues {
45 // The strange capitalization is so that the field matches the
46 // environment variable name exactly.
47 const char* DESKTOP_SESSION;
48 const char* HOME;
49 const char* KDEHOME;
50 const char* KDE_SESSION_VERSION;
51 const char* XDG_CURRENT_DESKTOP;
52 const char* auto_proxy;
53 const char* all_proxy;
54 const char* http_proxy;
55 const char* https_proxy;
56 const char* ftp_proxy;
57 const char* SOCKS_SERVER;
58 const char* SOCKS_VERSION;
59 const char* no_proxy;
60 const char* XDG_CONFIG_DIRS;
61 };
62
63 // Undo macro pollution from GDK includes (from message_loop.h).
64 #undef TRUE
65 #undef FALSE
66
67 // So as to distinguish between an unset boolean variable and
68 // one that is false.
69 enum BoolSettingValue { UNSET = 0, TRUE, FALSE };
70
71 // Set of values for all gsettings settings that we might query.
72 struct GSettingsValues {
73 // strings
74 const char* mode;
75 const char* autoconfig_url;
76 const char* http_host;
77 const char* secure_host;
78 const char* ftp_host;
79 const char* socks_host;
80 // integers
81 int http_port;
82 int secure_port;
83 int ftp_port;
84 int socks_port;
85 // booleans
86 BoolSettingValue use_proxy;
87 BoolSettingValue same_proxy;
88 BoolSettingValue use_auth;
89 // string list
90 std::vector<std::string> ignore_hosts;
91 };
92
93 // Mapping from a setting name to the location of the corresponding
94 // value (inside a EnvVarValues or GSettingsValues struct).
95 template <typename key_type, typename value_type>
96 struct SettingsTable {
97 typedef std::map<key_type, value_type*> map_type;
98
99 // Gets the value from its location
Getnet::__anonbab721530111::SettingsTable100 value_type Get(key_type key) {
101 auto it = settings.find(key);
102 // In case there's a typo or the unittest becomes out of sync.
103 CHECK(it != settings.end()) << "key " << key << " not found";
104 value_type* value_ptr = it->second;
105 return *value_ptr;
106 }
107
108 map_type settings;
109 };
110
111 class MockEnvironment : public base::Environment {
112 public:
MockEnvironment()113 MockEnvironment() {
114 #define ENTRY(x) table_[#x] = &values.x
115 ENTRY(DESKTOP_SESSION);
116 ENTRY(HOME);
117 ENTRY(KDEHOME);
118 ENTRY(KDE_SESSION_VERSION);
119 ENTRY(XDG_CURRENT_DESKTOP);
120 ENTRY(auto_proxy);
121 ENTRY(all_proxy);
122 ENTRY(http_proxy);
123 ENTRY(https_proxy);
124 ENTRY(ftp_proxy);
125 ENTRY(no_proxy);
126 ENTRY(SOCKS_SERVER);
127 ENTRY(SOCKS_VERSION);
128 ENTRY(XDG_CONFIG_DIRS);
129 #undef ENTRY
130 Reset();
131 }
132
133 // Zeroes all environment values.
Reset()134 void Reset() {
135 EnvVarValues zero_values = {nullptr};
136 values = zero_values;
137 }
138
139 // Begin base::Environment implementation.
GetVar(base::StringPiece variable_name,std::string * result)140 bool GetVar(base::StringPiece variable_name, std::string* result) override {
141 auto it = table_.find(variable_name);
142 if (it == table_.end() || !*it->second)
143 return false;
144
145 // Note that the variable may be defined but empty.
146 *result = *(it->second);
147 return true;
148 }
149
SetVar(base::StringPiece variable_name,const std::string & new_value)150 bool SetVar(base::StringPiece variable_name,
151 const std::string& new_value) override {
152 ADD_FAILURE();
153 return false;
154 }
155
UnSetVar(base::StringPiece variable_name)156 bool UnSetVar(base::StringPiece variable_name) override {
157 ADD_FAILURE();
158 return false;
159 }
160 // End base::Environment implementation.
161
162 // Intentionally public, for convenience when setting up a test.
163 EnvVarValues values;
164
165 private:
166 std::map<base::StringPiece, const char**> table_;
167 };
168
169 class MockSettingGetter : public ProxyConfigServiceLinux::SettingGetter {
170 public:
171 typedef ProxyConfigServiceLinux::SettingGetter SettingGetter;
MockSettingGetter()172 MockSettingGetter() {
173 #define ENTRY(key, field) \
174 strings_table.settings[SettingGetter::key] = &values.field
175 ENTRY(PROXY_MODE, mode);
176 ENTRY(PROXY_AUTOCONF_URL, autoconfig_url);
177 ENTRY(PROXY_HTTP_HOST, http_host);
178 ENTRY(PROXY_HTTPS_HOST, secure_host);
179 ENTRY(PROXY_FTP_HOST, ftp_host);
180 ENTRY(PROXY_SOCKS_HOST, socks_host);
181 #undef ENTRY
182 #define ENTRY(key, field) \
183 ints_table.settings[SettingGetter::key] = &values.field
184 ENTRY(PROXY_HTTP_PORT, http_port);
185 ENTRY(PROXY_HTTPS_PORT, secure_port);
186 ENTRY(PROXY_FTP_PORT, ftp_port);
187 ENTRY(PROXY_SOCKS_PORT, socks_port);
188 #undef ENTRY
189 #define ENTRY(key, field) \
190 bools_table.settings[SettingGetter::key] = &values.field
191 ENTRY(PROXY_USE_HTTP_PROXY, use_proxy);
192 ENTRY(PROXY_USE_SAME_PROXY, same_proxy);
193 ENTRY(PROXY_USE_AUTHENTICATION, use_auth);
194 #undef ENTRY
195 string_lists_table.settings[SettingGetter::PROXY_IGNORE_HOSTS] =
196 &values.ignore_hosts;
197 Reset();
198 }
199
200 // Zeros all environment values.
Reset()201 void Reset() {
202 GSettingsValues zero_values = {nullptr};
203 values = zero_values;
204 }
205
Init(const scoped_refptr<base::SingleThreadTaskRunner> & glib_task_runner)206 bool Init(const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner)
207 override {
208 task_runner_ = glib_task_runner;
209 return true;
210 }
211
ShutDown()212 void ShutDown() override {}
213
SetUpNotifications(ProxyConfigServiceLinux::Delegate * delegate)214 bool SetUpNotifications(
215 ProxyConfigServiceLinux::Delegate* delegate) override {
216 return true;
217 }
218
GetNotificationTaskRunner()219 const scoped_refptr<base::SequencedTaskRunner>& GetNotificationTaskRunner()
220 override {
221 return task_runner_;
222 }
223
GetString(StringSetting key,std::string * result)224 bool GetString(StringSetting key, std::string* result) override {
225 const char* value = strings_table.Get(key);
226 if (value) {
227 *result = value;
228 return true;
229 }
230 return false;
231 }
232
GetBool(BoolSetting key,bool * result)233 bool GetBool(BoolSetting key, bool* result) override {
234 BoolSettingValue value = bools_table.Get(key);
235 switch (value) {
236 case UNSET:
237 return false;
238 case TRUE:
239 *result = true;
240 break;
241 case FALSE:
242 *result = false;
243 }
244 return true;
245 }
246
GetInt(IntSetting key,int * result)247 bool GetInt(IntSetting key, int* result) override {
248 // We don't bother to distinguish unset keys from 0 values.
249 *result = ints_table.Get(key);
250 return true;
251 }
252
GetStringList(StringListSetting key,std::vector<std::string> * result)253 bool GetStringList(StringListSetting key,
254 std::vector<std::string>* result) override {
255 *result = string_lists_table.Get(key);
256 // We don't bother to distinguish unset keys from empty lists.
257 return !result->empty();
258 }
259
BypassListIsReversed()260 bool BypassListIsReversed() override { return false; }
261
UseSuffixMatching()262 bool UseSuffixMatching() override { return false; }
263
264 // Intentionally public, for convenience when setting up a test.
265 GSettingsValues values;
266
267 private:
268 scoped_refptr<base::SequencedTaskRunner> task_runner_;
269 SettingsTable<StringSetting, const char*> strings_table;
270 SettingsTable<BoolSetting, BoolSettingValue> bools_table;
271 SettingsTable<IntSetting, int> ints_table;
272 SettingsTable<StringListSetting, std::vector<std::string>> string_lists_table;
273 };
274
275 // This helper class runs ProxyConfigServiceLinux::GetLatestProxyConfig() on
276 // the main TaskRunner and synchronously waits for the result.
277 // Some code duplicated from pac_file_fetcher_unittest.cc.
278 class SyncConfigGetter : public ProxyConfigService::Observer {
279 public:
SyncConfigGetter(std::unique_ptr<ProxyConfigServiceLinux> config_service)280 explicit SyncConfigGetter(
281 std::unique_ptr<ProxyConfigServiceLinux> config_service)
282 : event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
283 base::WaitableEvent::InitialState::NOT_SIGNALED),
284 main_thread_("Main_Thread"),
285 config_service_(std::move(config_service)),
286 matches_pac_url_event_(
287 base::WaitableEvent::ResetPolicy::AUTOMATIC,
288 base::WaitableEvent::InitialState::NOT_SIGNALED) {
289 // Start the main IO thread.
290 base::Thread::Options options;
291 options.message_pump_type = base::MessagePumpType::IO;
292 main_thread_.StartWithOptions(std::move(options));
293
294 // Make sure the thread started.
295 main_thread_.task_runner()->PostTask(
296 FROM_HERE,
297 base::BindOnce(&SyncConfigGetter::Init, base::Unretained(this)));
298 Wait();
299 }
300
~SyncConfigGetter()301 ~SyncConfigGetter() override {
302 // Clean up the main thread.
303 main_thread_.task_runner()->PostTask(
304 FROM_HERE,
305 base::BindOnce(&SyncConfigGetter::CleanUp, base::Unretained(this)));
306 Wait();
307 }
308
309 // Does gsettings setup and initial fetch of the proxy config,
310 // all on the calling thread (meant to be the thread with the
311 // default glib main loop, which is the glib thread).
SetupAndInitialFetch()312 void SetupAndInitialFetch() {
313 config_service_->SetupAndFetchInitialConfig(
314 base::SingleThreadTaskRunner::GetCurrentDefault(),
315 main_thread_.task_runner(), TRAFFIC_ANNOTATION_FOR_TESTS);
316 }
317 // Synchronously gets the proxy config.
SyncGetLatestProxyConfig(ProxyConfigWithAnnotation * config)318 ProxyConfigService::ConfigAvailability SyncGetLatestProxyConfig(
319 ProxyConfigWithAnnotation* config) {
320 main_thread_.task_runner()->PostTask(
321 FROM_HERE, base::BindOnce(&SyncConfigGetter::GetLatestConfigOnIOThread,
322 base::Unretained(this)));
323 Wait();
324 *config = proxy_config_;
325 return get_latest_config_result_;
326 }
327
328 // Instructs |matches_pac_url_event_| to be signalled once the configuration
329 // changes to |pac_url|. The way to use this function is:
330 //
331 // SetExpectedPacUrl(..);
332 // EXPECT_TRUE(base::WriteFile(...))
333 // WaitUntilPacUrlMatchesExpectation();
334 //
335 // The expectation must be set *before* any file-level mutation is done,
336 // otherwise the change may be received before
337 // WaitUntilPacUrlMatchesExpectation(), and subsequently be lost.
SetExpectedPacUrl(const std::string & pac_url)338 void SetExpectedPacUrl(const std::string& pac_url) {
339 base::AutoLock lock(lock_);
340 expected_pac_url_ = GURL(pac_url);
341 }
342
343 // Blocks until the proxy config service has received a configuration
344 // matching the value previously passed to SetExpectedPacUrl().
WaitUntilPacUrlMatchesExpectation()345 void WaitUntilPacUrlMatchesExpectation() {
346 matches_pac_url_event_.Wait();
347 matches_pac_url_event_.Reset();
348 }
349
350 private:
OnProxyConfigChanged(const ProxyConfigWithAnnotation & config,ProxyConfigService::ConfigAvailability availability)351 void OnProxyConfigChanged(
352 const ProxyConfigWithAnnotation& config,
353 ProxyConfigService::ConfigAvailability availability) override {
354 // If the configuration changed to |expected_pac_url_| signal the event.
355 base::AutoLock lock(lock_);
356 if (config.value().has_pac_url() &&
357 config.value().pac_url() == expected_pac_url_) {
358 expected_pac_url_ = GURL();
359 matches_pac_url_event_.Signal();
360 }
361 }
362
363 // [Runs on |main_thread_|]
Init()364 void Init() {
365 config_service_->AddObserver(this);
366 event_.Signal();
367 }
368
369 // Calls GetLatestProxyConfig, running on |main_thread_| Signals |event_|
370 // on completion.
GetLatestConfigOnIOThread()371 void GetLatestConfigOnIOThread() {
372 get_latest_config_result_ =
373 config_service_->GetLatestProxyConfig(&proxy_config_);
374 event_.Signal();
375 }
376
377 // [Runs on |main_thread_|] Signals |event_| on cleanup completion.
CleanUp()378 void CleanUp() {
379 config_service_->RemoveObserver(this);
380 config_service_.reset();
381 base::RunLoop().RunUntilIdle();
382 event_.Signal();
383 }
384
Wait()385 void Wait() {
386 event_.Wait();
387 event_.Reset();
388 }
389
390 base::WaitableEvent event_;
391 base::Thread main_thread_;
392
393 std::unique_ptr<ProxyConfigServiceLinux> config_service_;
394
395 // The config obtained by |main_thread_| and read back by the main
396 // thread.
397 ProxyConfigWithAnnotation proxy_config_;
398
399 // Return value from GetLatestProxyConfig().
400 ProxyConfigService::ConfigAvailability get_latest_config_result_;
401
402 // If valid, |expected_pac_url_| is the URL that is being waited for in
403 // the proxy configuration. The URL should only be accessed while |lock_|
404 // is held. Once a configuration arrives for |expected_pac_url_| then the
405 // event |matches_pac_url_event_| will be signalled.
406 base::Lock lock_;
407 GURL expected_pac_url_;
408 base::WaitableEvent matches_pac_url_event_;
409 };
410
411 // This test fixture is only really needed for the KDEConfigParser test case,
412 // but all the test cases with the same prefix ("ProxyConfigServiceLinuxTest")
413 // must use the same test fixture class (also "ProxyConfigServiceLinuxTest").
414 class ProxyConfigServiceLinuxTest : public PlatformTest,
415 public WithTaskEnvironment {
416 protected:
SetUp()417 void SetUp() override {
418 PlatformTest::SetUp();
419 // Set up a temporary KDE home directory.
420 std::string prefix("ProxyConfigServiceLinuxTest_user_home");
421 base::CreateNewTempDirectory(prefix, &user_home_);
422 config_home_ = user_home_.Append(FILE_PATH_LITERAL(".config"));
423 kde_home_ = user_home_.Append(FILE_PATH_LITERAL(".kde"));
424 base::FilePath path = kde_home_.Append(FILE_PATH_LITERAL("share"));
425 path = path.Append(FILE_PATH_LITERAL("config"));
426 base::CreateDirectory(path);
427 kioslaverc_ = path.Append(FILE_PATH_LITERAL("kioslaverc"));
428 // Set up paths but do not create the directory for .kde4.
429 kde4_home_ = user_home_.Append(FILE_PATH_LITERAL(".kde4"));
430 path = kde4_home_.Append(FILE_PATH_LITERAL("share"));
431 kde4_config_ = path.Append(FILE_PATH_LITERAL("config"));
432 kioslaverc4_ = kde4_config_.Append(FILE_PATH_LITERAL("kioslaverc"));
433 // Set up paths for KDE 5
434 kioslaverc5_ = config_home_.Append(FILE_PATH_LITERAL("kioslaverc"));
435 config_xdg_home_ = user_home_.Append(FILE_PATH_LITERAL("xdg"));
436 config_kdedefaults_home_ =
437 config_home_.Append(FILE_PATH_LITERAL("kdedefaults"));
438 kioslaverc5_xdg_ = config_xdg_home_.Append(FILE_PATH_LITERAL("kioslaverc"));
439 kioslaverc5_kdedefaults_ =
440 config_kdedefaults_home_.Append(FILE_PATH_LITERAL("kioslaverc"));
441 }
442
TearDown()443 void TearDown() override {
444 // Delete the temporary KDE home directory.
445 base::DeletePathRecursively(user_home_);
446 PlatformTest::TearDown();
447 }
448
449 base::FilePath user_home_;
450 base::FilePath config_home_;
451 base::FilePath config_xdg_home_;
452 base::FilePath config_kdedefaults_home_;
453 // KDE3 paths.
454 base::FilePath kde_home_;
455 base::FilePath kioslaverc_;
456 // KDE4 paths.
457 base::FilePath kde4_home_;
458 base::FilePath kde4_config_;
459 base::FilePath kioslaverc4_;
460 // KDE5 paths.
461 base::FilePath kioslaverc5_;
462 base::FilePath kioslaverc5_xdg_;
463 base::FilePath kioslaverc5_kdedefaults_;
464 };
465
466 // Builds an identifier for each test in an array.
467 #define TEST_DESC(desc) base::StringPrintf("at line %d <%s>", __LINE__, desc)
468
TEST_F(ProxyConfigServiceLinuxTest,BasicGSettingsTest)469 TEST_F(ProxyConfigServiceLinuxTest, BasicGSettingsTest) {
470 std::vector<std::string> empty_ignores;
471
472 std::vector<std::string> google_ignores;
473 google_ignores.push_back("*.google.com");
474
475 // Inspired from proxy_config_service_win_unittest.cc.
476 // Very neat, but harder to track down failures though.
477 const struct {
478 // Short description to identify the test
479 std::string description;
480
481 // Input.
482 GSettingsValues values;
483
484 // Expected outputs (availability and fields of ProxyConfig).
485 ProxyConfigService::ConfigAvailability availability;
486 bool auto_detect;
487 GURL pac_url;
488 ProxyRulesExpectation proxy_rules;
489 } tests[] = {
490 {
491 TEST_DESC("No proxying"),
492 {
493 // Input.
494 "none", // mode
495 "", // autoconfig_url
496 "", "", "", "", // hosts
497 0, 0, 0, 0, // ports
498 FALSE, FALSE, FALSE, // use, same, auth
499 empty_ignores, // ignore_hosts
500 },
501
502 // Expected result.
503 ProxyConfigService::CONFIG_VALID,
504 false, // auto_detect
505 GURL(), // pac_url
506 ProxyRulesExpectation::Empty(),
507 },
508
509 {
510 TEST_DESC("Auto detect"),
511 {
512 // Input.
513 "auto", // mode
514 "", // autoconfig_url
515 "", "", "", "", // hosts
516 0, 0, 0, 0, // ports
517 FALSE, FALSE, FALSE, // use, same, auth
518 empty_ignores, // ignore_hosts
519 },
520
521 // Expected result.
522 ProxyConfigService::CONFIG_VALID,
523 true, // auto_detect
524 GURL(), // pac_url
525 ProxyRulesExpectation::Empty(),
526 },
527
528 {
529 TEST_DESC("Valid PAC URL"),
530 {
531 // Input.
532 "auto", // mode
533 "http://wpad/wpad.dat", // autoconfig_url
534 "", "", "", "", // hosts
535 0, 0, 0, 0, // ports
536 FALSE, FALSE, FALSE, // use, same, auth
537 empty_ignores, // ignore_hosts
538 },
539
540 // Expected result.
541 ProxyConfigService::CONFIG_VALID,
542 false, // auto_detect
543 GURL("http://wpad/wpad.dat"), // pac_url
544 ProxyRulesExpectation::Empty(),
545 },
546
547 {
548 TEST_DESC("Invalid PAC URL"),
549 {
550 // Input.
551 "auto", // mode
552 "wpad.dat", // autoconfig_url
553 "", "", "", "", // hosts
554 0, 0, 0, 0, // ports
555 FALSE, FALSE, FALSE, // use, same, auth
556 empty_ignores, // ignore_hosts
557 },
558
559 // Expected result.
560 ProxyConfigService::CONFIG_VALID,
561 false, // auto_detect
562 GURL(), // pac_url
563 ProxyRulesExpectation::Empty(),
564 },
565
566 {
567 TEST_DESC("Single-host in proxy list"),
568 {
569 // Input.
570 "manual", // mode
571 "", // autoconfig_url
572 "www.google.com", "", "", "", // hosts
573 80, 0, 0, 0, // ports
574 TRUE, TRUE, FALSE, // use, same, auth
575 empty_ignores, // ignore_hosts
576 },
577
578 // Expected result.
579 ProxyConfigService::CONFIG_VALID,
580 false, // auto_detect
581 GURL(), // pac_url
582 ProxyRulesExpectation::Single("www.google.com:80", // single proxy
583 ""), // bypass rules
584 },
585
586 {
587 TEST_DESC("use_http_proxy is honored"),
588 {
589 // Input.
590 "manual", // mode
591 "", // autoconfig_url
592 "www.google.com", "", "", "", // hosts
593 80, 0, 0, 0, // ports
594 FALSE, TRUE, FALSE, // use, same, auth
595 empty_ignores, // ignore_hosts
596 },
597
598 // Expected result.
599 ProxyConfigService::CONFIG_VALID,
600 false, // auto_detect
601 GURL(), // pac_url
602 ProxyRulesExpectation::Empty(),
603 },
604
605 {
606 TEST_DESC("use_http_proxy and use_same_proxy are optional"),
607 {
608 // Input.
609 "manual", // mode
610 "", // autoconfig_url
611 "www.google.com", "", "", "", // hosts
612 80, 0, 0, 0, // ports
613 UNSET, UNSET, FALSE, // use, same, auth
614 empty_ignores, // ignore_hosts
615 },
616
617 // Expected result.
618 ProxyConfigService::CONFIG_VALID,
619 false, // auto_detect
620 GURL(), // pac_url
621 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
622 "", // https
623 "", // ftp
624 ""), // bypass rules
625 },
626
627 {
628 TEST_DESC("Single-host, different port"),
629 {
630 // Input.
631 "manual", // mode
632 "", // autoconfig_url
633 "www.google.com", "", "", "", // hosts
634 88, 0, 0, 0, // ports
635 TRUE, TRUE, FALSE, // use, same, auth
636 empty_ignores, // ignore_hosts
637 },
638
639 // Expected result.
640 ProxyConfigService::CONFIG_VALID,
641 false, // auto_detect
642 GURL(), // pac_url
643 ProxyRulesExpectation::Single("www.google.com:88", // single proxy
644 ""), // bypass rules
645 },
646
647 {
648 TEST_DESC("Per-scheme proxy rules"),
649 {
650 // Input.
651 "manual", // mode
652 "", // autoconfig_url
653 "www.google.com", // http_host
654 "www.foo.com", // secure_host
655 "ftp.foo.com", // ftp
656 "", // socks
657 88, 110, 121, 0, // ports
658 TRUE, FALSE, FALSE, // use, same, auth
659 empty_ignores, // ignore_hosts
660 },
661
662 // Expected result.
663 ProxyConfigService::CONFIG_VALID,
664 false, // auto_detect
665 GURL(), // pac_url
666 ProxyRulesExpectation::PerScheme("www.google.com:88", // http
667 "www.foo.com:110", // https
668 "ftp.foo.com:121", // ftp
669 ""), // bypass rules
670 },
671
672 {
673 TEST_DESC("socks"),
674 {
675 // Input.
676 "manual", // mode
677 "", // autoconfig_url
678 "", "", "", "socks.com", // hosts
679 0, 0, 0, 99, // ports
680 TRUE, FALSE, FALSE, // use, same, auth
681 empty_ignores, // ignore_hosts
682 },
683
684 // Expected result.
685 ProxyConfigService::CONFIG_VALID,
686 false, // auto_detect
687 GURL(), // pac_url
688 ProxyRulesExpectation::Single(
689 "socks5://socks.com:99", // single proxy
690 "") // bypass rules
691 },
692
693 {
694 TEST_DESC("Per-scheme proxy rules with fallback to SOCKS"),
695 {
696 // Input.
697 "manual", // mode
698 "", // autoconfig_url
699 "www.google.com", // http_host
700 "www.foo.com", // secure_host
701 "ftp.foo.com", // ftp
702 "foobar.net", // socks
703 88, 110, 121, 99, // ports
704 TRUE, FALSE, FALSE, // use, same, auth
705 empty_ignores, // ignore_hosts
706 },
707
708 // Expected result.
709 ProxyConfigService::CONFIG_VALID,
710 false, // auto_detect
711 GURL(), // pac_url
712 ProxyRulesExpectation::PerSchemeWithSocks(
713 "www.google.com:88", // http
714 "www.foo.com:110", // https
715 "ftp.foo.com:121", // ftp
716 "socks5://foobar.net:99", // socks
717 ""), // bypass rules
718 },
719
720 {
721 TEST_DESC(
722 "Per-scheme proxy rules (just HTTP) with fallback to SOCKS"),
723 {
724 // Input.
725 "manual", // mode
726 "", // autoconfig_url
727 "www.google.com", // http_host
728 "", // secure_host
729 "", // ftp
730 "foobar.net", // socks
731 88, 0, 0, 99, // ports
732 TRUE, FALSE, FALSE, // use, same, auth
733 empty_ignores, // ignore_hosts
734 },
735
736 // Expected result.
737 ProxyConfigService::CONFIG_VALID,
738 false, // auto_detect
739 GURL(), // pac_url
740 ProxyRulesExpectation::PerSchemeWithSocks(
741 "www.google.com:88", // http
742 "", // https
743 "", // ftp
744 "socks5://foobar.net:99", // socks
745 ""), // bypass rules
746 },
747
748 {
749 TEST_DESC("Bypass *.google.com"),
750 {
751 // Input.
752 "manual", // mode
753 "", // autoconfig_url
754 "www.google.com", "", "", "", // hosts
755 80, 0, 0, 0, // ports
756 TRUE, TRUE, FALSE, // use, same, auth
757 google_ignores, // ignore_hosts
758 },
759
760 ProxyConfigService::CONFIG_VALID,
761 false, // auto_detect
762 GURL(), // pac_url
763 ProxyRulesExpectation::Single("www.google.com:80", // single proxy
764 "*.google.com"), // bypass rules
765 },
766 };
767
768 for (size_t i = 0; i < std::size(tests); ++i) {
769 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i,
770 tests[i].description.c_str()));
771 auto env = std::make_unique<MockEnvironment>();
772 auto setting_getter = std::make_unique<MockSettingGetter>();
773 auto* setting_getter_ptr = setting_getter.get();
774 SyncConfigGetter sync_config_getter(
775 std::make_unique<ProxyConfigServiceLinux>(
776 std::move(env), std::move(setting_getter),
777 TRAFFIC_ANNOTATION_FOR_TESTS));
778 ProxyConfigWithAnnotation config;
779 setting_getter_ptr->values = tests[i].values;
780 sync_config_getter.SetupAndInitialFetch();
781 ProxyConfigService::ConfigAvailability availability =
782 sync_config_getter.SyncGetLatestProxyConfig(&config);
783 EXPECT_EQ(tests[i].availability, availability);
784
785 if (availability == ProxyConfigService::CONFIG_VALID) {
786 EXPECT_EQ(tests[i].auto_detect, config.value().auto_detect());
787 EXPECT_EQ(tests[i].pac_url, config.value().pac_url());
788 EXPECT_TRUE(tests[i].proxy_rules.Matches(config.value().proxy_rules()));
789 }
790 }
791 }
792
TEST_F(ProxyConfigServiceLinuxTest,BasicEnvTest)793 TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) {
794 // Inspired from proxy_config_service_win_unittest.cc.
795 const struct {
796 // Short description to identify the test
797 std::string description;
798
799 // Input.
800 EnvVarValues values;
801
802 // Expected outputs (availability and fields of ProxyConfig).
803 ProxyConfigService::ConfigAvailability availability;
804 bool auto_detect;
805 GURL pac_url;
806 ProxyRulesExpectation proxy_rules;
807 } tests[] = {
808 {
809 TEST_DESC("No proxying"),
810 {
811 // Input.
812 nullptr, // DESKTOP_SESSION
813 nullptr, // HOME
814 nullptr, // KDEHOME
815 nullptr, // KDE_SESSION_VERSION
816 nullptr, // XDG_CURRENT_DESKTOP
817 nullptr, // auto_proxy
818 nullptr, // all_proxy
819 nullptr, nullptr, nullptr, // per-proto proxies
820 nullptr, nullptr, // SOCKS
821 "*", // no_proxy
822 },
823
824 // Expected result.
825 ProxyConfigService::CONFIG_VALID,
826 false, // auto_detect
827 GURL(), // pac_url
828 ProxyRulesExpectation::Empty(),
829 },
830
831 {
832 TEST_DESC("Auto detect"),
833 {
834 // Input.
835 nullptr, // DESKTOP_SESSION
836 nullptr, // HOME
837 nullptr, // KDEHOME
838 nullptr, // KDE_SESSION_VERSION
839 nullptr, // XDG_CURRENT_DESKTOP
840 "", // auto_proxy
841 nullptr, // all_proxy
842 nullptr, nullptr, nullptr, // per-proto proxies
843 nullptr, nullptr, // SOCKS
844 nullptr, // no_proxy
845 },
846
847 // Expected result.
848 ProxyConfigService::CONFIG_VALID,
849 true, // auto_detect
850 GURL(), // pac_url
851 ProxyRulesExpectation::Empty(),
852 },
853
854 {
855 TEST_DESC("Valid PAC URL"),
856 {
857 // Input.
858 nullptr, // DESKTOP_SESSION
859 nullptr, // HOME
860 nullptr, // KDEHOME
861 nullptr, // KDE_SESSION_VERSION
862 nullptr, // XDG_CURRENT_DESKTOP
863 "http://wpad/wpad.dat", // auto_proxy
864 nullptr, // all_proxy
865 nullptr, nullptr, nullptr, // per-proto proxies
866 nullptr, nullptr, // SOCKS
867 nullptr, // no_proxy
868 },
869
870 // Expected result.
871 ProxyConfigService::CONFIG_VALID,
872 false, // auto_detect
873 GURL("http://wpad/wpad.dat"), // pac_url
874 ProxyRulesExpectation::Empty(),
875 },
876
877 {
878 TEST_DESC("Invalid PAC URL"),
879 {
880 // Input.
881 nullptr, // DESKTOP_SESSION
882 nullptr, // HOME
883 nullptr, // KDEHOME
884 nullptr, // KDE_SESSION_VERSION
885 nullptr, // XDG_CURRENT_DESKTOP
886 "wpad.dat", // auto_proxy
887 nullptr, // all_proxy
888 nullptr, nullptr, nullptr, // per-proto proxies
889 nullptr, nullptr, // SOCKS
890 nullptr, // no_proxy
891 },
892
893 // Expected result.
894 ProxyConfigService::CONFIG_VALID,
895 false, // auto_detect
896 GURL(), // pac_url
897 ProxyRulesExpectation::Empty(),
898 },
899
900 {
901 TEST_DESC("Single-host in proxy list"),
902 {
903 // Input.
904 nullptr, // DESKTOP_SESSION
905 nullptr, // HOME
906 nullptr, // KDEHOME
907 nullptr, // KDE_SESSION_VERSION
908 nullptr, // XDG_CURRENT_DESKTOP
909 nullptr, // auto_proxy
910 "www.google.com", // all_proxy
911 nullptr, nullptr, nullptr, // per-proto proxies
912 nullptr, nullptr, // SOCKS
913 nullptr, // no_proxy
914 },
915
916 // Expected result.
917 ProxyConfigService::CONFIG_VALID,
918 false, // auto_detect
919 GURL(), // pac_url
920 ProxyRulesExpectation::Single("www.google.com:80", // single proxy
921 ""), // bypass rules
922 },
923
924 {
925 TEST_DESC("Single-host, different port"),
926 {
927 // Input.
928 nullptr, // DESKTOP_SESSION
929 nullptr, // HOME
930 nullptr, // KDEHOME
931 nullptr, // KDE_SESSION_VERSION
932 nullptr, // XDG_CURRENT_DESKTOP
933 nullptr, // auto_proxy
934 "www.google.com:99", // all_proxy
935 nullptr, nullptr, nullptr, // per-proto proxies
936 nullptr, nullptr, // SOCKS
937 nullptr, // no_proxy
938 },
939
940 // Expected result.
941 ProxyConfigService::CONFIG_VALID,
942 false, // auto_detect
943 GURL(), // pac_url
944 ProxyRulesExpectation::Single("www.google.com:99", // single
945 ""), // bypass rules
946 },
947
948 {
949 TEST_DESC("Tolerate a scheme"),
950 {
951 // Input.
952 nullptr, // DESKTOP_SESSION
953 nullptr, // HOME
954 nullptr, // KDEHOME
955 nullptr, // KDE_SESSION_VERSION
956 nullptr, // XDG_CURRENT_DESKTOP
957 nullptr, // auto_proxy
958 "http://www.google.com:99", // all_proxy
959 nullptr, nullptr, nullptr, // per-proto proxies
960 nullptr, nullptr, // SOCKS
961 nullptr, // no_proxy
962 },
963
964 // Expected result.
965 ProxyConfigService::CONFIG_VALID,
966 false, // auto_detect
967 GURL(), // pac_url
968 ProxyRulesExpectation::Single("www.google.com:99", // single proxy
969 ""), // bypass rules
970 },
971
972 {
973 TEST_DESC("Per-scheme proxy rules"),
974 {
975 // Input.
976 nullptr, // DESKTOP_SESSION
977 nullptr, // HOME
978 nullptr, // KDEHOME
979 nullptr, // KDE_SESSION_VERSION
980 nullptr, // XDG_CURRENT_DESKTOP
981 nullptr, // auto_proxy
982 nullptr, // all_proxy
983 "www.google.com:80", "www.foo.com:110",
984 "ftp.foo.com:121", // per-proto
985 nullptr, nullptr, // SOCKS
986 nullptr, // no_proxy
987 },
988
989 // Expected result.
990 ProxyConfigService::CONFIG_VALID,
991 false, // auto_detect
992 GURL(), // pac_url
993 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
994 "www.foo.com:110", // https
995 "ftp.foo.com:121", // ftp
996 ""), // bypass rules
997 },
998
999 {
1000 TEST_DESC("socks"),
1001 {
1002 // Input.
1003 nullptr, // DESKTOP_SESSION
1004 nullptr, // HOME
1005 nullptr, // KDEHOME
1006 nullptr, // KDE_SESSION_VERSION
1007 nullptr, // XDG_CURRENT_DESKTOP
1008 nullptr, // auto_proxy
1009 "", // all_proxy
1010 nullptr, nullptr, nullptr, // per-proto proxies
1011 "socks.com:888", nullptr, // SOCKS
1012 nullptr, // no_proxy
1013 },
1014
1015 // Expected result.
1016 ProxyConfigService::CONFIG_VALID,
1017 false, // auto_detect
1018 GURL(), // pac_url
1019 ProxyRulesExpectation::Single(
1020 "socks5://socks.com:888", // single proxy
1021 ""), // bypass rules
1022 },
1023
1024 {
1025 TEST_DESC("socks4"),
1026 {
1027 // Input.
1028 nullptr, // DESKTOP_SESSION
1029 nullptr, // HOME
1030 nullptr, // KDEHOME
1031 nullptr, // KDE_SESSION_VERSION
1032 nullptr, // XDG_CURRENT_DESKTOP
1033 nullptr, // auto_proxy
1034 "", // all_proxy
1035 nullptr, nullptr, nullptr, // per-proto proxies
1036 "socks.com:888", "4", // SOCKS
1037 nullptr, // no_proxy
1038 },
1039
1040 // Expected result.
1041 ProxyConfigService::CONFIG_VALID,
1042 false, // auto_detect
1043 GURL(), // pac_url
1044 ProxyRulesExpectation::Single(
1045 "socks4://socks.com:888", // single proxy
1046 ""), // bypass rules
1047 },
1048
1049 {
1050 TEST_DESC("socks default port"),
1051 {
1052 // Input.
1053 nullptr, // DESKTOP_SESSION
1054 nullptr, // HOME
1055 nullptr, // KDEHOME
1056 nullptr, // KDE_SESSION_VERSION
1057 nullptr, // XDG_CURRENT_DESKTOP
1058 nullptr, // auto_proxy
1059 "", // all_proxy
1060 nullptr, nullptr, nullptr, // per-proto proxies
1061 "socks.com", nullptr, // SOCKS
1062 nullptr, // no_proxy
1063 },
1064
1065 // Expected result.
1066 ProxyConfigService::CONFIG_VALID,
1067 false, // auto_detect
1068 GURL(), // pac_url
1069 ProxyRulesExpectation::Single(
1070 "socks5://socks.com:1080", // single proxy
1071 ""), // bypass rules
1072 },
1073
1074 {
1075 TEST_DESC("bypass"),
1076 {
1077 // Input.
1078 nullptr, // DESKTOP_SESSION
1079 nullptr, // HOME
1080 nullptr, // KDEHOME
1081 nullptr, // KDE_SESSION_VERSION
1082 nullptr, // XDG_CURRENT_DESKTOP
1083 nullptr, // auto_proxy
1084 "www.google.com", // all_proxy
1085 nullptr, nullptr, nullptr, // per-proto
1086 nullptr, nullptr, // SOCKS
1087 ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8", // no_proxy
1088 },
1089
1090 // Expected result.
1091 ProxyConfigService::CONFIG_VALID,
1092 false, // auto_detect
1093 GURL(), // pac_url
1094 ProxyRulesExpectation::Single(
1095 "www.google.com:80",
1096 "*.google.com,*foo.com:99,1.2.3.4:22,127.0.0.1/8"),
1097 },
1098 };
1099
1100 for (size_t i = 0; i < std::size(tests); ++i) {
1101 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i,
1102 tests[i].description.c_str()));
1103 auto env = std::make_unique<MockEnvironment>();
1104 env->values = tests[i].values;
1105 auto setting_getter = std::make_unique<MockSettingGetter>();
1106 SyncConfigGetter sync_config_getter(
1107 std::make_unique<ProxyConfigServiceLinux>(
1108 std::move(env), std::move(setting_getter),
1109 TRAFFIC_ANNOTATION_FOR_TESTS));
1110 ProxyConfigWithAnnotation config;
1111 sync_config_getter.SetupAndInitialFetch();
1112 ProxyConfigService::ConfigAvailability availability =
1113 sync_config_getter.SyncGetLatestProxyConfig(&config);
1114 EXPECT_EQ(tests[i].availability, availability);
1115
1116 if (availability == ProxyConfigService::CONFIG_VALID) {
1117 EXPECT_EQ(tests[i].auto_detect, config.value().auto_detect());
1118 EXPECT_EQ(tests[i].pac_url, config.value().pac_url());
1119 EXPECT_TRUE(tests[i].proxy_rules.Matches(config.value().proxy_rules()));
1120 }
1121 }
1122 }
1123
TEST_F(ProxyConfigServiceLinuxTest,GSettingsNotification)1124 TEST_F(ProxyConfigServiceLinuxTest, GSettingsNotification) {
1125 auto env = std::make_unique<MockEnvironment>();
1126 auto setting_getter = std::make_unique<MockSettingGetter>();
1127 auto* setting_getter_ptr = setting_getter.get();
1128 auto service = std::make_unique<ProxyConfigServiceLinux>(
1129 std::move(env), std::move(setting_getter), TRAFFIC_ANNOTATION_FOR_TESTS);
1130 auto* service_ptr = service.get();
1131 SyncConfigGetter sync_config_getter(std::move(service));
1132 ProxyConfigWithAnnotation config;
1133
1134 // Start with no proxy.
1135 setting_getter_ptr->values.mode = "none";
1136 sync_config_getter.SetupAndInitialFetch();
1137 EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1138 sync_config_getter.SyncGetLatestProxyConfig(&config));
1139 EXPECT_FALSE(config.value().auto_detect());
1140
1141 // Now set to auto-detect.
1142 setting_getter_ptr->values.mode = "auto";
1143 // Simulate setting change notification callback.
1144 service_ptr->OnCheckProxyConfigSettings();
1145 EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1146 sync_config_getter.SyncGetLatestProxyConfig(&config));
1147 EXPECT_TRUE(config.value().auto_detect());
1148
1149 // Simulate two settings changes, where PROXY_MODE is missing. This will make
1150 // the settings be interpreted as DIRECT.
1151 //
1152 // Trigering the check a *second* time is a regression test for
1153 // https://crbug.com/848237, where a comparison is done between two nullopts.
1154 for (size_t i = 0; i < 2; ++i) {
1155 setting_getter_ptr->values.mode = nullptr;
1156 service_ptr->OnCheckProxyConfigSettings();
1157 EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1158 sync_config_getter.SyncGetLatestProxyConfig(&config));
1159 EXPECT_FALSE(config.value().auto_detect());
1160 EXPECT_TRUE(config.value().proxy_rules().empty());
1161 }
1162 }
1163
TEST_F(ProxyConfigServiceLinuxTest,KDEConfigParser)1164 TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) {
1165 // One of the tests below needs a worst-case long line prefix. We build it
1166 // programmatically so that it will always be the right size.
1167 std::string long_line;
1168 size_t limit = ProxyConfigServiceLinux::SettingGetter::BUFFER_SIZE - 1;
1169 for (size_t i = 0; i < limit; ++i)
1170 long_line += "-";
1171
1172 // Inspired from proxy_config_service_win_unittest.cc.
1173 const struct {
1174 // Short description to identify the test
1175 std::string description;
1176
1177 // Input.
1178 std::string kioslaverc;
1179 EnvVarValues env_values;
1180
1181 // Expected outputs (availability and fields of ProxyConfig).
1182 ProxyConfigService::ConfigAvailability availability;
1183 bool auto_detect;
1184 GURL pac_url;
1185 ProxyRulesExpectation proxy_rules;
1186 } tests[] = {
1187 {
1188 TEST_DESC("No proxying"),
1189
1190 // Input.
1191 "[Proxy Settings]\nProxyType=0\n",
1192 {}, // env_values
1193
1194 // Expected result.
1195 ProxyConfigService::CONFIG_VALID,
1196 false, // auto_detect
1197 GURL(), // pac_url
1198 ProxyRulesExpectation::Empty(),
1199 },
1200 {
1201 TEST_DESC("Invalid proxy type (ProxyType=-3)"),
1202
1203 // Input.
1204 "[Proxy Settings]\nProxyType=-3\n",
1205 {}, // env_values
1206
1207 // Expected result.
1208 ProxyConfigService::CONFIG_VALID,
1209 false, // auto_detect
1210 GURL(), // pac_url
1211 ProxyRulesExpectation::Empty(),
1212 },
1213
1214 {
1215 TEST_DESC("Invalid proxy type (ProxyType=AB-)"),
1216
1217 // Input.
1218 "[Proxy Settings]\nProxyType=AB-\n",
1219 {}, // env_values
1220
1221 // Expected result.
1222 ProxyConfigService::CONFIG_VALID,
1223 false, // auto_detect
1224 GURL(), // pac_url
1225 ProxyRulesExpectation::Empty(),
1226 },
1227
1228 {
1229 TEST_DESC("Auto detect"),
1230
1231 // Input.
1232 "[Proxy Settings]\nProxyType=3\n",
1233 {}, // env_values
1234
1235 // Expected result.
1236 ProxyConfigService::CONFIG_VALID,
1237 true, // auto_detect
1238 GURL(), // pac_url
1239 ProxyRulesExpectation::Empty(),
1240 },
1241
1242 {
1243 TEST_DESC("Valid PAC URL"),
1244
1245 // Input.
1246 "[Proxy Settings]\nProxyType=2\n"
1247 "Proxy Config Script=http://wpad/wpad.dat\n",
1248 {}, // env_values
1249
1250 // Expected result.
1251 ProxyConfigService::CONFIG_VALID,
1252 false, // auto_detect
1253 GURL("http://wpad/wpad.dat"), // pac_url
1254 ProxyRulesExpectation::Empty(),
1255 },
1256
1257 {
1258 TEST_DESC("Valid PAC file without file://"),
1259
1260 // Input.
1261 "[Proxy Settings]\nProxyType=2\n"
1262 "Proxy Config Script=/wpad/wpad.dat\n",
1263 {}, // env_values
1264
1265 // Expected result.
1266 ProxyConfigService::CONFIG_VALID,
1267 false, // auto_detect
1268 GURL("file:///wpad/wpad.dat"), // pac_url
1269 ProxyRulesExpectation::Empty(),
1270 },
1271
1272 {
1273 TEST_DESC("Per-scheme proxy rules"),
1274
1275 // Input.
1276 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1277 "httpsProxy=www.foo.com\nftpProxy=ftp.foo.com\n",
1278 {}, // env_values
1279
1280 // Expected result.
1281 ProxyConfigService::CONFIG_VALID,
1282 false, // auto_detect
1283 GURL(), // pac_url
1284 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
1285 "www.foo.com:80", // https
1286 "ftp.foo.com:80", // http
1287 ""), // bypass rules
1288 },
1289
1290 {
1291 TEST_DESC("Only HTTP proxy specified"),
1292
1293 // Input.
1294 "[Proxy Settings]\nProxyType=1\n"
1295 "httpProxy=www.google.com\n",
1296 {}, // env_values
1297
1298 // Expected result.
1299 ProxyConfigService::CONFIG_VALID,
1300 false, // auto_detect
1301 GURL(), // pac_url
1302 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
1303 "", // https
1304 "", // ftp
1305 ""), // bypass rules
1306 },
1307
1308 {
1309 TEST_DESC("Only HTTP proxy specified, different port"),
1310
1311 // Input.
1312 "[Proxy Settings]\nProxyType=1\n"
1313 "httpProxy=www.google.com:88\n",
1314 {}, // env_values
1315
1316 // Expected result.
1317 ProxyConfigService::CONFIG_VALID,
1318 false, // auto_detect
1319 GURL(), // pac_url
1320 ProxyRulesExpectation::PerScheme("www.google.com:88", // http
1321 "", // https
1322 "", // ftp
1323 ""), // bypass rules
1324 },
1325
1326 {
1327 TEST_DESC(
1328 "Only HTTP proxy specified, different port, space-delimited"),
1329
1330 // Input.
1331 "[Proxy Settings]\nProxyType=1\n"
1332 "httpProxy=www.google.com 88\n",
1333 {}, // env_values
1334
1335 // Expected result.
1336 ProxyConfigService::CONFIG_VALID,
1337 false, // auto_detect
1338 GURL(), // pac_url
1339 ProxyRulesExpectation::PerScheme("www.google.com:88", // http
1340 "", // https
1341 "", // ftp
1342 ""), // bypass rules
1343 },
1344
1345 {
1346 TEST_DESC("Bypass *.google.com"),
1347
1348 // Input.
1349 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1350 "NoProxyFor=.google.com\n",
1351 {}, // env_values
1352
1353 // Expected result.
1354 ProxyConfigService::CONFIG_VALID,
1355 false, // auto_detect
1356 GURL(), // pac_url
1357 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
1358 "", // https
1359 "", // ftp
1360 "*.google.com"), // bypass rules
1361 },
1362
1363 {
1364 TEST_DESC("Bypass *.google.com and *.kde.org"),
1365
1366 // Input.
1367 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1368 "NoProxyFor=.google.com,.kde.org\n",
1369 {}, // env_values
1370
1371 // Expected result.
1372 ProxyConfigService::CONFIG_VALID,
1373 false, // auto_detect
1374 GURL(), // pac_url
1375 ProxyRulesExpectation::PerScheme(
1376 "www.google.com:80", // http
1377 "", // https
1378 "", // ftp
1379 "*.google.com,*.kde.org"), // bypass rules
1380 },
1381
1382 {
1383 TEST_DESC("Correctly parse bypass list with ReversedException=true"),
1384
1385 // Input.
1386 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1387 "NoProxyFor=.google.com\nReversedException=true\n",
1388 {}, // env_values
1389
1390 // Expected result.
1391 ProxyConfigService::CONFIG_VALID,
1392 false, // auto_detect
1393 GURL(), // pac_url
1394 ProxyRulesExpectation::PerSchemeWithBypassReversed(
1395 "www.google.com:80", // http
1396 "", // https
1397 "", // ftp
1398 "*.google.com"), // bypass rules
1399 },
1400
1401 {
1402 TEST_DESC("Correctly parse bypass list with ReversedException=false"),
1403
1404 // Input.
1405 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1406 "NoProxyFor=.google.com\nReversedException=false\n",
1407 {}, // env_values
1408
1409 // Expected result.
1410 ProxyConfigService::CONFIG_VALID,
1411 false, // auto_detect
1412 GURL(), // pac_url
1413 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
1414 "", // https
1415 "", // ftp
1416 "*.google.com"), // bypass rules
1417 },
1418
1419 {
1420 TEST_DESC("Correctly parse bypass list with ReversedException=1"),
1421
1422 // Input.
1423 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1424 "NoProxyFor=.google.com\nReversedException=1\n",
1425 {}, // env_values
1426
1427 // Expected result.
1428 ProxyConfigService::CONFIG_VALID,
1429 false, // auto_detect
1430 GURL(), // pac_url
1431 ProxyRulesExpectation::PerSchemeWithBypassReversed(
1432 "www.google.com:80", // http
1433 "", // https
1434 "", // ftp
1435 "*.google.com"), // bypass rules
1436 },
1437
1438 {
1439 TEST_DESC("Overflow: ReversedException=18446744073709551617"),
1440
1441 // Input.
1442 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1443 "NoProxyFor=.google.com\nReversedException=18446744073709551617\n",
1444 {}, // env_values
1445
1446 // Expected result.
1447 ProxyConfigService::CONFIG_VALID,
1448 false, // auto_detect
1449 GURL(), // pac_url
1450 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
1451 "", // https
1452 "", // ftp
1453 "*.google.com"), // bypass rules
1454 },
1455
1456 {
1457 TEST_DESC("Not a number: ReversedException=noitpecxE"),
1458
1459 // Input.
1460 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1461 "NoProxyFor=.google.com\nReversedException=noitpecxE\n",
1462 {}, // env_values
1463
1464 // Expected result.
1465 ProxyConfigService::CONFIG_VALID,
1466 false, // auto_detect
1467 GURL(), // pac_url
1468 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
1469 "", // https
1470 "", // ftp
1471 "*.google.com"), // bypass rules
1472 },
1473
1474 {
1475 TEST_DESC("socks"),
1476
1477 // Input.
1478 "[Proxy Settings]\nProxyType=1\nsocksProxy=socks.com 888\n",
1479 {}, // env_values
1480
1481 // Expected result.
1482 ProxyConfigService::CONFIG_VALID,
1483 false, // auto_detect
1484 GURL(), // pac_url
1485 ProxyRulesExpectation::Single(
1486 "socks5://socks.com:888", // single proxy
1487 ""), // bypass rules
1488 },
1489
1490 {
1491 TEST_DESC("socks4"),
1492
1493 // Input.
1494 "[Proxy Settings]\nProxyType=1\nsocksProxy=socks4://socks.com 888\n",
1495 {}, // env_values
1496
1497 // Expected result.
1498 ProxyConfigService::CONFIG_VALID,
1499 false, // auto_detect
1500 GURL(), // pac_url
1501 ProxyRulesExpectation::Single(
1502 "socks4://socks.com:888", // single proxy
1503 ""), // bypass rules
1504 },
1505
1506 {
1507 TEST_DESC("Treat all hostname patterns as wildcard patterns"),
1508
1509 // Input.
1510 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1511 "NoProxyFor=google.com,kde.org,<local>\n",
1512 {}, // env_values
1513
1514 // Expected result.
1515 ProxyConfigService::CONFIG_VALID,
1516 false, // auto_detect
1517 GURL(), // pac_url
1518 ProxyRulesExpectation::PerScheme(
1519 "www.google.com:80", // http
1520 "", // https
1521 "", // ftp
1522 "*google.com,*kde.org,<local>"), // bypass rules
1523 },
1524
1525 {
1526 TEST_DESC("Allow trailing whitespace after boolean value"),
1527
1528 // Input.
1529 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1530 "NoProxyFor=.google.com\nReversedException=true \n",
1531 {}, // env_values
1532
1533 // Expected result.
1534 ProxyConfigService::CONFIG_VALID,
1535 false, // auto_detect
1536 GURL(), // pac_url
1537 ProxyRulesExpectation::PerSchemeWithBypassReversed(
1538 "www.google.com:80", // http
1539 "", // https
1540 "", // ftp
1541 "*.google.com"), // bypass rules
1542 },
1543
1544 {
1545 TEST_DESC("Ignore settings outside [Proxy Settings]"),
1546
1547 // Input.
1548 "httpsProxy=www.foo.com\n[Proxy Settings]\nProxyType=1\n"
1549 "httpProxy=www.google.com\n[Other Section]\nftpProxy=ftp.foo.com\n",
1550 {}, // env_values
1551
1552 // Expected result.
1553 ProxyConfigService::CONFIG_VALID,
1554 false, // auto_detect
1555 GURL(), // pac_url
1556 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
1557 "", // https
1558 "", // ftp
1559 ""), // bypass rules
1560 },
1561
1562 {
1563 TEST_DESC("Handle CRLF line endings"),
1564
1565 // Input.
1566 "[Proxy Settings]\r\nProxyType=1\r\nhttpProxy=www.google.com\r\n",
1567 {}, // env_values
1568
1569 // Expected result.
1570 ProxyConfigService::CONFIG_VALID,
1571 false, // auto_detect
1572 GURL(), // pac_url
1573 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
1574 "", // https
1575 "", // ftp
1576 ""), // bypass rules
1577 },
1578
1579 {
1580 TEST_DESC("Handle blank lines and mixed line endings"),
1581
1582 // Input.
1583 "[Proxy Settings]\r\n\nProxyType=1\n\r\nhttpProxy=www.google.com\n\n",
1584 {}, // env_values
1585
1586 // Expected result.
1587 ProxyConfigService::CONFIG_VALID,
1588 false, // auto_detect
1589 GURL(), // pac_url
1590 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
1591 "", // https
1592 "", // ftp
1593 ""), // bypass rules
1594 },
1595
1596 {
1597 TEST_DESC("Handle localized settings"),
1598
1599 // Input.
1600 "[Proxy Settings]\nProxyType[$e]=1\nhttpProxy[$e]=www.google.com\n",
1601 {}, // env_values
1602
1603 // Expected result.
1604 ProxyConfigService::CONFIG_VALID,
1605 false, // auto_detect
1606 GURL(), // pac_url
1607 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
1608 "", // https
1609 "", // ftp
1610 ""), // bypass rules
1611 },
1612
1613 {
1614 TEST_DESC("Ignore malformed localized settings"),
1615
1616 // Input.
1617 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1618 "httpsProxy$e]=www.foo.com\nftpProxy=ftp.foo.com\n",
1619 {}, // env_values
1620
1621 // Expected result.
1622 ProxyConfigService::CONFIG_VALID,
1623 false, // auto_detect
1624 GURL(), // pac_url
1625 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
1626 "", // https
1627 "ftp.foo.com:80", // ftp
1628 ""), // bypass rules
1629 },
1630
1631 {
1632 TEST_DESC("Handle strange whitespace"),
1633
1634 // Input.
1635 "[Proxy Settings]\nProxyType [$e] =2\n"
1636 " Proxy Config Script = http:// foo\n",
1637 {}, // env_values
1638
1639 // Expected result.
1640 ProxyConfigService::CONFIG_VALID,
1641 false, // auto_detect
1642 GURL("http:// foo"), // pac_url
1643 ProxyRulesExpectation::Empty(),
1644 },
1645
1646 {
1647 TEST_DESC("Ignore all of a line which is too long"),
1648
1649 // Input.
1650 std::string("[Proxy Settings]\nProxyType=1\nftpProxy=ftp.foo.com\n") +
1651 long_line + "httpsProxy=www.foo.com\nhttpProxy=www.google.com\n",
1652 {}, // env_values
1653
1654 // Expected result.
1655 ProxyConfigService::CONFIG_VALID,
1656 false, // auto_detect
1657 GURL(), // pac_url
1658 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
1659 "", // https
1660 "ftp.foo.com:80", // ftp
1661 ""), // bypass rules
1662 },
1663
1664 {
1665 TEST_DESC("Indirect Proxy - no env vars set"),
1666
1667 // Input.
1668 "[Proxy Settings]\nProxyType=4\nhttpProxy=http_proxy\n"
1669 "httpsProxy=https_proxy\nftpProxy=ftp_proxy\nNoProxyFor=no_proxy\n",
1670 {}, // env_values
1671
1672 // Expected result.
1673 ProxyConfigService::CONFIG_VALID,
1674 false, // auto_detect
1675 GURL(), // pac_url
1676 ProxyRulesExpectation::Empty(),
1677 },
1678
1679 {
1680 TEST_DESC("Indirect Proxy - with env vars set"),
1681
1682 // Input.
1683 "[Proxy Settings]\nProxyType=4\nhttpProxy=http_proxy\n"
1684 "httpsProxy=https_proxy\nftpProxy=ftp_proxy\nNoProxyFor=no_proxy\n"
1685 "socksProxy=SOCKS_SERVER\n",
1686 {
1687 // env_values
1688 nullptr, // DESKTOP_SESSION
1689 nullptr, // HOME
1690 nullptr, // KDEHOME
1691 nullptr, // KDE_SESSION_VERSION
1692 nullptr, // XDG_CURRENT_DESKTOP
1693 nullptr, // auto_proxy
1694 nullptr, // all_proxy
1695 "www.normal.com", // http_proxy
1696 "www.secure.com", // https_proxy
1697 "ftp.foo.com", // ftp_proxy
1698 "socks.comfy.com:1234", nullptr, // SOCKS
1699 ".google.com, .kde.org", // no_proxy
1700 },
1701
1702 // Expected result.
1703 ProxyConfigService::CONFIG_VALID,
1704 false, // auto_detect
1705 GURL(), // pac_url
1706 ProxyRulesExpectation::PerSchemeWithSocks(
1707 "www.normal.com:80", // http
1708 "www.secure.com:80", // https
1709 "ftp.foo.com:80", // ftp
1710 "socks5://socks.comfy.com:1234", // socks
1711 "*.google.com,*.kde.org"), // bypass rules
1712 },
1713 };
1714
1715 for (size_t i = 0; i < std::size(tests); ++i) {
1716 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i,
1717 tests[i].description.c_str()));
1718 auto env = std::make_unique<MockEnvironment>();
1719 env->values = tests[i].env_values;
1720 // Force the KDE getter to be used and tell it where the test is.
1721 env->values.DESKTOP_SESSION = "kde4";
1722 env->values.KDEHOME = kde_home_.value().c_str();
1723 SyncConfigGetter sync_config_getter(
1724 std::make_unique<ProxyConfigServiceLinux>(
1725 std::move(env), TRAFFIC_ANNOTATION_FOR_TESTS));
1726 ProxyConfigWithAnnotation config;
1727 // Overwrite the kioslaverc file.
1728 base::WriteFile(kioslaverc_, tests[i].kioslaverc);
1729 sync_config_getter.SetupAndInitialFetch();
1730 ProxyConfigService::ConfigAvailability availability =
1731 sync_config_getter.SyncGetLatestProxyConfig(&config);
1732 EXPECT_EQ(tests[i].availability, availability);
1733
1734 if (availability == ProxyConfigService::CONFIG_VALID) {
1735 EXPECT_EQ(tests[i].auto_detect, config.value().auto_detect());
1736 EXPECT_EQ(tests[i].pac_url, config.value().pac_url());
1737 EXPECT_TRUE(tests[i].proxy_rules.Matches(config.value().proxy_rules()));
1738 }
1739 }
1740 }
1741
TEST_F(ProxyConfigServiceLinuxTest,KDEHomePicker)1742 TEST_F(ProxyConfigServiceLinuxTest, KDEHomePicker) {
1743 // Auto detect proxy settings.
1744 std::string slaverc3 = "[Proxy Settings]\nProxyType=3\n";
1745 // Valid PAC URL.
1746 std::string slaverc4 =
1747 "[Proxy Settings]\nProxyType=2\n"
1748 "Proxy Config Script=http://wpad/wpad.dat\n";
1749 GURL slaverc4_pac_url("http://wpad/wpad.dat");
1750 // Basic HTTP proxy setting.
1751 std::string slaverc5 =
1752 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com 80\n";
1753 ProxyRulesExpectation slaverc5_rules =
1754 ProxyRulesExpectation::PerScheme("www.google.com:80", // http
1755 "", // https
1756 "", // ftp
1757 ""); // bypass rules
1758
1759 // Overwrite the .kde kioslaverc file.
1760 base::WriteFile(kioslaverc_, slaverc3);
1761
1762 // If .kde4 exists it will mess up the first test. It should not, as
1763 // we created the directory for $HOME in the test setup.
1764 CHECK(!base::DirectoryExists(kde4_home_));
1765
1766 {
1767 SCOPED_TRACE("KDE4, no .kde4 directory, verify fallback");
1768 auto env = std::make_unique<MockEnvironment>();
1769 env->values.DESKTOP_SESSION = "kde4";
1770 env->values.HOME = user_home_.value().c_str();
1771 SyncConfigGetter sync_config_getter(
1772 std::make_unique<ProxyConfigServiceLinux>(
1773 std::move(env), TRAFFIC_ANNOTATION_FOR_TESTS));
1774 ProxyConfigWithAnnotation config;
1775 sync_config_getter.SetupAndInitialFetch();
1776 EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1777 sync_config_getter.SyncGetLatestProxyConfig(&config));
1778 EXPECT_TRUE(config.value().auto_detect());
1779 EXPECT_EQ(GURL(), config.value().pac_url());
1780 }
1781
1782 // Now create .kde4 and put a kioslaverc in the config directory.
1783 // Note that its timestamp will be at least as new as the .kde one.
1784 base::CreateDirectory(kde4_config_);
1785 base::WriteFile(kioslaverc4_, slaverc4);
1786 CHECK(base::PathExists(kioslaverc4_));
1787
1788 {
1789 SCOPED_TRACE("KDE4, .kde4 directory present, use it");
1790 auto env = std::make_unique<MockEnvironment>();
1791 env->values.DESKTOP_SESSION = "kde4";
1792 env->values.HOME = user_home_.value().c_str();
1793 SyncConfigGetter sync_config_getter(
1794 std::make_unique<ProxyConfigServiceLinux>(
1795 std::move(env), TRAFFIC_ANNOTATION_FOR_TESTS));
1796 ProxyConfigWithAnnotation config;
1797 sync_config_getter.SetupAndInitialFetch();
1798 EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1799 sync_config_getter.SyncGetLatestProxyConfig(&config));
1800 EXPECT_FALSE(config.value().auto_detect());
1801 EXPECT_EQ(slaverc4_pac_url, config.value().pac_url());
1802 }
1803
1804 {
1805 SCOPED_TRACE("KDE3, .kde4 directory present, ignore it");
1806 auto env = std::make_unique<MockEnvironment>();
1807 env->values.DESKTOP_SESSION = "kde";
1808 env->values.HOME = user_home_.value().c_str();
1809 SyncConfigGetter sync_config_getter(
1810 std::make_unique<ProxyConfigServiceLinux>(
1811 std::move(env), TRAFFIC_ANNOTATION_FOR_TESTS));
1812 ProxyConfigWithAnnotation config;
1813 sync_config_getter.SetupAndInitialFetch();
1814 EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1815 sync_config_getter.SyncGetLatestProxyConfig(&config));
1816 EXPECT_TRUE(config.value().auto_detect());
1817 EXPECT_EQ(GURL(), config.value().pac_url());
1818 }
1819
1820 {
1821 SCOPED_TRACE("KDE4, .kde4 directory present, KDEHOME set to .kde");
1822 auto env = std::make_unique<MockEnvironment>();
1823 env->values.DESKTOP_SESSION = "kde4";
1824 env->values.HOME = user_home_.value().c_str();
1825 env->values.KDEHOME = kde_home_.value().c_str();
1826 SyncConfigGetter sync_config_getter(
1827 std::make_unique<ProxyConfigServiceLinux>(
1828 std::move(env), TRAFFIC_ANNOTATION_FOR_TESTS));
1829 ProxyConfigWithAnnotation config;
1830 sync_config_getter.SetupAndInitialFetch();
1831 EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1832 sync_config_getter.SyncGetLatestProxyConfig(&config));
1833 EXPECT_TRUE(config.value().auto_detect());
1834 EXPECT_EQ(GURL(), config.value().pac_url());
1835 }
1836
1837 // Finally, make the .kde4 config directory older than the .kde directory
1838 // and make sure we then use .kde instead of .kde4 since it's newer.
1839 base::TouchFile(kde4_config_, base::Time(), base::Time());
1840
1841 {
1842 SCOPED_TRACE("KDE4, very old .kde4 directory present, use .kde");
1843 auto env = std::make_unique<MockEnvironment>();
1844 env->values.DESKTOP_SESSION = "kde4";
1845 env->values.HOME = user_home_.value().c_str();
1846 SyncConfigGetter sync_config_getter(
1847 std::make_unique<ProxyConfigServiceLinux>(
1848 std::move(env), TRAFFIC_ANNOTATION_FOR_TESTS));
1849 ProxyConfigWithAnnotation config;
1850 sync_config_getter.SetupAndInitialFetch();
1851 EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1852 sync_config_getter.SyncGetLatestProxyConfig(&config));
1853 EXPECT_TRUE(config.value().auto_detect());
1854 EXPECT_EQ(GURL(), config.value().pac_url());
1855 }
1856
1857 // For KDE 5 create ${HOME}/.config and put a kioslaverc in the directory.
1858 base::CreateDirectory(config_home_);
1859 base::WriteFile(kioslaverc5_, slaverc5);
1860 CHECK(base::PathExists(kioslaverc5_));
1861
1862 {
1863 SCOPED_TRACE("KDE5, .kde and .kde4 present, use .config");
1864 auto env = std::make_unique<MockEnvironment>();
1865 env->values.XDG_CURRENT_DESKTOP = "KDE";
1866 env->values.KDE_SESSION_VERSION = "5";
1867 env->values.HOME = user_home_.value().c_str();
1868 SyncConfigGetter sync_config_getter(
1869 std::make_unique<ProxyConfigServiceLinux>(
1870 std::move(env), TRAFFIC_ANNOTATION_FOR_TESTS));
1871 ProxyConfigWithAnnotation config;
1872 sync_config_getter.SetupAndInitialFetch();
1873 EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1874 sync_config_getter.SyncGetLatestProxyConfig(&config));
1875 EXPECT_FALSE(config.value().auto_detect());
1876 EXPECT_TRUE(slaverc5_rules.Matches(config.value().proxy_rules()));
1877 }
1878 }
1879
1880 // Tests that the KDE proxy config service watches for file and directory
1881 // changes.
TEST_F(ProxyConfigServiceLinuxTest,KDEFileChanged)1882 TEST_F(ProxyConfigServiceLinuxTest, KDEFileChanged) {
1883 // Set up the initial .kde kioslaverc file.
1884 EXPECT_TRUE(
1885 base::WriteFile(kioslaverc_,
1886 "[Proxy Settings]\nProxyType=2\n"
1887 "Proxy Config Script=http://version1/wpad.dat\n"));
1888
1889 // Initialize the config service using kioslaverc.
1890 auto env = std::make_unique<MockEnvironment>();
1891 env->values.DESKTOP_SESSION = "kde4";
1892 env->values.HOME = user_home_.value().c_str();
1893 SyncConfigGetter sync_config_getter(std::make_unique<ProxyConfigServiceLinux>(
1894 std::move(env), TRAFFIC_ANNOTATION_FOR_TESTS));
1895 ProxyConfigWithAnnotation config;
1896 sync_config_getter.SetupAndInitialFetch();
1897 EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1898 sync_config_getter.SyncGetLatestProxyConfig(&config));
1899 EXPECT_TRUE(config.value().has_pac_url());
1900 EXPECT_EQ(GURL("http://version1/wpad.dat"), config.value().pac_url());
1901
1902 //-----------------------------------------------------
1903
1904 // Change the kioslaverc file by overwriting it. Verify that the change was
1905 // observed.
1906 sync_config_getter.SetExpectedPacUrl("http://version2/wpad.dat");
1907
1908 // Initialization posts a task to start watching kioslaverc file. Ensure that
1909 // registration has happened before modifying it or the file change won't be
1910 // observed.
1911 base::ThreadPoolInstance::Get()->FlushForTesting();
1912
1913 EXPECT_TRUE(
1914 base::WriteFile(kioslaverc_,
1915 "[Proxy Settings]\nProxyType=2\n"
1916 "Proxy Config Script=http://version2/wpad.dat\n"));
1917
1918 // Wait for change to be noticed.
1919 sync_config_getter.WaitUntilPacUrlMatchesExpectation();
1920
1921 //-----------------------------------------------------
1922
1923 // Change the kioslaverc file by renaming it. If only the file's inode
1924 // were being watched (rather than directory) this will not result in
1925 // an observable change. Note that KDE when re-writing proxy settings does
1926 // so by renaming a new file, so the inode will change.
1927 sync_config_getter.SetExpectedPacUrl("http://version3/wpad.dat");
1928
1929 // Create a new file, and rename it into place.
1930 EXPECT_TRUE(
1931 base::WriteFile(kioslaverc_.AddExtension("new"),
1932 "[Proxy Settings]\nProxyType=2\n"
1933 "Proxy Config Script=http://version3/wpad.dat\n"));
1934 base::Move(kioslaverc_, kioslaverc_.AddExtension("old"));
1935 base::Move(kioslaverc_.AddExtension("new"), kioslaverc_);
1936
1937 // Wait for change to be noticed.
1938 sync_config_getter.WaitUntilPacUrlMatchesExpectation();
1939
1940 //-----------------------------------------------------
1941
1942 // Change the kioslaverc file once more by ovewriting it. This is really
1943 // just another test to make sure things still work after the directory
1944 // change was observed (this final test probably isn't very useful).
1945 sync_config_getter.SetExpectedPacUrl("http://version4/wpad.dat");
1946
1947 EXPECT_TRUE(
1948 base::WriteFile(kioslaverc_,
1949 "[Proxy Settings]\nProxyType=2\n"
1950 "Proxy Config Script=http://version4/wpad.dat\n"));
1951
1952 // Wait for change to be noticed.
1953 sync_config_getter.WaitUntilPacUrlMatchesExpectation();
1954
1955 //-----------------------------------------------------
1956
1957 // TODO(eroman): Add a test where kioslaverc is deleted next. Currently this
1958 // doesn't trigger any notifications, but it probably should.
1959 }
1960
TEST_F(ProxyConfigServiceLinuxTest,KDEMultipleKioslaverc)1961 TEST_F(ProxyConfigServiceLinuxTest, KDEMultipleKioslaverc) {
1962 std::string xdg_config_dirs = config_kdedefaults_home_.value();
1963 xdg_config_dirs += ':';
1964 xdg_config_dirs += config_xdg_home_.value();
1965
1966 const struct {
1967 // Short description to identify the test
1968 std::string description;
1969
1970 // Input.
1971 std::string kioslaverc;
1972 base::FilePath kioslaverc_path;
1973 bool auto_detect;
1974 GURL pac_url;
1975 ProxyRulesExpectation proxy_rules;
1976 } tests[] = {
1977 {
1978 TEST_DESC("Use xdg/kioslaverc"),
1979
1980 // Input.
1981 "[Proxy Settings]\nProxyType=3\n"
1982 "Proxy Config Script=http://wpad/wpad.dat\n"
1983 "httpsProxy=www.foo.com\n",
1984 kioslaverc5_xdg_, // kioslaverc path
1985 true, // auto_detect
1986 GURL(), // pac_url
1987 ProxyRulesExpectation::Empty(),
1988 },
1989 {
1990 TEST_DESC(".config/kdedefaults/kioslaverc overrides xdg/kioslaverc"),
1991
1992 // Input.
1993 "[Proxy Settings]\nProxyType=2\n"
1994 "NoProxyFor=.google.com,.kde.org\n",
1995 kioslaverc5_kdedefaults_, // kioslaverc path
1996 false, // auto_detect
1997 GURL("http://wpad/wpad.dat"), // pac_url
1998 ProxyRulesExpectation::Empty(),
1999 },
2000 {
2001 TEST_DESC(".config/kioslaverc overrides others"),
2002
2003 // Input.
2004 "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com 80\n"
2005 "ReversedException=true\n",
2006 kioslaverc5_, // kioslaverc path
2007 false, // auto_detect
2008 GURL(), // pac_url
2009 ProxyRulesExpectation::PerSchemeWithBypassReversed(
2010 "www.google.com:80", // http
2011 "www.foo.com:80", // https
2012 "", // ftp
2013 "*.google.com,*.kde.org"), // bypass rules,
2014 },
2015 };
2016
2017 // Create directories for all configs
2018 base::CreateDirectory(config_home_);
2019 base::CreateDirectory(config_xdg_home_);
2020 base::CreateDirectory(config_kdedefaults_home_);
2021
2022 for (size_t i = 0; i < std::size(tests); ++i) {
2023 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i,
2024 tests[i].description.c_str()));
2025 auto env = std::make_unique<MockEnvironment>();
2026 env->values.XDG_CURRENT_DESKTOP = "KDE";
2027 env->values.KDE_SESSION_VERSION = "5";
2028 env->values.HOME = user_home_.value().c_str();
2029 env->values.XDG_CONFIG_DIRS = xdg_config_dirs.c_str();
2030 SyncConfigGetter sync_config_getter(
2031 std::make_unique<ProxyConfigServiceLinux>(
2032 std::move(env), TRAFFIC_ANNOTATION_FOR_TESTS));
2033 ProxyConfigWithAnnotation config;
2034 // Write the kioslaverc file to specified location.
2035 base::WriteFile(tests[i].kioslaverc_path, tests[i].kioslaverc);
2036 CHECK(base::PathExists(tests[i].kioslaverc_path));
2037 sync_config_getter.SetupAndInitialFetch();
2038 ProxyConfigService::ConfigAvailability availability =
2039 sync_config_getter.SyncGetLatestProxyConfig(&config);
2040 EXPECT_EQ(availability, ProxyConfigService::CONFIG_VALID);
2041
2042 if (availability == ProxyConfigService::CONFIG_VALID) {
2043 EXPECT_EQ(tests[i].auto_detect, config.value().auto_detect());
2044 EXPECT_EQ(tests[i].pac_url, config.value().pac_url());
2045 EXPECT_TRUE(tests[i].proxy_rules.Matches(config.value().proxy_rules()));
2046 }
2047 }
2048 }
2049
2050 } // namespace
2051
2052 } // namespace net
2053