blob: d04bb6b9e92ae534142e262e6f1dd966847357f8 [file] [log] [blame]
// Copyright 2015 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/core/browser/data_reduction_proxy_config.h"
#include <stddef.h>
#include <stdint.h>
#include <cstdlib>
#include <map>
#include <memory>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial.h"
#include "base/run_loop.h"
#include "base/strings/safe_sprintf.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/threading/platform_thread.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
#include "components/data_reduction_proxy/core/browser/network_properties_manager.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h"
#include "components/data_reduction_proxy/proto/client_config.pb.h"
#include "components/previews/core/previews_experiments.h"
#include "components/previews/core/test_previews_decider.h"
#include "components/variations/variations_associated_data.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/base/network_change_notifier.h"
#include "net/base/proxy_server.h"
#include "net/http/http_status_code.h"
#include "net/log/test_net_log.h"
#include "net/nqe/effective_connection_type.h"
#include "net/nqe/network_quality_estimator_test_util.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_test_util.h"
using testing::_;
using testing::AnyNumber;
using testing::Return;
namespace data_reduction_proxy {
namespace {
void SetProxiesForHttpOnCommandLine(
const std::vector<net::ProxyServer>& proxies_for_http) {
std::vector<std::string> proxy_strings;
for (const net::ProxyServer& proxy : proxies_for_http)
proxy_strings.push_back(proxy.ToURI());
// Proxies specified via kDataReductionProxyHttpProxies command line switch
// have type ProxyServer::UNSPECIFIED_TYPE.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
data_reduction_proxy::switches::kDataReductionProxyHttpProxies,
base::JoinString(proxy_strings, ";"));
}
std::string GetRetryMapKeyFromOrigin(const std::string& origin) {
// The retry map has the scheme prefix for https but not for http.
return origin;
}
} // namespace
class DataReductionProxyConfigTest : public testing::Test {
public:
DataReductionProxyConfigTest() : mock_config_used_(false) {}
~DataReductionProxyConfigTest() override {}
void SetUp() override {
net::NetworkChangeNotifier::SetTestNotificationsOnly(true);
base::RunLoop().RunUntilIdle();
network_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock());
test_context_ = DataReductionProxyTestContext::Builder()
.WithMockDataReductionProxyService()
.Build();
ResetSettings();
expected_params_.reset(new TestDataReductionProxyParams());
}
void RecreateContextWithMockConfig() {
mock_config_used_ = true;
test_context_ = DataReductionProxyTestContext::Builder()
.WithMockConfig()
.WithMockDataReductionProxyService()
.Build();
ResetSettings();
expected_params_.reset(new TestDataReductionProxyParams());
}
void ResetSettings() {
if (mock_config_used_)
mock_config()->ResetParamFlagsForTest();
else
test_config()->ResetParamFlagsForTest();
}
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner() {
return message_loop_.task_runner();
}
class TestResponder {
public:
void ExecuteCallback(SecureProxyCheckerCallback callback) {
callback.Run(response, status, http_response_code);
}
std::string response;
net::URLRequestStatus status;
int http_response_code;
};
void CheckSecureProxyCheckOnNetworkChange(
net::NetworkChangeNotifier::ConnectionType connection_type,
const std::string& response,
bool is_captive_portal,
int response_code,
net::URLRequestStatus status,
SecureProxyCheckFetchResult expected_fetch_result,
const std::vector<net::ProxyServer>& expected_proxies_for_http) {
base::HistogramTester histogram_tester;
net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
connection_type);
TestResponder responder;
responder.response = response;
responder.status = status;
responder.http_response_code = response_code;
EXPECT_CALL(*mock_config(), SecureProxyCheck(_))
.Times(1)
.WillRepeatedly(testing::WithArgs<0>(
testing::Invoke(&responder, &TestResponder::ExecuteCallback)));
mock_config()->SetIsCaptivePortal(is_captive_portal);
test_context_->RunUntilIdle();
EXPECT_EQ(expected_proxies_for_http, GetConfiguredProxiesForHttp());
if (!status.is_success() &&
status.error() != net::ERR_INTERNET_DISCONNECTED) {
histogram_tester.ExpectUniqueSample("DataReductionProxy.ProbeURLNetError",
std::abs(status.error()), 1);
} else {
histogram_tester.ExpectTotalCount("DataReductionProxy.ProbeURLNetError",
0);
}
histogram_tester.ExpectUniqueSample("DataReductionProxy.ProbeURL",
expected_fetch_result, 1);
}
void RunUntilIdle() {
test_context_->RunUntilIdle();
}
std::unique_ptr<DataReductionProxyConfig> BuildConfig(
std::unique_ptr<DataReductionProxyParams> params) {
return std::make_unique<DataReductionProxyConfig>(
task_runner(), test_context_->net_log(), std::move(params),
test_context_->configurator(), test_context_->event_creator());
}
MockDataReductionProxyConfig* mock_config() {
DCHECK(mock_config_used_);
return test_context_->mock_config();
}
TestDataReductionProxyConfig* test_config() {
DCHECK(!mock_config_used_);
return test_context_->config();
}
DataReductionProxyConfigurator* configurator() const {
return test_context_->configurator();
}
TestDataReductionProxyParams* params() const {
return expected_params_.get();
}
DataReductionProxyEventCreator* event_creator() const {
return test_context_->event_creator();
}
net::NetLog* net_log() const { return test_context_->net_log(); }
std::vector<net::ProxyServer> GetConfiguredProxiesForHttp() const {
return test_context_->GetConfiguredProxiesForHttp();
}
base::MessageLoopForIO message_loop_;
std::unique_ptr<DataReductionProxyTestContext> test_context_;
private:
std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
std::unique_ptr<TestDataReductionProxyParams> expected_params_;
bool mock_config_used_;
};
TEST_F(DataReductionProxyConfigTest, TestReloadConfigHoldback) {
base::FieldTrialList field_trial_list(nullptr);
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
"DataCompressionProxyHoldback", "Enabled"));
const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
"https://secure_origin.net:443", net::ProxyServer::SCHEME_HTTP);
const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI(
"insecure_origin.net:80", net::ProxyServer::SCHEME_HTTP);
SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy});
ResetSettings();
test_config()->UpdateConfigForTesting(true, false, true);
test_config()->OnNewClientConfigFetched();
EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp());
}
TEST_F(DataReductionProxyConfigTest, TestOnConnectionChangePersistedData) {
base::FieldTrialList field_trial_list(nullptr);
const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
"https://secure_origin.net:443", net::ProxyServer::SCHEME_HTTP);
const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI(
"insecure_origin.net:80", net::ProxyServer::SCHEME_HTTP);
SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy});
ResetSettings();
test_config()->SetProxyConfig(true, true);
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
test_config()->SetCurrentNetworkID("wifi,test");
net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
net::NetworkChangeNotifier::CONNECTION_WIFI);
base::RunLoop().RunUntilIdle();
test_config()->UpdateConfigForTesting(true /* enabled */,
false /* secure_proxies_allowed */,
true /* insecure_proxies_allowed */);
test_config()->OnNewClientConfigFetched();
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}),
GetConfiguredProxiesForHttp());
base::RunLoop().RunUntilIdle();
test_config()->SetCurrentNetworkID("cell,test");
net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
net::NetworkChangeNotifier::CONNECTION_2G);
base::RunLoop().RunUntilIdle();
test_config()->UpdateConfigForTesting(true /* enabled */,
false /* secure_proxies_allowed */,
false /* insecure_proxies_allowed */);
test_config()->OnNewClientConfigFetched();
EXPECT_EQ(std::vector<net::ProxyServer>({}), GetConfiguredProxiesForHttp());
// On network change, persisted config should be read, and config reloaded.
test_config()->SetCurrentNetworkID("wifi,test");
net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
net::NetworkChangeNotifier::CONNECTION_WIFI);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}),
GetConfiguredProxiesForHttp());
}
TEST_F(DataReductionProxyConfigTest, TestOnNetworkChanged) {
RecreateContextWithMockConfig();
const net::URLRequestStatus kSuccess(net::URLRequestStatus::SUCCESS, net::OK);
const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
"https://secure_origin.net:443", net::ProxyServer::SCHEME_HTTP);
const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI(
"insecure_origin.net:80", net::ProxyServer::SCHEME_HTTP);
SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy});
ResetSettings();
// The proxy is enabled initially.
mock_config()->UpdateConfigForTesting(true, true, true);
mock_config()->OnNewClientConfigFetched();
// Connection change triggers a secure proxy check that succeeds. Proxy
// remains unrestricted.
CheckSecureProxyCheckOnNetworkChange(
net::NetworkChangeNotifier::CONNECTION_WIFI, "OK", false, net::HTTP_OK,
kSuccess, SUCCEEDED_PROXY_ALREADY_ENABLED, {kHttpsProxy, kHttpProxy});
// Connection change triggers a secure proxy check that succeeds but captive
// portal fails. Proxy is restricted.
CheckSecureProxyCheckOnNetworkChange(
net::NetworkChangeNotifier::CONNECTION_WIFI, "OK", true, net::HTTP_OK,
kSuccess, SUCCEEDED_PROXY_ALREADY_ENABLED,
std::vector<net::ProxyServer>(1, kHttpProxy));
// Connection change triggers a secure proxy check that fails. Proxy is
// restricted.
CheckSecureProxyCheckOnNetworkChange(
net::NetworkChangeNotifier::CONNECTION_WIFI, "Bad", false, net::HTTP_OK,
kSuccess, FAILED_PROXY_DISABLED,
std::vector<net::ProxyServer>(1, kHttpProxy));
// Connection change triggers a secure proxy check that succeeds. Proxies
// are unrestricted.
CheckSecureProxyCheckOnNetworkChange(
net::NetworkChangeNotifier::CONNECTION_WIFI, "OK", false, net::HTTP_OK,
kSuccess, SUCCEEDED_PROXY_ENABLED, {kHttpsProxy, kHttpProxy});
// Connection change triggers a secure proxy check that fails. Proxy is
// restricted.
CheckSecureProxyCheckOnNetworkChange(
net::NetworkChangeNotifier::CONNECTION_WIFI, "Bad", true, net::HTTP_OK,
kSuccess, FAILED_PROXY_DISABLED,
std::vector<net::ProxyServer>(1, kHttpProxy));
// Connection change triggers a secure proxy check that fails due to the
// network changing again. This should be ignored, so the proxy should remain
// unrestricted.
CheckSecureProxyCheckOnNetworkChange(
net::NetworkChangeNotifier::CONNECTION_WIFI, std::string(), false,
net::URLFetcher::RESPONSE_CODE_INVALID,
net::URLRequestStatus(net::URLRequestStatus::FAILED,
net::ERR_INTERNET_DISCONNECTED),
INTERNET_DISCONNECTED, std::vector<net::ProxyServer>(1, kHttpProxy));
// Connection change triggers a secure proxy check that fails. Proxy remains
// restricted.
CheckSecureProxyCheckOnNetworkChange(
net::NetworkChangeNotifier::CONNECTION_WIFI, "Bad", false, net::HTTP_OK,
kSuccess, FAILED_PROXY_ALREADY_DISABLED,
std::vector<net::ProxyServer>(1, kHttpProxy));
// Connection change triggers a secure proxy check that succeeds. Proxy is
// unrestricted.
CheckSecureProxyCheckOnNetworkChange(
net::NetworkChangeNotifier::CONNECTION_WIFI, "OK", false, net::HTTP_OK,
kSuccess, SUCCEEDED_PROXY_ENABLED, {kHttpsProxy, kHttpProxy});
// Connection change triggers a secure proxy check that fails due to the
// network changing again. This should be ignored, so the proxy should remain
// unrestricted.
CheckSecureProxyCheckOnNetworkChange(
net::NetworkChangeNotifier::CONNECTION_WIFI, std::string(), false,
net::URLFetcher::RESPONSE_CODE_INVALID,
net::URLRequestStatus(net::URLRequestStatus::FAILED,
net::ERR_INTERNET_DISCONNECTED),
INTERNET_DISCONNECTED, {kHttpsProxy, kHttpProxy});
// Connection change triggers a secure proxy check that fails because of a
// redirect response, e.g. by a captive portal. Proxy is restricted.
CheckSecureProxyCheckOnNetworkChange(
net::NetworkChangeNotifier::CONNECTION_WIFI, "Bad", false,
net::HTTP_FOUND,
net::URLRequestStatus(net::URLRequestStatus::CANCELED, net::ERR_ABORTED),
FAILED_PROXY_DISABLED, std::vector<net::ProxyServer>(1, kHttpProxy));
}
// Verifies that the warm up URL is fetched correctly.
TEST_F(DataReductionProxyConfigTest, WarmupURL) {
const net::URLRequestStatus kSuccess(net::URLRequestStatus::SUCCESS, net::OK);
const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
"https://secure_origin.net:443", net::ProxyServer::SCHEME_HTTP);
const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI(
"insecure_origin.net:80", net::ProxyServer::SCHEME_HTTP);
// Set up the embedded test server from where the warm up URL will be fetched.
net::EmbeddedTestServer embedded_test_server;
embedded_test_server.AddDefaultHandlers(
base::FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest")));
EXPECT_TRUE(embedded_test_server.Start());
GURL warmup_url = embedded_test_server.GetURL("/simple.html");
const struct {
bool data_reduction_proxy_enabled;
} tests[] = {
{
false,
},
{
true,
},
};
for (const auto& test : tests) {
SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy});
ASSERT_FALSE(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableDataReductionProxyWarmupURLFetch));
ResetSettings();
variations::testing::ClearAllVariationParams();
std::map<std::string, std::string> variation_params;
variation_params["warmup_url"] = warmup_url.spec();
ASSERT_TRUE(variations::AssociateVariationParams(
params::GetQuicFieldTrialName(), "Enabled", variation_params));
base::FieldTrialList field_trial_list(nullptr);
base::FieldTrialList::CreateFieldTrial(params::GetQuicFieldTrialName(),
"Enabled");
base::CommandLine::ForCurrentProcess()->InitFromArgv(0, nullptr);
TestDataReductionProxyConfig config(task_runner(), nullptr, configurator(),
event_creator());
NetworkPropertiesManager network_properties_manager(
base::DefaultClock::GetInstance(), test_context_->pref_service(),
test_context_->task_runner());
config.InitializeOnIOThread(test_context_->request_context_getter(),
test_context_->request_context_getter(),
&network_properties_manager);
RunUntilIdle();
{
base::HistogramTester histogram_tester;
// Set the connection type to WiFi so that warm up URL is fetched even if
// the test device does not have connectivity.
config.connection_type_ = net::NetworkChangeNotifier::CONNECTION_WIFI;
config.SetProxyConfig(test.data_reduction_proxy_enabled, true);
ASSERT_TRUE(params::FetchWarmupProbeURLEnabled());
if (test.data_reduction_proxy_enabled) {
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURL.FetchInitiated", 1, 1);
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURL.FetchAttemptEvent",
0 /* kFetchInitiated */, 1);
} else {
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURL.FetchAttemptEvent",
2 /* kProxyNotEnabledByUser */, 1);
}
}
{
base::HistogramTester histogram_tester;
// Set the connection type to 4G so that warm up URL is fetched even if
// the test device does not have connectivity.
net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
net::NetworkChangeNotifier::CONNECTION_4G);
RunUntilIdle();
if (test.data_reduction_proxy_enabled) {
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURL.FetchInitiated", 1, 1);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchAttemptEvent", 2);
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURL.FetchAttemptEvent",
2 /* kProxyNotEnabledByUser */, 1);
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURL.FetchAttemptEvent",
0 /* kFetchInitiated */, 1);
} else {
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 0);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchSuccessful", 0);
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURL.FetchAttemptEvent",
2 /* kProxyNotEnabledByUser */, 2);
}
}
{
base::HistogramTester histogram_tester;
// Warm up URL should not be fetched since the device does not have
// connectivity.
net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
net::NetworkChangeNotifier::CONNECTION_NONE);
RunUntilIdle();
if (test.data_reduction_proxy_enabled) {
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 0);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchAttemptEvent", 2);
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURL.FetchAttemptEvent",
1 /* kConnectionTypeNone */, 1);
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURL.FetchAttemptEvent",
2 /* kProxyNotEnabledByUser */, 1);
} else {
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 0);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchSuccessful", 0);
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURL.FetchAttemptEvent",
2 /* kProxyNotEnabledByUser */, 2);
}
}
}
}
TEST_F(DataReductionProxyConfigTest, AreProxiesBypassed) {
const struct {
// proxy flags
bool allowed;
bool fallback_allowed;
// is https request
bool is_https;
// proxies in retry map
bool origin;
bool fallback_origin;
bool expected_result;
} tests[] = {
{
// proxy flags
false, false,
// is https request
false,
// proxies in retry map
false, false,
// expected result
false,
},
{
// proxy flags
false, false,
// is https request
true,
// proxies in retry map
false, false,
// expected result
false,
},
{
// proxy flags
false, true,
// is https request
false,
// proxies in retry map
false, false,
// expected result
false,
},
{
// proxy flags
true, false,
// is https request
false,
// proxies in retry map
false, false,
// expected result
false,
},
{
// proxy flags
true, false,
// is https request
false,
// proxies in retry map
true, false,
// expected result
true,
},
{
// proxy flags
true, true,
// is https request
false,
// proxies in retry map
false, false,
// expected result
false,
},
{
// proxy flags
true, true,
// is https request
false,
// proxies in retry map
true, false,
// expected result
false,
},
{
// proxy flags
true, true,
// is https request
false,
// proxies in retry map
true, true,
// expected result
true,
},
{
// proxy flags
true, true,
// is https request
true,
// proxies in retry map
false, false,
// expected result
false,
},
{
// proxy flags
true, true,
// is https request
true,
// proxies in retry map
false, false,
// expected result
false,
},
{
// proxy flags
true, true,
// is https request
false,
// proxies in retry map
false, true,
// expected result
false,
},
{
// proxy flags
true, true,
// is https request
true,
// proxies in retry map
true, true,
// expected result
false,
},
};
// The retry map has the scheme prefix for https but not for http.
std::string origin = GetRetryMapKeyFromOrigin(params()
->proxies_for_http()
.front()
.proxy_server()
.host_port_pair()
.ToString());
std::string fallback_origin =
GetRetryMapKeyFromOrigin(params()
->proxies_for_http()
.at(1)
.proxy_server()
.host_port_pair()
.ToString());
for (size_t i = 0; i < arraysize(tests); ++i) {
net::ProxyConfig::ProxyRules rules;
std::vector<std::string> proxies;
if (tests[i].allowed)
proxies.push_back(origin);
if (tests[i].allowed && tests[i].fallback_allowed)
proxies.push_back(fallback_origin);
std::string proxy_rules = "http=" + base::JoinString(proxies, ",") +
",direct://;";
rules.ParseFromString(proxy_rules);
std::unique_ptr<TestDataReductionProxyParams> params(
new TestDataReductionProxyParams());
std::unique_ptr<DataReductionProxyConfig> config =
BuildConfig(std::move(params));
net::ProxyRetryInfoMap retry_map;
net::ProxyRetryInfo retry_info;
retry_info.bad_until = base::TimeTicks() + base::TimeDelta::Max();
if (tests[i].origin)
retry_map[origin] = retry_info;
if (tests[i].fallback_origin)
retry_map[fallback_origin] = retry_info;
bool was_bypassed = config->AreProxiesBypassed(retry_map, rules,
tests[i].is_https, nullptr);
EXPECT_EQ(tests[i].expected_result, was_bypassed) << i;
}
}
TEST_F(DataReductionProxyConfigTest, AreProxiesBypassedRetryDelay) {
std::string origin = GetRetryMapKeyFromOrigin(params()
->proxies_for_http()
.front()
.proxy_server()
.host_port_pair()
.ToString());
std::string fallback_origin =
GetRetryMapKeyFromOrigin(params()
->proxies_for_http()
.at(1)
.proxy_server()
.host_port_pair()
.ToString());
net::ProxyConfig::ProxyRules rules;
std::vector<std::string> proxies;
proxies.push_back(origin);
proxies.push_back(fallback_origin);
std::string proxy_rules =
"http=" + base::JoinString(proxies, ",") + ",direct://;";
rules.ParseFromString(proxy_rules);
std::unique_ptr<TestDataReductionProxyParams> params(
new TestDataReductionProxyParams());
std::unique_ptr<DataReductionProxyConfig> config =
BuildConfig(std::move(params));
net::ProxyRetryInfoMap retry_map;
net::ProxyRetryInfo retry_info;
retry_info.bad_until = base::TimeTicks() + base::TimeDelta::Max();
retry_map[origin] = retry_info;
retry_info.bad_until = base::TimeTicks();
retry_map[fallback_origin] = retry_info;
bool was_bypassed =
config->AreProxiesBypassed(retry_map, rules, false, nullptr);
EXPECT_FALSE(was_bypassed);
base::TimeDelta delay = base::TimeDelta::FromHours(2);
retry_info.bad_until = base::TimeTicks::Now() + delay;
retry_info.current_delay = delay;
retry_map[origin] = retry_info;
delay = base::TimeDelta::FromHours(1);
retry_info.bad_until = base::TimeTicks::Now() + delay;
retry_info.current_delay = delay;
retry_map[fallback_origin] = retry_info;
base::TimeDelta min_retry_delay;
was_bypassed = config->AreProxiesBypassed(retry_map,
rules,
false,
&min_retry_delay);
EXPECT_TRUE(was_bypassed);
EXPECT_EQ(delay, min_retry_delay);
}
TEST_F(DataReductionProxyConfigTest,
FindConfiguredDataReductionProxyWithParams) {
std::unique_ptr<TestDataReductionProxyParams> params(
new TestDataReductionProxyParams());
const std::vector<DataReductionProxyServer> expected_proxies =
params->proxies_for_http();
ASSERT_LT(0U, expected_proxies.size());
DataReductionProxyConfig config(task_runner(), net_log(), std::move(params),
configurator(), event_creator());
for (size_t expected_proxy_index = 0U;
expected_proxy_index < expected_proxies.size(); ++expected_proxy_index) {
base::Optional<DataReductionProxyTypeInfo> proxy_type_info =
config.FindConfiguredDataReductionProxy(
expected_proxies[expected_proxy_index].proxy_server());
ASSERT_TRUE(proxy_type_info.has_value());
EXPECT_EQ(expected_proxies, proxy_type_info->proxy_servers);
EXPECT_EQ(expected_proxy_index, proxy_type_info->proxy_index);
}
}
TEST_F(DataReductionProxyConfigTest,
FindConfiguredDataReductionProxyWithMutableConfig) {
std::vector<DataReductionProxyServer> proxies_for_http;
proxies_for_http.push_back(DataReductionProxyServer(
net::ProxyServer::FromURI("https://origin.net:443",
net::ProxyServer::SCHEME_HTTP),
ProxyServer::CORE));
proxies_for_http.push_back(DataReductionProxyServer(
net::ProxyServer::FromURI("http://origin.net:80",
net::ProxyServer::SCHEME_HTTP),
ProxyServer::CORE));
proxies_for_http.push_back(DataReductionProxyServer(
net::ProxyServer::FromURI("quic://anotherorigin.net:443",
net::ProxyServer::SCHEME_HTTP),
ProxyServer::CORE));
const struct {
DataReductionProxyServer proxy_server;
bool expected_result;
size_t expected_proxy_index;
} tests[] = {
{proxies_for_http[0], true, 0U},
{proxies_for_http[1], true, 1U},
{proxies_for_http[2], true, 2U},
{DataReductionProxyServer(net::ProxyServer(),
ProxyServer::UNSPECIFIED_TYPE),
false, 0U},
{DataReductionProxyServer(net::ProxyServer(net::ProxyServer::SCHEME_HTTPS,
net::HostPortPair::FromString(
"otherorigin.net:443")),
ProxyServer::UNSPECIFIED_TYPE),
false, 0U},
// Verifies that when determining if a proxy is a valid data reduction
// proxy, only the host port pairs are compared.
{DataReductionProxyServer(
net::ProxyServer::FromURI("origin.net:443",
net::ProxyServer::SCHEME_QUIC),
ProxyServer::UNSPECIFIED_TYPE),
true, 0U},
{DataReductionProxyServer(
net::ProxyServer::FromURI("origin2.net:443",
net::ProxyServer::SCHEME_HTTPS),
ProxyServer::UNSPECIFIED_TYPE),
false, 0U},
{DataReductionProxyServer(
net::ProxyServer::FromURI("origin2.net:443",
net::ProxyServer::SCHEME_QUIC),
ProxyServer::UNSPECIFIED_TYPE),
false, 0U},
};
std::unique_ptr<DataReductionProxyMutableConfigValues> config_values =
std::make_unique<DataReductionProxyMutableConfigValues>();
config_values->UpdateValues(proxies_for_http);
std::unique_ptr<DataReductionProxyConfig> config(new DataReductionProxyConfig(
task_runner(), net_log(), std::move(config_values), configurator(),
event_creator()));
for (const auto& test : tests) {
base::Optional<DataReductionProxyTypeInfo> proxy_type_info =
config->FindConfiguredDataReductionProxy(
test.proxy_server.proxy_server());
EXPECT_EQ(test.expected_result, proxy_type_info.has_value());
if (proxy_type_info) {
EXPECT_EQ(proxies_for_http, proxy_type_info->proxy_servers);
EXPECT_EQ(test.expected_proxy_index, proxy_type_info->proxy_index);
}
}
}
TEST_F(DataReductionProxyConfigTest,
ShouldAcceptServerPreviewAllPreviewsDisabled) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitFromCommandLine(
"DataReductionProxyDecidesTransform" /* enable_features */,
"Previews" /* disable_features */);
net::TestURLRequestContext context;
net::TestDelegate delegate;
std::unique_ptr<net::URLRequest> request =
context.CreateRequest(GURL("http://origin.net:80"
""),
net::IDLE, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
request->SetLoadFlags(request->load_flags() |
net::LOAD_MAIN_FRAME_DEPRECATED);
std::unique_ptr<previews::TestPreviewsDecider> previews_decider =
std::make_unique<previews::TestPreviewsDecider>(true);
EXPECT_FALSE(
test_config()->ShouldAcceptServerPreview(*request, *previews_decider));
}
TEST_F(DataReductionProxyConfigTest,
ShouldAcceptServerPreviewServerPreviewsDisabled) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitFromCommandLine(
"Previews" /* enable_features */,
"DataReductionProxyDecidesTransform" /* disable_features */);
net::TestURLRequestContext context;
net::TestDelegate delegate;
std::unique_ptr<net::URLRequest> request =
context.CreateRequest(GURL("http://origin.net:80"
""),
net::IDLE, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
request->SetLoadFlags(request->load_flags() |
net::LOAD_MAIN_FRAME_DEPRECATED);
std::unique_ptr<previews::TestPreviewsDecider> previews_decider =
std::make_unique<previews::TestPreviewsDecider>(true);
EXPECT_FALSE(
test_config()->ShouldAcceptServerPreview(*request, *previews_decider));
}
TEST_F(DataReductionProxyConfigTest, ShouldAcceptServerPreview) {
// Turn on proxy-decides-transform feature to satisfy DCHECK.
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitFromCommandLine(
"Previews,DataReductionProxyDecidesTransform" /* enable_features */,
std::string() /* disable_features */);
base::FieldTrialList field_trial_list(nullptr);
base::FieldTrialList::CreateFieldTrial(
"DataReductionProxyPreviewsBlackListTransition", "Enabled");
base::HistogramTester histogram_tester;
net::TestURLRequestContext context_;
net::TestDelegate delegate_;
std::unique_ptr<net::URLRequest> request =
context_.CreateRequest(GURL("http://origin.net:80"), net::IDLE,
&delegate_, TRAFFIC_ANNOTATION_FOR_TESTS);
request->SetLoadFlags(request->load_flags() |
net::LOAD_MAIN_FRAME_DEPRECATED);
std::unique_ptr<previews::TestPreviewsDecider> previews_decider =
std::make_unique<previews::TestPreviewsDecider>(true);
// Verify true for no flags.
EXPECT_TRUE(
test_config()->ShouldAcceptServerPreview(*request, *previews_decider));
// Verify PreviewsDecider check.
base::CommandLine::ForCurrentProcess()->InitFromArgv(0, nullptr);
previews_decider = std::make_unique<previews::TestPreviewsDecider>(false);
EXPECT_FALSE(
test_config()->ShouldAcceptServerPreview(*request, *previews_decider));
histogram_tester.ExpectBucketCount(
"DataReductionProxy.Protocol.NotAcceptingTransform",
1 /* NOT_ACCEPTING_TRANSFORM_BLACKLISTED */, 1);
previews_decider = std::make_unique<previews::TestPreviewsDecider>(true);
}
TEST_F(DataReductionProxyConfigTest, HandleWarmupFetcherResponse) {
base::HistogramTester histogram_tester;
const net::URLRequestStatus kSuccess(net::URLRequestStatus::SUCCESS, net::OK);
const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
"https://origin.net:443", net::ProxyServer::SCHEME_HTTP);
const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI(
"fallback.net:80", net::ProxyServer::SCHEME_HTTP);
const net::ProxyServer kNonDataSaverProxy = net::ProxyServer::FromURI(
"https://non-data-saver-proxy.net:443", net::ProxyServer::SCHEME_HTTP);
SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy});
ResetSettings();
// The proxy is enabled.
test_config()->UpdateConfigForTesting(true, true, true);
test_config()->OnNewClientConfigFetched();
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
// Set the details of the proxy to which the warmup URL probe is in-flight to
// avoid triggering the DCHECKs in HandleWarmupFetcherResponse method.
test_config()->SetInFlightWarmupProxyDetails(
std::make_pair(true /* is_secure_proxy */, false /* is_core_proxy */));
// Report successful warmup of |kHttpsProxy|.
test_config()->HandleWarmupFetcherResponse(
kHttpsProxy, WarmupURLFetcher::FetchResult::kSuccessful);
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
1, 1);
// Report failed warmup |kHttpsProxy| and verify it is removed from the list
// of proxies.
test_config()->SetInFlightWarmupProxyDetails(
std::make_pair(true /* is_secure_proxy */, false /* is_core_proxy */));
test_config()->HandleWarmupFetcherResponse(
kHttpsProxy, WarmupURLFetcher::FetchResult::kFailed);
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}),
GetConfiguredProxiesForHttp());
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
0, 1);
// Report failed warmup |kHttpsProxy| again, and verify it does not change the
// list of proxies.
test_config()->SetInFlightWarmupProxyDetails(
std::make_pair(true /* is_secure_proxy */, false /* is_core_proxy */));
test_config()->HandleWarmupFetcherResponse(
kHttpsProxy, WarmupURLFetcher::FetchResult::kFailed);
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}),
GetConfiguredProxiesForHttp());
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
0, 2);
// |kHttpsProxy| should now be added back to the list of proxies.
test_config()->SetInFlightWarmupProxyDetails(
std::make_pair(true /* is_secure_proxy */, false /* is_core_proxy */));
test_config()->HandleWarmupFetcherResponse(
kHttpsProxy, WarmupURLFetcher::FetchResult::kSuccessful);
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
1, 2);
// Report successful warmup |kHttpsProxy| again, and verify that there is no
// change in the list of proxies.
test_config()->SetInFlightWarmupProxyDetails(
std::make_pair(true /* is_secure_proxy */, false /* is_core_proxy */));
test_config()->HandleWarmupFetcherResponse(
kHttpsProxy, WarmupURLFetcher::FetchResult::kSuccessful);
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
1, 3);
// |kHttpsProxy| should be removed again from the list of proxies.
test_config()->SetInFlightWarmupProxyDetails(
std::make_pair(true /* is_secure_proxy */, false /* is_core_proxy */));
test_config()->HandleWarmupFetcherResponse(
kHttpsProxy, WarmupURLFetcher::FetchResult::kFailed);
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}),
GetConfiguredProxiesForHttp());
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
0, 3);
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
1, 3);
// Now report failed warmup for |kHttpProxy| and verify that it is also
// removed from the list of proxies.
test_config()->SetInFlightWarmupProxyDetails(
std::make_pair(false /* is_secure_proxy */, false /* is_core_proxy */));
test_config()->HandleWarmupFetcherResponse(
kHttpProxy, WarmupURLFetcher::FetchResult::kFailed);
EXPECT_EQ(std::vector<net::ProxyServer>({}), GetConfiguredProxiesForHttp());
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"InsecureProxy.NonCore",
0, 1);
// Both proxies should be added back.
test_config()->SetInFlightWarmupProxyDetails(
std::make_pair(true /* is_secure_proxy */, false /* is_core_proxy */));
test_config()->HandleWarmupFetcherResponse(
kHttpsProxy, WarmupURLFetcher::FetchResult::kSuccessful);
test_config()->SetInFlightWarmupProxyDetails(
std::make_pair(false /* is_secure_proxy */, false /* is_core_proxy */));
test_config()->HandleWarmupFetcherResponse(
kHttpProxy, WarmupURLFetcher::FetchResult::kSuccessful);
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
0, 3);
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
1, 4);
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"InsecureProxy.NonCore",
0, 1);
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"InsecureProxy.NonCore",
1, 1);
// If the warmup URL is unsuccessfully fetched using a non-data saver proxy,
// then there is no change in the list of proxies.
test_config()->HandleWarmupFetcherResponse(
kNonDataSaverProxy, WarmupURLFetcher::FetchResult::kFailed);
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
}
// Tests that the proxy server last used for fetching the warmup URL is marked
// as failed when the warmup fetched callback returns an invalid proxy.
TEST_F(DataReductionProxyConfigTest,
HandleWarmupFetcherResponse_InvalidProxyServer) {
const net::URLRequestStatus kSuccess(net::URLRequestStatus::SUCCESS, net::OK);
const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
"https://origin.net:443", net::ProxyServer::SCHEME_HTTP);
const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI(
"fallback.net:80", net::ProxyServer::SCHEME_HTTP);
SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy});
ResetSettings();
// The proxy is enabled.
test_config()->UpdateConfigForTesting(true, true, true);
test_config()->OnNewClientConfigFetched();
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
// Report failed warmup for a non-DataSaver proxy, and verify that it
// changes the list of data saver proxies.
test_config()->HandleWarmupFetcherResponse(
net::ProxyServer(),
WarmupURLFetcher::FetchResult::kFailed /* success_response */);
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}),
GetConfiguredProxiesForHttp());
}
// Tests that the proxy server last used for fetching the warmup URL is marked
// as failed when the warmup fetched callback returns a direct proxy.
TEST_F(DataReductionProxyConfigTest,
HandleWarmupFetcherResponse_DirectProxyServer) {
const net::URLRequestStatus kSuccess(net::URLRequestStatus::SUCCESS, net::OK);
const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
"https://origin.net:443", net::ProxyServer::SCHEME_HTTP);
const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI(
"fallback.net:80", net::ProxyServer::SCHEME_HTTP);
SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy});
ResetSettings();
// The proxy is enabled.
test_config()->UpdateConfigForTesting(true, true, true);
test_config()->OnNewClientConfigFetched();
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
// Report failed warmup for a non-DataSaver proxy, and verify that it
// changes the list of data saver proxies.
test_config()->HandleWarmupFetcherResponse(
net::ProxyServer::Direct(),
WarmupURLFetcher::FetchResult::kFailed /* success_response */);
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}),
GetConfiguredProxiesForHttp());
}
TEST_F(DataReductionProxyConfigTest, HandleWarmupFetcherRetry) {
constexpr size_t kMaxWarmupURLFetchAttempts = 3;
base::HistogramTester histogram_tester;
const net::URLRequestStatus kSuccess(net::URLRequestStatus::SUCCESS, net::OK);
const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
"https://origin.net:443", net::ProxyServer::SCHEME_HTTP);
const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI(
"fallback.net:80", net::ProxyServer::SCHEME_HTTP);
SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy});
ResetSettings();
// Enable the proxy.
test_config()->SetWarmupURLFetchAttemptCounts(0);
test_config()->UpdateConfigForTesting(true, true, true);
test_config()->SetIsFetchInFlight(true);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 0);
test_config()->OnNewClientConfigFetched();
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"InsecureProxy.NonCore",
0);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
0);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 1);
// The first probe should go through the HTTPS data saver proxy.
test_config()->HandleWarmupFetcherResponse(
kHttpsProxy, WarmupURLFetcher::FetchResult::kFailed);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}),
GetConfiguredProxiesForHttp());
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
0, 1);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 2);
test_config()->SetInFlightWarmupProxyDetails(base::nullopt);
EXPECT_EQ(std::make_pair(false, false),
test_config()->GetInFlightWarmupProxyDetails());
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 2);
// The second probe should go through the HTTP data saver proxy.
test_config()->HandleWarmupFetcherResponse(
kHttpProxy, WarmupURLFetcher::FetchResult::kFailed);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(std::vector<net::ProxyServer>({}), GetConfiguredProxiesForHttp());
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"InsecureProxy.NonCore",
0, 1);
EXPECT_EQ(std::make_pair(true, false),
test_config()->GetInFlightWarmupProxyDetails());
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 3);
EXPECT_EQ(std::make_pair(true, false),
test_config()->GetInFlightWarmupProxyDetails());
for (size_t i = 1; i <= 4; ++i) {
// Two more probes should go through the HTTPS data saver proxy, and two
// more probes through the HTTP proxy.
if (i <= 2) {
EXPECT_EQ(std::make_pair(true, false),
test_config()->GetInFlightWarmupProxyDetails());
test_config()->HandleWarmupFetcherResponse(
kHttpsProxy, WarmupURLFetcher::FetchResult::kFailed);
} else {
EXPECT_EQ(std::make_pair(false, false),
test_config()->GetInFlightWarmupProxyDetails());
test_config()->HandleWarmupFetcherResponse(
kHttpProxy, WarmupURLFetcher::FetchResult::kFailed);
}
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated",
std::min(3 + i,
kMaxWarmupURLFetchAttempts + kMaxWarmupURLFetchAttempts));
}
EXPECT_EQ(std::vector<net::ProxyServer>({}), GetConfiguredProxiesForHttp());
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
1, 0);
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
0, 3);
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"InsecureProxy.NonCore",
1, 0);
histogram_tester.ExpectBucketCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"InsecureProxy.NonCore",
0, 3);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 6);
for (size_t i = 1; i <= 10; ++i) {
// Set the details of the proxy to which the warmup URL probe is in-flight
// to avoid triggering the DCHECKs in HandleWarmupFetcherResponse method.
test_config()->SetInFlightWarmupProxyDetails(
std::make_pair(false /* is_secure_proxy */, false /* is_core_proxy */));
// Fetcher callback should not trigger fetching of probe URL since
// kMaxWarmupURLFetchAttempts probes have been tried through each of the
// data saver proxy.
test_config()->HandleWarmupFetcherResponse(
kHttpProxy, WarmupURLFetcher::FetchResult::kFailed);
base::RunLoop().RunUntilIdle();
// At most kMaxWarmupURLFetchAttempts warmup URLs should be fetched via
// each of the two insecure proxies.
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated",
kMaxWarmupURLFetchAttempts + kMaxWarmupURLFetchAttempts);
}
test_config()->SetInFlightWarmupProxyDetails(base::nullopt);
}
// Tests the behavior when warmup URL fetcher times out.
TEST_F(DataReductionProxyConfigTest, HandleWarmupFetcherTimeout) {
base::HistogramTester histogram_tester;
const net::URLRequestStatus kSuccess(net::URLRequestStatus::SUCCESS, net::OK);
const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
"https://origin.net:443", net::ProxyServer::SCHEME_HTTP);
const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI(
"fallback.net:80", net::ProxyServer::SCHEME_HTTP);
SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy});
ResetSettings();
// Enable the proxy.
test_config()->SetWarmupURLFetchAttemptCounts(0);
test_config()->UpdateConfigForTesting(true, true, true);
test_config()->SetIsFetchInFlight(true);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 0);
test_config()->OnNewClientConfigFetched();
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"InsecureProxy.NonCore",
0);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
0);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 1);
// The first probe should go through the HTTPS data saver proxy. On fetch
// timeout, the HTTPS proxy must be disabled even though the callback did
// not specify a proxy.
test_config()->HandleWarmupFetcherResponse(
net::ProxyServer(), WarmupURLFetcher::FetchResult::kTimedOut);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}),
GetConfiguredProxiesForHttp());
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
0, 1);
// Warmup URL should be fetched from the next proxy.
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 2);
}
TEST_F(DataReductionProxyConfigTest,
HandleWarmupFetcherRetryWithConnectionChange) {
constexpr size_t kMaxWarmupURLFetchAttempts = 3;
base::HistogramTester histogram_tester;
const net::URLRequestStatus kSuccess(net::URLRequestStatus::SUCCESS, net::OK);
const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
"https://origin.net:443", net::ProxyServer::SCHEME_HTTP);
const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI(
"fallback.net:80", net::ProxyServer::SCHEME_HTTP);
SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy});
ResetSettings();
// Enable the proxy.
test_config()->SetWarmupURLFetchAttemptCounts(0);
test_config()->UpdateConfigForTesting(true, true, true);
test_config()->SetIsFetchInFlight(true);
test_config()->OnNewClientConfigFetched();
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 1);
// The first probe should go through the HTTPS data saver proxy.
test_config()->HandleWarmupFetcherResponse(
kHttpsProxy, WarmupURLFetcher::FetchResult::kFailed);
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 2);
test_config()->SetInFlightWarmupProxyDetails(base::nullopt);
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 2);
// The second probe should go through the HTTP data saver proxy.
test_config()->HandleWarmupFetcherResponse(
kHttpProxy, WarmupURLFetcher::FetchResult::kFailed);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(std::vector<net::ProxyServer>({}), GetConfiguredProxiesForHttp());
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 3);
EXPECT_EQ(std::make_pair(true, false),
test_config()->GetInFlightWarmupProxyDetails());
for (size_t i = 1; i <= 4; ++i) {
// Two more probes should go through the HTTPS data saver proxy, and two
// more probes through the HTTP proxy.
if (i <= 2) {
test_config()->HandleWarmupFetcherResponse(
kHttpsProxy, WarmupURLFetcher::FetchResult::kFailed);
} else {
test_config()->HandleWarmupFetcherResponse(
kHttpProxy, WarmupURLFetcher::FetchResult::kFailed);
}
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated",
std::min(3 + i,
kMaxWarmupURLFetchAttempts + kMaxWarmupURLFetchAttempts));
}
EXPECT_EQ(std::make_pair(false, false),
test_config()->GetInFlightWarmupProxyDetails());
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated", 6);
test_config()->SetInFlightWarmupProxyDetails(base::nullopt);
EXPECT_EQ(std::vector<net::ProxyServer>({}), GetConfiguredProxiesForHttp());
// A change in the connection type should reset the probe fetch attempt count,
// and trigger fetching of the probe URL.
test_config()->SetCurrentNetworkID("wifi,test");
net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
net::NetworkChangeNotifier::CONNECTION_WIFI);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(std::make_pair(true, false),
test_config()->GetInFlightWarmupProxyDetails());
EXPECT_NE(std::vector<net::ProxyServer>({}), GetConfiguredProxiesForHttp());
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated",
kMaxWarmupURLFetchAttempts + kMaxWarmupURLFetchAttempts + 1);
// At most kMaxWarmupURLFetchAttempts warmup URLs should be fetched via
// secure proxy, and kMaxWarmupURLFetchAttempts via insecure.
test_config()->HandleWarmupFetcherResponse(
kHttpsProxy, WarmupURLFetcher::FetchResult::kFailed);
base::RunLoop().RunUntilIdle();
test_config()->HandleWarmupFetcherResponse(
kHttpProxy, WarmupURLFetcher::FetchResult::kFailed);
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated",
kMaxWarmupURLFetchAttempts + kMaxWarmupURLFetchAttempts + 3);
for (size_t i = 1; i <= 2; ++i) {
test_config()->HandleWarmupFetcherResponse(
kHttpsProxy, WarmupURLFetcher::FetchResult::kFailed);
base::RunLoop().RunUntilIdle();
}
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated",
kMaxWarmupURLFetchAttempts + kMaxWarmupURLFetchAttempts + 5);
for (size_t i = 1; i <= 2; ++i) {
test_config()->HandleWarmupFetcherResponse(
kHttpProxy, WarmupURLFetcher::FetchResult::kFailed);
base::RunLoop().RunUntilIdle();
}
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.FetchInitiated",
kMaxWarmupURLFetchAttempts + kMaxWarmupURLFetchAttempts + 6);
}
} // namespace data_reduction_proxy