Home | History | Annotate | Download | only in proxy
      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 
     26 namespace net {
     27 namespace {
     28 
     29 // Set of values for all environment variables that we might
     30 // query. NULL represents an unset variable.
     31 struct 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.
     48 enum BoolSettingValue {
     49   UNSET = 0, TRUE, FALSE
     50 };
     51 
     52 // Set of values for all gconf settings that we might query.
     53 struct 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).
     67 template<typename key_type, typename value_type>
     68 struct 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 
     83 class 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 
    140 class 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.
    264 class 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 
    351 namespace 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").
    356 class 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 
    394 TEST_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 
    706 TEST_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 
   1014 TEST_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 
   1038 TEST_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 
   1523 TEST_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