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