blob: 0dd2a6a8505ce40e334e0a160345b615e0cc6cf2 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/data_reduction_proxy/browser/data_reduction_proxy_settings.h"
#include "base/command_line.h"
#include "base/md5.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "components/data_reduction_proxy/browser/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.h"
#include "components/data_reduction_proxy/common/data_reduction_proxy_pref_names.h"
#include "components/data_reduction_proxy/common/data_reduction_proxy_switches.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_cache.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace {
const char kDataReductionProxy[] = "https://foo.com:443/";
const char kDataReductionProxyDev[] = "http://foo-dev.com:80";
const char kDataReductionProxyFallback[] = "http://bar.com:80";
const char kDataReductionProxyKey[] = "12345";
const char kDataReductionProxyAlt[] = "https://alt.com:443/";
const char kDataReductionProxyAltFallback[] = "http://alt2.com:80";
const char kDataReductionProxySSL[] = "http://ssl.com:80";
const char kProbeURLWithOKResponse[] = "http://ok.org/";
const char kProbeURLWithBadResponse[] = "http://bad.org/";
const char kProbeURLWithNoResponse[] = "http://no.org/";
const char kWarmupURLWithNoContentResponse[] = "http://warm.org/";
} // namespace
namespace data_reduction_proxy {
class DataReductionProxySettingsTest
: public ConcreteDataReductionProxySettingsTest<
DataReductionProxySettings> {
};
TEST_F(DataReductionProxySettingsTest, TestAuthenticationInit) {
net::HttpAuthCache cache;
DataReductionProxyParams drp_params(
DataReductionProxyParams::kAllowed |
DataReductionProxyParams::kFallbackAllowed |
DataReductionProxyParams::kPromoAllowed);
drp_params.set_key(kDataReductionProxyKey);
DataReductionProxySettings::InitDataReductionAuthentication(
&cache, &drp_params);
DataReductionProxyParams::DataReductionProxyList proxies =
drp_params.GetAllowedProxies();
for (DataReductionProxyParams::DataReductionProxyList::iterator it =
proxies.begin(); it != proxies.end(); ++it) {
net::HttpAuthCache::Entry* entry = cache.LookupByPath(*it,
std::string("/"));
EXPECT_TRUE(entry != NULL);
EXPECT_EQ(net::HttpAuth::AUTH_SCHEME_SPDYPROXY, entry->scheme());
EXPECT_EQ("SpdyProxy", entry->auth_challenge().substr(0,9));
}
GURL bad_server = GURL("https://bad.proxy.com/");
net::HttpAuthCache::Entry* entry =
cache.LookupByPath(bad_server, std::string());
EXPECT_TRUE(entry == NULL);
}
TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxyOrigin) {
// SetUp() adds the origin to the command line, which should be returned here.
std::string result =
settings_->params()->origin().spec();
EXPECT_EQ(GURL(kDataReductionProxy), GURL(result));
}
TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxyDevOrigin) {
CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kDataReductionProxyDev, kDataReductionProxyDev);
ResetSettings(true, true, false, true);
std::string result =
settings_->params()->origin().spec();
EXPECT_EQ(GURL(kDataReductionProxyDev), GURL(result));
}
TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxies) {
DataReductionProxyParams drp_params(
DataReductionProxyParams::kAllowed |
DataReductionProxyParams::kFallbackAllowed |
DataReductionProxyParams::kPromoAllowed);
DataReductionProxyParams::DataReductionProxyList proxies =
drp_params.GetAllowedProxies();
unsigned int expected_proxy_size = 2u;
EXPECT_EQ(expected_proxy_size, proxies.size());
// Command line proxies have precedence, so even if there were other values
// compiled in, these should be the ones in the list.
EXPECT_EQ("foo.com", proxies[0].host());
EXPECT_EQ(443 ,proxies[0].EffectiveIntPort());
EXPECT_EQ("bar.com", proxies[1].host());
EXPECT_EQ(80, proxies[1].EffectiveIntPort());
}
TEST_F(DataReductionProxySettingsTest, TestAuthHashGeneration) {
std::string salt = "8675309"; // Jenny's number to test the hash generator.
std::string salted_key = salt + kDataReductionProxyKey + salt;
base::string16 expected_hash = base::UTF8ToUTF16(base::MD5String(salted_key));
EXPECT_EQ(expected_hash,
DataReductionProxySettings::AuthHashForSalt(
8675309, kDataReductionProxyKey));
}
TEST_F(DataReductionProxySettingsTest, TestSetProxyConfigs) {
CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kDataReductionProxyAlt, kDataReductionProxyAlt);
CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kDataReductionProxyAltFallback, kDataReductionProxyAltFallback);
CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kDataReductionSSLProxy, kDataReductionProxySSL);
ResetSettings(true, true, true, true);
TestDataReductionProxyConfig* config =
static_cast<TestDataReductionProxyConfig*>(
settings_->configurator());
settings_->SetProxyConfigs(true, true, false, false);
EXPECT_TRUE(config->enabled_);
EXPECT_TRUE(net::HostPortPair::FromString(kDataReductionProxyAlt).Equals(
net::HostPortPair::FromString(config->origin_)));
EXPECT_TRUE(
net::HostPortPair::FromString(kDataReductionProxyAltFallback).Equals(
net::HostPortPair::FromString(config->fallback_origin_)));
EXPECT_TRUE(net::HostPortPair::FromString(kDataReductionProxySSL).Equals(
net::HostPortPair::FromString(config->ssl_origin_)));
settings_->SetProxyConfigs(true, false, false, false);
EXPECT_TRUE(config->enabled_);
EXPECT_TRUE(net::HostPortPair::FromString(kDataReductionProxy).Equals(
net::HostPortPair::FromString(config->origin_)));
EXPECT_TRUE(net::HostPortPair::FromString(kDataReductionProxyFallback).Equals(
net::HostPortPair::FromString(config->fallback_origin_)));
EXPECT_EQ("", config->ssl_origin_);
settings_->SetProxyConfigs(false, true, false, false);
EXPECT_FALSE(config->enabled_);
EXPECT_EQ("", config->origin_);
EXPECT_EQ("", config->fallback_origin_);
EXPECT_EQ("", config->ssl_origin_);
settings_->SetProxyConfigs(false, false, false, false);
EXPECT_FALSE(config->enabled_);
EXPECT_EQ("", config->origin_);
EXPECT_EQ("", config->fallback_origin_);
EXPECT_EQ("", config->ssl_origin_);
}
TEST_F(DataReductionProxySettingsTest, TestIsProxyEnabledOrManaged) {
settings_->InitPrefMembers();
base::MessageLoopForUI loop;
// The proxy is disabled initially.
settings_->enabled_by_user_ = false;
settings_->SetProxyConfigs(false, false, false, false);
EXPECT_FALSE(settings_->IsDataReductionProxyEnabled());
EXPECT_FALSE(settings_->IsDataReductionProxyManaged());
CheckOnPrefChange(true, true, false);
EXPECT_TRUE(settings_->IsDataReductionProxyEnabled());
EXPECT_FALSE(settings_->IsDataReductionProxyManaged());
CheckOnPrefChange(true, true, true);
EXPECT_TRUE(settings_->IsDataReductionProxyEnabled());
EXPECT_TRUE(settings_->IsDataReductionProxyManaged());
base::MessageLoop::current()->RunUntilIdle();
}
TEST_F(DataReductionProxySettingsTest, TestAcceptableChallenges) {
typedef struct {
std::string host;
std::string realm;
bool expected_to_succeed;
} challenge_test;
challenge_test tests[] = {
{"foo.com:443", "", false}, // 0. No realm.
{"foo.com:443", "xxx", false}, // 1. Wrong realm.
{"foo.com:443", "spdyproxy", false}, // 2. Case matters.
{"foo.com:443", "SpdyProxy", true}, // 3. OK.
{"foo.com:443", "SpdyProxy1234567", true}, // 4. OK
{"bar.com:80", "SpdyProxy1234567", true}, // 5. OK.
{"foo.com:443", "SpdyProxyxxx", true}, // 6. OK
{"", "SpdyProxy1234567", false}, // 7. No challenger.
{"xxx.net:443", "SpdyProxy1234567", false}, // 8. Wrong host.
{"foo.com", "SpdyProxy1234567", false}, // 9. No port.
{"foo.com:80", "SpdyProxy1234567", false}, // 10.Wrong port.
{"bar.com:81", "SpdyProxy1234567", false}, // 11.Wrong port.
};
for (int i = 0; i <= 11; ++i) {
scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo);
auth_info->challenger = net::HostPortPair::FromString(tests[i].host);
auth_info->realm = tests[i].realm;
EXPECT_EQ(tests[i].expected_to_succeed,
settings_->IsAcceptableAuthChallenge(auth_info.get()));
}
}
TEST_F(DataReductionProxySettingsTest, TestChallengeTokens) {
typedef struct {
std::string realm;
bool expected_empty_token;
} token_test;
token_test tests[] = {
{"", true}, // 0. No realm.
{"xxx", true}, // 1. realm too short.
{"spdyproxy", true}, // 2. no salt.
{"SpdyProxyxxx", true}, // 3. Salt not an int.
{"SpdyProxy1234567", false}, // 4. OK
};
for (int i = 0; i <= 4; ++i) {
scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo);
auth_info->challenger =
net::HostPortPair::FromString(kDataReductionProxy);
auth_info->realm = tests[i].realm;
base::string16 token = settings_->GetTokenForAuthChallenge(auth_info.get());
EXPECT_EQ(tests[i].expected_empty_token, token.empty());
}
}
TEST_F(DataReductionProxySettingsTest, TestResetDataReductionStatistics) {
int64 original_content_length;
int64 received_content_length;
int64 last_update_time;
settings_->ResetDataReductionStatistics();
settings_->GetContentLengths(kNumDaysInHistory,
&original_content_length,
&received_content_length,
&last_update_time);
EXPECT_EQ(0L, original_content_length);
EXPECT_EQ(0L, received_content_length);
EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time);
}
TEST_F(DataReductionProxySettingsTest, TestContentLengths) {
int64 original_content_length;
int64 received_content_length;
int64 last_update_time;
// Request |kNumDaysInHistory| days.
settings_->GetContentLengths(kNumDaysInHistory,
&original_content_length,
&received_content_length,
&last_update_time);
const unsigned int days = kNumDaysInHistory;
// Received content length history values are 0 to |kNumDaysInHistory - 1|.
int64 expected_total_received_content_length = (days - 1L) * days / 2;
// Original content length history values are 0 to
// |2 * (kNumDaysInHistory - 1)|.
long expected_total_original_content_length = (days - 1L) * days;
EXPECT_EQ(expected_total_original_content_length, original_content_length);
EXPECT_EQ(expected_total_received_content_length, received_content_length);
EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time);
// Request |kNumDaysInHistory - 1| days.
settings_->GetContentLengths(kNumDaysInHistory - 1,
&original_content_length,
&received_content_length,
&last_update_time);
expected_total_received_content_length -= (days - 1);
expected_total_original_content_length -= 2 * (days - 1);
EXPECT_EQ(expected_total_original_content_length, original_content_length);
EXPECT_EQ(expected_total_received_content_length, received_content_length);
// Request 0 days.
settings_->GetContentLengths(0,
&original_content_length,
&received_content_length,
&last_update_time);
expected_total_received_content_length = 0;
expected_total_original_content_length = 0;
EXPECT_EQ(expected_total_original_content_length, original_content_length);
EXPECT_EQ(expected_total_received_content_length, received_content_length);
// Request 1 day. First day had 0 bytes so should be same as 0 days.
settings_->GetContentLengths(1,
&original_content_length,
&received_content_length,
&last_update_time);
EXPECT_EQ(expected_total_original_content_length, original_content_length);
EXPECT_EQ(expected_total_received_content_length, received_content_length);
}
// TODO(marq): Add a test to verify that MaybeActivateDataReductionProxy
// is called when the pref in |settings_| is enabled.
TEST_F(DataReductionProxySettingsTest, TestMaybeActivateDataReductionProxy) {
// Initialize the pref member in |settings_| without the usual callback
// so it won't trigger MaybeActivateDataReductionProxy when the pref value
// is set.
settings_->spdy_proxy_auth_enabled_.Init(
prefs::kDataReductionProxyEnabled,
settings_->GetOriginalProfilePrefs());
settings_->data_reduction_proxy_alternative_enabled_.Init(
prefs::kDataReductionProxyAltEnabled,
settings_->GetOriginalProfilePrefs());
// TODO(bengr): Test enabling/disabling while a probe is outstanding.
base::MessageLoopForUI loop;
// The proxy is enabled and unrestructed initially.
// Request succeeded but with bad response, expect proxy to be restricted.
CheckProbe(true,
kProbeURLWithBadResponse,
kWarmupURLWithNoContentResponse,
"Bad",
true,
true,
true,
false);
// Request succeeded with valid response, expect proxy to be unrestricted.
CheckProbe(true,
kProbeURLWithOKResponse,
kWarmupURLWithNoContentResponse,
"OK",
true,
true,
false,
false);
// Request failed, expect proxy to be enabled but restricted.
CheckProbe(true,
kProbeURLWithNoResponse,
kWarmupURLWithNoContentResponse,
"",
false,
true,
true,
false);
// The proxy is disabled initially. Probes should not be emitted to change
// state.
CheckProbe(false,
kProbeURLWithOKResponse,
kWarmupURLWithNoContentResponse,
"OK",
true,
false,
false,
false);
}
TEST_F(DataReductionProxySettingsTest, TestOnIPAddressChanged) {
base::MessageLoopForUI loop;
// The proxy is enabled initially.
pref_service_.SetBoolean(prefs::kDataReductionProxyEnabled, true);
settings_->spdy_proxy_auth_enabled_.Init(
prefs::kDataReductionProxyEnabled,
settings_->GetOriginalProfilePrefs());
settings_->data_reduction_proxy_alternative_enabled_.Init(
prefs::kDataReductionProxyAltEnabled,
settings_->GetOriginalProfilePrefs());
settings_->enabled_by_user_ = true;
settings_->restricted_by_carrier_ = false;
settings_->SetProxyConfigs(true, false, false, true);
// IP address change triggers a probe that succeeds. Proxy remains
// unrestricted.
CheckProbeOnIPChange(kProbeURLWithOKResponse,
kWarmupURLWithNoContentResponse,
"OK",
true,
false,
false);
// IP address change triggers a probe that fails. Proxy is restricted.
CheckProbeOnIPChange(kProbeURLWithBadResponse,
kWarmupURLWithNoContentResponse,
"Bad",
true,
true,
false);
// IP address change triggers a probe that fails. Proxy remains restricted.
CheckProbeOnIPChange(kProbeURLWithBadResponse,
kWarmupURLWithNoContentResponse,
"Bad",
true,
true,
false);
// IP address change triggers a probe that succeed. Proxy is unrestricted.
CheckProbeOnIPChange(kProbeURLWithBadResponse,
kWarmupURLWithNoContentResponse,
"OK",
true,
false,
false);
}
TEST_F(DataReductionProxySettingsTest, TestOnProxyEnabledPrefChange) {
settings_->InitPrefMembers();
base::MessageLoopForUI loop;
// The proxy is enabled initially.
settings_->enabled_by_user_ = true;
settings_->SetProxyConfigs(true, false, false, true);
// The pref is disabled, so correspondingly should be the proxy.
CheckOnPrefChange(false, false, false);
// The pref is enabled, so correspondingly should be the proxy.
CheckOnPrefChange(true, true, false);
}
TEST_F(DataReductionProxySettingsTest, TestInitDataReductionProxyOn) {
MockSettings* settings = static_cast<MockSettings*>(settings_.get());
EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED));
pref_service_.SetBoolean(prefs::kDataReductionProxyEnabled, true);
CheckInitDataReductionProxy(true);
}
TEST_F(DataReductionProxySettingsTest, TestInitDataReductionProxyOff) {
// InitDataReductionProxySettings with the preference off will directly call
// LogProxyState.
MockSettings* settings = static_cast<MockSettings*>(settings_.get());
EXPECT_CALL(*settings, RecordStartupState(PROXY_DISABLED));
pref_service_.SetBoolean(prefs::kDataReductionProxyEnabled, false);
CheckInitDataReductionProxy(false);
}
TEST_F(DataReductionProxySettingsTest, TestSetProxyFromCommandLine) {
MockSettings* settings = static_cast<MockSettings*>(settings_.get());
EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED));
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDataReductionProxy);
CheckInitDataReductionProxy(true);
}
TEST_F(DataReductionProxySettingsTest, TestGetDailyContentLengths) {
DataReductionProxySettings::ContentLengthList result =
settings_->GetDailyContentLengths(prefs::kDailyHttpOriginalContentLength);
ASSERT_FALSE(result.empty());
ASSERT_EQ(kNumDaysInHistory, result.size());
for (size_t i = 0; i < kNumDaysInHistory; ++i) {
long expected_length =
static_cast<long>((kNumDaysInHistory - 1 - i) * 2);
ASSERT_EQ(expected_length, result[i]);
}
}
TEST_F(DataReductionProxySettingsTest, CheckInitMetricsWhenNotAllowed) {
// No call to |AddProxyToCommandLine()| was made, so the proxy feature
// should be unavailable.
base::MessageLoopForUI loop;
// Clear the command line. Setting flags can force the proxy to be allowed.
CommandLine::ForCurrentProcess()->InitFromArgv(0, NULL);
ResetSettings(false, false, false, false);
MockSettings* settings = static_cast<MockSettings*>(settings_.get());
EXPECT_FALSE(settings->params()->allowed());
EXPECT_CALL(*settings, RecordStartupState(PROXY_NOT_AVAILABLE));
scoped_ptr<DataReductionProxyConfigurator> configurator(
new TestDataReductionProxyConfig());
settings_->SetProxyConfigurator(configurator.Pass());
scoped_refptr<net::TestURLRequestContextGetter> request_context =
new net::TestURLRequestContextGetter(base::MessageLoopProxy::current());
settings_->InitDataReductionProxySettings(&pref_service_,
&pref_service_,
request_context.get());
base::MessageLoop::current()->RunUntilIdle();
}
} // namespace data_reduction_proxy