summaryrefslogtreecommitdiffstats
path: root/components/data_reduction_proxy
diff options
context:
space:
mode:
authorsclittle <sclittle@chromium.org>2014-09-23 16:22:00 -0700
committerCommit bot <commit-bot@chromium.org>2014-09-23 23:22:29 +0000
commitba1e1e3f7ea6edae987e6cfa92086807bf74260b (patch)
treeccf0234968f5f8e884cac150875034577cc52f04 /components/data_reduction_proxy
parent46cbfd62f398472650985747d459bb7869578918 (diff)
downloadchromium_src-ba1e1e3f7ea6edae987e6cfa92086807bf74260b.zip
chromium_src-ba1e1e3f7ea6edae987e6cfa92086807bf74260b.tar.gz
chromium_src-ba1e1e3f7ea6edae987e6cfa92086807bf74260b.tar.bz2
Adds UMA to measure when the data reduction proxy via header is missing
Keep track of the situations when Chrome expects the data reduction proxy via header to be present in a response, but the data reduction proxy via header is missing. BUG=412888 Review URL: https://codereview.chromium.org/577343002 Cr-Commit-Position: refs/heads/master@{#296297}
Diffstat (limited to 'components/data_reduction_proxy')
-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.cc252
-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
10 files changed, 391 insertions, 52 deletions
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..e873bf8 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,13 @@ 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();
+ DCHECK(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 +73,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();
+
+ DCHECK(fake_request->response_headers() != NULL);
+ return fake_request.Pass();
+ }
+
// Required for base::MessageLoopProxy::current().
base::MessageLoopForUI loop_;
base::MessageLoopProxy* loop_proxy_;
@@ -66,6 +104,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 +228,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 {};