Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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/ref_counted.h" | |
| 11 #include "base/memory/scoped_ptr.h" | |
| 12 #include "base/message_loop.h" | |
| 13 #include "base/synchronization/waitable_event.h" | |
| 14 #include "base/threading/thread.h" | |
| 15 #include "net/proxy/proxy_config.h" | |
| 16 #include "net/proxy/proxy_config_service_android.h" | |
| 17 #include "net/proxy/proxy_info.h" | |
| 18 #include "testing/gtest/include/gtest/gtest.h" | |
| 19 | |
| 20 namespace net { | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 scoped_ptr<base::WaitableEvent> MakeWaitableEvent() { | |
| 25 return scoped_ptr<base::WaitableEvent>( | |
| 26 new base::WaitableEvent( | |
| 27 false /* automatic reset */, false /* not signaled initialy */)); | |
| 28 } | |
| 29 | |
| 30 class TestObserver : public ProxyConfigService::Observer { | |
| 31 public: | |
| 32 TestObserver(base::WaitableEvent* proxy_config_changed_event) | |
| 33 : main_thread_loop_(MessageLoop::current()), | |
| 34 proxy_config_changed_event_(proxy_config_changed_event) {} | |
| 35 | |
| 36 // ProxyConfigService::Observer: | |
| 37 virtual void OnProxyConfigChanged( | |
| 38 const ProxyConfig& config, | |
| 39 ProxyConfigService::ConfigAvailability availability) OVERRIDE { | |
| 40 // Called from network thread. | |
| 41 main_thread_loop_->PostTask( | |
| 42 FROM_HERE, | |
| 43 base::Bind(&TestObserver::UpdateConfig, | |
| 44 base::Unretained(this), config, availability)); | |
| 45 proxy_config_changed_event_->Signal(); | |
| 46 } | |
| 47 | |
| 48 // Called from main thread. | |
| 49 ProxyConfigService::ConfigAvailability availability() const { | |
| 50 return availability_; | |
| 51 } | |
| 52 | |
| 53 const ProxyConfig& config() const { | |
| 54 return config_; | |
| 55 } | |
| 56 | |
| 57 private: | |
| 58 void UpdateConfig(const ProxyConfig& config, | |
| 59 ProxyConfigService::ConfigAvailability availability) { | |
| 60 config_ = config; | |
| 61 availability_ = availability; | |
| 62 main_thread_loop_->Quit(); | |
| 63 } | |
| 64 | |
| 65 MessageLoop* const main_thread_loop_; | |
| 66 base::WaitableEvent* const proxy_config_changed_event_; | |
| 67 // Accessed only from the main thread. | |
| 68 ProxyConfig config_; | |
| 69 ProxyConfigService::ConfigAvailability availability_; | |
| 70 }; | |
| 71 | |
| 72 std::string ToString(const ProxyInfo& proxy_info) { | |
| 73 ProxyInfo proxy_info_copy(proxy_info); | |
| 74 BoundNetLog net_log; | |
| 75 std::string result; | |
| 76 while (!proxy_info_copy.is_empty()) { | |
| 77 if (!result.empty()) | |
| 78 result += ";"; | |
| 79 if (!proxy_info_copy.is_direct()) | |
| 80 result += proxy_info_copy.proxy_server().host_port_pair().ToString(); | |
| 81 proxy_info_copy.Fallback(net_log); | |
| 82 } | |
| 83 return result; | |
|
Ryan Sleevi
2012/05/25 17:42:14
Use ProxyInfo.ToPacString() - this whole loop is a
Philippe
2012/05/29 10:05:30
Done.
| |
| 84 } | |
| 85 | |
| 86 } // namespace | |
| 87 | |
| 88 class ProxyConfigServiceAndroidTest : public testing::Test { | |
| 89 protected: | |
| 90 ProxyConfigServiceAndroidTest() : service_(NULL) {} | |
| 91 | |
| 92 typedef std::map<std::string, std::string> StringMap; | |
| 93 | |
| 94 // testing::Test: | |
| 95 virtual void SetUp() OVERRIDE { | |
| 96 proxy_config_changed_event_ = MakeWaitableEvent(); | |
| 97 observer_.reset(new TestObserver(proxy_config_changed_event_.get())); | |
| 98 | |
| 99 jni_thread_.reset(new base::Thread("jni_thread")); | |
| 100 network_thread_.reset(new base::Thread("network_thread")); | |
| 101 | |
| 102 jni_thread_->Start(); | |
| 103 network_thread_->Start(); | |
| 104 | |
| 105 ClearConfiguration(); | |
| 106 service_.reset(new ProxyConfigServiceAndroid( | |
| 107 network_thread_->message_loop_proxy(), | |
| 108 jni_thread_->message_loop_proxy(), | |
| 109 base::Bind(&ProxyConfigServiceAndroidTest::GetPropertyOnJNIThread, | |
| 110 base::Unretained(this)))); | |
| 111 | |
| 112 AddObserver(); | |
| 113 } | |
| 114 | |
| 115 virtual void TearDown() OVERRIDE { | |
| 116 service_.reset(); | |
| 117 network_thread_.reset(); | |
| 118 jni_thread_.reset(); | |
| 119 proxy_config_changed_event_.reset(); | |
| 120 } | |
| 121 | |
| 122 void AddProperty(const std::string& key, const std::string& value) { | |
| 123 jni_thread_->message_loop_proxy()->PostTask( | |
| 124 FROM_HERE, | |
| 125 base::Bind(&ProxyConfigServiceAndroidTest::AddPropertyOnJNIThread, | |
| 126 base::Unretained(this), key, value)); | |
| 127 } | |
| 128 | |
| 129 void ClearConfiguration() { | |
| 130 jni_thread_->message_loop_proxy()->PostTask( | |
| 131 FROM_HERE, | |
| 132 base::Bind(&StringMap::clear, base::Unretained(&configuration_))); | |
| 133 } | |
| 134 | |
| 135 void ProxySettingsChanged() { | |
| 136 jni_thread_->message_loop_proxy()->PostTask( | |
| 137 FROM_HERE, | |
| 138 base::Bind(&ProxyConfigServiceAndroid::ProxySettingsChanged, | |
| 139 base::Unretained(service_.get()), static_cast<JNIEnv*>(NULL), | |
| 140 static_cast<jobject>(NULL))); | |
| 141 proxy_config_changed_event_->Wait(); | |
| 142 MessageLoop::current()->Run(); | |
| 143 } | |
| 144 | |
| 145 ProxyConfigService::ConfigAvailability GetLatestProxyConfig( | |
| 146 ProxyConfig* proxy_config) { | |
| 147 // Post ProxyConfigServiceAndroid::GetLatestProxyConfig() on the network | |
| 148 // thread and wait for its completion. | |
| 149 scoped_ptr<base::WaitableEvent> completion_event(MakeWaitableEvent()); | |
| 150 ProxyConfigService::ConfigAvailability availability; | |
| 151 network_thread_->message_loop_proxy()->PostTask( | |
| 152 FROM_HERE, | |
| 153 base::Bind( | |
| 154 &ProxyConfigServiceAndroidTest::GetLatestProxyConfigOnNetworkThread, | |
| 155 base::Unretained(this), proxy_config, &availability, | |
| 156 completion_event.get())); | |
| 157 completion_event->Wait(); | |
| 158 return availability; | |
| 159 } | |
| 160 | |
| 161 void TestMapping(const std::string& url, const std::string& expected) { | |
| 162 ProxyConfig proxy_config = observer_->config(); | |
| 163 TestMappingForProxyConfig( | |
| 164 url, expected, observer_->availability(), &proxy_config); | |
| 165 } | |
| 166 | |
| 167 static void TestMappingForProxyConfig( | |
| 168 const std::string& url, | |
| 169 const std::string& expected, | |
| 170 ProxyConfigService::ConfigAvailability availability, | |
| 171 ProxyConfig* proxy_config) { | |
| 172 EXPECT_EQ(ProxyConfigService::CONFIG_VALID, availability); | |
| 173 ProxyInfo proxy_info; | |
| 174 proxy_config->proxy_rules().Apply(GURL(url), &proxy_info); | |
| 175 EXPECT_EQ(expected, ToString(proxy_info)); | |
| 176 } | |
| 177 | |
| 178 // Accessed only from the JNI thread. | |
| 179 StringMap configuration_; | |
| 180 | |
| 181 scoped_ptr<TestObserver> observer_; | |
| 182 | |
| 183 private: | |
| 184 std::string GetPropertyOnJNIThread(const std::string& property) { | |
| 185 DCHECK(OnJNIThread()); | |
| 186 StringMap::const_iterator it = configuration_.find(property); | |
| 187 if (it == configuration_.end()) | |
| 188 return ""; | |
| 189 return it->second; | |
| 190 } | |
| 191 | |
| 192 void AddPropertyOnJNIThread(const std::string& key, | |
| 193 const std::string& value) { | |
| 194 DCHECK(OnJNIThread()); | |
| 195 configuration_[key] = value; | |
| 196 } | |
| 197 | |
| 198 void AddObserver() { | |
| 199 jni_thread_->message_loop_proxy()->PostTask( | |
| 200 FROM_HERE, | |
| 201 base::Bind( | |
| 202 &ProxyConfigServiceAndroidTest::AddObserverAfterInitialConfigIsSet, | |
| 203 base::Unretained(this))); | |
| 204 } | |
| 205 | |
| 206 void AddObserverAfterInitialConfigIsSet() { | |
| 207 DCHECK(OnJNIThread()); | |
| 208 network_thread_->message_loop_proxy()->PostTask( | |
| 209 FROM_HERE, | |
| 210 base::Bind(&ProxyConfigServiceAndroid::AddObserver, | |
| 211 base::Unretained(service_.get()), observer_.get())); | |
| 212 } | |
| 213 | |
| 214 void GetLatestProxyConfigOnNetworkThread( | |
| 215 ProxyConfig* proxy_config, | |
| 216 ProxyConfigService::ConfigAvailability* availability, | |
| 217 base::WaitableEvent* completion_event) { | |
| 218 DCHECK(OnNetworkThread()); | |
| 219 *availability = service_->GetLatestProxyConfig(proxy_config); | |
| 220 completion_event->Signal(); | |
| 221 } | |
| 222 | |
| 223 bool OnJNIThread() const { | |
| 224 return jni_thread_->message_loop_proxy()->BelongsToCurrentThread(); | |
| 225 } | |
| 226 | |
| 227 bool OnNetworkThread() const { | |
| 228 return network_thread_->message_loop_proxy()->BelongsToCurrentThread(); | |
| 229 } | |
| 230 | |
| 231 scoped_ptr<base::WaitableEvent> proxy_config_changed_event_; | |
| 232 scoped_ptr<base::Thread> jni_thread_; | |
| 233 scoped_ptr<base::Thread> network_thread_; | |
| 234 scoped_ptr<ProxyConfigServiceAndroid> service_; | |
| 235 }; | |
| 236 | |
| 237 TEST_F(ProxyConfigServiceAndroidTest, TestChangePropertiesNotification) { | |
| 238 // Set up a non-empty configuration | |
| 239 AddProperty("http.proxyHost", "localhost"); | |
| 240 ProxySettingsChanged(); | |
| 241 EXPECT_EQ(ProxyConfigService::CONFIG_VALID, observer_->availability()); | |
| 242 EXPECT_FALSE(observer_->config().proxy_rules().empty()); | |
| 243 | |
| 244 // Set up an empty configuration | |
| 245 ClearConfiguration(); | |
| 246 ProxySettingsChanged(); | |
| 247 EXPECT_EQ(ProxyConfigService::CONFIG_VALID, observer_->availability()); | |
| 248 EXPECT_TRUE(observer_->config().proxy_rules().empty()); | |
| 249 } | |
| 250 | |
| 251 TEST_F(ProxyConfigServiceAndroidTest, GetLatestConfigWithoutUsingObserver) { | |
| 252 AddProperty("http.proxyHost", "httpproxy.com"); | |
| 253 AddProperty("http.proxyPort", "8080"); | |
| 254 ProxySettingsChanged(); | |
| 255 ProxyConfig proxy_config; | |
| 256 ProxyConfigService::ConfigAvailability availability = | |
| 257 GetLatestProxyConfig(&proxy_config); | |
| 258 TestMappingForProxyConfig( | |
| 259 "http://example.com/", "httpproxy.com:8080", availability, &proxy_config); | |
| 260 } | |
| 261 | |
| 262 // !! The following test cases are automatically generated from | |
| 263 // !! net/android/tools/proxy_test_cases.py. | |
| 264 // !! Please edit that file instead of editing the test cases below and | |
| 265 // !! update also the corresponding Java unit tests in | |
| 266 // !! AndroidProxySelectorTest.java | |
| 267 | |
| 268 TEST_F(ProxyConfigServiceAndroidTest, NoProxy) { | |
| 269 // Test direct mapping when no proxy defined. | |
| 270 ProxySettingsChanged(); | |
| 271 TestMapping("ftp://example.com/", ""); | |
| 272 TestMapping("http://example.com/", ""); | |
| 273 TestMapping("https://example.com/", ""); | |
| 274 } | |
| 275 | |
| 276 TEST_F(ProxyConfigServiceAndroidTest, HttpProxyHostAndPort) { | |
| 277 // Test http.proxyHost and http.proxyPort works. | |
| 278 AddProperty("http.proxyHost", "httpproxy.com"); | |
| 279 AddProperty("http.proxyPort", "8080"); | |
| 280 ProxySettingsChanged(); | |
| 281 TestMapping("ftp://example.com/", ""); | |
| 282 TestMapping("http://example.com/", "httpproxy.com:8080"); | |
| 283 TestMapping("https://example.com/", ""); | |
| 284 } | |
| 285 | |
| 286 TEST_F(ProxyConfigServiceAndroidTest, HttpProxyHostOnly) { | |
| 287 // We should get the default port (80) for proxied hosts. | |
| 288 AddProperty("http.proxyHost", "httpproxy.com"); | |
| 289 ProxySettingsChanged(); | |
| 290 TestMapping("ftp://example.com/", ""); | |
| 291 TestMapping("http://example.com/", "httpproxy.com:80"); | |
| 292 TestMapping("https://example.com/", ""); | |
| 293 } | |
| 294 | |
| 295 TEST_F(ProxyConfigServiceAndroidTest, HttpProxyPortOnly) { | |
| 296 // http.proxyPort only should not result in any hosts being proxied. | |
| 297 AddProperty("http.proxyPort", "8080"); | |
| 298 ProxySettingsChanged(); | |
| 299 TestMapping("ftp://example.com/", ""); | |
| 300 TestMapping("http://example.com/", ""); | |
| 301 TestMapping("https://example.com/", ""); | |
| 302 } | |
| 303 | |
| 304 TEST_F(ProxyConfigServiceAndroidTest, HttpNonProxyHosts1) { | |
| 305 // Test that HTTP non proxy hosts are mapped correctly | |
| 306 AddProperty("http.nonProxyHosts", "slashdot.org"); | |
| 307 AddProperty("http.proxyHost", "httpproxy.com"); | |
| 308 AddProperty("http.proxyPort", "8080"); | |
| 309 ProxySettingsChanged(); | |
| 310 TestMapping("http://example.com/", "httpproxy.com:8080"); | |
| 311 TestMapping("http://slashdot.org/", ""); | |
| 312 } | |
| 313 | |
| 314 TEST_F(ProxyConfigServiceAndroidTest, HttpNonProxyHosts2) { | |
| 315 // Test that | pattern works. | |
| 316 AddProperty("http.nonProxyHosts", "slashdot.org|freecode.net"); | |
| 317 AddProperty("http.proxyHost", "httpproxy.com"); | |
| 318 AddProperty("http.proxyPort", "8080"); | |
| 319 ProxySettingsChanged(); | |
| 320 TestMapping("http://example.com/", "httpproxy.com:8080"); | |
| 321 TestMapping("http://freecode.net/", ""); | |
| 322 TestMapping("http://slashdot.org/", ""); | |
| 323 } | |
| 324 | |
| 325 TEST_F(ProxyConfigServiceAndroidTest, HttpNonProxyHosts3) { | |
| 326 // Test that * pattern works. | |
| 327 AddProperty("http.nonProxyHosts", "*example.com"); | |
| 328 AddProperty("http.proxyHost", "httpproxy.com"); | |
| 329 AddProperty("http.proxyPort", "8080"); | |
| 330 ProxySettingsChanged(); | |
| 331 TestMapping("http://example.com/", ""); | |
| 332 TestMapping("http://slashdot.org/", "httpproxy.com:8080"); | |
| 333 TestMapping("http://www.example.com/", ""); | |
| 334 } | |
| 335 | |
| 336 TEST_F(ProxyConfigServiceAndroidTest, FtpNonProxyHosts) { | |
| 337 // Test that FTP non proxy hosts are mapped correctly | |
| 338 AddProperty("ftp.nonProxyHosts", "slashdot.org"); | |
| 339 AddProperty("ftp.proxyHost", "httpproxy.com"); | |
| 340 AddProperty("ftp.proxyPort", "8080"); | |
| 341 ProxySettingsChanged(); | |
| 342 TestMapping("ftp://example.com/", "httpproxy.com:8080"); | |
| 343 TestMapping("http://example.com/", ""); | |
| 344 } | |
| 345 | |
| 346 TEST_F(ProxyConfigServiceAndroidTest, FtpProxyHostAndPort) { | |
| 347 // Test ftp.proxyHost and ftp.proxyPort works. | |
| 348 AddProperty("ftp.proxyHost", "httpproxy.com"); | |
| 349 AddProperty("ftp.proxyPort", "8080"); | |
| 350 ProxySettingsChanged(); | |
| 351 TestMapping("ftp://example.com/", "httpproxy.com:8080"); | |
| 352 TestMapping("http://example.com/", ""); | |
| 353 TestMapping("https://example.com/", ""); | |
| 354 } | |
| 355 | |
| 356 TEST_F(ProxyConfigServiceAndroidTest, FtpProxyHostOnly) { | |
| 357 // Test ftp.proxyHost and default port. | |
| 358 AddProperty("ftp.proxyHost", "httpproxy.com"); | |
| 359 ProxySettingsChanged(); | |
| 360 TestMapping("ftp://example.com/", "httpproxy.com:80"); | |
| 361 TestMapping("http://example.com/", ""); | |
| 362 TestMapping("https://example.com/", ""); | |
| 363 } | |
| 364 | |
| 365 TEST_F(ProxyConfigServiceAndroidTest, HttpsProxyHostAndPort) { | |
| 366 // Test https.proxyHost and https.proxyPort works. | |
| 367 AddProperty("https.proxyHost", "httpproxy.com"); | |
| 368 AddProperty("https.proxyPort", "8080"); | |
| 369 ProxySettingsChanged(); | |
| 370 TestMapping("ftp://example.com/", ""); | |
| 371 TestMapping("http://example.com/", ""); | |
| 372 TestMapping("https://example.com/", "httpproxy.com:8080"); | |
| 373 } | |
| 374 | |
| 375 TEST_F(ProxyConfigServiceAndroidTest, HttpsProxyHostOnly) { | |
| 376 // Test https.proxyHost and default port. | |
| 377 AddProperty("https.proxyHost", "httpproxy.com"); | |
| 378 ProxySettingsChanged(); | |
| 379 TestMapping("ftp://example.com/", ""); | |
| 380 TestMapping("http://example.com/", ""); | |
| 381 TestMapping("https://example.com/", "httpproxy.com:443"); | |
| 382 } | |
| 383 | |
| 384 TEST_F(ProxyConfigServiceAndroidTest, HttpProxyHostIPv6) { | |
| 385 // Test IPv6 https.proxyHost and default port. | |
| 386 AddProperty("http.proxyHost", "a:b:c::d:1"); | |
| 387 ProxySettingsChanged(); | |
| 388 TestMapping("ftp://example.com/", ""); | |
| 389 TestMapping("http://example.com/", "[a:b:c::d:1]:80"); | |
| 390 } | |
| 391 | |
| 392 TEST_F(ProxyConfigServiceAndroidTest, HttpProxyHostAndPortIPv6) { | |
| 393 // Test IPv6 http.proxyHost and http.proxyPort works. | |
| 394 AddProperty("http.proxyHost", "a:b:c::d:1"); | |
| 395 AddProperty("http.proxyPort", "8080"); | |
| 396 ProxySettingsChanged(); | |
| 397 TestMapping("ftp://example.com/", ""); | |
| 398 TestMapping("http://example.com/", "[a:b:c::d:1]:8080"); | |
| 399 } | |
| 400 | |
| 401 TEST_F(ProxyConfigServiceAndroidTest, HttpProxyHostAndInvalidPort) { | |
| 402 // Test invalid http.proxyPort does not crash. | |
| 403 AddProperty("http.proxyHost", "a:b:c::d:1"); | |
| 404 AddProperty("http.proxyPort", "65536"); | |
| 405 ProxySettingsChanged(); | |
| 406 TestMapping("ftp://example.com/", ""); | |
| 407 TestMapping("http://example.com/", ""); | |
| 408 } | |
| 409 | |
| 410 TEST_F(ProxyConfigServiceAndroidTest, DefaultProxyExplictPort) { | |
| 411 // Default http proxy is used if a scheme-specific one is not found. | |
| 412 AddProperty("ftp.proxyHost", "httpproxy.com"); | |
| 413 AddProperty("ftp.proxyPort", "8080"); | |
| 414 AddProperty("proxyHost", "defaultproxy.com"); | |
| 415 AddProperty("proxyPort", "8080"); | |
| 416 ProxySettingsChanged(); | |
| 417 TestMapping("ftp://example.com/", "httpproxy.com:8080"); | |
| 418 TestMapping("http://example.com/", "defaultproxy.com:8080"); | |
| 419 TestMapping("https://example.com/", "defaultproxy.com:8080"); | |
| 420 } | |
| 421 | |
| 422 TEST_F(ProxyConfigServiceAndroidTest, DefaultProxyDefaultPort) { | |
| 423 // Check that the default proxy port is as expected. | |
| 424 AddProperty("proxyHost", "defaultproxy.com"); | |
| 425 ProxySettingsChanged(); | |
| 426 TestMapping("http://example.com/", "defaultproxy.com:80"); | |
| 427 TestMapping("https://example.com/", "defaultproxy.com:443"); | |
| 428 } | |
| 429 | |
| 430 TEST_F(ProxyConfigServiceAndroidTest, FallbackToSocks) { | |
| 431 // SOCKS proxy is used if scheme-specific one is not found. | |
| 432 AddProperty("http.proxyHost", "defaultproxy.com"); | |
| 433 AddProperty("socksProxyHost", "socksproxy.com"); | |
| 434 ProxySettingsChanged(); | |
| 435 TestMapping("ftp://example.com", "socksproxy.com:1080"); | |
| 436 TestMapping("http://example.com/", "defaultproxy.com:80"); | |
| 437 TestMapping("https://example.com/", "socksproxy.com:1080"); | |
| 438 } | |
| 439 | |
| 440 TEST_F(ProxyConfigServiceAndroidTest, SocksExplicitPort) { | |
| 441 // SOCKS proxy port is used if specified | |
| 442 AddProperty("socksProxyHost", "socksproxy.com"); | |
| 443 AddProperty("socksProxyPort", "9000"); | |
| 444 ProxySettingsChanged(); | |
| 445 TestMapping("http://example.com/", "socksproxy.com:9000"); | |
| 446 } | |
| 447 | |
| 448 TEST_F(ProxyConfigServiceAndroidTest, HttpProxySupercedesSocks) { | |
| 449 // SOCKS proxy is ignored if default HTTP proxy defined. | |
| 450 AddProperty("proxyHost", "defaultproxy.com"); | |
| 451 AddProperty("socksProxyHost", "socksproxy.com"); | |
| 452 AddProperty("socksProxyPort", "9000"); | |
| 453 ProxySettingsChanged(); | |
| 454 TestMapping("http://example.com/", "defaultproxy.com:80"); | |
| 455 } | |
| 456 | |
| 457 } // namespace net | |
| OLD | NEW |