summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/net/chrome_network_delegate.cc5
-rw-r--r--components/data_reduction_proxy.gypi2
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_protocol.cc6
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_protocol_unittest.cc13
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.cc9
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_tamper_detection_unittest.cc7
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.cc72
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.h37
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats_unittest.cc253
-rw-r--r--components/data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.cc17
-rw-r--r--components/data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.h17
-rw-r--r--components/data_reduction_proxy/common/data_reduction_proxy_headers_unittest.cc13
-rw-r--r--tools/metrics/histograms/histograms.xml35
13 files changed, 432 insertions, 54 deletions
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
index 093139d..ca6c04a 100644
--- a/chrome/browser/net/chrome_network_delegate.cc
+++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -582,11 +582,12 @@ void ChromeNetworkDelegate::OnCompleted(net::URLRequest* request,
RecordContentLengthHistograms(received_content_length,
original_content_length,
freshness_lifetime);
+
if (data_reduction_proxy_enabled_ &&
data_reduction_proxy_usage_stats_ &&
!proxy_config_getter_.is_null()) {
- data_reduction_proxy_usage_stats_->RecordBypassedBytesHistograms(
- *request,
+ data_reduction_proxy_usage_stats_->RecordBytesHistograms(
+ request,
*data_reduction_proxy_enabled_,
proxy_config_getter_.Run());
}
diff --git a/components/data_reduction_proxy.gypi b/components/data_reduction_proxy.gypi
index bc0f00c..0fa2bab 100644
--- a/components/data_reduction_proxy.gypi
+++ b/components/data_reduction_proxy.gypi
@@ -89,6 +89,8 @@
'data_reduction_proxy/browser/data_reduction_proxy_params_test_utils.h',
'data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.cc',
'data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.h',
+ 'data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.cc',
+ 'data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.h',
],
},
{
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_protocol.cc b/components/data_reduction_proxy/browser/data_reduction_proxy_protocol.cc
index 565621d..b638c2c 100644
--- a/components/data_reduction_proxy/browser/data_reduction_proxy_protocol.cc
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_protocol.cc
@@ -65,6 +65,12 @@ bool MaybeBypassProxyAndPrepareToRetry(
if (data_reduction_proxy_type_info.proxy_servers.first.is_empty())
return false;
+ // At this point, the response is expected to have the data reduction proxy
+ // via header, so detect and report cases where the via header is missing.
+ DataReductionProxyUsageStats::DetectAndRecordMissingViaHeaderResponseCode(
+ !data_reduction_proxy_type_info.proxy_servers.second.is_empty(),
+ original_response_headers);
+
DataReductionProxyTamperDetection::DetectAndReport(
original_response_headers,
data_reduction_proxy_type_info.proxy_servers.first.SchemeIsSecure());
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_protocol_unittest.cc b/components/data_reduction_proxy/browser/data_reduction_proxy_protocol_unittest.cc
index c4c13ee..d54aa86 100644
--- a/components/data_reduction_proxy/browser/data_reduction_proxy_protocol_unittest.cc
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_protocol_unittest.cc
@@ -13,6 +13,7 @@
#include "base/strings/stringprintf.h"
#include "components/data_reduction_proxy/browser/data_reduction_proxy_params_test_utils.h"
#include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
+#include "components/data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.h"
#include "net/base/completion_callback.h"
#include "net/base/host_port_pair.h"
#include "net/base/load_flags.h"
@@ -39,18 +40,6 @@ using net::URLRequest;
using net::TestURLRequestContext;
-namespace {
-// Transform "normal"-looking headers (\n-separated) to the appropriate
-// input format for ParseRawHeaders (\0-separated).
-void HeadersToRaw(std::string* headers) {
- std::replace(headers->begin(), headers->end(), '\n', '\0');
- if (!headers->empty())
- *headers += '\0';
-}
-
-} // namespace
-
-
namespace data_reduction_proxy {
// A test network delegate that exercises the bypass logic of the data
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.cc b/components/data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.cc
index de7d983..e2b1d68 100644
--- a/components/data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.cc
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.cc
@@ -14,6 +14,7 @@
#include "base/time/time.h"
#include "components/data_reduction_proxy/browser/data_reduction_proxy_prefs.h"
#include "components/data_reduction_proxy/browser/data_reduction_proxy_statistics_prefs.h"
+#include "components/data_reduction_proxy/common/data_reduction_proxy_headers_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"
@@ -31,14 +32,6 @@ const char kProxy[] = "proxy";
namespace data_reduction_proxy {
-// Transform "normal"-looking headers (\n-separated) to the appropriate
-// input format for ParseRawHeaders (\0-separated).
-void HeadersToRaw(std::string* headers) {
- std::replace(headers->begin(), headers->end(), '\n', '\0');
- if (!headers->empty())
- *headers += '\0';
-}
-
ProbeURLFetchResult FetchResult(bool enabled, bool success) {
if (enabled) {
if (success)
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_tamper_detection_unittest.cc b/components/data_reduction_proxy/browser/data_reduction_proxy_tamper_detection_unittest.cc
index 6c28806..6f48752 100644
--- a/components/data_reduction_proxy/browser/data_reduction_proxy_tamper_detection_unittest.cc
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_tamper_detection_unittest.cc
@@ -15,6 +15,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
+#include "components/data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.h"
#include "net/http/http_response_headers.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -25,12 +26,6 @@
namespace {
-void HeadersToRaw(std::string* headers) {
- std::replace(headers->begin(), headers->end(), '\n', '\0');
- if (!headers->empty())
- *headers += '\0';
-}
-
// Calcuates MD5 hash value for a string and then base64 encode it. Testcases
// contain expected fingerprint in plain text, which needs to be encoded before
// comparison.
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.cc b/components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.cc
index adda1d3..a7426f5 100644
--- a/components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.cc
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.cc
@@ -9,8 +9,11 @@
#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/histogram.h"
#include "base/metrics/sparse_histogram.h"
+#include "base/prefs/pref_member.h"
#include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
#include "net/base/net_errors.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
#include "net/proxy/proxy_retry_info.h"
#include "net/proxy/proxy_server.h"
#include "net/proxy/proxy_service.h"
@@ -76,6 +79,26 @@ void DataReductionProxyUsageStats::RecordDataReductionProxyBypassInfo(
}
}
+// static
+void DataReductionProxyUsageStats::DetectAndRecordMissingViaHeaderResponseCode(
+ bool is_primary,
+ const net::HttpResponseHeaders* headers) {
+ if (HasDataReductionProxyViaHeader(headers, NULL)) {
+ // The data reduction proxy via header is present, so don't record anything.
+ return;
+ }
+
+ if (is_primary) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "DataReductionProxy.MissingViaHeader.ResponseCode.Primary",
+ headers->response_code());
+ } else {
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "DataReductionProxy.MissingViaHeader.ResponseCode.Fallback",
+ headers->response_code());
+ }
+}
+
DataReductionProxyUsageStats::DataReductionProxyUsageStats(
DataReductionProxyParams* params,
const scoped_refptr<MessageLoopProxy>& ui_thread_proxy)
@@ -145,22 +168,31 @@ void DataReductionProxyUsageStats::SetBypassType(
triggering_request_ = true;
}
+void DataReductionProxyUsageStats::RecordBytesHistograms(
+ net::URLRequest* request,
+ const BooleanPrefMember& data_reduction_proxy_enabled,
+ const net::ProxyConfig& data_reduction_proxy_config) {
+ RecordBypassedBytesHistograms(request, data_reduction_proxy_enabled,
+ data_reduction_proxy_config);
+ RecordMissingViaHeaderBytes(request);
+}
+
void DataReductionProxyUsageStats::RecordBypassedBytesHistograms(
- net::URLRequest& request,
+ net::URLRequest* request,
const BooleanPrefMember& data_reduction_proxy_enabled,
const net::ProxyConfig& data_reduction_proxy_config) {
- int64 content_length = request.received_response_content_length();
+ int64 content_length = request->received_response_content_length();
if (data_reduction_proxy_enabled.GetValue() &&
!data_reduction_proxy_config.Equals(
- request.context()->proxy_service()->config())) {
+ request->context()->proxy_service()->config())) {
RecordBypassedBytes(last_bypass_type_,
DataReductionProxyUsageStats::MANAGED_PROXY_CONFIG,
content_length);
return;
}
- if (data_reduction_proxy_params_->WasDataReductionProxyUsed(&request, NULL)) {
+ if (data_reduction_proxy_params_->WasDataReductionProxyUsed(request, NULL)) {
RecordBypassedBytes(last_bypass_type_,
DataReductionProxyUsageStats::NOT_BYPASSED,
content_length);
@@ -168,7 +200,7 @@ void DataReductionProxyUsageStats::RecordBypassedBytesHistograms(
}
if (data_reduction_proxy_enabled.GetValue() &&
- request.url().SchemeIs(url::kHttpsScheme)) {
+ request->url().SchemeIs(url::kHttpsScheme)) {
RecordBypassedBytes(last_bypass_type_,
DataReductionProxyUsageStats::SSL,
content_length);
@@ -177,7 +209,7 @@ void DataReductionProxyUsageStats::RecordBypassedBytesHistograms(
if (data_reduction_proxy_enabled.GetValue() &&
data_reduction_proxy_params_->IsBypassedByDataReductionProxyLocalRules(
- request, data_reduction_proxy_config)) {
+ *request, data_reduction_proxy_config)) {
RecordBypassedBytes(last_bypass_type_,
DataReductionProxyUsageStats::LOCAL_BYPASS_RULES,
content_length);
@@ -191,7 +223,7 @@ void DataReductionProxyUsageStats::RecordBypassedBytesHistograms(
last_bypass_type_ == BYPASS_EVENT_TYPE_MEDIUM ||
last_bypass_type_ == BYPASS_EVENT_TYPE_LONG)) {
std::string mime_type;
- request.GetMimeType(&mime_type);
+ request->GetMimeType(&mime_type);
// MIME types are named by <media-type>/<subtype>. Check to see if the
// media type is audio or video. Only record when triggered by short bypass,
// there isn't an audio or video bucket for medium or long bypasses.
@@ -218,7 +250,7 @@ void DataReductionProxyUsageStats::RecordBypassedBytesHistograms(
return;
}
- if (data_reduction_proxy_params_->AreDataReductionProxiesBypassed(request,
+ if (data_reduction_proxy_params_->AreDataReductionProxiesBypassed(*request,
NULL)) {
RecordBypassedBytes(last_bypass_type_,
DataReductionProxyUsageStats::NETWORK_ERROR,
@@ -378,6 +410,30 @@ void DataReductionProxyUsageStats::RecordBypassedBytes(
}
}
+void DataReductionProxyUsageStats::RecordMissingViaHeaderBytes(
+ URLRequest* request) {
+ // Responses that were served from cache should have been filtered out
+ // already.
+ DCHECK(!request->was_cached());
+
+ if (!data_reduction_proxy_params_->WasDataReductionProxyUsed(request, NULL) ||
+ HasDataReductionProxyViaHeader(request->response_headers(), NULL)) {
+ // Only track requests that used the data reduction proxy and had responses
+ // that were missing the data reduction proxy via header.
+ return;
+ }
+
+ if (request->GetResponseCode() >= net::HTTP_BAD_REQUEST &&
+ request->GetResponseCode() < net::HTTP_INTERNAL_SERVER_ERROR) {
+ // Track 4xx responses that are missing via headers separately.
+ UMA_HISTOGRAM_COUNTS("DataReductionProxy.MissingViaHeader.Bytes.4xx",
+ request->received_response_content_length());
+ } else {
+ UMA_HISTOGRAM_COUNTS("DataReductionProxy.MissingViaHeader.Bytes.Other",
+ request->received_response_content_length());
+ }
+}
+
} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.h b/components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.h
index 9ab5fef..b56abc6 100644
--- a/components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.h
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.h
@@ -16,6 +16,8 @@
#include "net/url_request/url_request.h"
namespace net {
+class HttpResponseHeaders;
+class ProxyConfig;
class ProxyServer;
}
@@ -33,6 +35,13 @@ class DataReductionProxyUsageStats
const net::ProxyServer& proxy_server,
DataReductionProxyBypassType bypass_type);
+ // For the given response |headers| that are expected to include the data
+ // reduction proxy via header, records response code UMA if the data reduction
+ // proxy via header is not present.
+ static void DetectAndRecordMissingViaHeaderResponseCode(
+ bool is_primary,
+ const net::HttpResponseHeaders* headers);
+
// MessageLoopProxy instance is owned by io_thread. |params| outlives
// this class instance.
DataReductionProxyUsageStats(
@@ -56,12 +65,10 @@ class DataReductionProxyUsageStats
// cause the current bypass.
void SetBypassType(DataReductionProxyBypassType type);
- // Given |data_reduction_proxy_enabled|, a |request|, and the
- // |data_reduction_proxy_config| records the number of bypassed bytes for that
- // |request| into UMAs based on bypass type. |data_reduction_proxy_enabled|
- // tells us the state of the kDataReductionProxyEnabled preference.
- void RecordBypassedBytesHistograms(
- net::URLRequest& request,
+ // Records all the data reduction proxy bytes-related histograms for the
+ // completed URLRequest |request|.
+ void RecordBytesHistograms(
+ net::URLRequest* request,
const BooleanPrefMember& data_reduction_proxy_enabled,
const net::ProxyConfig& data_reduction_proxy_config);
@@ -71,6 +78,10 @@ class DataReductionProxyUsageStats
int net_error);
private:
+ friend class DataReductionProxyUsageStatsTest;
+ FRIEND_TEST_ALL_PREFIXES(DataReductionProxyUsageStatsTest,
+ RecordMissingViaHeaderBytes);
+
enum BypassedBytesType {
NOT_BYPASSED = 0, /* Not bypassed. */
SSL, /* Bypass due to SSL. */
@@ -82,6 +93,20 @@ class DataReductionProxyUsageStats
BYPASSED_BYTES_TYPE_MAX /* This must always be last.*/
};
+ // Given |data_reduction_proxy_enabled|, a |request|, and the
+ // |data_reduction_proxy_config| records the number of bypassed bytes for that
+ // |request| into UMAs based on bypass type. |data_reduction_proxy_enabled|
+ // tells us the state of the kDataReductionProxyEnabled preference.
+ void RecordBypassedBytesHistograms(
+ net::URLRequest* request,
+ const BooleanPrefMember& data_reduction_proxy_enabled,
+ const net::ProxyConfig& data_reduction_proxy_config);
+
+ // Records UMA of the number of response bytes of responses that are expected
+ // to have the data reduction proxy via header, but where the data reduction
+ // proxy via header is not present.
+ void RecordMissingViaHeaderBytes(net::URLRequest* request);
+
// NetworkChangeNotifier::NetworkChangeObserver:
virtual void OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats_unittest.cc b/components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats_unittest.cc
index 2ae4986..b6100fa 100644
--- a/components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats_unittest.cc
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats_unittest.cc
@@ -4,12 +4,21 @@
#include "components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.h"
+#include <string>
+
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/test/histogram_tester.h"
+#include "components/data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.h"
#include "net/base/host_port_pair.h"
#include "net/base/request_priority.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_job_factory_impl.h"
#include "net/url_request/url_request_status.h"
+#include "net/url_request/url_request_test_job.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -49,6 +58,14 @@ class DataReductionProxyUsageStatsTest : public testing::Test {
context_(true),
unavailable_(false) {
context_.Init();
+
+ // The |test_job_factory_| takes ownership of the interceptor.
+ test_job_interceptor_ = new net::TestJobInterceptor();
+ EXPECT_TRUE(test_job_factory_.SetProtocolHandler(url::kHttpScheme,
+ test_job_interceptor_));
+
+ context_.set_job_factory(&test_job_factory_);
+
mock_url_request_ = context_.CreateRequest(GURL(), net::IDLE, &delegate_,
NULL);
}
@@ -57,6 +74,28 @@ class DataReductionProxyUsageStatsTest : public testing::Test {
unavailable_ = unavailable;
}
+ scoped_ptr<net::URLRequest> CreateURLRequestWithResponseHeaders(
+ const GURL& url,
+ const std::string& raw_response_headers) {
+ scoped_ptr<net::URLRequest> fake_request = context_.CreateRequest(
+ url, net::IDLE, &delegate_, NULL);
+
+ // Create a test job that will fill in the given response headers for the
+ // |fake_request|.
+ scoped_refptr<net::URLRequestTestJob> test_job(
+ new net::URLRequestTestJob(fake_request.get(),
+ context_.network_delegate(),
+ raw_response_headers, std::string(), true));
+
+ // Configure the interceptor to use the test job to handle the next request.
+ test_job_interceptor_->set_main_intercept_job(test_job.get());
+ fake_request->Start();
+ base::MessageLoop::current()->RunUntilIdle();
+
+ EXPECT_TRUE(fake_request->response_headers() != NULL);
+ return fake_request.Pass();
+ }
+
// Required for base::MessageLoopProxy::current().
base::MessageLoopForUI loop_;
base::MessageLoopProxy* loop_proxy_;
@@ -66,6 +105,9 @@ class DataReductionProxyUsageStatsTest : public testing::Test {
net::TestDelegate delegate_;
DataReductionProxyParamsMock mock_params_;
scoped_ptr<net::URLRequest> mock_url_request_;
+ // |test_job_interceptor_| is owned by |test_job_factory_|.
+ net::TestJobInterceptor* test_job_interceptor_;
+ net::URLRequestJobFactoryImpl test_job_factory_;
bool unavailable_;
};
@@ -187,4 +229,215 @@ TEST_F(DataReductionProxyUsageStatsTest, ProxyReachableThenUnreachable) {
EXPECT_TRUE(unavailable_);
}
+TEST_F(DataReductionProxyUsageStatsTest,
+ DetectAndRecordMissingViaHeaderResponseCode) {
+ const std::string kPrimaryHistogramName =
+ "DataReductionProxy.MissingViaHeader.ResponseCode.Primary";
+ const std::string kFallbackHistogramName =
+ "DataReductionProxy.MissingViaHeader.ResponseCode.Fallback";
+
+ struct TestCase {
+ bool is_primary;
+ const char* headers;
+ int expected_primary_sample; // -1 indicates no expected sample.
+ int expected_fallback_sample; // -1 indicates no expected sample.
+ };
+ const TestCase test_cases[] = {
+ {
+ true,
+ "HTTP/1.1 200 OK\n"
+ "Via: 1.1 Chrome-Compression-Proxy\n",
+ -1,
+ -1
+ },
+ {
+ false,
+ "HTTP/1.1 200 OK\n"
+ "Via: 1.1 Chrome-Compression-Proxy\n",
+ -1,
+ -1
+ },
+ {
+ true,
+ "HTTP/1.1 200 OK\n",
+ 200,
+ -1
+ },
+ {
+ false,
+ "HTTP/1.1 200 OK\n",
+ -1,
+ 200
+ },
+ {
+ true,
+ "HTTP/1.1 304 Not Modified\n",
+ 304,
+ -1
+ },
+ {
+ false,
+ "HTTP/1.1 304 Not Modified\n",
+ -1,
+ 304
+ },
+ {
+ true,
+ "HTTP/1.1 404 Not Found\n",
+ 404,
+ -1
+ },
+ {
+ false,
+ "HTTP/1.1 404 Not Found\n",
+ -1,
+ 404
+ }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
+ base::HistogramTester histogram_tester;
+ std::string raw_headers(test_cases[i].headers);
+ HeadersToRaw(&raw_headers);
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(raw_headers));
+
+ DataReductionProxyUsageStats::DetectAndRecordMissingViaHeaderResponseCode(
+ test_cases[i].is_primary, headers.get());
+
+ if (test_cases[i].expected_primary_sample == -1) {
+ histogram_tester.ExpectTotalCount(kPrimaryHistogramName, 0);
+ } else {
+ histogram_tester.ExpectUniqueSample(
+ kPrimaryHistogramName, test_cases[i].expected_primary_sample, 1);
+ }
+
+ if (test_cases[i].expected_fallback_sample == -1) {
+ histogram_tester.ExpectTotalCount(kFallbackHistogramName, 0);
+ } else {
+ histogram_tester.ExpectUniqueSample(
+ kFallbackHistogramName, test_cases[i].expected_fallback_sample, 1);
+ }
+ }
+}
+
+TEST_F(DataReductionProxyUsageStatsTest, RecordMissingViaHeaderBytes) {
+ const std::string k4xxHistogramName =
+ "DataReductionProxy.MissingViaHeader.Bytes.4xx";
+ const std::string kOtherHistogramName =
+ "DataReductionProxy.MissingViaHeader.Bytes.Other";
+ const int64 kResponseContentLength = 100;
+
+ struct TestCase {
+ bool was_proxy_used;
+ const char* headers;
+ bool is_4xx_sample_expected;
+ bool is_other_sample_expected;
+ };
+ const TestCase test_cases[] = {
+ // Nothing should be recorded for requests that don't use the proxy.
+ {
+ false,
+ "HTTP/1.1 404 Not Found\n",
+ false,
+ false
+ },
+ {
+ false,
+ "HTTP/1.1 200 OK\n",
+ false,
+ false
+ },
+ // Nothing should be recorded for responses that have the via header.
+ {
+ true,
+ "HTTP/1.1 404 Not Found\n"
+ "Via: 1.1 Chrome-Compression-Proxy\n",
+ false,
+ false
+ },
+ {
+ true,
+ "HTTP/1.1 200 OK\n"
+ "Via: 1.1 Chrome-Compression-Proxy\n",
+ false,
+ false
+ },
+ // 4xx responses that used the proxy and don't have the via header should be
+ // recorded.
+ {
+ true,
+ "HTTP/1.1 404 Not Found\n",
+ true,
+ false
+ },
+ {
+ true,
+ "HTTP/1.1 400 Bad Request\n",
+ true,
+ false
+ },
+ {
+ true,
+ "HTTP/1.1 499 Big Client Error Response Code\n",
+ true,
+ false
+ },
+ // Non-4xx responses that used the proxy and don't have the via header
+ // should be recorded.
+ {
+ true,
+ "HTTP/1.1 200 OK\n",
+ false,
+ true
+ },
+ {
+ true,
+ "HTTP/1.1 399 Big Redirection Response Code\n",
+ false,
+ true
+ },
+ {
+ true,
+ "HTTP/1.1 500 Internal Server Error\n",
+ false,
+ true
+ }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
+ base::HistogramTester histogram_tester;
+ scoped_ptr<DataReductionProxyUsageStats> usage_stats(
+ new DataReductionProxyUsageStats(&mock_params_, loop_proxy_));
+
+ std::string raw_headers(test_cases[i].headers);
+ HeadersToRaw(&raw_headers);
+
+ scoped_ptr<net::URLRequest> fake_request(
+ CreateURLRequestWithResponseHeaders(GURL("http://www.google.com/"),
+ raw_headers));
+ fake_request->set_received_response_content_length(kResponseContentLength);
+
+ EXPECT_CALL(mock_params_,
+ WasDataReductionProxyUsed(fake_request.get(), NULL))
+ .WillRepeatedly(Return(test_cases[i].was_proxy_used));
+
+ usage_stats->RecordMissingViaHeaderBytes(fake_request.get());
+
+ if (test_cases[i].is_4xx_sample_expected) {
+ histogram_tester.ExpectUniqueSample(k4xxHistogramName,
+ kResponseContentLength, 1);
+ } else {
+ histogram_tester.ExpectTotalCount(k4xxHistogramName, 0);
+ }
+
+ if (test_cases[i].is_other_sample_expected) {
+ histogram_tester.ExpectUniqueSample(kOtherHistogramName,
+ kResponseContentLength, 1);
+ } else {
+ histogram_tester.ExpectTotalCount(kOtherHistogramName, 0);
+ }
+ }
+}
+
} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.cc b/components/data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.cc
new file mode 100644
index 0000000..1540c80
--- /dev/null
+++ b/components/data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.cc
@@ -0,0 +1,17 @@
+// 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/common/data_reduction_proxy_headers_test_utils.h"
+
+#include <algorithm>
+
+namespace data_reduction_proxy {
+
+void HeadersToRaw(std::string* headers) {
+ std::replace(headers->begin(), headers->end(), '\n', '\0');
+ if (!headers->empty())
+ *headers += '\0';
+}
+
+} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.h b/components/data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.h
new file mode 100644
index 0000000..143dcd5d
--- /dev/null
+++ b/components/data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.h
@@ -0,0 +1,17 @@
+// 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.
+
+#ifndef COMPONENTS_DATA_REDUCTION_PROXY_COMMON_DATA_REDUCTION_PROXY_HEADERS_TEST_UTILS_H_
+#define COMPONENTS_DATA_REDUCTION_PROXY_COMMON_DATA_REDUCTION_PROXY_HEADERS_TEST_UTILS_H_
+
+#include <string>
+
+namespace data_reduction_proxy {
+
+// Transform "normal"-looking headers (\n-separated) to the appropriate
+// input format for ParseRawHeaders (\0-separated).
+void HeadersToRaw(std::string* headers);
+
+} // namespace data_reduction_proxy
+#endif // COMPONENTS_DATA_REDUCTION_PROXY_COMMON_DATA_REDUCTION_PROXY_HEADERS_TEST_UTILS_H_
diff --git a/components/data_reduction_proxy/common/data_reduction_proxy_headers_unittest.cc b/components/data_reduction_proxy/common/data_reduction_proxy_headers_unittest.cc
index 61bad7e..a8984ce 100644
--- a/components/data_reduction_proxy/common/data_reduction_proxy_headers_unittest.cc
+++ b/components/data_reduction_proxy/common/data_reduction_proxy_headers_unittest.cc
@@ -6,22 +6,11 @@
#include <vector>
+#include "components/data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.h"
#include "net/http/http_response_headers.h"
#include "net/proxy/proxy_service.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace {
-
-// Transform "normal"-looking headers (\n-separated) to the appropriate
-// input format for ParseRawHeaders (\0-separated).
-void HeadersToRaw(std::string* headers) {
- std::replace(headers->begin(), headers->end(), '\n', '\0');
- if (!headers->empty())
- *headers += '\0';
-}
-
-} // namespace
-
namespace data_reduction_proxy {
class DataReductionProxyHeadersTest : public testing::Test {};
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 0c722c2..6feef49 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -3582,6 +3582,27 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</summary>
</histogram>
+<histogram name="DataReductionProxy.MissingViaHeader.Bytes" units="bytes">
+ <owner>bengr@chromium.org</owner>
+ <owner>sclittle@chromium.org</owner>
+ <summary>
+ Counts the response bytes of responses that Chrome expected to come through
+ a data reduction proxy and have the data reduction proxy via header, but
+ where the data reduction proxy via header was missing. Note that this does
+ not include responses that were bypassed.
+ </summary>
+</histogram>
+
+<histogram name="DataReductionProxy.MissingViaHeader.ResponseCode">
+ <owner>bengr@chromium.org</owner>
+ <owner>sclittle@chromium.org</owner>
+ <summary>
+ Counts the different HTTP response codes of responses that Chrome expected
+ to come through a data reduction proxy and have the data reduction proxy via
+ header, but where the data reduction proxy via header was missing.
+ </summary>
+</histogram>
+
<histogram name="DataReductionProxy.NetworkChangeEvents"
enum="DataReductionProxyNetworkChangeEvent">
<owner>bengr@chromium.org</owner>
@@ -53121,6 +53142,20 @@ To add a new entry, add it with any value and run test to compute valid value.
<affected-histogram name="DataReductionProxy.BypassedBytes"/>
</histogram_suffixes>
+<histogram_suffixes name="DataReductionProxyMissingViaHeaderBytes"
+ separator=".">
+ <suffix name="4xx" label="Response with 4xx response code"/>
+ <suffix name="Other" label="Other response"/>
+ <affected-histogram name="DataReductionProxy.MissingViaHeader.Bytes"/>
+</histogram_suffixes>
+
+<histogram_suffixes name="DataReductionProxyMissingViaHeaderResponseCode"
+ separator=".">
+ <suffix name="Primary" label="Primary data reduction proxy"/>
+ <suffix name="Fallback" label="Fallback data reduction proxy"/>
+ <affected-histogram name="DataReductionProxy.MissingViaHeader.ResponseCode"/>
+</histogram_suffixes>
+
<histogram_suffixes name="DefaultAppsExperiment">
<suffix name="NoDefaultApps" label="User's without default apps installed"/>
<suffix name="WithDefaultApps" label="User's with default apps installed"/>