Coalesce payload length statistics in ChromeNetworkDelegate

BUG=


Review URL: https://chromiumcodereview.appspot.com/11137022

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@163956 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
index 0c406d3..b99c700 100644
--- a/chrome/browser/net/chrome_network_delegate.cc
+++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -4,8 +4,9 @@
 
 #include "chrome/browser/net/chrome_network_delegate.h"
 
-#include "base/logging.h"
 #include "base/base_paths.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
 #include "base/path_service.h"
 #include "chrome/browser/api/prefs/pref_member.h"
 #include "chrome/browser/browser_process.h"
@@ -136,6 +137,54 @@
   }
 }
 
+void UpdateContentLengthPrefs(int received_content_length,
+                              int original_content_length) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK_GE(received_content_length, 0);
+  DCHECK_GE(original_content_length, 0);
+
+  PrefService* prefs = g_browser_process->local_state();
+
+  int64 total_received = prefs->GetInt64(prefs::kHttpReceivedContentLength);
+  int64 total_original = prefs->GetInt64(prefs::kHttpOriginalContentLength);
+  total_received += received_content_length;
+  total_original += original_content_length;
+  prefs->SetInt64(prefs::kHttpReceivedContentLength, total_received);
+  prefs->SetInt64(prefs::kHttpOriginalContentLength, total_original);
+}
+
+void StoreAccumulatedContentLength(int received_content_length,
+                                   int original_content_length) {
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+      base::Bind(&UpdateContentLengthPrefs,
+                 received_content_length, original_content_length));
+}
+
+void RecordContentLengthHistograms(
+    int64 received_content_length, int64 original_content_length) {
+#if defined(OS_ANDROID)
+  // Add the current resource to these histograms only when a valid
+  // X-Original-Content-Length header is present.
+  if (original_content_length >= 0) {
+    UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthWithValidOCL",
+                         received_content_length);
+    UMA_HISTOGRAM_COUNTS("Net.HttpOriginalContentLengthWithValidOCL",
+                         original_content_length);
+    UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthDifferenceWithValidOCL",
+                         original_content_length - received_content_length);
+  } else {
+    // Presume the original content length is the same as the received content
+    // length if the X-Original-Content-Header is not present.
+    original_content_length = received_content_length;
+  }
+  UMA_HISTOGRAM_COUNTS("Net.HttpContentLength", received_content_length);
+  UMA_HISTOGRAM_COUNTS("Net.HttpOriginalContentLength",
+                       original_content_length);
+  UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthDifference",
+                       original_content_length - received_content_length);
+#endif
+}
+
 }  // namespace
 
 ChromeNetworkDelegate::ChromeNetworkDelegate(
@@ -156,7 +205,9 @@
       enable_do_not_track_(enable_do_not_track),
       url_blacklist_manager_(url_blacklist_manager),
       managed_mode_url_filter_(managed_mode_url_filter),
-      load_time_stats_(load_time_stats) {
+      load_time_stats_(load_time_stats),
+      received_content_length_(0),
+      original_content_length_(0) {
   DCHECK(event_router);
   DCHECK(enable_referrers);
   DCHECK(!profile || cookie_settings);
@@ -190,6 +241,26 @@
   g_allow_file_access_ = true;
 }
 
+// static
+Value* ChromeNetworkDelegate::HistoricNetworkStatsInfoToValue() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  PrefService* prefs = g_browser_process->local_state();
+  int64 total_received = prefs->GetInt64(prefs::kHttpReceivedContentLength);
+  int64 total_original = prefs->GetInt64(prefs::kHttpOriginalContentLength);
+
+  DictionaryValue* dict = new DictionaryValue();
+  dict->SetInteger("historic_received_content_length", total_received);
+  dict->SetInteger("historic_original_content_length", total_original);
+  return dict;
+}
+
+Value* ChromeNetworkDelegate::SessionNetworkStatsInfoToValue() const {
+  DictionaryValue* dict = new DictionaryValue();
+  dict->SetInteger("session_received_content_length", received_content_length_);
+  dict->SetInteger("session_original_content_length", original_content_length_);
+  return dict;
+}
+
 int ChromeNetworkDelegate::OnBeforeURLRequest(
     net::URLRequest* request,
     const net::CompletionCallback& callback,
@@ -278,6 +349,36 @@
 void ChromeNetworkDelegate::OnCompleted(net::URLRequest* request,
                                         bool started) {
   if (request->status().status() == net::URLRequestStatus::SUCCESS) {
+    // For better accuracy, we use the actual bytes read instead of the length
+    // specified with the Content-Length header, which may be inaccurate,
+    // or missing, as is the case with chunked encoding.
+    int64 received_content_length = request->received_response_content_length();
+
+    // Only record for http or https urls.
+    bool is_http = request->url().SchemeIs("http");
+    bool is_https = request->url().SchemeIs("https");
+
+    if (!request->was_cached() &&         // Don't record cached content
+        received_content_length &&        // Zero-byte responses aren't useful.
+        (is_http || is_https)) {          // Only record for HTTP or HTTPS urls.
+      int64 original_content_length =
+          request->response_info().headers->GetInt64HeaderValue(
+              "x-original-content-length");
+      // Since there was no indication of the original content length, presume
+      // it is no different from the number of bytes read.
+      int64 adjusted_original_content_length = original_content_length;
+      if (adjusted_original_content_length == -1)
+        adjusted_original_content_length = received_content_length;
+      AccumulateContentLength(received_content_length,
+                              adjusted_original_content_length);
+      RecordContentLengthHistograms(received_content_length,
+                                    original_content_length);
+      DVLOG(2) << __FUNCTION__
+          << " received content length: " << received_content_length
+          << " original content length: " << original_content_length
+          << " url: " << request->url();
+    }
+
     bool is_redirect = request->response_headers() &&
         net::HttpResponseHeaders::IsRedirectResponseCode(
             request->response_headers()->response_code());
@@ -459,3 +560,13 @@
   if (load_time_stats_)
     load_time_stats_->OnRequestWaitStateChange(request, state);
 }
+
+void ChromeNetworkDelegate::AccumulateContentLength(
+    int64 received_content_length, int64 original_content_length) {
+  DCHECK_GE(received_content_length, 0);
+  DCHECK_GE(original_content_length, 0);
+  StoreAccumulatedContentLength(received_content_length,
+                                original_content_length);
+  received_content_length_ += received_content_length;
+  original_content_length_ += original_content_length;
+}