1// Copyright 2014 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 "components/data_reduction_proxy/browser/data_reduction_proxy_settings.h" 6 7#include "base/command_line.h" 8#include "base/md5.h" 9#include "base/message_loop/message_loop.h" 10#include "base/strings/utf_string_conversions.h" 11#include "components/data_reduction_proxy/browser/data_reduction_proxy_params.h" 12#include "components/data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.h" 13#include "components/data_reduction_proxy/common/data_reduction_proxy_pref_names.h" 14#include "components/data_reduction_proxy/common/data_reduction_proxy_switches.h" 15#include "net/http/http_auth.h" 16#include "net/http/http_auth_cache.h" 17#include "testing/gmock/include/gmock/gmock.h" 18#include "testing/gtest/include/gtest/gtest.h" 19#include "url/gurl.h" 20 21namespace { 22 23const char kDataReductionProxy[] = "https://foo.com:443/"; 24const char kDataReductionProxyDev[] = "http://foo-dev.com:80"; 25const char kDataReductionProxyFallback[] = "http://bar.com:80"; 26const char kDataReductionProxyKey[] = "12345"; 27const char kDataReductionProxyAlt[] = "https://alt.com:443/"; 28const char kDataReductionProxyAltFallback[] = "http://alt2.com:80"; 29const char kDataReductionProxySSL[] = "http://ssl.com:80"; 30 31const char kProbeURLWithOKResponse[] = "http://ok.org/"; 32const char kProbeURLWithBadResponse[] = "http://bad.org/"; 33const char kProbeURLWithNoResponse[] = "http://no.org/"; 34const char kWarmupURLWithNoContentResponse[] = "http://warm.org/"; 35 36} // namespace 37 38namespace data_reduction_proxy { 39 40class DataReductionProxySettingsTest 41 : public ConcreteDataReductionProxySettingsTest< 42 DataReductionProxySettings> { 43}; 44 45 46TEST_F(DataReductionProxySettingsTest, TestAuthenticationInit) { 47 net::HttpAuthCache cache; 48 DataReductionProxyParams drp_params( 49 DataReductionProxyParams::kAllowed | 50 DataReductionProxyParams::kFallbackAllowed | 51 DataReductionProxyParams::kPromoAllowed); 52 drp_params.set_key(kDataReductionProxyKey); 53 DataReductionProxySettings::InitDataReductionAuthentication( 54 &cache, &drp_params); 55 DataReductionProxyParams::DataReductionProxyList proxies = 56 drp_params.GetAllowedProxies(); 57 for (DataReductionProxyParams::DataReductionProxyList::iterator it = 58 proxies.begin(); it != proxies.end(); ++it) { 59 net::HttpAuthCache::Entry* entry = cache.LookupByPath(*it, 60 std::string("/")); 61 EXPECT_TRUE(entry != NULL); 62 EXPECT_EQ(net::HttpAuth::AUTH_SCHEME_SPDYPROXY, entry->scheme()); 63 EXPECT_EQ("SpdyProxy", entry->auth_challenge().substr(0,9)); 64 } 65 GURL bad_server = GURL("https://bad.proxy.com/"); 66 net::HttpAuthCache::Entry* entry = 67 cache.LookupByPath(bad_server, std::string()); 68 EXPECT_TRUE(entry == NULL); 69} 70 71TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxyOrigin) { 72 // SetUp() adds the origin to the command line, which should be returned here. 73 std::string result = 74 settings_->params()->origin().spec(); 75 EXPECT_EQ(GURL(kDataReductionProxy), GURL(result)); 76} 77 78TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxyDevOrigin) { 79 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 80 switches::kDataReductionProxyDev, kDataReductionProxyDev); 81 ResetSettings(true, true, false, true); 82 std::string result = 83 settings_->params()->origin().spec(); 84 EXPECT_EQ(GURL(kDataReductionProxyDev), GURL(result)); 85} 86 87 88TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxies) { 89 DataReductionProxyParams drp_params( 90 DataReductionProxyParams::kAllowed | 91 DataReductionProxyParams::kFallbackAllowed | 92 DataReductionProxyParams::kPromoAllowed); 93 DataReductionProxyParams::DataReductionProxyList proxies = 94 drp_params.GetAllowedProxies(); 95 96 unsigned int expected_proxy_size = 2u; 97 EXPECT_EQ(expected_proxy_size, proxies.size()); 98 99 // Command line proxies have precedence, so even if there were other values 100 // compiled in, these should be the ones in the list. 101 EXPECT_EQ("foo.com", proxies[0].host()); 102 EXPECT_EQ(443 ,proxies[0].EffectiveIntPort()); 103 EXPECT_EQ("bar.com", proxies[1].host()); 104 EXPECT_EQ(80, proxies[1].EffectiveIntPort()); 105} 106 107TEST_F(DataReductionProxySettingsTest, TestAuthHashGeneration) { 108 std::string salt = "8675309"; // Jenny's number to test the hash generator. 109 std::string salted_key = salt + kDataReductionProxyKey + salt; 110 base::string16 expected_hash = base::UTF8ToUTF16(base::MD5String(salted_key)); 111 EXPECT_EQ(expected_hash, 112 DataReductionProxySettings::AuthHashForSalt( 113 8675309, kDataReductionProxyKey)); 114} 115 116TEST_F(DataReductionProxySettingsTest, TestSetProxyConfigs) { 117 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 118 switches::kDataReductionProxyAlt, kDataReductionProxyAlt); 119 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 120 switches::kDataReductionProxyAltFallback, kDataReductionProxyAltFallback); 121 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 122 switches::kDataReductionSSLProxy, kDataReductionProxySSL); 123 ResetSettings(true, true, true, true); 124 TestDataReductionProxyConfig* config = 125 static_cast<TestDataReductionProxyConfig*>( 126 settings_->configurator()); 127 128 settings_->SetProxyConfigs(true, true, false, false); 129 EXPECT_TRUE(config->enabled_); 130 EXPECT_TRUE(net::HostPortPair::FromString(kDataReductionProxyAlt).Equals( 131 net::HostPortPair::FromString(config->origin_))); 132 EXPECT_TRUE( 133 net::HostPortPair::FromString(kDataReductionProxyAltFallback).Equals( 134 net::HostPortPair::FromString(config->fallback_origin_))); 135 EXPECT_TRUE(net::HostPortPair::FromString(kDataReductionProxySSL).Equals( 136 net::HostPortPair::FromString(config->ssl_origin_))); 137 138 settings_->SetProxyConfigs(true, false, false, false); 139 EXPECT_TRUE(config->enabled_); 140 EXPECT_TRUE(net::HostPortPair::FromString(kDataReductionProxy).Equals( 141 net::HostPortPair::FromString(config->origin_))); 142 EXPECT_TRUE(net::HostPortPair::FromString(kDataReductionProxyFallback).Equals( 143 net::HostPortPair::FromString(config->fallback_origin_))); 144 EXPECT_EQ("", config->ssl_origin_); 145 146 settings_->SetProxyConfigs(false, true, false, false); 147 EXPECT_FALSE(config->enabled_); 148 EXPECT_EQ("", config->origin_); 149 EXPECT_EQ("", config->fallback_origin_); 150 EXPECT_EQ("", config->ssl_origin_); 151 152 settings_->SetProxyConfigs(false, false, false, false); 153 EXPECT_FALSE(config->enabled_); 154 EXPECT_EQ("", config->origin_); 155 EXPECT_EQ("", config->fallback_origin_); 156 EXPECT_EQ("", config->ssl_origin_); 157} 158 159TEST_F(DataReductionProxySettingsTest, TestIsProxyEnabledOrManaged) { 160 settings_->InitPrefMembers(); 161 base::MessageLoopForUI loop; 162 // The proxy is disabled initially. 163 settings_->enabled_by_user_ = false; 164 settings_->SetProxyConfigs(false, false, false, false); 165 166 EXPECT_FALSE(settings_->IsDataReductionProxyEnabled()); 167 EXPECT_FALSE(settings_->IsDataReductionProxyManaged()); 168 169 CheckOnPrefChange(true, true, false); 170 EXPECT_TRUE(settings_->IsDataReductionProxyEnabled()); 171 EXPECT_FALSE(settings_->IsDataReductionProxyManaged()); 172 173 CheckOnPrefChange(true, true, true); 174 EXPECT_TRUE(settings_->IsDataReductionProxyEnabled()); 175 EXPECT_TRUE(settings_->IsDataReductionProxyManaged()); 176 177 base::MessageLoop::current()->RunUntilIdle(); 178} 179 180TEST_F(DataReductionProxySettingsTest, TestAcceptableChallenges) { 181 typedef struct { 182 std::string host; 183 std::string realm; 184 bool expected_to_succeed; 185 } challenge_test; 186 187 challenge_test tests[] = { 188 {"foo.com:443", "", false}, // 0. No realm. 189 {"foo.com:443", "xxx", false}, // 1. Wrong realm. 190 {"foo.com:443", "spdyproxy", false}, // 2. Case matters. 191 {"foo.com:443", "SpdyProxy", true}, // 3. OK. 192 {"foo.com:443", "SpdyProxy1234567", true}, // 4. OK 193 {"bar.com:80", "SpdyProxy1234567", true}, // 5. OK. 194 {"foo.com:443", "SpdyProxyxxx", true}, // 6. OK 195 {"", "SpdyProxy1234567", false}, // 7. No challenger. 196 {"xxx.net:443", "SpdyProxy1234567", false}, // 8. Wrong host. 197 {"foo.com", "SpdyProxy1234567", false}, // 9. No port. 198 {"foo.com:80", "SpdyProxy1234567", false}, // 10.Wrong port. 199 {"bar.com:81", "SpdyProxy1234567", false}, // 11.Wrong port. 200 }; 201 202 for (int i = 0; i <= 11; ++i) { 203 scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo); 204 auth_info->challenger = net::HostPortPair::FromString(tests[i].host); 205 auth_info->realm = tests[i].realm; 206 EXPECT_EQ(tests[i].expected_to_succeed, 207 settings_->IsAcceptableAuthChallenge(auth_info.get())); 208 } 209} 210 211TEST_F(DataReductionProxySettingsTest, TestChallengeTokens) { 212 typedef struct { 213 std::string realm; 214 bool expected_empty_token; 215 } token_test; 216 217 token_test tests[] = { 218 {"", true}, // 0. No realm. 219 {"xxx", true}, // 1. realm too short. 220 {"spdyproxy", true}, // 2. no salt. 221 {"SpdyProxyxxx", true}, // 3. Salt not an int. 222 {"SpdyProxy1234567", false}, // 4. OK 223 }; 224 225 for (int i = 0; i <= 4; ++i) { 226 scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo); 227 auth_info->challenger = 228 net::HostPortPair::FromString(kDataReductionProxy); 229 auth_info->realm = tests[i].realm; 230 base::string16 token = settings_->GetTokenForAuthChallenge(auth_info.get()); 231 EXPECT_EQ(tests[i].expected_empty_token, token.empty()); 232 } 233} 234 235TEST_F(DataReductionProxySettingsTest, TestResetDataReductionStatistics) { 236 int64 original_content_length; 237 int64 received_content_length; 238 int64 last_update_time; 239 settings_->ResetDataReductionStatistics(); 240 settings_->GetContentLengths(kNumDaysInHistory, 241 &original_content_length, 242 &received_content_length, 243 &last_update_time); 244 EXPECT_EQ(0L, original_content_length); 245 EXPECT_EQ(0L, received_content_length); 246 EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time); 247} 248 249TEST_F(DataReductionProxySettingsTest, TestContentLengths) { 250 int64 original_content_length; 251 int64 received_content_length; 252 int64 last_update_time; 253 254 // Request |kNumDaysInHistory| days. 255 settings_->GetContentLengths(kNumDaysInHistory, 256 &original_content_length, 257 &received_content_length, 258 &last_update_time); 259 const unsigned int days = kNumDaysInHistory; 260 // Received content length history values are 0 to |kNumDaysInHistory - 1|. 261 int64 expected_total_received_content_length = (days - 1L) * days / 2; 262 // Original content length history values are 0 to 263 // |2 * (kNumDaysInHistory - 1)|. 264 long expected_total_original_content_length = (days - 1L) * days; 265 EXPECT_EQ(expected_total_original_content_length, original_content_length); 266 EXPECT_EQ(expected_total_received_content_length, received_content_length); 267 EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time); 268 269 // Request |kNumDaysInHistory - 1| days. 270 settings_->GetContentLengths(kNumDaysInHistory - 1, 271 &original_content_length, 272 &received_content_length, 273 &last_update_time); 274 expected_total_received_content_length -= (days - 1); 275 expected_total_original_content_length -= 2 * (days - 1); 276 EXPECT_EQ(expected_total_original_content_length, original_content_length); 277 EXPECT_EQ(expected_total_received_content_length, received_content_length); 278 279 // Request 0 days. 280 settings_->GetContentLengths(0, 281 &original_content_length, 282 &received_content_length, 283 &last_update_time); 284 expected_total_received_content_length = 0; 285 expected_total_original_content_length = 0; 286 EXPECT_EQ(expected_total_original_content_length, original_content_length); 287 EXPECT_EQ(expected_total_received_content_length, received_content_length); 288 289 // Request 1 day. First day had 0 bytes so should be same as 0 days. 290 settings_->GetContentLengths(1, 291 &original_content_length, 292 &received_content_length, 293 &last_update_time); 294 EXPECT_EQ(expected_total_original_content_length, original_content_length); 295 EXPECT_EQ(expected_total_received_content_length, received_content_length); 296} 297 298// TODO(marq): Add a test to verify that MaybeActivateDataReductionProxy 299// is called when the pref in |settings_| is enabled. 300TEST_F(DataReductionProxySettingsTest, TestMaybeActivateDataReductionProxy) { 301 // Initialize the pref member in |settings_| without the usual callback 302 // so it won't trigger MaybeActivateDataReductionProxy when the pref value 303 // is set. 304 settings_->spdy_proxy_auth_enabled_.Init( 305 prefs::kDataReductionProxyEnabled, 306 settings_->GetOriginalProfilePrefs()); 307 settings_->data_reduction_proxy_alternative_enabled_.Init( 308 prefs::kDataReductionProxyAltEnabled, 309 settings_->GetOriginalProfilePrefs()); 310 311 // TODO(bengr): Test enabling/disabling while a probe is outstanding. 312 base::MessageLoopForUI loop; 313 // The proxy is enabled and unrestructed initially. 314 // Request succeeded but with bad response, expect proxy to be restricted. 315 CheckProbe(true, 316 kProbeURLWithBadResponse, 317 kWarmupURLWithNoContentResponse, 318 "Bad", 319 true, 320 true, 321 true, 322 false); 323 // Request succeeded with valid response, expect proxy to be unrestricted. 324 CheckProbe(true, 325 kProbeURLWithOKResponse, 326 kWarmupURLWithNoContentResponse, 327 "OK", 328 true, 329 true, 330 false, 331 false); 332 // Request failed, expect proxy to be enabled but restricted. 333 CheckProbe(true, 334 kProbeURLWithNoResponse, 335 kWarmupURLWithNoContentResponse, 336 "", 337 false, 338 true, 339 true, 340 false); 341 // The proxy is disabled initially. Probes should not be emitted to change 342 // state. 343 CheckProbe(false, 344 kProbeURLWithOKResponse, 345 kWarmupURLWithNoContentResponse, 346 "OK", 347 true, 348 false, 349 false, 350 false); 351} 352 353TEST_F(DataReductionProxySettingsTest, TestOnIPAddressChanged) { 354 base::MessageLoopForUI loop; 355 // The proxy is enabled initially. 356 pref_service_.SetBoolean(prefs::kDataReductionProxyEnabled, true); 357 settings_->spdy_proxy_auth_enabled_.Init( 358 prefs::kDataReductionProxyEnabled, 359 settings_->GetOriginalProfilePrefs()); 360 settings_->data_reduction_proxy_alternative_enabled_.Init( 361 prefs::kDataReductionProxyAltEnabled, 362 settings_->GetOriginalProfilePrefs()); 363 settings_->enabled_by_user_ = true; 364 settings_->restricted_by_carrier_ = false; 365 settings_->SetProxyConfigs(true, false, false, true); 366 // IP address change triggers a probe that succeeds. Proxy remains 367 // unrestricted. 368 CheckProbeOnIPChange(kProbeURLWithOKResponse, 369 kWarmupURLWithNoContentResponse, 370 "OK", 371 true, 372 false, 373 false); 374 // IP address change triggers a probe that fails. Proxy is restricted. 375 CheckProbeOnIPChange(kProbeURLWithBadResponse, 376 kWarmupURLWithNoContentResponse, 377 "Bad", 378 true, 379 true, 380 false); 381 // IP address change triggers a probe that fails. Proxy remains restricted. 382 CheckProbeOnIPChange(kProbeURLWithBadResponse, 383 kWarmupURLWithNoContentResponse, 384 "Bad", 385 true, 386 true, 387 false); 388 // IP address change triggers a probe that succeed. Proxy is unrestricted. 389 CheckProbeOnIPChange(kProbeURLWithBadResponse, 390 kWarmupURLWithNoContentResponse, 391 "OK", 392 true, 393 false, 394 false); 395} 396 397TEST_F(DataReductionProxySettingsTest, TestOnProxyEnabledPrefChange) { 398 settings_->InitPrefMembers(); 399 base::MessageLoopForUI loop; 400 // The proxy is enabled initially. 401 settings_->enabled_by_user_ = true; 402 settings_->SetProxyConfigs(true, false, false, true); 403 // The pref is disabled, so correspondingly should be the proxy. 404 CheckOnPrefChange(false, false, false); 405 // The pref is enabled, so correspondingly should be the proxy. 406 CheckOnPrefChange(true, true, false); 407} 408 409TEST_F(DataReductionProxySettingsTest, TestInitDataReductionProxyOn) { 410 MockSettings* settings = static_cast<MockSettings*>(settings_.get()); 411 EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED)); 412 413 pref_service_.SetBoolean(prefs::kDataReductionProxyEnabled, true); 414 CheckInitDataReductionProxy(true); 415} 416 417TEST_F(DataReductionProxySettingsTest, TestInitDataReductionProxyOff) { 418 // InitDataReductionProxySettings with the preference off will directly call 419 // LogProxyState. 420 MockSettings* settings = static_cast<MockSettings*>(settings_.get()); 421 EXPECT_CALL(*settings, RecordStartupState(PROXY_DISABLED)); 422 423 pref_service_.SetBoolean(prefs::kDataReductionProxyEnabled, false); 424 CheckInitDataReductionProxy(false); 425} 426 427TEST_F(DataReductionProxySettingsTest, TestSetProxyFromCommandLine) { 428 MockSettings* settings = static_cast<MockSettings*>(settings_.get()); 429 EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED)); 430 431 CommandLine::ForCurrentProcess()->AppendSwitch( 432 switches::kEnableDataReductionProxy); 433 CheckInitDataReductionProxy(true); 434} 435 436TEST_F(DataReductionProxySettingsTest, TestGetDailyContentLengths) { 437 DataReductionProxySettings::ContentLengthList result = 438 settings_->GetDailyContentLengths(prefs::kDailyHttpOriginalContentLength); 439 440 ASSERT_FALSE(result.empty()); 441 ASSERT_EQ(kNumDaysInHistory, result.size()); 442 443 for (size_t i = 0; i < kNumDaysInHistory; ++i) { 444 long expected_length = 445 static_cast<long>((kNumDaysInHistory - 1 - i) * 2); 446 ASSERT_EQ(expected_length, result[i]); 447 } 448} 449 450TEST_F(DataReductionProxySettingsTest, CheckInitMetricsWhenNotAllowed) { 451 // No call to |AddProxyToCommandLine()| was made, so the proxy feature 452 // should be unavailable. 453 base::MessageLoopForUI loop; 454 // Clear the command line. Setting flags can force the proxy to be allowed. 455 CommandLine::ForCurrentProcess()->InitFromArgv(0, NULL); 456 457 ResetSettings(false, false, false, false); 458 MockSettings* settings = static_cast<MockSettings*>(settings_.get()); 459 EXPECT_FALSE(settings->params()->allowed()); 460 EXPECT_CALL(*settings, RecordStartupState(PROXY_NOT_AVAILABLE)); 461 462 scoped_ptr<DataReductionProxyConfigurator> configurator( 463 new TestDataReductionProxyConfig()); 464 settings_->SetProxyConfigurator(configurator.Pass()); 465 scoped_refptr<net::TestURLRequestContextGetter> request_context = 466 new net::TestURLRequestContextGetter(base::MessageLoopProxy::current()); 467 settings_->InitDataReductionProxySettings(&pref_service_, 468 &pref_service_, 469 request_context.get()); 470 471 base::MessageLoop::current()->RunUntilIdle(); 472} 473 474} // namespace data_reduction_proxy 475