Commit 34a83025 authored by Tarun Bansal's avatar Tarun Bansal Committed by Commit Bot

Disable data saver proxy if the warmup URL fetch fails

If the fetch of the warmup URL (aka probe URL) fails, the
corresponding proxy is disabled, and the config is reloaded.

A future CL will add retries -- If the fetch of the probe URL
due to network flakiness fails, then the probe will be retried
(up to 3 times) on the same proxy.

Bug: 760294
Change-Id: Ib255f8178ef106f5e2882ad3dc32bde143c40a90
Reviewed-on: https://chromium-review.googlesource.com/807592Reviewed-by: default avatarSteven Holte <holte@chromium.org>
Reviewed-by: default avatarDoug Arnett <dougarnett@chromium.org>
Commit-Queue: Tarun Bansal <tbansal@chromium.org>
Cr-Commit-Position: refs/heads/master@{#521951}
parent df8ebd61
......@@ -163,7 +163,11 @@ void DataReductionProxyConfig::InitializeOnIOThread(
secure_proxy_checker_.reset(
new SecureProxyChecker(basic_url_request_context_getter));
warmup_url_fetcher_.reset(new WarmupURLFetcher(url_request_context_getter));
warmup_url_fetcher_.reset(new WarmupURLFetcher(
url_request_context_getter,
base::BindRepeating(
&DataReductionProxyConfig::HandleWarmupFetcherResponse,
base::Unretained(this))));
if (ShouldAddDefaultProxyBypassRules())
AddDefaultProxyBypassRules();
......@@ -178,6 +182,7 @@ bool DataReductionProxyConfig::ShouldAddDefaultProxyBypassRules() const {
void DataReductionProxyConfig::OnNewClientConfigFetched() {
DCHECK(thread_checker_.CalledOnValidThread());
ReloadConfig();
FetchWarmupURL();
}
void DataReductionProxyConfig::ReloadConfig() {
......@@ -201,6 +206,26 @@ bool DataReductionProxyConfig::WasDataReductionProxyUsed(
return IsDataReductionProxy(request->proxy_server(), proxy_info);
}
bool DataReductionProxyConfig::IsDataReductionProxyServerCore(
const net::ProxyServer& proxy_server) const {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(IsDataReductionProxy(proxy_server, nullptr /* proxy_info */));
const net::HostPortPair& host_port_pair = proxy_server.host_port_pair();
const std::vector<DataReductionProxyServer>& data_reduction_proxy_servers =
config_values_->proxies_for_http();
const auto proxy_it = std::find_if(
data_reduction_proxy_servers.begin(), data_reduction_proxy_servers.end(),
[&host_port_pair](const DataReductionProxyServer& proxy) {
return proxy.proxy_server().is_valid() &&
proxy.proxy_server().host_port_pair().Equals(host_port_pair);
});
return proxy_it->IsCoreProxy();
}
bool DataReductionProxyConfig::IsDataReductionProxy(
const net::ProxyServer& proxy_server,
DataReductionProxyTypeInfo* proxy_info) const {
......@@ -413,6 +438,56 @@ void DataReductionProxyConfig::SetNetworkPropertiesManagerForTesting(
network_properties_manager_ = manager;
}
void DataReductionProxyConfig::HandleWarmupFetcherResponse(
const net::ProxyServer& proxy_server,
bool success_response) {
DCHECK(thread_checker_.CalledOnValidThread());
// Check the proxy server used, or disable all data saver proxies?
if (!IsDataReductionProxy(proxy_server, nullptr)) {
// No need to do anything here.
return;
}
bool is_secure_drp_proxy = proxy_server.is_https() || proxy_server.is_quic();
bool is_core_proxy = IsDataReductionProxyServerCore(proxy_server);
if (is_secure_drp_proxy && is_core_proxy) {
UMA_HISTOGRAM_BOOLEAN(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.Core",
success_response);
} else if (is_secure_drp_proxy && !is_core_proxy) {
UMA_HISTOGRAM_BOOLEAN(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"SecureProxy.NonCore",
success_response);
} else if (!is_secure_drp_proxy && is_core_proxy) {
UMA_HISTOGRAM_BOOLEAN(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"InsecureProxy.Core",
success_response);
} else {
UMA_HISTOGRAM_BOOLEAN(
"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
"InsecureProxy.NonCore",
success_response);
}
bool warmup_url_failed_past =
network_properties_manager_->HasWarmupURLProbeFailed(is_secure_drp_proxy,
is_core_proxy);
network_properties_manager_->SetHasWarmupURLProbeFailed(
is_secure_drp_proxy, is_core_proxy,
!success_response /* warmup failed */);
if (warmup_url_failed_past !=
network_properties_manager_->HasWarmupURLProbeFailed(is_secure_drp_proxy,
is_core_proxy)) {
ReloadConfig();
}
}
void DataReductionProxyConfig::HandleSecureProxyCheckResponse(
const std::string& response,
const net::URLRequestStatus& status,
......
......@@ -223,6 +223,13 @@ class DataReductionProxyConfig
// Returns the ID of the current network by calling the platform APIs.
virtual std::string GetCurrentNetworkID() const;
// Callback that is executed when the warmup URL fetch is complete.
// |proxy_server| is the proxy server over which the warmup URL was fetched.
// |success_response| is true if the fetching of the URL was successful or
// not.
void HandleWarmupFetcherResponse(const net::ProxyServer& proxy_server,
bool success_response);
private:
friend class MockDataReductionProxyConfig;
friend class TestDataReductionProxyConfig;
......@@ -297,6 +304,12 @@ class DataReductionProxyConfig
// Fetches the warmup URL.
void FetchWarmupURL();
// Returns true if |proxy_server| is a core data reduction proxy server.
// Should be called only if |proxy_server| is a valid data reduction proxy
// server.
bool IsDataReductionProxyServerCore(
const net::ProxyServer& proxy_server) const;
// URL fetcher used for performing the secure proxy check.
std::unique_ptr<SecureProxyChecker> secure_proxy_checker_;
......
......@@ -159,6 +159,10 @@ class DataReductionProxyConfigServiceClientTest : public testing::Test {
context_->Init();
// Disable fetching of warmup URL to avoid generating extra traffic which
// would need to be satisfied using mock sockets.
test_context_->DisableWarmupURLFetch();
test_context_->InitSettings();
ResetBackoffEntryReleaseTime();
test_context_->test_config_client()->SetNow(base::Time::UnixEpoch());
......
......@@ -108,6 +108,7 @@ class TestDataReductionProxyConfig : public DataReductionProxyConfig {
using DataReductionProxyConfig::UpdateConfigForTesting;
using DataReductionProxyConfig::OnInsecureProxyWarmupURLProbeStatusChange;
using DataReductionProxyConfig::HandleWarmupFetcherResponse;
private:
bool GetIsCaptivePortal() const override;
......
......@@ -75,6 +75,8 @@ void SetProxiesForHttpOnCommandLine(
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, ";"));
......@@ -1099,4 +1101,129 @@ TEST_F(DataReductionProxyConfigTest, ShouldAcceptServerPreview) {
*request.get(), *previews_decider.get()));
}
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());
// Report failed warmup for a non-DataSaver proxy, and verify that it does not
// change the list of data saver proxies.
test_config()->HandleWarmupFetcherResponse(net::ProxyServer(),
false /* success_response */);
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
// Report successful warmup of |kHttpsProxy|.
test_config()->HandleWarmupFetcherResponse(kHttpsProxy, true);
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()->HandleWarmupFetcherResponse(kHttpsProxy, false);
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()->HandleWarmupFetcherResponse(kHttpsProxy, false);
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()->HandleWarmupFetcherResponse(kHttpsProxy, true);
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()->HandleWarmupFetcherResponse(kHttpsProxy, true);
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()->HandleWarmupFetcherResponse(kHttpsProxy, false);
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()->HandleWarmupFetcherResponse(kHttpProxy, false);
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()->HandleWarmupFetcherResponse(kHttpsProxy, true);
test_config()->HandleWarmupFetcherResponse(kHttpProxy, true);
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, false);
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
}
} // namespace data_reduction_proxy
......@@ -4,6 +4,7 @@
#include "components/data_reduction_proxy/core/browser/warmup_url_fetcher.h"
#include "base/callback.h"
#include "base/guid.h"
#include "base/metrics/histogram_macros.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
......@@ -11,6 +12,7 @@
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_util.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "net/base/load_flags.h"
#include "net/http/http_status_code.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_context_getter.h"
......@@ -20,8 +22,10 @@ namespace data_reduction_proxy {
WarmupURLFetcher::WarmupURLFetcher(
const scoped_refptr<net::URLRequestContextGetter>&
url_request_context_getter)
: url_request_context_getter_(url_request_context_getter) {
url_request_context_getter,
WarmupURLFetcherCallback callback)
: url_request_context_getter_(url_request_context_getter),
callback_(callback) {
DCHECK(url_request_context_getter_);
}
......@@ -111,7 +115,23 @@ void WarmupURLFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
util::ConvertNetProxySchemeToProxyScheme(
source->ProxyServerUsed().scheme()),
PROXY_SCHEME_MAX);
if (!source->GetStatus().is_success() &&
source->GetStatus().error() == net::ERR_INTERNET_DISCONNECTED) {
// Fetching failed due to Internet unavailability, and not due to some
// error. Set the proxy server to unknown.
callback_.Run(net::ProxyServer(), true);
return;
}
}
bool success_response =
source->GetStatus().status() == net::URLRequestStatus::SUCCESS &&
source->GetResponseCode() == net::HTTP_NO_CONTENT &&
source->GetResponseHeaders() &&
HasDataReductionProxyViaHeader(*(source->GetResponseHeaders()),
nullptr /* has_intermediary */);
callback_.Run(source->ProxyServerUsed(), success_response);
}
} // namespace data_reduction_proxy
\ No newline at end of file
......@@ -7,6 +7,7 @@
#include <utility>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "net/url_request/url_fetcher_delegate.h"
......@@ -15,6 +16,7 @@ class GURL;
namespace net {
class ProxyServer;
class URLFetcher;
class URLRequestContextGetter;
......@@ -25,8 +27,14 @@ namespace data_reduction_proxy {
// URLFetcherDelegate for fetching the warmup URL.
class WarmupURLFetcher : public net::URLFetcherDelegate {
public:
explicit WarmupURLFetcher(const scoped_refptr<net::URLRequestContextGetter>&
url_request_context_getter);
// The proxy server that was used to fetch the request, and whether the fetch
// was successful.
typedef base::RepeatingCallback<void(const net::ProxyServer&, bool)>
WarmupURLFetcherCallback;
WarmupURLFetcher(const scoped_refptr<net::URLRequestContextGetter>&
url_request_context_getter,
WarmupURLFetcherCallback callback);
~WarmupURLFetcher() override;
......@@ -46,6 +54,10 @@ class WarmupURLFetcher : public net::URLFetcherDelegate {
// The URLFetcher being used for fetching the warmup URL.
std::unique_ptr<net::URLFetcher> fetcher_;
// Callback that should be executed when the fetching of the warmup URL is
// completed.
WarmupURLFetcherCallback callback_;
DISALLOW_COPY_AND_ASSIGN(WarmupURLFetcher);
};
......
......@@ -6,6 +6,7 @@
#include <vector>
#include "base/bind_helpers.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
......@@ -27,14 +28,33 @@ class WarmupURLFetcherTest : public WarmupURLFetcher {
public:
WarmupURLFetcherTest(const scoped_refptr<net::URLRequestContextGetter>&
url_request_context_getter)
: WarmupURLFetcher(url_request_context_getter) {}
: WarmupURLFetcher(url_request_context_getter,
base::BindRepeating(
&WarmupURLFetcherTest::HandleWarmupFetcherResponse,
base::Unretained(this))) {}
~WarmupURLFetcherTest() override {}
size_t callback_received_count() const { return callback_received_count_; }
const net::ProxyServer& proxy_server_last() const {
return proxy_server_last_;
}
bool success_response_last() const { return success_response_last_; }
using WarmupURLFetcher::FetchWarmupURL;
using WarmupURLFetcher::GetWarmupURLWithQueryParam;
private:
void HandleWarmupFetcherResponse(const net::ProxyServer& proxy_server,
bool success_response) {
callback_received_count_++;
proxy_server_last_ = proxy_server;
success_response_last_ = success_response;
}
size_t callback_received_count_ = 0;
net::ProxyServer proxy_server_last_;
bool success_response_last_ = false;
DISALLOW_COPY_AND_ASSIGN(WarmupURLFetcherTest);
};
......@@ -70,7 +90,7 @@ TEST(WarmupURLFetcherTest, TestGetWarmupURLWithQueryParam) {
EXPECT_TRUE(query_param_different);
}
TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURL) {
TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURLNoViaHeader) {
base::HistogramTester histogram_tester;
base::MessageLoopForIO message_loop;
const std::string config = "foobarbaz";
......@@ -113,6 +133,66 @@ TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURL) {
"DataReductionProxy.WarmupURL.ProxySchemeUsed",
util::ConvertNetProxySchemeToProxyScheme(net::ProxyServer::SCHEME_DIRECT),
1);
EXPECT_EQ(1u, warmup_url_fetcher.callback_received_count());
EXPECT_EQ(net::ProxyServer::SCHEME_DIRECT,
warmup_url_fetcher.proxy_server_last().scheme());
// success_response_last() should be false since the response does not contain
// the via header.
EXPECT_FALSE(warmup_url_fetcher.success_response_last());
}
TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURLWithViaHeader) {
base::HistogramTester histogram_tester;
base::MessageLoopForIO message_loop;
const std::string config = "foobarbaz";
std::vector<std::unique_ptr<net::SocketDataProvider>> socket_data_providers;
net::MockClientSocketFactory mock_socket_factory;
net::MockRead success_reads[3];
success_reads[0] = net::MockRead(
"HTTP/1.1 204 OK\r\nVia: 1.1 Chrome-Compression-Proxy\r\n\r\n");
success_reads[1] = net::MockRead(net::ASYNC, config.c_str(), config.length());
success_reads[2] = net::MockRead(net::SYNCHRONOUS, net::OK);
socket_data_providers.push_back(
(base::MakeUnique<net::StaticSocketDataProvider>(
success_reads, arraysize(success_reads), nullptr, 0)));
mock_socket_factory.AddSocketDataProvider(socket_data_providers.back().get());
std::unique_ptr<net::TestURLRequestContext> test_request_context(
new net::TestURLRequestContext(true));
test_request_context->set_client_socket_factory(&mock_socket_factory);
test_request_context->Init();
scoped_refptr<net::URLRequestContextGetter> request_context_getter =
new net::TestURLRequestContextGetter(message_loop.task_runner(),
std::move(test_request_context));
WarmupURLFetcherTest warmup_url_fetcher(request_context_getter);
warmup_url_fetcher.FetchWarmupURL();
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURL.FetchInitiated", 1, 1);
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURL.FetchSuccessful", 1, 1);
histogram_tester.ExpectUniqueSample("DataReductionProxy.WarmupURL.NetError",
net::OK, 1);
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURL.HttpResponseCode", net::HTTP_NO_CONTENT, 1);
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURL.HasViaHeader", 1, 1);
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.WarmupURL.ProxySchemeUsed",
util::ConvertNetProxySchemeToProxyScheme(net::ProxyServer::SCHEME_DIRECT),
1);
EXPECT_EQ(1u, warmup_url_fetcher.callback_received_count());
EXPECT_EQ(net::ProxyServer::SCHEME_DIRECT,
warmup_url_fetcher.proxy_server_last().scheme());
// success_response_last() should be true since the response contains the via
// header.
EXPECT_TRUE(warmup_url_fetcher.success_response_last());
}
TEST(WarmupURLFetcherTest, TestConnectionResetFetchWarmupURL) {
......@@ -155,6 +235,10 @@ TEST(WarmupURLFetcherTest, TestConnectionResetFetchWarmupURL) {
0);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.WarmupURL.ProxySchemeUsed", 0);
EXPECT_EQ(1u, warmup_url_fetcher.callback_received_count());
EXPECT_EQ(net::ProxyServer::SCHEME_INVALID,
warmup_url_fetcher.proxy_server_last().scheme());
EXPECT_FALSE(warmup_url_fetcher.success_response_last());
}
} // namespace
......
......@@ -50,6 +50,10 @@ DataReductionProxyServer::ConvertToNetProxyServers(
return net_proxy_servers;
}
bool DataReductionProxyServer::IsCoreProxy() const {
return proxy_type_ == ProxyServer_ProxyType_CORE;
}
ProxyServer_ProxyType DataReductionProxyServer::GetProxyTypeForTesting() const {
return proxy_type_;
}
......
......@@ -35,6 +35,8 @@ class DataReductionProxyServer {
const std::vector<DataReductionProxyServer>&
data_reduction_proxy_servers);
bool IsCoreProxy() const;
// Returns |proxy_type_| for verification by tests.
ProxyServer_ProxyType GetProxyTypeForTesting() const;
......
......@@ -13481,6 +13481,15 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
</summary>
</histogram>
<histogram name="DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch"
enum="BooleanSuccess">
<owner>tbansal@chromium.org</owner>
<summary>
Whether the warmup (or probe) URL was successfully fetched over a data saver
proxy.
</summary>
</histogram>
<histogram name="DataUsage.MatchingRulesCount.Invalid" units="count">
<owner>bengr@chromium.org</owner>
<owner>rajendrant@chromium.org</owner>
......@@ -100765,6 +100774,20 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
<affected-histogram name="Previews.OriginalContentLength"/>
</histogram_suffixes>
<histogram_suffixes name="DataSaverProxyTypes" separator=".">
<owner>tbansal@chromium.org</owner>
<suffix name="SecureProxy.Core"
label="Over a secure, core data saver proxy."/>
<suffix name="SecureProxy.NonCore"
label="Over a secure, non-core data saver proxy."/>
<suffix name="InsecureProxy.Core"
label="Over an insecure, core data saver proxy."/>
<suffix name="InsecureProxy.NonCore"
label="Over an insecure, non-core data saver proxy."/>
<affected-histogram
name="DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch"/>
</histogram_suffixes>
<histogram_suffixes name="DataUsageReportSubmissionBytes" separator=".">
<suffix name="Failed"
label="Platform external data use observer reported the submission as
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment