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 <map>
      6 #include <string>
      7 
      8 #include "base/bind.h"
      9 #include "base/compiler_specific.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "net/proxy/proxy_config.h"
     13 #include "net/proxy/proxy_config_service_android.h"
     14 #include "net/proxy/proxy_info.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 namespace net {
     18 
     19 namespace {
     20 
     21 class TestObserver : public ProxyConfigService::Observer {
     22  public:
     23   TestObserver() : availability_(ProxyConfigService::CONFIG_UNSET) {}
     24 
     25   // ProxyConfigService::Observer:
     26   virtual void OnProxyConfigChanged(
     27       const ProxyConfig& config,
     28       ProxyConfigService::ConfigAvailability availability) OVERRIDE {
     29     config_ = config;
     30     availability_ = availability;
     31   }
     32 
     33   ProxyConfigService::ConfigAvailability availability() const {
     34     return availability_;
     35   }
     36 
     37   const ProxyConfig& config() const {
     38     return config_;
     39   }
     40 
     41  private:
     42   ProxyConfig config_;
     43   ProxyConfigService::ConfigAvailability availability_;
     44 };
     45 
     46 }  // namespace
     47 
     48 typedef std::map<std::string, std::string> StringMap;
     49 
     50 class ProxyConfigServiceAndroidTestBase : public testing::Test {
     51  protected:
     52   // Note that the current thread's message loop is initialized by the test
     53   // suite (see net/test/net_test_suite.cc).
     54   ProxyConfigServiceAndroidTestBase(const StringMap& initial_configuration)
     55       : configuration_(initial_configuration),
     56         message_loop_(base::MessageLoop::current()),
     57         service_(message_loop_->message_loop_proxy(),
     58                  message_loop_->message_loop_proxy(),
     59                  base::Bind(&ProxyConfigServiceAndroidTestBase::GetProperty,
     60                             base::Unretained(this))) {}
     61 
     62   virtual ~ProxyConfigServiceAndroidTestBase() {}
     63 
     64   // testing::Test:
     65   virtual void SetUp() OVERRIDE {
     66     message_loop_->RunUntilIdle();
     67     service_.AddObserver(&observer_);
     68   }
     69 
     70   virtual void TearDown() OVERRIDE {
     71     service_.RemoveObserver(&observer_);
     72   }
     73 
     74   void ClearConfiguration() {
     75     configuration_.clear();
     76   }
     77 
     78   void AddProperty(const std::string& key, const std::string& value) {
     79     configuration_[key] = value;
     80   }
     81 
     82   std::string GetProperty(const std::string& key) {
     83     StringMap::const_iterator it = configuration_.find(key);
     84     if (it == configuration_.end())
     85       return std::string();
     86     return it->second;
     87   }
     88 
     89   void ProxySettingsChanged() {
     90     service_.ProxySettingsChanged();
     91     message_loop_->RunUntilIdle();
     92   }
     93 
     94   void TestMapping(const std::string& url, const std::string& expected) {
     95     ProxyConfigService::ConfigAvailability availability;
     96     ProxyConfig proxy_config;
     97     availability = service_.GetLatestProxyConfig(&proxy_config);
     98     EXPECT_EQ(ProxyConfigService::CONFIG_VALID, availability);
     99     ProxyInfo proxy_info;
    100     proxy_config.proxy_rules().Apply(GURL(url), &proxy_info);
    101     EXPECT_EQ(expected, proxy_info.ToPacString());
    102   }
    103 
    104   StringMap configuration_;
    105   TestObserver observer_;
    106   base::MessageLoop* const message_loop_;
    107   ProxyConfigServiceAndroid service_;
    108 };
    109 
    110 class ProxyConfigServiceAndroidTest : public ProxyConfigServiceAndroidTestBase {
    111  public:
    112   ProxyConfigServiceAndroidTest()
    113       : ProxyConfigServiceAndroidTestBase(StringMap()) {}
    114 };
    115 
    116 class ProxyConfigServiceAndroidWithInitialConfigTest
    117     : public ProxyConfigServiceAndroidTestBase {
    118  public:
    119   ProxyConfigServiceAndroidWithInitialConfigTest()
    120       : ProxyConfigServiceAndroidTestBase(MakeInitialConfiguration()) {}
    121 
    122  private:
    123   StringMap MakeInitialConfiguration() {
    124     StringMap initial_configuration;
    125     initial_configuration["http.proxyHost"] = "httpproxy.com";
    126     initial_configuration["http.proxyPort"] = "8080";
    127     return initial_configuration;
    128   }
    129 };
    130 
    131 TEST_F(ProxyConfigServiceAndroidTest, TestChangePropertiesNotification) {
    132   // Set up a non-empty configuration
    133   AddProperty("http.proxyHost", "localhost");
    134   ProxySettingsChanged();
    135   EXPECT_EQ(ProxyConfigService::CONFIG_VALID, observer_.availability());
    136   EXPECT_FALSE(observer_.config().proxy_rules().empty());
    137 
    138   // Set up an empty configuration
    139   ClearConfiguration();
    140   ProxySettingsChanged();
    141   EXPECT_EQ(ProxyConfigService::CONFIG_VALID, observer_.availability());
    142   EXPECT_TRUE(observer_.config().proxy_rules().empty());
    143 }
    144 
    145 TEST_F(ProxyConfigServiceAndroidWithInitialConfigTest, TestInitialConfig) {
    146   // Make sure that the initial config is set.
    147   TestMapping("ftp://example.com/", "DIRECT");
    148   TestMapping("http://example.com/", "PROXY httpproxy.com:8080");
    149 
    150   // Override the initial configuration.
    151   ClearConfiguration();
    152   AddProperty("http.proxyHost", "httpproxy.com");
    153   ProxySettingsChanged();
    154   TestMapping("http://example.com/", "PROXY httpproxy.com:80");
    155 }
    156 
    157 // !! The following test cases are automatically generated from
    158 // !! net/android/tools/proxy_test_cases.py.
    159 // !! Please edit that file instead of editing the test cases below and
    160 // !! update also the corresponding Java unit tests in
    161 // !! AndroidProxySelectorTest.java
    162 
    163 TEST_F(ProxyConfigServiceAndroidTest, NoProxy) {
    164   // Test direct mapping when no proxy defined.
    165   ProxySettingsChanged();
    166   TestMapping("ftp://example.com/", "DIRECT");
    167   TestMapping("http://example.com/", "DIRECT");
    168   TestMapping("https://example.com/", "DIRECT");
    169 }
    170 
    171 TEST_F(ProxyConfigServiceAndroidTest, HttpProxyHostAndPort) {
    172   // Test http.proxyHost and http.proxyPort works.
    173   AddProperty("http.proxyHost", "httpproxy.com");
    174   AddProperty("http.proxyPort", "8080");
    175   ProxySettingsChanged();
    176   TestMapping("ftp://example.com/", "DIRECT");
    177   TestMapping("http://example.com/", "PROXY httpproxy.com:8080");
    178   TestMapping("https://example.com/", "DIRECT");
    179 }
    180 
    181 TEST_F(ProxyConfigServiceAndroidTest, HttpProxyHostOnly) {
    182   // We should get the default port (80) for proxied hosts.
    183   AddProperty("http.proxyHost", "httpproxy.com");
    184   ProxySettingsChanged();
    185   TestMapping("ftp://example.com/", "DIRECT");
    186   TestMapping("http://example.com/", "PROXY httpproxy.com:80");
    187   TestMapping("https://example.com/", "DIRECT");
    188 }
    189 
    190 TEST_F(ProxyConfigServiceAndroidTest, HttpProxyPortOnly) {
    191   // http.proxyPort only should not result in any hosts being proxied.
    192   AddProperty("http.proxyPort", "8080");
    193   ProxySettingsChanged();
    194   TestMapping("ftp://example.com/", "DIRECT");
    195   TestMapping("http://example.com/", "DIRECT");
    196   TestMapping("https://example.com/", "DIRECT");
    197 }
    198 
    199 TEST_F(ProxyConfigServiceAndroidTest, HttpNonProxyHosts1) {
    200   // Test that HTTP non proxy hosts are mapped correctly
    201   AddProperty("http.nonProxyHosts", "slashdot.org");
    202   AddProperty("http.proxyHost", "httpproxy.com");
    203   AddProperty("http.proxyPort", "8080");
    204   ProxySettingsChanged();
    205   TestMapping("http://example.com/", "PROXY httpproxy.com:8080");
    206   TestMapping("http://slashdot.org/", "DIRECT");
    207 }
    208 
    209 TEST_F(ProxyConfigServiceAndroidTest, HttpNonProxyHosts2) {
    210   // Test that | pattern works.
    211   AddProperty("http.nonProxyHosts", "slashdot.org|freecode.net");
    212   AddProperty("http.proxyHost", "httpproxy.com");
    213   AddProperty("http.proxyPort", "8080");
    214   ProxySettingsChanged();
    215   TestMapping("http://example.com/", "PROXY httpproxy.com:8080");
    216   TestMapping("http://freecode.net/", "DIRECT");
    217   TestMapping("http://slashdot.org/", "DIRECT");
    218 }
    219 
    220 TEST_F(ProxyConfigServiceAndroidTest, HttpNonProxyHosts3) {
    221   // Test that * pattern works.
    222   AddProperty("http.nonProxyHosts", "*example.com");
    223   AddProperty("http.proxyHost", "httpproxy.com");
    224   AddProperty("http.proxyPort", "8080");
    225   ProxySettingsChanged();
    226   TestMapping("http://example.com/", "DIRECT");
    227   TestMapping("http://slashdot.org/", "PROXY httpproxy.com:8080");
    228   TestMapping("http://www.example.com/", "DIRECT");
    229 }
    230 
    231 TEST_F(ProxyConfigServiceAndroidTest, FtpNonProxyHosts) {
    232   // Test that FTP non proxy hosts are mapped correctly
    233   AddProperty("ftp.nonProxyHosts", "slashdot.org");
    234   AddProperty("ftp.proxyHost", "httpproxy.com");
    235   AddProperty("ftp.proxyPort", "8080");
    236   ProxySettingsChanged();
    237   TestMapping("ftp://example.com/", "PROXY httpproxy.com:8080");
    238   TestMapping("http://example.com/", "DIRECT");
    239 }
    240 
    241 TEST_F(ProxyConfigServiceAndroidTest, FtpProxyHostAndPort) {
    242   // Test ftp.proxyHost and ftp.proxyPort works.
    243   AddProperty("ftp.proxyHost", "httpproxy.com");
    244   AddProperty("ftp.proxyPort", "8080");
    245   ProxySettingsChanged();
    246   TestMapping("ftp://example.com/", "PROXY httpproxy.com:8080");
    247   TestMapping("http://example.com/", "DIRECT");
    248   TestMapping("https://example.com/", "DIRECT");
    249 }
    250 
    251 TEST_F(ProxyConfigServiceAndroidTest, FtpProxyHostOnly) {
    252   // Test ftp.proxyHost and default port.
    253   AddProperty("ftp.proxyHost", "httpproxy.com");
    254   ProxySettingsChanged();
    255   TestMapping("ftp://example.com/", "PROXY httpproxy.com:80");
    256   TestMapping("http://example.com/", "DIRECT");
    257   TestMapping("https://example.com/", "DIRECT");
    258 }
    259 
    260 TEST_F(ProxyConfigServiceAndroidTest, HttpsProxyHostAndPort) {
    261   // Test https.proxyHost and https.proxyPort works.
    262   AddProperty("https.proxyHost", "httpproxy.com");
    263   AddProperty("https.proxyPort", "8080");
    264   ProxySettingsChanged();
    265   TestMapping("ftp://example.com/", "DIRECT");
    266   TestMapping("http://example.com/", "DIRECT");
    267   TestMapping("https://example.com/", "PROXY httpproxy.com:8080");
    268 }
    269 
    270 TEST_F(ProxyConfigServiceAndroidTest, HttpsProxyHostOnly) {
    271   // Test https.proxyHost and default port.
    272   AddProperty("https.proxyHost", "httpproxy.com");
    273   ProxySettingsChanged();
    274   TestMapping("ftp://example.com/", "DIRECT");
    275   TestMapping("http://example.com/", "DIRECT");
    276   TestMapping("https://example.com/", "PROXY httpproxy.com:80");
    277 }
    278 
    279 TEST_F(ProxyConfigServiceAndroidTest, HttpProxyHostIPv6) {
    280   // Test IPv6 https.proxyHost and default port.
    281   AddProperty("http.proxyHost", "a:b:c::d:1");
    282   ProxySettingsChanged();
    283   TestMapping("ftp://example.com/", "DIRECT");
    284   TestMapping("http://example.com/", "PROXY [a:b:c::d:1]:80");
    285 }
    286 
    287 TEST_F(ProxyConfigServiceAndroidTest, HttpProxyHostAndPortIPv6) {
    288   // Test IPv6 http.proxyHost and http.proxyPort works.
    289   AddProperty("http.proxyHost", "a:b:c::d:1");
    290   AddProperty("http.proxyPort", "8080");
    291   ProxySettingsChanged();
    292   TestMapping("ftp://example.com/", "DIRECT");
    293   TestMapping("http://example.com/", "PROXY [a:b:c::d:1]:8080");
    294 }
    295 
    296 TEST_F(ProxyConfigServiceAndroidTest, HttpProxyHostAndInvalidPort) {
    297   // Test invalid http.proxyPort does not crash.
    298   AddProperty("http.proxyHost", "a:b:c::d:1");
    299   AddProperty("http.proxyPort", "65536");
    300   ProxySettingsChanged();
    301   TestMapping("ftp://example.com/", "DIRECT");
    302   TestMapping("http://example.com/", "DIRECT");
    303 }
    304 
    305 TEST_F(ProxyConfigServiceAndroidTest, DefaultProxyExplictPort) {
    306   // Default http proxy is used if a scheme-specific one is not found.
    307   AddProperty("ftp.proxyHost", "httpproxy.com");
    308   AddProperty("ftp.proxyPort", "8080");
    309   AddProperty("proxyHost", "defaultproxy.com");
    310   AddProperty("proxyPort", "8080");
    311   ProxySettingsChanged();
    312   TestMapping("ftp://example.com/", "PROXY httpproxy.com:8080");
    313   TestMapping("http://example.com/", "PROXY defaultproxy.com:8080");
    314   TestMapping("https://example.com/", "PROXY defaultproxy.com:8080");
    315 }
    316 
    317 TEST_F(ProxyConfigServiceAndroidTest, DefaultProxyDefaultPort) {
    318   // Check that the default proxy port is as expected.
    319   AddProperty("proxyHost", "defaultproxy.com");
    320   ProxySettingsChanged();
    321   TestMapping("http://example.com/", "PROXY defaultproxy.com:80");
    322   TestMapping("https://example.com/", "PROXY defaultproxy.com:80");
    323 }
    324 
    325 TEST_F(ProxyConfigServiceAndroidTest, FallbackToSocks) {
    326   // SOCKS proxy is used if scheme-specific one is not found.
    327   AddProperty("http.proxyHost", "defaultproxy.com");
    328   AddProperty("socksProxyHost", "socksproxy.com");
    329   ProxySettingsChanged();
    330   TestMapping("ftp://example.com", "SOCKS5 socksproxy.com:1080");
    331   TestMapping("http://example.com/", "PROXY defaultproxy.com:80");
    332   TestMapping("https://example.com/", "SOCKS5 socksproxy.com:1080");
    333 }
    334 
    335 TEST_F(ProxyConfigServiceAndroidTest, SocksExplicitPort) {
    336   // SOCKS proxy port is used if specified
    337   AddProperty("socksProxyHost", "socksproxy.com");
    338   AddProperty("socksProxyPort", "9000");
    339   ProxySettingsChanged();
    340   TestMapping("http://example.com/", "SOCKS5 socksproxy.com:9000");
    341 }
    342 
    343 TEST_F(ProxyConfigServiceAndroidTest, HttpProxySupercedesSocks) {
    344   // SOCKS proxy is ignored if default HTTP proxy defined.
    345   AddProperty("proxyHost", "defaultproxy.com");
    346   AddProperty("socksProxyHost", "socksproxy.com");
    347   AddProperty("socksProxyPort", "9000");
    348   ProxySettingsChanged();
    349   TestMapping("http://example.com/", "PROXY defaultproxy.com:80");
    350 }
    351 
    352 }  // namespace net
    353