1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/proxy/proxy_config_service_linux.h"
6
7#include <map>
8#include <string>
9#include <vector>
10
11#include "base/bind.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/logging.h"
17#include "base/strings/string_util.h"
18#include "base/strings/stringprintf.h"
19#include "base/synchronization/waitable_event.h"
20#include "base/threading/thread.h"
21#include "net/proxy/proxy_config.h"
22#include "net/proxy/proxy_config_service_common_unittest.h"
23#include "testing/gtest/include/gtest/gtest.h"
24#include "testing/platform_test.h"
25
26namespace net {
27namespace {
28
29// Set of values for all environment variables that we might
30// query. NULL represents an unset variable.
31struct EnvVarValues {
32  // The strange capitalization is so that the field matches the
33  // environment variable name exactly.
34  const char *DESKTOP_SESSION, *HOME,
35      *KDEHOME, *KDE_SESSION_VERSION,
36      *auto_proxy, *all_proxy,
37      *http_proxy, *https_proxy, *ftp_proxy,
38      *SOCKS_SERVER, *SOCKS_VERSION,
39      *no_proxy;
40};
41
42// Undo macro pollution from GDK includes (from message_loop.h).
43#undef TRUE
44#undef FALSE
45
46// So as to distinguish between an unset gconf boolean variable and
47// one that is false.
48enum BoolSettingValue {
49  UNSET = 0, TRUE, FALSE
50};
51
52// Set of values for all gconf settings that we might query.
53struct GConfValues {
54  // strings
55  const char *mode, *autoconfig_url,
56      *http_host, *secure_host, *ftp_host, *socks_host;
57  // integers
58  int http_port, secure_port, ftp_port, socks_port;
59  // booleans
60  BoolSettingValue use_proxy, same_proxy, use_auth;
61  // string list
62  std::vector<std::string> ignore_hosts;
63};
64
65// Mapping from a setting name to the location of the corresponding
66// value (inside a EnvVarValues or GConfValues struct).
67template<typename key_type, typename value_type>
68struct SettingsTable {
69  typedef std::map<key_type, value_type*> map_type;
70
71  // Gets the value from its location
72  value_type Get(key_type key) {
73    typename map_type::const_iterator it = settings.find(key);
74    // In case there's a typo or the unittest becomes out of sync.
75    CHECK(it != settings.end()) << "key " << key << " not found";
76    value_type* value_ptr = it->second;
77    return *value_ptr;
78  }
79
80  map_type settings;
81};
82
83class MockEnvironment : public base::Environment {
84 public:
85  MockEnvironment() {
86#define ENTRY(x) table[#x] = &values.x
87    ENTRY(DESKTOP_SESSION);
88    ENTRY(HOME);
89    ENTRY(KDEHOME);
90    ENTRY(KDE_SESSION_VERSION);
91    ENTRY(auto_proxy);
92    ENTRY(all_proxy);
93    ENTRY(http_proxy);
94    ENTRY(https_proxy);
95    ENTRY(ftp_proxy);
96    ENTRY(no_proxy);
97    ENTRY(SOCKS_SERVER);
98    ENTRY(SOCKS_VERSION);
99#undef ENTRY
100    Reset();
101  }
102
103  // Zeroes all environment values.
104  void Reset() {
105    EnvVarValues zero_values = { 0 };
106    values = zero_values;
107  }
108
109  // Begin base::Environment implementation.
110  virtual bool GetVar(const char* variable_name, std::string* result) OVERRIDE {
111    std::map<std::string, const char**>::iterator it =
112        table.find(variable_name);
113    if (it != table.end() && *(it->second) != NULL) {
114      // Note that the variable may be defined but empty.
115      *result = *(it->second);
116      return true;
117    }
118    return false;
119  }
120
121  virtual bool SetVar(const char* variable_name, const std::string& new_value)
122      OVERRIDE {
123    ADD_FAILURE();
124    return false;
125  }
126
127  virtual bool UnSetVar(const char* variable_name) OVERRIDE {
128    ADD_FAILURE();
129    return false;
130  }
131  // End base::Environment implementation.
132
133  // Intentionally public, for convenience when setting up a test.
134  EnvVarValues values;
135
136 private:
137  std::map<std::string, const char**> table;
138};
139
140class MockSettingGetter
141    : public ProxyConfigServiceLinux::SettingGetter {
142 public:
143  typedef ProxyConfigServiceLinux::SettingGetter SettingGetter;
144  MockSettingGetter() {
145#define ENTRY(key, field) \
146      strings_table.settings[SettingGetter::key] = &values.field
147    ENTRY(PROXY_MODE, mode);
148    ENTRY(PROXY_AUTOCONF_URL, autoconfig_url);
149    ENTRY(PROXY_HTTP_HOST, http_host);
150    ENTRY(PROXY_HTTPS_HOST, secure_host);
151    ENTRY(PROXY_FTP_HOST, ftp_host);
152    ENTRY(PROXY_SOCKS_HOST, socks_host);
153#undef ENTRY
154#define ENTRY(key, field) \
155      ints_table.settings[SettingGetter::key] = &values.field
156    ENTRY(PROXY_HTTP_PORT, http_port);
157    ENTRY(PROXY_HTTPS_PORT, secure_port);
158    ENTRY(PROXY_FTP_PORT, ftp_port);
159    ENTRY(PROXY_SOCKS_PORT, socks_port);
160#undef ENTRY
161#define ENTRY(key, field) \
162      bools_table.settings[SettingGetter::key] = &values.field
163    ENTRY(PROXY_USE_HTTP_PROXY, use_proxy);
164    ENTRY(PROXY_USE_SAME_PROXY, same_proxy);
165    ENTRY(PROXY_USE_AUTHENTICATION, use_auth);
166#undef ENTRY
167    string_lists_table.settings[SettingGetter::PROXY_IGNORE_HOSTS] =
168        &values.ignore_hosts;
169    Reset();
170  }
171
172  // Zeros all environment values.
173  void Reset() {
174    GConfValues zero_values = { 0 };
175    values = zero_values;
176  }
177
178  virtual bool Init(
179      const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner,
180      const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner)
181      OVERRIDE {
182    task_runner_ = glib_task_runner;
183    return true;
184  }
185
186  virtual void ShutDown() OVERRIDE {}
187
188  virtual bool SetUpNotifications(ProxyConfigServiceLinux::Delegate* delegate)
189      OVERRIDE {
190    return true;
191  }
192
193  virtual const scoped_refptr<base::SingleThreadTaskRunner>&
194  GetNotificationTaskRunner() OVERRIDE {
195    return task_runner_;
196  }
197
198  virtual ProxyConfigSource GetConfigSource() OVERRIDE {
199    return PROXY_CONFIG_SOURCE_TEST;
200  }
201
202  virtual bool GetString(StringSetting key, std::string* result) OVERRIDE {
203    const char* value = strings_table.Get(key);
204    if (value) {
205      *result = value;
206      return true;
207    }
208    return false;
209  }
210
211  virtual bool GetBool(BoolSetting key, bool* result) OVERRIDE {
212    BoolSettingValue value = bools_table.Get(key);
213    switch (value) {
214    case UNSET:
215      return false;
216    case TRUE:
217      *result = true;
218      break;
219    case FALSE:
220      *result = false;
221    }
222    return true;
223  }
224
225  virtual bool GetInt(IntSetting key, int* result) OVERRIDE {
226    // We don't bother to distinguish unset keys from 0 values.
227    *result = ints_table.Get(key);
228    return true;
229  }
230
231  virtual bool GetStringList(StringListSetting key,
232                             std::vector<std::string>* result) OVERRIDE {
233    *result = string_lists_table.Get(key);
234    // We don't bother to distinguish unset keys from empty lists.
235    return !result->empty();
236  }
237
238  virtual bool BypassListIsReversed() OVERRIDE {
239    return false;
240  }
241
242  virtual bool MatchHostsUsingSuffixMatching() OVERRIDE {
243    return false;
244  }
245
246  // Intentionally public, for convenience when setting up a test.
247  GConfValues values;
248
249 private:
250  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
251  SettingsTable<StringSetting, const char*> strings_table;
252  SettingsTable<BoolSetting, BoolSettingValue> bools_table;
253  SettingsTable<IntSetting, int> ints_table;
254  SettingsTable<StringListSetting,
255                std::vector<std::string> > string_lists_table;
256};
257
258}  // namespace
259}  // namespace net
260
261// This helper class runs ProxyConfigServiceLinux::GetLatestProxyConfig() on
262// the IO thread and synchronously waits for the result.
263// Some code duplicated from proxy_script_fetcher_unittest.cc.
264class SynchConfigGetter {
265 public:
266  // Takes ownership of |config_service|.
267  explicit SynchConfigGetter(net::ProxyConfigServiceLinux* config_service)
268      : event_(false, false),
269        io_thread_("IO_Thread"),
270        config_service_(config_service) {
271    // Start an IO thread.
272    base::Thread::Options options;
273    options.message_loop_type = base::MessageLoop::TYPE_IO;
274    io_thread_.StartWithOptions(options);
275
276    // Make sure the thread started.
277    io_thread_.message_loop()->PostTask(FROM_HERE,
278        base::Bind(&SynchConfigGetter::Init, base::Unretained(this)));
279    Wait();
280  }
281
282  ~SynchConfigGetter() {
283    // Let the config service post a destroy message to the IO thread
284    // before cleaning up that thread.
285    delete config_service_;
286    // Clean up the IO thread.
287    io_thread_.message_loop()->PostTask(FROM_HERE,
288        base::Bind(&SynchConfigGetter::CleanUp, base::Unretained(this)));
289    Wait();
290  }
291
292  // Does gconf setup and initial fetch of the proxy config,
293  // all on the calling thread (meant to be the thread with the
294  // default glib main loop, which is the UI thread).
295  void SetupAndInitialFetch() {
296    // We pass the mock IO thread as both the IO and file threads.
297    config_service_->SetupAndFetchInitialConfig(
298        base::MessageLoopProxy::current(),
299        io_thread_.message_loop_proxy(),
300        io_thread_.message_loop_proxy());
301  }
302  // Synchronously gets the proxy config.
303  net::ProxyConfigService::ConfigAvailability SyncGetLatestProxyConfig(
304      net::ProxyConfig* config) {
305    io_thread_.message_loop()->PostTask(FROM_HERE,
306        base::Bind(&SynchConfigGetter::GetLatestConfigOnIOThread,
307                   base::Unretained(this)));
308    Wait();
309    *config = proxy_config_;
310    return get_latest_config_result_;
311  }
312
313 private:
314  // [Runs on |io_thread_|]
315  void Init() {
316    event_.Signal();
317  }
318
319  // Calls GetLatestProxyConfig, running on |io_thread_| Signals |event_|
320  // on completion.
321  void GetLatestConfigOnIOThread() {
322    get_latest_config_result_ =
323        config_service_->GetLatestProxyConfig(&proxy_config_);
324    event_.Signal();
325  }
326
327  // [Runs on |io_thread_|] Signals |event_| on cleanup completion.
328  void CleanUp() {
329    base::MessageLoop::current()->RunUntilIdle();
330    event_.Signal();
331  }
332
333  void Wait() {
334    event_.Wait();
335    event_.Reset();
336  }
337
338  base::WaitableEvent event_;
339  base::Thread io_thread_;
340
341  net::ProxyConfigServiceLinux* config_service_;
342
343  // The config obtained by |io_thread_| and read back by the main
344  // thread.
345  net::ProxyConfig proxy_config_;
346
347  // Return value from GetLatestProxyConfig().
348  net::ProxyConfigService::ConfigAvailability get_latest_config_result_;
349};
350
351namespace net {
352
353// This test fixture is only really needed for the KDEConfigParser test case,
354// but all the test cases with the same prefix ("ProxyConfigServiceLinuxTest")
355// must use the same test fixture class (also "ProxyConfigServiceLinuxTest").
356class ProxyConfigServiceLinuxTest : public PlatformTest {
357 protected:
358  virtual void SetUp() OVERRIDE {
359    PlatformTest::SetUp();
360    // Set up a temporary KDE home directory.
361    std::string prefix("ProxyConfigServiceLinuxTest_user_home");
362    base::CreateNewTempDirectory(prefix, &user_home_);
363    kde_home_ = user_home_.Append(FILE_PATH_LITERAL(".kde"));
364    base::FilePath path = kde_home_.Append(FILE_PATH_LITERAL("share"));
365    path = path.Append(FILE_PATH_LITERAL("config"));
366    base::CreateDirectory(path);
367    kioslaverc_ = path.Append(FILE_PATH_LITERAL("kioslaverc"));
368    // Set up paths but do not create the directory for .kde4.
369    kde4_home_ = user_home_.Append(FILE_PATH_LITERAL(".kde4"));
370    path = kde4_home_.Append(FILE_PATH_LITERAL("share"));
371    kde4_config_ = path.Append(FILE_PATH_LITERAL("config"));
372    kioslaverc4_ = kde4_config_.Append(FILE_PATH_LITERAL("kioslaverc"));
373  }
374
375  virtual void TearDown() OVERRIDE {
376    // Delete the temporary KDE home directory.
377    base::DeleteFile(user_home_, true);
378    PlatformTest::TearDown();
379  }
380
381  base::FilePath user_home_;
382  // KDE3 paths.
383  base::FilePath kde_home_;
384  base::FilePath kioslaverc_;
385  // KDE4 paths.
386  base::FilePath kde4_home_;
387  base::FilePath kde4_config_;
388  base::FilePath kioslaverc4_;
389};
390
391// Builds an identifier for each test in an array.
392#define TEST_DESC(desc) base::StringPrintf("at line %d <%s>", __LINE__, desc)
393
394TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) {
395  std::vector<std::string> empty_ignores;
396
397  std::vector<std::string> google_ignores;
398  google_ignores.push_back("*.google.com");
399
400  // Inspired from proxy_config_service_win_unittest.cc.
401  // Very neat, but harder to track down failures though.
402  const struct {
403    // Short description to identify the test
404    std::string description;
405
406    // Input.
407    GConfValues values;
408
409    // Expected outputs (availability and fields of ProxyConfig).
410    ProxyConfigService::ConfigAvailability availability;
411    bool auto_detect;
412    GURL pac_url;
413    ProxyRulesExpectation proxy_rules;
414  } tests[] = {
415    {
416      TEST_DESC("No proxying"),
417      { // Input.
418        "none",                   // mode
419        "",                       // autoconfig_url
420        "", "", "", "",           // hosts
421        0, 0, 0, 0,               // ports
422        FALSE, FALSE, FALSE,      // use, same, auth
423        empty_ignores,            // ignore_hosts
424      },
425
426      // Expected result.
427      ProxyConfigService::CONFIG_VALID,
428      false,                      // auto_detect
429      GURL(),                     // pac_url
430      ProxyRulesExpectation::Empty(),
431    },
432
433    {
434      TEST_DESC("Auto detect"),
435      { // Input.
436        "auto",                   // mode
437        "",                       // autoconfig_url
438        "", "", "", "",           // hosts
439        0, 0, 0, 0,               // ports
440        FALSE, FALSE, FALSE,      // use, same, auth
441        empty_ignores,            // ignore_hosts
442      },
443
444      // Expected result.
445      ProxyConfigService::CONFIG_VALID,
446      true,                       // auto_detect
447      GURL(),                     // pac_url
448      ProxyRulesExpectation::Empty(),
449    },
450
451    {
452      TEST_DESC("Valid PAC URL"),
453      { // Input.
454        "auto",                      // mode
455        "http://wpad/wpad.dat",      // autoconfig_url
456        "", "", "", "",              // hosts
457        0, 0, 0, 0,                  // ports
458        FALSE, FALSE, FALSE,         // use, same, auth
459        empty_ignores,               // ignore_hosts
460      },
461
462      // Expected result.
463      ProxyConfigService::CONFIG_VALID,
464      false,                         // auto_detect
465      GURL("http://wpad/wpad.dat"),  // pac_url
466      ProxyRulesExpectation::Empty(),
467    },
468
469    {
470      TEST_DESC("Invalid PAC URL"),
471      { // Input.
472        "auto",                      // mode
473        "wpad.dat",                  // autoconfig_url
474        "", "", "", "",              // hosts
475        0, 0, 0, 0,                  // ports
476        FALSE, FALSE, FALSE,         // use, same, auth
477        empty_ignores,               // ignore_hosts
478      },
479
480      // Expected result.
481      ProxyConfigService::CONFIG_VALID,
482      false,                          // auto_detect
483      GURL(),                        // pac_url
484      ProxyRulesExpectation::Empty(),
485    },
486
487    {
488      TEST_DESC("Single-host in proxy list"),
489      { // Input.
490        "manual",                              // mode
491        "",                                    // autoconfig_url
492        "www.google.com", "", "", "",          // hosts
493        80, 0, 0, 0,                           // ports
494        TRUE, TRUE, FALSE,                     // use, same, auth
495        empty_ignores,                         // ignore_hosts
496      },
497
498      // Expected result.
499      ProxyConfigService::CONFIG_VALID,
500      false,                                   // auto_detect
501      GURL(),                                  // pac_url
502      ProxyRulesExpectation::Single(
503          "www.google.com:80",  // single proxy
504          ""),                  // bypass rules
505    },
506
507    {
508      TEST_DESC("use_http_proxy is honored"),
509      { // Input.
510        "manual",                              // mode
511        "",                                    // autoconfig_url
512        "www.google.com", "", "", "",          // hosts
513        80, 0, 0, 0,                           // ports
514        FALSE, TRUE, FALSE,                    // use, same, auth
515        empty_ignores,                         // ignore_hosts
516      },
517
518      // Expected result.
519      ProxyConfigService::CONFIG_VALID,
520      false,                                   // auto_detect
521      GURL(),                                  // pac_url
522      ProxyRulesExpectation::Empty(),
523    },
524
525    {
526      TEST_DESC("use_http_proxy and use_same_proxy are optional"),
527      { // Input.
528        "manual",                                     // mode
529        "",                                           // autoconfig_url
530        "www.google.com", "", "", "",                 // hosts
531        80, 0, 0, 0,                                  // ports
532        UNSET, UNSET, FALSE,                          // use, same, auth
533        empty_ignores,                                // ignore_hosts
534      },
535
536      // Expected result.
537      ProxyConfigService::CONFIG_VALID,
538      false,                                          // auto_detect
539      GURL(),                                         // pac_url
540      ProxyRulesExpectation::PerScheme(
541          "www.google.com:80",  // http
542          "",                   // https
543          "",                   // ftp
544          ""),                  // bypass rules
545    },
546
547    {
548      TEST_DESC("Single-host, different port"),
549      { // Input.
550        "manual",                                     // mode
551        "",                                           // autoconfig_url
552        "www.google.com", "", "", "",                 // hosts
553        88, 0, 0, 0,                                  // ports
554        TRUE, TRUE, FALSE,                            // use, same, auth
555        empty_ignores,                                // ignore_hosts
556      },
557
558      // Expected result.
559      ProxyConfigService::CONFIG_VALID,
560      false,                                          // auto_detect
561      GURL(),                                         // pac_url
562      ProxyRulesExpectation::Single(
563          "www.google.com:88",  // single proxy
564          ""),                  // bypass rules
565    },
566
567    {
568      TEST_DESC("Per-scheme proxy rules"),
569      { // Input.
570        "manual",                                     // mode
571        "",                                           // autoconfig_url
572        "www.google.com",                             // http_host
573        "www.foo.com",                                // secure_host
574        "ftp.foo.com",                                // ftp
575        "",                                           // socks
576        88, 110, 121, 0,                              // ports
577        TRUE, FALSE, FALSE,                           // use, same, auth
578        empty_ignores,                                // ignore_hosts
579      },
580
581      // Expected result.
582      ProxyConfigService::CONFIG_VALID,
583      false,                                          // auto_detect
584      GURL(),                                         // pac_url
585      ProxyRulesExpectation::PerScheme(
586          "www.google.com:88",  // http
587          "www.foo.com:110",    // https
588          "ftp.foo.com:121",    // ftp
589          ""),                  // bypass rules
590    },
591
592    {
593      TEST_DESC("socks"),
594      { // Input.
595        "manual",                                     // mode
596        "",                                           // autoconfig_url
597        "", "", "", "socks.com",                      // hosts
598        0, 0, 0, 99,                                  // ports
599        TRUE, FALSE, FALSE,                           // use, same, auth
600        empty_ignores,                                // ignore_hosts
601      },
602
603      // Expected result.
604      ProxyConfigService::CONFIG_VALID,
605      false,                                          // auto_detect
606      GURL(),                                         // pac_url
607      ProxyRulesExpectation::Single(
608          "socks5://socks.com:99",  // single proxy
609          "")                       // bypass rules
610    },
611
612    {
613      TEST_DESC("Per-scheme proxy rules with fallback to SOCKS"),
614      { // Input.
615        "manual",                                     // mode
616        "",                                           // autoconfig_url
617        "www.google.com",                             // http_host
618        "www.foo.com",                                // secure_host
619        "ftp.foo.com",                                // ftp
620        "foobar.net",                                 // socks
621        88, 110, 121, 99,                             // ports
622        TRUE, FALSE, FALSE,                           // use, same, auth
623        empty_ignores,                                // ignore_hosts
624      },
625
626      // Expected result.
627      ProxyConfigService::CONFIG_VALID,
628      false,                                          // auto_detect
629      GURL(),                                         // pac_url
630      ProxyRulesExpectation::PerSchemeWithSocks(
631          "www.google.com:88",      // http
632          "www.foo.com:110",        // https
633          "ftp.foo.com:121",        // ftp
634          "socks5://foobar.net:99", // socks
635          ""),                      // bypass rules
636    },
637
638    {
639      TEST_DESC("Per-scheme proxy rules (just HTTP) with fallback to SOCKS"),
640      { // Input.
641        "manual",                                     // mode
642        "",                                           // autoconfig_url
643        "www.google.com",                             // http_host
644        "",                                           // secure_host
645        "",                                           // ftp
646        "foobar.net",                                 // socks
647        88, 0, 0, 99,                                 // ports
648        TRUE, FALSE, FALSE,                           // use, same, auth
649        empty_ignores,                                // ignore_hosts
650      },
651
652      // Expected result.
653      ProxyConfigService::CONFIG_VALID,
654      false,                                          // auto_detect
655      GURL(),                                         // pac_url
656      ProxyRulesExpectation::PerSchemeWithSocks(
657          "www.google.com:88",      // http
658          "",                       // https
659          "",                       // ftp
660          "socks5://foobar.net:99", // socks
661          ""),                      // bypass rules
662    },
663
664    {
665      TEST_DESC("Bypass *.google.com"),
666      { // Input.
667        "manual",                                     // mode
668        "",                                           // autoconfig_url
669        "www.google.com", "", "", "",                 // hosts
670        80, 0, 0, 0,                                  // ports
671        TRUE, TRUE, FALSE,                            // use, same, auth
672        google_ignores,                               // ignore_hosts
673      },
674
675      ProxyConfigService::CONFIG_VALID,
676      false,                                          // auto_detect
677      GURL(),                                         // pac_url
678      ProxyRulesExpectation::Single(
679          "www.google.com:80",   // single proxy
680          "*.google.com"),       // bypass rules
681    },
682  };
683
684  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
685    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i,
686                                    tests[i].description.c_str()));
687    MockEnvironment* env = new MockEnvironment;
688    MockSettingGetter* setting_getter = new MockSettingGetter;
689    SynchConfigGetter sync_config_getter(
690        new ProxyConfigServiceLinux(env, setting_getter));
691    ProxyConfig config;
692    setting_getter->values = tests[i].values;
693    sync_config_getter.SetupAndInitialFetch();
694    ProxyConfigService::ConfigAvailability availability =
695        sync_config_getter.SyncGetLatestProxyConfig(&config);
696    EXPECT_EQ(tests[i].availability, availability);
697
698    if (availability == ProxyConfigService::CONFIG_VALID) {
699      EXPECT_EQ(tests[i].auto_detect, config.auto_detect());
700      EXPECT_EQ(tests[i].pac_url, config.pac_url());
701      EXPECT_TRUE(tests[i].proxy_rules.Matches(config.proxy_rules()));
702    }
703  }
704}
705
706TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) {
707  // Inspired from proxy_config_service_win_unittest.cc.
708  const struct {
709    // Short description to identify the test
710    std::string description;
711
712    // Input.
713    EnvVarValues values;
714
715    // Expected outputs (availability and fields of ProxyConfig).
716    ProxyConfigService::ConfigAvailability availability;
717    bool auto_detect;
718    GURL pac_url;
719    ProxyRulesExpectation proxy_rules;
720  } tests[] = {
721    {
722      TEST_DESC("No proxying"),
723      { // Input.
724        NULL,  // DESKTOP_SESSION
725        NULL,  // HOME
726        NULL,  // KDEHOME
727        NULL,  // KDE_SESSION_VERSION
728        NULL,  // auto_proxy
729        NULL,  // all_proxy
730        NULL, NULL, NULL,  // per-proto proxies
731        NULL, NULL,  // SOCKS
732        "*",  // no_proxy
733      },
734
735      // Expected result.
736      ProxyConfigService::CONFIG_VALID,
737      false,                      // auto_detect
738      GURL(),                     // pac_url
739      ProxyRulesExpectation::Empty(),
740    },
741
742    {
743      TEST_DESC("Auto detect"),
744      { // Input.
745        NULL,  // DESKTOP_SESSION
746        NULL,  // HOME
747        NULL,  // KDEHOME
748        NULL,  // KDE_SESSION_VERSION
749        "",    // auto_proxy
750        NULL,  // all_proxy
751        NULL, NULL, NULL,  // per-proto proxies
752        NULL, NULL,  // SOCKS
753        NULL,  // no_proxy
754      },
755
756      // Expected result.
757      ProxyConfigService::CONFIG_VALID,
758      true,                       // auto_detect
759      GURL(),                     // pac_url
760      ProxyRulesExpectation::Empty(),
761    },
762
763    {
764      TEST_DESC("Valid PAC URL"),
765      { // Input.
766        NULL,  // DESKTOP_SESSION
767        NULL,  // HOME
768        NULL,  // KDEHOME
769        NULL,  // KDE_SESSION_VERSION
770        "http://wpad/wpad.dat",  // auto_proxy
771        NULL,  // all_proxy
772        NULL, NULL, NULL,  // per-proto proxies
773        NULL, NULL,  // SOCKS
774        NULL,  // no_proxy
775      },
776
777      // Expected result.
778      ProxyConfigService::CONFIG_VALID,
779      false,                         // auto_detect
780      GURL("http://wpad/wpad.dat"),  // pac_url
781      ProxyRulesExpectation::Empty(),
782    },
783
784    {
785      TEST_DESC("Invalid PAC URL"),
786      { // Input.
787        NULL,  // DESKTOP_SESSION
788        NULL,  // HOME
789        NULL,  // KDEHOME
790        NULL,  // KDE_SESSION_VERSION
791        "wpad.dat",  // auto_proxy
792        NULL,  // all_proxy
793        NULL, NULL, NULL,  // per-proto proxies
794        NULL, NULL,  // SOCKS
795        NULL,  // no_proxy
796      },
797
798      // Expected result.
799      ProxyConfigService::CONFIG_VALID,
800      false,                       // auto_detect
801      GURL(),                     // pac_url
802      ProxyRulesExpectation::Empty(),
803    },
804
805    {
806      TEST_DESC("Single-host in proxy list"),
807      { // Input.
808        NULL,  // DESKTOP_SESSION
809        NULL,  // HOME
810        NULL,  // KDEHOME
811        NULL,  // KDE_SESSION_VERSION
812        NULL,  // auto_proxy
813        "www.google.com",  // all_proxy
814        NULL, NULL, NULL,  // per-proto proxies
815        NULL, NULL,  // SOCKS
816        NULL,  // no_proxy
817      },
818
819      // Expected result.
820      ProxyConfigService::CONFIG_VALID,
821      false,                                   // auto_detect
822      GURL(),                                  // pac_url
823      ProxyRulesExpectation::Single(
824          "www.google.com:80",  // single proxy
825          ""),                  // bypass rules
826    },
827
828    {
829      TEST_DESC("Single-host, different port"),
830      { // Input.
831        NULL,  // DESKTOP_SESSION
832        NULL,  // HOME
833        NULL,  // KDEHOME
834        NULL,  // KDE_SESSION_VERSION
835        NULL,  // auto_proxy
836        "www.google.com:99",  // all_proxy
837        NULL, NULL, NULL,  // per-proto proxies
838        NULL, NULL,  // SOCKS
839        NULL,  // no_proxy
840      },
841
842      // Expected result.
843      ProxyConfigService::CONFIG_VALID,
844      false,                                   // auto_detect
845      GURL(),                                  // pac_url
846      ProxyRulesExpectation::Single(
847          "www.google.com:99",  // single
848          ""),                  // bypass rules
849    },
850
851    {
852      TEST_DESC("Tolerate a scheme"),
853      { // Input.
854        NULL,  // DESKTOP_SESSION
855        NULL,  // HOME
856        NULL,  // KDEHOME
857        NULL,  // KDE_SESSION_VERSION
858        NULL,  // auto_proxy
859        "http://www.google.com:99",  // all_proxy
860        NULL, NULL, NULL,  // per-proto proxies
861        NULL, NULL,  // SOCKS
862        NULL,  // no_proxy
863      },
864
865      // Expected result.
866      ProxyConfigService::CONFIG_VALID,
867      false,                                   // auto_detect
868      GURL(),                                  // pac_url
869      ProxyRulesExpectation::Single(
870          "www.google.com:99",  // single proxy
871          ""),                  // bypass rules
872    },
873
874    {
875      TEST_DESC("Per-scheme proxy rules"),
876      { // Input.
877        NULL,  // DESKTOP_SESSION
878        NULL,  // HOME
879        NULL,  // KDEHOME
880        NULL,  // KDE_SESSION_VERSION
881        NULL,  // auto_proxy
882        NULL,  // all_proxy
883        "www.google.com:80", "www.foo.com:110", "ftp.foo.com:121",  // per-proto
884        NULL, NULL,  // SOCKS
885        NULL,  // no_proxy
886      },
887
888      // Expected result.
889      ProxyConfigService::CONFIG_VALID,
890      false,                                   // auto_detect
891      GURL(),                                  // pac_url
892      ProxyRulesExpectation::PerScheme(
893          "www.google.com:80",  // http
894          "www.foo.com:110",    // https
895          "ftp.foo.com:121",    // ftp
896          ""),                  // bypass rules
897    },
898
899    {
900      TEST_DESC("socks"),
901      { // Input.
902        NULL,  // DESKTOP_SESSION
903        NULL,  // HOME
904        NULL,  // KDEHOME
905        NULL,  // KDE_SESSION_VERSION
906        NULL,  // auto_proxy
907        "",  // all_proxy
908        NULL, NULL, NULL,  // per-proto proxies
909        "socks.com:888", NULL,  // SOCKS
910        NULL,  // no_proxy
911      },
912
913      // Expected result.
914      ProxyConfigService::CONFIG_VALID,
915      false,                                   // auto_detect
916      GURL(),                                  // pac_url
917      ProxyRulesExpectation::Single(
918          "socks5://socks.com:888",  // single proxy
919          ""),                       // bypass rules
920    },
921
922    {
923      TEST_DESC("socks4"),
924      { // Input.
925        NULL,  // DESKTOP_SESSION
926        NULL,  // HOME
927        NULL,  // KDEHOME
928        NULL,  // KDE_SESSION_VERSION
929        NULL,  // auto_proxy
930        "",  // all_proxy
931        NULL, NULL, NULL,  // per-proto proxies
932        "socks.com:888", "4",  // SOCKS
933        NULL,  // no_proxy
934      },
935
936      // Expected result.
937      ProxyConfigService::CONFIG_VALID,
938      false,                                   // auto_detect
939      GURL(),                                  // pac_url
940      ProxyRulesExpectation::Single(
941          "socks4://socks.com:888",  // single proxy
942          ""),                       // bypass rules
943    },
944
945    {
946      TEST_DESC("socks default port"),
947      { // Input.
948        NULL,  // DESKTOP_SESSION
949        NULL,  // HOME
950        NULL,  // KDEHOME
951        NULL,  // KDE_SESSION_VERSION
952        NULL,  // auto_proxy
953        "",  // all_proxy
954        NULL, NULL, NULL,  // per-proto proxies
955        "socks.com", NULL,  // SOCKS
956        NULL,  // no_proxy
957      },
958
959      // Expected result.
960      ProxyConfigService::CONFIG_VALID,
961      false,                                   // auto_detect
962      GURL(),                                  // pac_url
963      ProxyRulesExpectation::Single(
964          "socks5://socks.com:1080",  // single proxy
965          ""),                        // bypass rules
966    },
967
968    {
969      TEST_DESC("bypass"),
970      { // Input.
971        NULL,  // DESKTOP_SESSION
972        NULL,  // HOME
973        NULL,  // KDEHOME
974        NULL,  // KDE_SESSION_VERSION
975        NULL,  // auto_proxy
976        "www.google.com",  // all_proxy
977        NULL, NULL, NULL,  // per-proto
978        NULL, NULL,  // SOCKS
979        ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8",  // no_proxy
980      },
981
982      // Expected result.
983      ProxyConfigService::CONFIG_VALID,
984      false,                      // auto_detect
985      GURL(),                     // pac_url
986      ProxyRulesExpectation::Single(
987          "www.google.com:80",
988          "*.google.com,*foo.com:99,1.2.3.4:22,127.0.0.1/8"),
989    },
990  };
991
992  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
993    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i,
994                                    tests[i].description.c_str()));
995    MockEnvironment* env = new MockEnvironment;
996    MockSettingGetter* setting_getter = new MockSettingGetter;
997    SynchConfigGetter sync_config_getter(
998        new ProxyConfigServiceLinux(env, setting_getter));
999    ProxyConfig config;
1000    env->values = tests[i].values;
1001    sync_config_getter.SetupAndInitialFetch();
1002    ProxyConfigService::ConfigAvailability availability =
1003        sync_config_getter.SyncGetLatestProxyConfig(&config);
1004    EXPECT_EQ(tests[i].availability, availability);
1005
1006    if (availability == ProxyConfigService::CONFIG_VALID) {
1007      EXPECT_EQ(tests[i].auto_detect, config.auto_detect());
1008      EXPECT_EQ(tests[i].pac_url, config.pac_url());
1009      EXPECT_TRUE(tests[i].proxy_rules.Matches(config.proxy_rules()));
1010    }
1011  }
1012}
1013
1014TEST_F(ProxyConfigServiceLinuxTest, GconfNotification) {
1015  MockEnvironment* env = new MockEnvironment;
1016  MockSettingGetter* setting_getter = new MockSettingGetter;
1017  ProxyConfigServiceLinux* service =
1018      new ProxyConfigServiceLinux(env, setting_getter);
1019  SynchConfigGetter sync_config_getter(service);
1020  ProxyConfig config;
1021
1022  // Start with no proxy.
1023  setting_getter->values.mode = "none";
1024  sync_config_getter.SetupAndInitialFetch();
1025  EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1026            sync_config_getter.SyncGetLatestProxyConfig(&config));
1027  EXPECT_FALSE(config.auto_detect());
1028
1029  // Now set to auto-detect.
1030  setting_getter->values.mode = "auto";
1031  // Simulate setting change notification callback.
1032  service->OnCheckProxyConfigSettings();
1033  EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1034            sync_config_getter.SyncGetLatestProxyConfig(&config));
1035  EXPECT_TRUE(config.auto_detect());
1036}
1037
1038TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) {
1039  // One of the tests below needs a worst-case long line prefix. We build it
1040  // programmatically so that it will always be the right size.
1041  std::string long_line;
1042  size_t limit = ProxyConfigServiceLinux::SettingGetter::BUFFER_SIZE - 1;
1043  for (size_t i = 0; i < limit; ++i)
1044    long_line += "-";
1045
1046  // Inspired from proxy_config_service_win_unittest.cc.
1047  const struct {
1048    // Short description to identify the test
1049    std::string description;
1050
1051    // Input.
1052    std::string kioslaverc;
1053    EnvVarValues env_values;
1054
1055    // Expected outputs (availability and fields of ProxyConfig).
1056    ProxyConfigService::ConfigAvailability availability;
1057    bool auto_detect;
1058    GURL pac_url;
1059    ProxyRulesExpectation proxy_rules;
1060  } tests[] = {
1061    {
1062      TEST_DESC("No proxying"),
1063
1064      // Input.
1065      "[Proxy Settings]\nProxyType=0\n",
1066      {},                                      // env_values
1067
1068      // Expected result.
1069      ProxyConfigService::CONFIG_VALID,
1070      false,                      // auto_detect
1071      GURL(),                     // pac_url
1072      ProxyRulesExpectation::Empty(),
1073    },
1074
1075    {
1076      TEST_DESC("Auto detect"),
1077
1078      // Input.
1079      "[Proxy Settings]\nProxyType=3\n",
1080      {},                                      // env_values
1081
1082      // Expected result.
1083      ProxyConfigService::CONFIG_VALID,
1084      true,                       // auto_detect
1085      GURL(),                     // pac_url
1086      ProxyRulesExpectation::Empty(),
1087    },
1088
1089    {
1090      TEST_DESC("Valid PAC URL"),
1091
1092      // Input.
1093      "[Proxy Settings]\nProxyType=2\n"
1094          "Proxy Config Script=http://wpad/wpad.dat\n",
1095      {},                                      // env_values
1096
1097      // Expected result.
1098      ProxyConfigService::CONFIG_VALID,
1099      false,                         // auto_detect
1100      GURL("http://wpad/wpad.dat"),  // pac_url
1101      ProxyRulesExpectation::Empty(),
1102    },
1103
1104    {
1105      TEST_DESC("Valid PAC file without file://"),
1106
1107      // Input.
1108      "[Proxy Settings]\nProxyType=2\n"
1109          "Proxy Config Script=/wpad/wpad.dat\n",
1110      {},                                      // env_values
1111
1112      // Expected result.
1113      ProxyConfigService::CONFIG_VALID,
1114      false,                         // auto_detect
1115      GURL("file:///wpad/wpad.dat"),  // pac_url
1116      ProxyRulesExpectation::Empty(),
1117    },
1118
1119    {
1120      TEST_DESC("Per-scheme proxy rules"),
1121
1122      // Input.
1123      "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1124          "httpsProxy=www.foo.com\nftpProxy=ftp.foo.com\n",
1125      {},                                      // env_values
1126
1127      // Expected result.
1128      ProxyConfigService::CONFIG_VALID,
1129      false,                                   // auto_detect
1130      GURL(),                                  // pac_url
1131      ProxyRulesExpectation::PerScheme(
1132          "www.google.com:80",  // http
1133          "www.foo.com:80",     // https
1134          "ftp.foo.com:80",     // http
1135          ""),                  // bypass rules
1136    },
1137
1138    {
1139      TEST_DESC("Only HTTP proxy specified"),
1140
1141      // Input.
1142      "[Proxy Settings]\nProxyType=1\n"
1143          "httpProxy=www.google.com\n",
1144      {},                                      // env_values
1145
1146      // Expected result.
1147      ProxyConfigService::CONFIG_VALID,
1148      false,                                   // auto_detect
1149      GURL(),                                  // pac_url
1150      ProxyRulesExpectation::PerScheme(
1151          "www.google.com:80",  // http
1152          "",                   // https
1153          "",                   // ftp
1154          ""),                  // bypass rules
1155    },
1156
1157    {
1158      TEST_DESC("Only HTTP proxy specified, different port"),
1159
1160      // Input.
1161      "[Proxy Settings]\nProxyType=1\n"
1162          "httpProxy=www.google.com:88\n",
1163      {},                                      // env_values
1164
1165      // Expected result.
1166      ProxyConfigService::CONFIG_VALID,
1167      false,                                   // auto_detect
1168      GURL(),                                  // pac_url
1169      ProxyRulesExpectation::PerScheme(
1170          "www.google.com:88",  // http
1171          "",                   // https
1172          "",                   // ftp
1173          ""),                  // bypass rules
1174    },
1175
1176    {
1177      TEST_DESC("Only HTTP proxy specified, different port, space-delimited"),
1178
1179      // Input.
1180      "[Proxy Settings]\nProxyType=1\n"
1181          "httpProxy=www.google.com 88\n",
1182      {},                                      // env_values
1183
1184      // Expected result.
1185      ProxyConfigService::CONFIG_VALID,
1186      false,                                   // auto_detect
1187      GURL(),                                  // pac_url
1188      ProxyRulesExpectation::PerScheme(
1189          "www.google.com:88",  // http
1190          "",                   // https
1191          "",                   // ftp
1192          ""),                  // bypass rules
1193    },
1194
1195    {
1196      TEST_DESC("Bypass *.google.com"),
1197
1198      // Input.
1199      "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1200          "NoProxyFor=.google.com\n",
1201      {},                                      // env_values
1202
1203      // Expected result.
1204      ProxyConfigService::CONFIG_VALID,
1205      false,                                   // auto_detect
1206      GURL(),                                  // pac_url
1207      ProxyRulesExpectation::PerScheme(
1208          "www.google.com:80",  // http
1209          "",                   // https
1210          "",                   // ftp
1211          "*.google.com"),      // bypass rules
1212    },
1213
1214    {
1215      TEST_DESC("Bypass *.google.com and *.kde.org"),
1216
1217      // Input.
1218      "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1219          "NoProxyFor=.google.com,.kde.org\n",
1220      {},                                      // env_values
1221
1222      // Expected result.
1223      ProxyConfigService::CONFIG_VALID,
1224      false,                                   // auto_detect
1225      GURL(),                                  // pac_url
1226      ProxyRulesExpectation::PerScheme(
1227          "www.google.com:80",           // http
1228          "",                            // https
1229          "",                            // ftp
1230          "*.google.com,*.kde.org"),     // bypass rules
1231    },
1232
1233    {
1234      TEST_DESC("Correctly parse bypass list with ReversedException"),
1235
1236      // Input.
1237      "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1238          "NoProxyFor=.google.com\nReversedException=true\n",
1239      {},                                      // env_values
1240
1241      // Expected result.
1242      ProxyConfigService::CONFIG_VALID,
1243      false,                                   // auto_detect
1244      GURL(),                                  // pac_url
1245      ProxyRulesExpectation::PerSchemeWithBypassReversed(
1246          "www.google.com:80",  // http
1247          "",                   // https
1248          "",                   // ftp
1249          "*.google.com"),      // bypass rules
1250    },
1251
1252    {
1253      TEST_DESC("socks"),
1254
1255      // Input.
1256      "[Proxy Settings]\nProxyType=1\nsocksProxy=socks.com 888\n",
1257      {},                                      // env_values
1258
1259      // Expected result.
1260      ProxyConfigService::CONFIG_VALID,
1261      false,                                   // auto_detect
1262      GURL(),                                  // pac_url
1263      ProxyRulesExpectation::Single(
1264          "socks5://socks.com:888",  // single proxy
1265          ""),                       // bypass rules
1266    },
1267
1268    {
1269      TEST_DESC("socks4"),
1270
1271      // Input.
1272      "[Proxy Settings]\nProxyType=1\nsocksProxy=socks4://socks.com 888\n",
1273      {},                                      // env_values
1274
1275      // Expected result.
1276      ProxyConfigService::CONFIG_VALID,
1277      false,                                   // auto_detect
1278      GURL(),                                  // pac_url
1279      ProxyRulesExpectation::Single(
1280          "socks4://socks.com:888",  // single proxy
1281          ""),                       // bypass rules
1282    },
1283
1284    {
1285      TEST_DESC("Treat all hostname patterns as wildcard patterns"),
1286
1287      // Input.
1288      "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1289          "NoProxyFor=google.com,kde.org,<local>\n",
1290      {},                                      // env_values
1291
1292      // Expected result.
1293      ProxyConfigService::CONFIG_VALID,
1294      false,                                   // auto_detect
1295      GURL(),                                  // pac_url
1296      ProxyRulesExpectation::PerScheme(
1297          "www.google.com:80",              // http
1298          "",                               // https
1299          "",                               // ftp
1300          "*google.com,*kde.org,<local>"),  // bypass rules
1301    },
1302
1303    {
1304      TEST_DESC("Allow trailing whitespace after boolean value"),
1305
1306      // Input.
1307      "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1308          "NoProxyFor=.google.com\nReversedException=true  \n",
1309      {},                                      // env_values
1310
1311      // Expected result.
1312      ProxyConfigService::CONFIG_VALID,
1313      false,                                   // auto_detect
1314      GURL(),                                  // pac_url
1315      ProxyRulesExpectation::PerSchemeWithBypassReversed(
1316          "www.google.com:80",  // http
1317          "",                   // https
1318          "",                   // ftp
1319          "*.google.com"),      // bypass rules
1320    },
1321
1322    {
1323      TEST_DESC("Ignore settings outside [Proxy Settings]"),
1324
1325      // Input.
1326      "httpsProxy=www.foo.com\n[Proxy Settings]\nProxyType=1\n"
1327          "httpProxy=www.google.com\n[Other Section]\nftpProxy=ftp.foo.com\n",
1328      {},                                      // env_values
1329
1330      // Expected result.
1331      ProxyConfigService::CONFIG_VALID,
1332      false,                                   // auto_detect
1333      GURL(),                                  // pac_url
1334      ProxyRulesExpectation::PerScheme(
1335          "www.google.com:80",  // http
1336          "",                   // https
1337          "",                   // ftp
1338          ""),                  // bypass rules
1339    },
1340
1341    {
1342      TEST_DESC("Handle CRLF line endings"),
1343
1344      // Input.
1345      "[Proxy Settings]\r\nProxyType=1\r\nhttpProxy=www.google.com\r\n",
1346      {},                                      // env_values
1347
1348      // Expected result.
1349      ProxyConfigService::CONFIG_VALID,
1350      false,                                   // auto_detect
1351      GURL(),                                  // pac_url
1352      ProxyRulesExpectation::PerScheme(
1353          "www.google.com:80",  // http
1354          "",                   // https
1355          "",                   // ftp
1356          ""),                  // bypass rules
1357    },
1358
1359    {
1360      TEST_DESC("Handle blank lines and mixed line endings"),
1361
1362      // Input.
1363      "[Proxy Settings]\r\n\nProxyType=1\n\r\nhttpProxy=www.google.com\n\n",
1364      {},                                      // env_values
1365
1366      // Expected result.
1367      ProxyConfigService::CONFIG_VALID,
1368      false,                                   // auto_detect
1369      GURL(),                                  // pac_url
1370      ProxyRulesExpectation::PerScheme(
1371          "www.google.com:80",  // http
1372          "",                   // https
1373          "",                   // ftp
1374          ""),                  // bypass rules
1375    },
1376
1377    {
1378      TEST_DESC("Handle localized settings"),
1379
1380      // Input.
1381      "[Proxy Settings]\nProxyType[$e]=1\nhttpProxy[$e]=www.google.com\n",
1382      {},                                      // env_values
1383
1384      // Expected result.
1385      ProxyConfigService::CONFIG_VALID,
1386      false,                                   // auto_detect
1387      GURL(),                                  // pac_url
1388      ProxyRulesExpectation::PerScheme(
1389          "www.google.com:80",  // http
1390          "",                   // https
1391          "",                   // ftp
1392          ""),                  // bypass rules
1393    },
1394
1395    {
1396      TEST_DESC("Ignore malformed localized settings"),
1397
1398      // Input.
1399      "[Proxy Settings]\nProxyType=1\nhttpProxy=www.google.com\n"
1400          "httpsProxy$e]=www.foo.com\nftpProxy=ftp.foo.com\n",
1401      {},                                      // env_values
1402
1403      // Expected result.
1404      ProxyConfigService::CONFIG_VALID,
1405      false,                                   // auto_detect
1406      GURL(),                                  // pac_url
1407      ProxyRulesExpectation::PerScheme(
1408          "www.google.com:80",  // http
1409          "",                   // https
1410          "ftp.foo.com:80",     // ftp
1411          ""),                  // bypass rules
1412    },
1413
1414    {
1415      TEST_DESC("Handle strange whitespace"),
1416
1417      // Input.
1418      "[Proxy Settings]\nProxyType [$e] =2\n"
1419          "  Proxy Config Script =  http:// foo\n",
1420      {},                                      // env_values
1421
1422      // Expected result.
1423      ProxyConfigService::CONFIG_VALID,
1424      false,                                   // auto_detect
1425      GURL("http:// foo"),                     // pac_url
1426      ProxyRulesExpectation::Empty(),
1427    },
1428
1429    {
1430      TEST_DESC("Ignore all of a line which is too long"),
1431
1432      // Input.
1433      std::string("[Proxy Settings]\nProxyType=1\nftpProxy=ftp.foo.com\n") +
1434          long_line + "httpsProxy=www.foo.com\nhttpProxy=www.google.com\n",
1435      {},                                          // env_values
1436
1437      // Expected result.
1438      ProxyConfigService::CONFIG_VALID,
1439      false,                                       // auto_detect
1440      GURL(),                                      // pac_url
1441      ProxyRulesExpectation::PerScheme(
1442          "www.google.com:80",  // http
1443          "",                   // https
1444          "ftp.foo.com:80",     // ftp
1445          ""),                  // bypass rules
1446    },
1447
1448    {
1449      TEST_DESC("Indirect Proxy - no env vars set"),
1450
1451      // Input.
1452      "[Proxy Settings]\nProxyType=4\nhttpProxy=http_proxy\n"
1453          "httpsProxy=https_proxy\nftpProxy=ftp_proxy\nNoProxyFor=no_proxy\n",
1454      {},                                      // env_values
1455
1456      // Expected result.
1457      ProxyConfigService::CONFIG_VALID,
1458      false,                                   // auto_detect
1459      GURL(),                                  // pac_url
1460      ProxyRulesExpectation::Empty(),
1461    },
1462
1463    {
1464      TEST_DESC("Indirect Proxy - with env vars set"),
1465
1466      // Input.
1467      "[Proxy Settings]\nProxyType=4\nhttpProxy=http_proxy\n"
1468          "httpsProxy=https_proxy\nftpProxy=ftp_proxy\nNoProxyFor=no_proxy\n",
1469      {  // env_values
1470        NULL,  // DESKTOP_SESSION
1471        NULL,  // HOME
1472        NULL,  // KDEHOME
1473        NULL,  // KDE_SESSION_VERSION
1474        NULL,  // auto_proxy
1475        NULL,  // all_proxy
1476        "www.normal.com",  // http_proxy
1477        "www.secure.com",  // https_proxy
1478        "ftp.foo.com",  // ftp_proxy
1479        NULL, NULL,  // SOCKS
1480        ".google.com, .kde.org",  // no_proxy
1481      },
1482
1483      // Expected result.
1484      ProxyConfigService::CONFIG_VALID,
1485      false,                                   // auto_detect
1486      GURL(),                                  // pac_url
1487      ProxyRulesExpectation::PerScheme(
1488          "www.normal.com:80",           // http
1489          "www.secure.com:80",           // https
1490          "ftp.foo.com:80",              // ftp
1491          "*.google.com,*.kde.org"),     // bypass rules
1492    },
1493
1494  };
1495
1496  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1497    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i,
1498                                    tests[i].description.c_str()));
1499    MockEnvironment* env = new MockEnvironment;
1500    env->values = tests[i].env_values;
1501    // Force the KDE getter to be used and tell it where the test is.
1502    env->values.DESKTOP_SESSION = "kde4";
1503    env->values.KDEHOME = kde_home_.value().c_str();
1504    SynchConfigGetter sync_config_getter(
1505        new ProxyConfigServiceLinux(env));
1506    ProxyConfig config;
1507    // Overwrite the kioslaverc file.
1508    base::WriteFile(kioslaverc_, tests[i].kioslaverc.c_str(),
1509                    tests[i].kioslaverc.length());
1510    sync_config_getter.SetupAndInitialFetch();
1511    ProxyConfigService::ConfigAvailability availability =
1512        sync_config_getter.SyncGetLatestProxyConfig(&config);
1513    EXPECT_EQ(tests[i].availability, availability);
1514
1515    if (availability == ProxyConfigService::CONFIG_VALID) {
1516      EXPECT_EQ(tests[i].auto_detect, config.auto_detect());
1517      EXPECT_EQ(tests[i].pac_url, config.pac_url());
1518      EXPECT_TRUE(tests[i].proxy_rules.Matches(config.proxy_rules()));
1519    }
1520  }
1521}
1522
1523TEST_F(ProxyConfigServiceLinuxTest, KDEHomePicker) {
1524  // Auto detect proxy settings.
1525  std::string slaverc3 = "[Proxy Settings]\nProxyType=3\n";
1526  // Valid PAC URL.
1527  std::string slaverc4 = "[Proxy Settings]\nProxyType=2\n"
1528                             "Proxy Config Script=http://wpad/wpad.dat\n";
1529  GURL slaverc4_pac_url("http://wpad/wpad.dat");
1530
1531  // Overwrite the .kde kioslaverc file.
1532  base::WriteFile(kioslaverc_, slaverc3.c_str(), slaverc3.length());
1533
1534  // If .kde4 exists it will mess up the first test. It should not, as
1535  // we created the directory for $HOME in the test setup.
1536  CHECK(!base::DirectoryExists(kde4_home_));
1537
1538  { SCOPED_TRACE("KDE4, no .kde4 directory, verify fallback");
1539    MockEnvironment* env = new MockEnvironment;
1540    env->values.DESKTOP_SESSION = "kde4";
1541    env->values.HOME = user_home_.value().c_str();
1542    SynchConfigGetter sync_config_getter(
1543        new ProxyConfigServiceLinux(env));
1544    ProxyConfig config;
1545    sync_config_getter.SetupAndInitialFetch();
1546    EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1547              sync_config_getter.SyncGetLatestProxyConfig(&config));
1548    EXPECT_TRUE(config.auto_detect());
1549    EXPECT_EQ(GURL(), config.pac_url());
1550  }
1551
1552  // Now create .kde4 and put a kioslaverc in the config directory.
1553  // Note that its timestamp will be at least as new as the .kde one.
1554  base::CreateDirectory(kde4_config_);
1555  base::WriteFile(kioslaverc4_, slaverc4.c_str(), slaverc4.length());
1556  CHECK(base::PathExists(kioslaverc4_));
1557
1558  { SCOPED_TRACE("KDE4, .kde4 directory present, use it");
1559    MockEnvironment* env = new MockEnvironment;
1560    env->values.DESKTOP_SESSION = "kde4";
1561    env->values.HOME = user_home_.value().c_str();
1562    SynchConfigGetter sync_config_getter(
1563        new ProxyConfigServiceLinux(env));
1564    ProxyConfig config;
1565    sync_config_getter.SetupAndInitialFetch();
1566    EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1567              sync_config_getter.SyncGetLatestProxyConfig(&config));
1568    EXPECT_FALSE(config.auto_detect());
1569    EXPECT_EQ(slaverc4_pac_url, config.pac_url());
1570  }
1571
1572  { SCOPED_TRACE("KDE3, .kde4 directory present, ignore it");
1573    MockEnvironment* env = new MockEnvironment;
1574    env->values.DESKTOP_SESSION = "kde";
1575    env->values.HOME = user_home_.value().c_str();
1576    SynchConfigGetter sync_config_getter(
1577        new ProxyConfigServiceLinux(env));
1578    ProxyConfig config;
1579    sync_config_getter.SetupAndInitialFetch();
1580    EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1581              sync_config_getter.SyncGetLatestProxyConfig(&config));
1582    EXPECT_TRUE(config.auto_detect());
1583    EXPECT_EQ(GURL(), config.pac_url());
1584  }
1585
1586  { SCOPED_TRACE("KDE4, .kde4 directory present, KDEHOME set to .kde");
1587    MockEnvironment* env = new MockEnvironment;
1588    env->values.DESKTOP_SESSION = "kde4";
1589    env->values.HOME = user_home_.value().c_str();
1590    env->values.KDEHOME = kde_home_.value().c_str();
1591    SynchConfigGetter sync_config_getter(
1592        new ProxyConfigServiceLinux(env));
1593    ProxyConfig config;
1594    sync_config_getter.SetupAndInitialFetch();
1595    EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1596              sync_config_getter.SyncGetLatestProxyConfig(&config));
1597    EXPECT_TRUE(config.auto_detect());
1598    EXPECT_EQ(GURL(), config.pac_url());
1599  }
1600
1601  // Finally, make the .kde4 config directory older than the .kde directory
1602  // and make sure we then use .kde instead of .kde4 since it's newer.
1603  base::TouchFile(kde4_config_, base::Time(), base::Time());
1604
1605  { SCOPED_TRACE("KDE4, very old .kde4 directory present, use .kde");
1606    MockEnvironment* env = new MockEnvironment;
1607    env->values.DESKTOP_SESSION = "kde4";
1608    env->values.HOME = user_home_.value().c_str();
1609    SynchConfigGetter sync_config_getter(
1610        new ProxyConfigServiceLinux(env));
1611    ProxyConfig config;
1612    sync_config_getter.SetupAndInitialFetch();
1613    EXPECT_EQ(ProxyConfigService::CONFIG_VALID,
1614              sync_config_getter.SyncGetLatestProxyConfig(&config));
1615    EXPECT_TRUE(config.auto_detect());
1616    EXPECT_EQ(GURL(), config.pac_url());
1617  }
1618}
1619
1620}  // namespace net
1621