• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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