Home | History | Annotate | Download | only in net
      1 // Copyright (c) 2011 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 "chrome/browser/net/pref_proxy_config_service.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/file_path.h"
      9 #include "chrome/browser/net/chrome_url_request_context.h"
     10 #include "chrome/browser/prefs/pref_service_mock_builder.h"
     11 #include "chrome/browser/prefs/proxy_config_dictionary.h"
     12 #include "chrome/common/chrome_switches.h"
     13 #include "chrome/common/pref_names.h"
     14 #include "chrome/test/testing_pref_service.h"
     15 #include "net/proxy/proxy_config_service_common_unittest.h"
     16 #include "testing/gmock/include/gmock/gmock.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 
     19 using testing::_;
     20 using testing::Mock;
     21 
     22 namespace {
     23 
     24 const char kFixedPacUrl[] = "http://chromium.org/fixed_pac_url";
     25 
     26 // Testing proxy config service that allows us to fire notifications at will.
     27 class TestProxyConfigService : public net::ProxyConfigService {
     28  public:
     29   TestProxyConfigService(const net::ProxyConfig& config,
     30                          ConfigAvailability availability)
     31       : config_(config),
     32         availability_(availability) {}
     33 
     34   void SetProxyConfig(const net::ProxyConfig config,
     35                       ConfigAvailability availability) {
     36     config_ = config;
     37     availability_ = availability;
     38     FOR_EACH_OBSERVER(net::ProxyConfigService::Observer, observers_,
     39                       OnProxyConfigChanged(config, availability));
     40   }
     41 
     42  private:
     43   virtual void AddObserver(net::ProxyConfigService::Observer* observer) {
     44     observers_.AddObserver(observer);
     45   }
     46 
     47   virtual void RemoveObserver(net::ProxyConfigService::Observer* observer) {
     48     observers_.RemoveObserver(observer);
     49   }
     50 
     51   virtual net::ProxyConfigService::ConfigAvailability GetLatestProxyConfig(
     52       net::ProxyConfig* config) {
     53     *config = config_;
     54     return availability_;
     55   }
     56 
     57   net::ProxyConfig config_;
     58   ConfigAvailability availability_;
     59   ObserverList<net::ProxyConfigService::Observer, true> observers_;
     60 };
     61 
     62 // A mock observer for capturing callbacks.
     63 class MockObserver : public net::ProxyConfigService::Observer {
     64  public:
     65   MOCK_METHOD2(OnProxyConfigChanged,
     66                void(const net::ProxyConfig&,
     67                     net::ProxyConfigService::ConfigAvailability));
     68 };
     69 
     70 template<typename TESTBASE>
     71 class PrefProxyConfigServiceTestBase : public TESTBASE {
     72  protected:
     73   PrefProxyConfigServiceTestBase()
     74       : ui_thread_(BrowserThread::UI, &loop_),
     75         io_thread_(BrowserThread::IO, &loop_) {}
     76 
     77   virtual void Init(PrefService* pref_service) {
     78     ASSERT_TRUE(pref_service);
     79     PrefProxyConfigService::RegisterPrefs(pref_service);
     80     fixed_config_.set_pac_url(GURL(kFixedPacUrl));
     81     delegate_service_ =
     82         new TestProxyConfigService(fixed_config_,
     83                                    net::ProxyConfigService::CONFIG_VALID);
     84     proxy_config_tracker_ = new PrefProxyConfigTracker(pref_service);
     85     proxy_config_service_.reset(
     86         new PrefProxyConfigService(proxy_config_tracker_.get(),
     87                                    delegate_service_));
     88   }
     89 
     90   virtual void TearDown() {
     91     proxy_config_tracker_->DetachFromPrefService();
     92     loop_.RunAllPending();
     93     proxy_config_service_.reset();
     94   }
     95 
     96   MessageLoop loop_;
     97   TestProxyConfigService* delegate_service_; // weak
     98   scoped_ptr<PrefProxyConfigService> proxy_config_service_;
     99   net::ProxyConfig fixed_config_;
    100 
    101  private:
    102   scoped_refptr<PrefProxyConfigTracker> proxy_config_tracker_;
    103   BrowserThread ui_thread_;
    104   BrowserThread io_thread_;
    105 };
    106 
    107 class PrefProxyConfigServiceTest
    108     : public PrefProxyConfigServiceTestBase<testing::Test> {
    109  protected:
    110   virtual void SetUp() {
    111     pref_service_.reset(new TestingPrefService());
    112     Init(pref_service_.get());
    113   }
    114 
    115   scoped_ptr<TestingPrefService> pref_service_;
    116 };
    117 
    118 TEST_F(PrefProxyConfigServiceTest, BaseConfiguration) {
    119   net::ProxyConfig actual_config;
    120   EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
    121             proxy_config_service_->GetLatestProxyConfig(&actual_config));
    122   EXPECT_EQ(GURL(kFixedPacUrl), actual_config.pac_url());
    123 }
    124 
    125 TEST_F(PrefProxyConfigServiceTest, DynamicPrefOverrides) {
    126   pref_service_->SetManagedPref(
    127       prefs::kProxy,
    128       ProxyConfigDictionary::CreateFixedServers("http://example.com:3128", ""));
    129   loop_.RunAllPending();
    130 
    131   net::ProxyConfig actual_config;
    132   EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
    133             proxy_config_service_->GetLatestProxyConfig(&actual_config));
    134   EXPECT_FALSE(actual_config.auto_detect());
    135   EXPECT_EQ(net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY,
    136             actual_config.proxy_rules().type);
    137   EXPECT_EQ(actual_config.proxy_rules().single_proxy,
    138             net::ProxyServer::FromURI("http://example.com:3128",
    139                                       net::ProxyServer::SCHEME_HTTP));
    140 
    141   pref_service_->SetManagedPref(prefs::kProxy,
    142                                 ProxyConfigDictionary::CreateAutoDetect());
    143   loop_.RunAllPending();
    144 
    145   EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
    146             proxy_config_service_->GetLatestProxyConfig(&actual_config));
    147   EXPECT_TRUE(actual_config.auto_detect());
    148 }
    149 
    150 // Compares proxy configurations, but allows different identifiers.
    151 MATCHER_P(ProxyConfigMatches, config, "") {
    152   net::ProxyConfig reference(config);
    153   reference.set_id(arg.id());
    154   return reference.Equals(arg);
    155 }
    156 
    157 TEST_F(PrefProxyConfigServiceTest, Observers) {
    158   const net::ProxyConfigService::ConfigAvailability CONFIG_VALID =
    159       net::ProxyConfigService::CONFIG_VALID;
    160   MockObserver observer;
    161   proxy_config_service_->AddObserver(&observer);
    162 
    163   // Firing the observers in the delegate should trigger a notification.
    164   net::ProxyConfig config2;
    165   config2.set_auto_detect(true);
    166   EXPECT_CALL(observer, OnProxyConfigChanged(ProxyConfigMatches(config2),
    167                                              CONFIG_VALID)).Times(1);
    168   delegate_service_->SetProxyConfig(config2, CONFIG_VALID);
    169   loop_.RunAllPending();
    170   Mock::VerifyAndClearExpectations(&observer);
    171 
    172   // Override configuration, this should trigger a notification.
    173   net::ProxyConfig pref_config;
    174   pref_config.set_pac_url(GURL(kFixedPacUrl));
    175 
    176   EXPECT_CALL(observer, OnProxyConfigChanged(ProxyConfigMatches(pref_config),
    177                                              CONFIG_VALID)).Times(1);
    178   pref_service_->SetManagedPref(
    179       prefs::kProxy,
    180       ProxyConfigDictionary::CreatePacScript(kFixedPacUrl));
    181   loop_.RunAllPending();
    182   Mock::VerifyAndClearExpectations(&observer);
    183 
    184   // Since there are pref overrides, delegate changes should be ignored.
    185   net::ProxyConfig config3;
    186   config3.proxy_rules().ParseFromString("http=config3:80");
    187   EXPECT_CALL(observer, OnProxyConfigChanged(_, _)).Times(0);
    188   fixed_config_.set_auto_detect(true);
    189   delegate_service_->SetProxyConfig(config3, CONFIG_VALID);
    190   loop_.RunAllPending();
    191   Mock::VerifyAndClearExpectations(&observer);
    192 
    193   // Clear the override should switch back to the fixed configuration.
    194   EXPECT_CALL(observer, OnProxyConfigChanged(ProxyConfigMatches(config3),
    195                                              CONFIG_VALID)).Times(1);
    196   pref_service_->RemoveManagedPref(prefs::kProxy);
    197   loop_.RunAllPending();
    198   Mock::VerifyAndClearExpectations(&observer);
    199 
    200   // Delegate service notifications should show up again.
    201   net::ProxyConfig config4;
    202   config4.proxy_rules().ParseFromString("socks:config4");
    203   EXPECT_CALL(observer, OnProxyConfigChanged(ProxyConfigMatches(config4),
    204                                              CONFIG_VALID)).Times(1);
    205   delegate_service_->SetProxyConfig(config4, CONFIG_VALID);
    206   loop_.RunAllPending();
    207   Mock::VerifyAndClearExpectations(&observer);
    208 
    209   proxy_config_service_->RemoveObserver(&observer);
    210 }
    211 
    212 TEST_F(PrefProxyConfigServiceTest, Fallback) {
    213   const net::ProxyConfigService::ConfigAvailability CONFIG_VALID =
    214       net::ProxyConfigService::CONFIG_VALID;
    215   MockObserver observer;
    216   net::ProxyConfig actual_config;
    217   delegate_service_->SetProxyConfig(net::ProxyConfig::CreateDirect(),
    218                                     net::ProxyConfigService::CONFIG_UNSET);
    219   proxy_config_service_->AddObserver(&observer);
    220 
    221   // Prepare test data.
    222   net::ProxyConfig recommended_config = net::ProxyConfig::CreateAutoDetect();
    223   net::ProxyConfig user_config =
    224       net::ProxyConfig::CreateFromCustomPacURL(GURL(kFixedPacUrl));
    225 
    226   // Set a recommended pref.
    227   EXPECT_CALL(observer,
    228               OnProxyConfigChanged(ProxyConfigMatches(recommended_config),
    229                                    CONFIG_VALID)).Times(1);
    230   pref_service_->SetRecommendedPref(
    231       prefs::kProxy,
    232       ProxyConfigDictionary::CreateAutoDetect());
    233   loop_.RunAllPending();
    234   Mock::VerifyAndClearExpectations(&observer);
    235   EXPECT_EQ(CONFIG_VALID,
    236             proxy_config_service_->GetLatestProxyConfig(&actual_config));
    237   EXPECT_TRUE(actual_config.Equals(recommended_config));
    238 
    239   // Override in user prefs.
    240   EXPECT_CALL(observer,
    241               OnProxyConfigChanged(ProxyConfigMatches(user_config),
    242                                    CONFIG_VALID)).Times(1);
    243   pref_service_->SetManagedPref(
    244       prefs::kProxy,
    245       ProxyConfigDictionary::CreatePacScript(kFixedPacUrl));
    246   loop_.RunAllPending();
    247   Mock::VerifyAndClearExpectations(&observer);
    248   EXPECT_EQ(CONFIG_VALID,
    249             proxy_config_service_->GetLatestProxyConfig(&actual_config));
    250   EXPECT_TRUE(actual_config.Equals(user_config));
    251 
    252   // Go back to recommended pref.
    253   EXPECT_CALL(observer,
    254               OnProxyConfigChanged(ProxyConfigMatches(recommended_config),
    255                                    CONFIG_VALID)).Times(1);
    256   pref_service_->RemoveManagedPref(prefs::kProxy);
    257   loop_.RunAllPending();
    258   Mock::VerifyAndClearExpectations(&observer);
    259   EXPECT_EQ(CONFIG_VALID,
    260             proxy_config_service_->GetLatestProxyConfig(&actual_config));
    261   EXPECT_TRUE(actual_config.Equals(recommended_config));
    262 
    263   proxy_config_service_->RemoveObserver(&observer);
    264 }
    265 
    266 // Test parameter object for testing command line proxy configuration.
    267 struct CommandLineTestParams {
    268   // Explicit assignment operator, so testing::TestWithParam works with MSVC.
    269   CommandLineTestParams& operator=(const CommandLineTestParams& other) {
    270     description = other.description;
    271     for (unsigned int i = 0; i < arraysize(switches); i++)
    272       switches[i] = other.switches[i];
    273     is_null = other.is_null;
    274     auto_detect = other.auto_detect;
    275     pac_url = other.pac_url;
    276     proxy_rules = other.proxy_rules;
    277     return *this;
    278   }
    279 
    280   // Short description to identify the test.
    281   const char* description;
    282 
    283   // The command line to build a ProxyConfig from.
    284   struct SwitchValue {
    285     const char* name;
    286     const char* value;
    287   } switches[2];
    288 
    289   // Expected outputs (fields of the ProxyConfig).
    290   bool is_null;
    291   bool auto_detect;
    292   GURL pac_url;
    293   net::ProxyRulesExpectation proxy_rules;
    294 };
    295 
    296 void PrintTo(const CommandLineTestParams& params, std::ostream* os) {
    297   *os << params.description;
    298 }
    299 
    300 class PrefProxyConfigServiceCommandLineTest
    301     : public PrefProxyConfigServiceTestBase<
    302           testing::TestWithParam<CommandLineTestParams> > {
    303  protected:
    304   PrefProxyConfigServiceCommandLineTest()
    305       : command_line_(CommandLine::NO_PROGRAM) {}
    306 
    307   virtual void SetUp() {
    308     for (size_t i = 0; i < arraysize(GetParam().switches); i++) {
    309       const char* name = GetParam().switches[i].name;
    310       const char* value = GetParam().switches[i].value;
    311       if (name && value)
    312         command_line_.AppendSwitchASCII(name, value);
    313       else if (name)
    314         command_line_.AppendSwitch(name);
    315     }
    316     pref_service_.reset(
    317         PrefServiceMockBuilder().WithCommandLine(&command_line_).Create());
    318     Init(pref_service_.get());
    319   }
    320 
    321  private:
    322   CommandLine command_line_;
    323   scoped_ptr<PrefService> pref_service_;
    324 };
    325 
    326 TEST_P(PrefProxyConfigServiceCommandLineTest, CommandLine) {
    327   net::ProxyConfig config;
    328   EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
    329             proxy_config_service_->GetLatestProxyConfig(&config));
    330 
    331   if (GetParam().is_null) {
    332     EXPECT_EQ(GURL(kFixedPacUrl), config.pac_url());
    333   } else {
    334     EXPECT_NE(GURL(kFixedPacUrl), config.pac_url());
    335     EXPECT_EQ(GetParam().auto_detect, config.auto_detect());
    336     EXPECT_EQ(GetParam().pac_url, config.pac_url());
    337     EXPECT_TRUE(GetParam().proxy_rules.Matches(config.proxy_rules()));
    338   }
    339 }
    340 
    341 static const CommandLineTestParams kCommandLineTestParams[] = {
    342   {
    343     "Empty command line",
    344     // Input
    345     { },
    346     // Expected result
    347     true,                                               // is_null
    348     false,                                              // auto_detect
    349     GURL(),                                             // pac_url
    350     net::ProxyRulesExpectation::Empty(),
    351   },
    352   {
    353     "No proxy",
    354     // Input
    355     {
    356       { switches::kNoProxyServer, NULL },
    357     },
    358     // Expected result
    359     false,                                              // is_null
    360     false,                                              // auto_detect
    361     GURL(),                                             // pac_url
    362     net::ProxyRulesExpectation::Empty(),
    363   },
    364   {
    365     "No proxy with extra parameters.",
    366     // Input
    367     {
    368       { switches::kNoProxyServer, NULL },
    369       { switches::kProxyServer, "http://proxy:8888" },
    370     },
    371     // Expected result
    372     false,                                              // is_null
    373     false,                                              // auto_detect
    374     GURL(),                                             // pac_url
    375     net::ProxyRulesExpectation::Empty(),
    376   },
    377   {
    378     "Single proxy.",
    379     // Input
    380     {
    381       { switches::kProxyServer, "http://proxy:8888" },
    382     },
    383     // Expected result
    384     false,                                              // is_null
    385     false,                                              // auto_detect
    386     GURL(),                                             // pac_url
    387     net::ProxyRulesExpectation::Single(
    388         "proxy:8888",  // single proxy
    389         ""),           // bypass rules
    390   },
    391   {
    392     "Per scheme proxy.",
    393     // Input
    394     {
    395       { switches::kProxyServer, "http=httpproxy:8888;ftp=ftpproxy:8889" },
    396     },
    397     // Expected result
    398     false,                                              // is_null
    399     false,                                              // auto_detect
    400     GURL(),                                             // pac_url
    401     net::ProxyRulesExpectation::PerScheme(
    402         "httpproxy:8888",  // http
    403         "",                // https
    404         "ftpproxy:8889",   // ftp
    405         ""),               // bypass rules
    406   },
    407   {
    408     "Per scheme proxy with bypass URLs.",
    409     // Input
    410     {
    411       { switches::kProxyServer, "http=httpproxy:8888;ftp=ftpproxy:8889" },
    412       { switches::kProxyBypassList,
    413         ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8" },
    414     },
    415     // Expected result
    416     false,                                              // is_null
    417     false,                                              // auto_detect
    418     GURL(),                                             // pac_url
    419     net::ProxyRulesExpectation::PerScheme(
    420         "httpproxy:8888",  // http
    421         "",                // https
    422         "ftpproxy:8889",   // ftp
    423         "*.google.com,foo.com:99,1.2.3.4:22,127.0.0.1/8"),
    424   },
    425   {
    426     "Pac URL",
    427     // Input
    428     {
    429       { switches::kProxyPacUrl, "http://wpad/wpad.dat" },
    430     },
    431     // Expected result
    432     false,                                              // is_null
    433     false,                                              // auto_detect
    434     GURL("http://wpad/wpad.dat"),                       // pac_url
    435     net::ProxyRulesExpectation::Empty(),
    436   },
    437   {
    438     "Autodetect",
    439     // Input
    440     {
    441       { switches::kProxyAutoDetect, NULL },
    442     },
    443     // Expected result
    444     false,                                              // is_null
    445     true,                                               // auto_detect
    446     GURL(),                                             // pac_url
    447     net::ProxyRulesExpectation::Empty(),
    448   },
    449 };
    450 
    451 INSTANTIATE_TEST_CASE_P(
    452     PrefProxyConfigServiceCommandLineTestInstance,
    453     PrefProxyConfigServiceCommandLineTest,
    454     testing::ValuesIn(kCommandLineTestParams));
    455 
    456 }  // namespace
    457