Home | History | Annotate | Download | only in browser
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "components/data_reduction_proxy/browser/data_reduction_proxy_settings.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/metrics/field_trial.h"
     10 #include "base/metrics/histogram.h"
     11 #include "base/prefs/pref_member.h"
     12 #include "base/prefs/pref_service.h"
     13 #include "base/prefs/scoped_user_pref_update.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "base/strings/string_util.h"
     16 #include "base/strings/stringprintf.h"
     17 #include "base/strings/utf_string_conversions.h"
     18 #include "components/data_reduction_proxy/browser/data_reduction_proxy_configurator.h"
     19 #include "components/data_reduction_proxy/browser/data_reduction_proxy_params.h"
     20 #include "components/data_reduction_proxy/common/data_reduction_proxy_pref_names.h"
     21 #include "components/data_reduction_proxy/common/data_reduction_proxy_switches.h"
     22 #include "crypto/random.h"
     23 #include "net/base/auth.h"
     24 #include "net/base/host_port_pair.h"
     25 #include "net/base/load_flags.h"
     26 #include "net/base/net_errors.h"
     27 #include "net/http/http_auth.h"
     28 #include "net/http/http_auth_cache.h"
     29 #include "net/http/http_network_session.h"
     30 #include "net/http/http_response_headers.h"
     31 #include "net/url_request/url_fetcher.h"
     32 #include "net/url_request/url_fetcher_delegate.h"
     33 #include "net/url_request/url_request_context_getter.h"
     34 #include "net/url_request/url_request_status.h"
     35 #include "url/gurl.h"
     36 
     37 
     38 using base::StringPrintf;
     39 
     40 namespace {
     41 
     42 // Key of the UMA DataReductionProxy.StartupState histogram.
     43 const char kUMAProxyStartupStateHistogram[] =
     44     "DataReductionProxy.StartupState";
     45 
     46 // Key of the UMA DataReductionProxy.ProbeURL histogram.
     47 const char kUMAProxyProbeURL[] = "DataReductionProxy.ProbeURL";
     48 
     49 // TODO(marq): Factor this string out into a constant here and in
     50 //             http_auth_handler_spdyproxy.
     51 const char kAuthenticationRealmName[] = "SpdyProxy";
     52 
     53 int64 GetInt64PrefValue(const base::ListValue& list_value, size_t index) {
     54   int64 val = 0;
     55   std::string pref_value;
     56   bool rv = list_value.GetString(index, &pref_value);
     57   DCHECK(rv);
     58   if (rv) {
     59     rv = base::StringToInt64(pref_value, &val);
     60     DCHECK(rv);
     61   }
     62   return val;
     63 }
     64 
     65 }  // namespace
     66 
     67 namespace data_reduction_proxy {
     68 
     69 DataReductionProxySettings::DataReductionProxySettings(
     70     DataReductionProxyParams* params)
     71     : restricted_by_carrier_(false),
     72       enabled_by_user_(false),
     73       prefs_(NULL),
     74       local_state_prefs_(NULL),
     75       url_request_context_getter_(NULL) {
     76   DCHECK(params);
     77   params_.reset(params);
     78 }
     79 
     80 DataReductionProxySettings::~DataReductionProxySettings() {
     81   if (params_->allowed())
     82     spdy_proxy_auth_enabled_.Destroy();
     83 }
     84 
     85 void DataReductionProxySettings::InitPrefMembers() {
     86   DCHECK(thread_checker_.CalledOnValidThread());
     87   spdy_proxy_auth_enabled_.Init(
     88       prefs::kDataReductionProxyEnabled,
     89       GetOriginalProfilePrefs(),
     90       base::Bind(&DataReductionProxySettings::OnProxyEnabledPrefChange,
     91                  base::Unretained(this)));
     92   data_reduction_proxy_alternative_enabled_.Init(
     93       prefs::kDataReductionProxyAltEnabled,
     94       GetOriginalProfilePrefs(),
     95       base::Bind(
     96           &DataReductionProxySettings::OnProxyAlternativeEnabledPrefChange,
     97           base::Unretained(this)));
     98 }
     99 
    100 void DataReductionProxySettings::InitDataReductionProxySettings(
    101     PrefService* prefs,
    102     PrefService* local_state_prefs,
    103     net::URLRequestContextGetter* url_request_context_getter) {
    104   DCHECK(thread_checker_.CalledOnValidThread());
    105   DCHECK(prefs);
    106   DCHECK(local_state_prefs);
    107   DCHECK(url_request_context_getter);
    108   prefs_ = prefs;
    109   local_state_prefs_ = local_state_prefs;
    110   url_request_context_getter_ = url_request_context_getter;
    111   InitPrefMembers();
    112   RecordDataReductionInit();
    113 
    114   // Disable the proxy if it is not allowed to be used.
    115   if (!params_->allowed())
    116     return;
    117 
    118   AddDefaultProxyBypassRules();
    119   net::NetworkChangeNotifier::AddIPAddressObserver(this);
    120 
    121   // We set or reset the proxy pref at startup.
    122   MaybeActivateDataReductionProxy(true);
    123 }
    124 
    125 void DataReductionProxySettings::InitDataReductionProxySettings(
    126     PrefService* prefs,
    127     PrefService* local_state_prefs,
    128     net::URLRequestContextGetter* url_request_context_getter,
    129     scoped_ptr<DataReductionProxyConfigurator> configurator) {
    130   InitDataReductionProxySettings(prefs,
    131                                  local_state_prefs,
    132                                  url_request_context_getter);
    133   SetProxyConfigurator(configurator.Pass());
    134 }
    135 
    136 void DataReductionProxySettings::SetProxyConfigurator(
    137     scoped_ptr<DataReductionProxyConfigurator> configurator) {
    138   DCHECK(configurator);
    139   configurator_ = configurator.Pass();
    140 }
    141 
    142 // static
    143 void DataReductionProxySettings::InitDataReductionProxySession(
    144     net::HttpNetworkSession* session,
    145     const DataReductionProxyParams* params) {
    146 // This is a no-op unless the authentication parameters are compiled in.
    147 // (even though values for them may be specified on the command line).
    148 // Authentication will still work if the command line parameters are used,
    149 // however there will be a round-trip overhead for each challenge/response
    150 // (typically once per session).
    151 // TODO(bengr):Pass a configuration struct into DataReductionProxyConfigurator's
    152 // constructor. The struct would carry everything in the preprocessor flags.
    153   DCHECK(session);
    154   net::HttpAuthCache* auth_cache = session->http_auth_cache();
    155   DCHECK(auth_cache);
    156   InitDataReductionAuthentication(auth_cache, params);
    157 }
    158 
    159 // static
    160 void DataReductionProxySettings::InitDataReductionAuthentication(
    161     net::HttpAuthCache* auth_cache,
    162     const DataReductionProxyParams* params) {
    163   DCHECK(auth_cache);
    164   DCHECK(params);
    165   int64 timestamp =
    166       (base::Time::Now() - base::Time::UnixEpoch()).InMilliseconds() / 1000;
    167 
    168   DataReductionProxyParams::DataReductionProxyList proxies =
    169       params->GetAllowedProxies();
    170   for (DataReductionProxyParams::DataReductionProxyList::iterator it =
    171            proxies.begin();
    172        it != proxies.end(); ++it) {
    173     GURL auth_origin = (*it).GetOrigin();
    174 
    175     int32 rand[3];
    176     crypto::RandBytes(rand, 3 * sizeof(rand[0]));
    177 
    178     std::string realm =
    179         base::StringPrintf("%s%lld", kAuthenticationRealmName,
    180                            static_cast<long long>(timestamp));
    181     std::string challenge = base::StringPrintf(
    182         "%s realm=\"%s\", ps=\"%lld-%u-%u-%u\"",
    183         kAuthenticationRealmName,
    184         realm.data(),
    185         static_cast<long long>(timestamp),
    186         rand[0],
    187         rand[1],
    188         rand[2]);
    189     base::string16 password = AuthHashForSalt(timestamp, params->key());
    190 
    191     DVLOG(1) << "origin: [" << auth_origin << "] realm: [" << realm
    192         << "] challenge: [" << challenge << "] password: [" << password << "]";
    193 
    194     net::AuthCredentials credentials(base::string16(), password);
    195     // |HttpAuthController| searches this cache by origin and path, the latter
    196     // being '/' in the case of the data reduction proxy.
    197     auth_cache->Add(auth_origin,
    198                     realm,
    199                     net::HttpAuth::AUTH_SCHEME_SPDYPROXY,
    200                     challenge,
    201                     credentials,
    202                     std::string("/"));
    203   }
    204 }
    205 
    206 bool DataReductionProxySettings::IsAcceptableAuthChallenge(
    207     net::AuthChallengeInfo* auth_info) {
    208   // Challenge realm must start with the authentication realm name.
    209   std::string realm_prefix =
    210       auth_info->realm.substr(0, strlen(kAuthenticationRealmName));
    211   if (realm_prefix != kAuthenticationRealmName)
    212     return false;
    213 
    214   // The challenger must be one of the configured proxies.
    215   DataReductionProxyParams::DataReductionProxyList proxies =
    216       params_->GetAllowedProxies();
    217   for (DataReductionProxyParams::DataReductionProxyList::iterator it =
    218        proxies.begin();
    219        it != proxies.end(); ++it) {
    220     net::HostPortPair origin_host = net::HostPortPair::FromURL(*it);
    221     if (origin_host.Equals(auth_info->challenger))
    222       return true;
    223   }
    224   return false;
    225 }
    226 
    227 base::string16 DataReductionProxySettings::GetTokenForAuthChallenge(
    228     net::AuthChallengeInfo* auth_info) {
    229   if (auth_info->realm.length() > strlen(kAuthenticationRealmName)) {
    230     int64 salt;
    231     std::string realm_suffix =
    232         auth_info->realm.substr(strlen(kAuthenticationRealmName));
    233     if (base::StringToInt64(realm_suffix, &salt)) {
    234       return AuthHashForSalt(salt, params_->key());
    235     } else {
    236       DVLOG(1) << "Unable to parse realm name " << auth_info->realm
    237                << "into an int for salting.";
    238       return base::string16();
    239     }
    240   } else {
    241     return base::string16();
    242   }
    243 }
    244 
    245 bool DataReductionProxySettings::IsDataReductionProxyEnabled() {
    246   // We should not check for DataReductionProxyParams::IsKeySetOnCommandLine()
    247   // here because when we enable drp in cmd and supply a wrong key to drp,
    248   // drp is supposed to disable itself and fallback to direct loading after
    249   // repeated authentication failures.
    250   return spdy_proxy_auth_enabled_.GetValue();
    251 }
    252 
    253 bool
    254 DataReductionProxySettings::IsDataReductionProxyAlternativeEnabled() const {
    255   return data_reduction_proxy_alternative_enabled_.GetValue();
    256 }
    257 
    258 bool DataReductionProxySettings::IsDataReductionProxyManaged() {
    259   return spdy_proxy_auth_enabled_.IsManaged();
    260 }
    261 
    262 void DataReductionProxySettings::SetDataReductionProxyEnabled(bool enabled) {
    263   DCHECK(thread_checker_.CalledOnValidThread());
    264   // Prevent configuring the proxy when it is not allowed to be used.
    265   if (!params_->allowed())
    266     return;
    267 
    268   if (spdy_proxy_auth_enabled_.GetValue() != enabled) {
    269     spdy_proxy_auth_enabled_.SetValue(enabled);
    270     OnProxyEnabledPrefChange();
    271   }
    272 }
    273 
    274 void DataReductionProxySettings::SetDataReductionProxyAlternativeEnabled(
    275     bool enabled) {
    276   DCHECK(thread_checker_.CalledOnValidThread());
    277   // Prevent configuring the proxy when it is not allowed to be used.
    278   if (!params_->alternative_allowed())
    279     return;
    280   if (data_reduction_proxy_alternative_enabled_.GetValue() != enabled) {
    281     data_reduction_proxy_alternative_enabled_.SetValue(enabled);
    282     OnProxyAlternativeEnabledPrefChange();
    283   }
    284 }
    285 
    286 int64 DataReductionProxySettings::GetDataReductionLastUpdateTime() {
    287   DCHECK(thread_checker_.CalledOnValidThread());
    288   PrefService* local_state = GetLocalStatePrefs();
    289   int64 last_update_internal =
    290       local_state->GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate);
    291   base::Time last_update = base::Time::FromInternalValue(last_update_internal);
    292   return static_cast<int64>(last_update.ToJsTime());
    293 }
    294 
    295 DataReductionProxySettings::ContentLengthList
    296 DataReductionProxySettings::GetDailyOriginalContentLengths() {
    297   DCHECK(thread_checker_.CalledOnValidThread());
    298   return GetDailyContentLengths(prefs::kDailyHttpOriginalContentLength);
    299 }
    300 
    301 DataReductionProxySettings::ContentLengthList
    302 DataReductionProxySettings::GetDailyReceivedContentLengths() {
    303   DCHECK(thread_checker_.CalledOnValidThread());
    304   return GetDailyContentLengths(prefs::kDailyHttpReceivedContentLength);
    305 }
    306 
    307 void DataReductionProxySettings::OnURLFetchComplete(
    308     const net::URLFetcher* source) {
    309   DCHECK(thread_checker_.CalledOnValidThread());
    310 
    311   // The purpose of sending a request for the warmup URL is to warm the
    312   // connection to the data_reduction_proxy. The result is ignored.
    313   if (source == warmup_fetcher_.get())
    314     return;
    315 
    316   DCHECK(source == fetcher_.get());
    317   net::URLRequestStatus status = source->GetStatus();
    318   if (status.status() == net::URLRequestStatus::FAILED &&
    319       status.error() == net::ERR_INTERNET_DISCONNECTED) {
    320     RecordProbeURLFetchResult(INTERNET_DISCONNECTED);
    321     return;
    322   }
    323 
    324   std::string response;
    325   source->GetResponseAsString(&response);
    326 
    327   if ("OK" == response.substr(0, 2)) {
    328     DVLOG(1) << "The data reduction proxy is unrestricted.";
    329 
    330     if (enabled_by_user_) {
    331       if (restricted_by_carrier_) {
    332         // The user enabled the proxy, but sometime previously in the session,
    333         // the network operator had blocked the canary and restricted the user.
    334         // The current network doesn't block the canary, so don't restrict the
    335         // proxy configurations.
    336         SetProxyConfigs(true /* enabled */,
    337                         IsDataReductionProxyAlternativeEnabled(),
    338                         false /* restricted */,
    339                         false /* at_startup */);
    340         RecordProbeURLFetchResult(SUCCEEDED_PROXY_ENABLED);
    341       } else {
    342         RecordProbeURLFetchResult(SUCCEEDED_PROXY_ALREADY_ENABLED);
    343       }
    344     }
    345     restricted_by_carrier_ = false;
    346     return;
    347   }
    348   DVLOG(1) << "The data reduction proxy is restricted to the configured "
    349            << "fallback proxy.";
    350   if (enabled_by_user_) {
    351     if (!restricted_by_carrier_) {
    352       // Restrict the proxy.
    353       SetProxyConfigs(true /* enabled */,
    354                       IsDataReductionProxyAlternativeEnabled(),
    355                       true /* restricted */,
    356                       false /* at_startup */);
    357       RecordProbeURLFetchResult(FAILED_PROXY_DISABLED);
    358     } else {
    359       RecordProbeURLFetchResult(FAILED_PROXY_ALREADY_DISABLED);
    360     }
    361   }
    362   restricted_by_carrier_ = true;
    363 }
    364 
    365 PrefService* DataReductionProxySettings::GetOriginalProfilePrefs() {
    366   DCHECK(thread_checker_.CalledOnValidThread());
    367   return prefs_;
    368 }
    369 
    370 PrefService* DataReductionProxySettings::GetLocalStatePrefs() {
    371   DCHECK(thread_checker_.CalledOnValidThread());
    372   return local_state_prefs_;
    373 }
    374 
    375 void DataReductionProxySettings::AddDefaultProxyBypassRules() {
    376   // localhost
    377   configurator_->AddHostPatternToBypass("<local>");
    378   // RFC1918 private addresses.
    379   configurator_->AddHostPatternToBypass("10.0.0.0/8");
    380   configurator_->AddHostPatternToBypass("172.16.0.0/12");
    381   configurator_->AddHostPatternToBypass("192.168.0.0/16");
    382   // RFC4193 private addresses.
    383   configurator_->AddHostPatternToBypass("fc00::/7");
    384   // IPV6 probe addresses.
    385   configurator_->AddHostPatternToBypass("*-ds.metric.gstatic.com");
    386   configurator_->AddHostPatternToBypass("*-v4.metric.gstatic.com");
    387 }
    388 
    389 void DataReductionProxySettings::LogProxyState(
    390     bool enabled, bool restricted, bool at_startup) {
    391   // This must stay a LOG(WARNING); the output is used in processing customer
    392   // feedback.
    393   const char kAtStartup[] = "at startup";
    394   const char kByUser[] = "by user action";
    395   const char kOn[] = "ON";
    396   const char kOff[] = "OFF";
    397   const char kRestricted[] = "(Restricted)";
    398   const char kUnrestricted[] = "(Unrestricted)";
    399 
    400   std::string annotated_on =
    401       kOn + std::string(" ") + (restricted ? kRestricted : kUnrestricted);
    402 
    403   LOG(WARNING) << "SPDY proxy " << (enabled ? annotated_on : kOff)
    404                << " " << (at_startup ? kAtStartup : kByUser);
    405 }
    406 
    407 void DataReductionProxySettings::OnIPAddressChanged() {
    408   DCHECK(thread_checker_.CalledOnValidThread());
    409   if (enabled_by_user_) {
    410     DCHECK(params_->allowed());
    411     ProbeWhetherDataReductionProxyIsAvailable();
    412     WarmProxyConnection();
    413   }
    414 }
    415 
    416 void DataReductionProxySettings::OnProxyEnabledPrefChange() {
    417   DCHECK(thread_checker_.CalledOnValidThread());
    418   if (!params_->allowed())
    419     return;
    420   MaybeActivateDataReductionProxy(false);
    421 }
    422 
    423 void DataReductionProxySettings::OnProxyAlternativeEnabledPrefChange() {
    424   DCHECK(thread_checker_.CalledOnValidThread());
    425   if (!params_->alternative_allowed())
    426     return;
    427   MaybeActivateDataReductionProxy(false);
    428 }
    429 
    430 void DataReductionProxySettings::ResetDataReductionStatistics() {
    431   DCHECK(thread_checker_.CalledOnValidThread());
    432   PrefService* prefs = GetLocalStatePrefs();
    433   if (!prefs)
    434     return;
    435   ListPrefUpdate original_update(prefs, prefs::kDailyHttpOriginalContentLength);
    436   ListPrefUpdate received_update(prefs, prefs::kDailyHttpReceivedContentLength);
    437   original_update->Clear();
    438   received_update->Clear();
    439   for (size_t i = 0; i < kNumDaysInHistory; ++i) {
    440     original_update->AppendString(base::Int64ToString(0));
    441     received_update->AppendString(base::Int64ToString(0));
    442   }
    443 }
    444 
    445 void DataReductionProxySettings::MaybeActivateDataReductionProxy(
    446     bool at_startup) {
    447   DCHECK(thread_checker_.CalledOnValidThread());
    448   PrefService* prefs = GetOriginalProfilePrefs();
    449   // TODO(marq): Consider moving this so stats are wiped the first time the
    450   // proxy settings are actually (not maybe) turned on.
    451   if (spdy_proxy_auth_enabled_.GetValue() &&
    452       !prefs->GetBoolean(prefs::kDataReductionProxyWasEnabledBefore)) {
    453     prefs->SetBoolean(prefs::kDataReductionProxyWasEnabledBefore, true);
    454     ResetDataReductionStatistics();
    455   }
    456 
    457   // Configure use of the data reduction proxy if it is enabled.
    458   enabled_by_user_= IsDataReductionProxyEnabled();
    459   SetProxyConfigs(enabled_by_user_,
    460                   IsDataReductionProxyAlternativeEnabled(),
    461                   restricted_by_carrier_,
    462                   at_startup);
    463 
    464   // Check if the proxy has been restricted explicitly by the carrier.
    465   if (enabled_by_user_) {
    466     ProbeWhetherDataReductionProxyIsAvailable();
    467     WarmProxyConnection();
    468   }
    469 }
    470 
    471 void DataReductionProxySettings::SetProxyConfigs(bool enabled,
    472                                                  bool alternative_enabled,
    473                                                  bool restricted,
    474                                                  bool at_startup) {
    475   DCHECK(thread_checker_.CalledOnValidThread());
    476   LogProxyState(enabled, restricted, at_startup);
    477   // The alternative is only configured if the standard configuration is
    478   // is enabled.
    479   if (enabled) {
    480     if (alternative_enabled) {
    481       configurator_->Enable(restricted,
    482                             !params_->fallback_allowed(),
    483                             params_->alt_origin().spec(),
    484                             params_->alt_fallback_origin().spec(),
    485                             params_->ssl_origin().spec());
    486     } else {
    487       configurator_->Enable(restricted,
    488                             !params_->fallback_allowed(),
    489                             params_->origin().spec(),
    490                             params_->fallback_origin().spec(),
    491                             std::string());
    492     }
    493   } else {
    494     configurator_->Disable();
    495   }
    496 }
    497 
    498 // Metrics methods
    499 void DataReductionProxySettings::RecordDataReductionInit() {
    500   DCHECK(thread_checker_.CalledOnValidThread());
    501   ProxyStartupState state = PROXY_NOT_AVAILABLE;
    502   if (params_->allowed()) {
    503     if (IsDataReductionProxyEnabled())
    504       state = PROXY_ENABLED;
    505     else
    506       state = PROXY_DISABLED;
    507   }
    508 
    509   RecordStartupState(state);
    510 }
    511 
    512 void DataReductionProxySettings::RecordProbeURLFetchResult(
    513     ProbeURLFetchResult result) {
    514   UMA_HISTOGRAM_ENUMERATION(kUMAProxyProbeURL,
    515                             result,
    516                             PROBE_URL_FETCH_RESULT_COUNT);
    517 }
    518 
    519 void DataReductionProxySettings::RecordStartupState(ProxyStartupState state) {
    520   UMA_HISTOGRAM_ENUMERATION(kUMAProxyStartupStateHistogram,
    521                             state,
    522                             PROXY_STARTUP_STATE_COUNT);
    523 }
    524 
    525 void DataReductionProxySettings::ResetParamsForTest(
    526     DataReductionProxyParams* params) {
    527   params_.reset(params);
    528 }
    529 
    530 DataReductionProxySettings::ContentLengthList
    531 DataReductionProxySettings::GetDailyContentLengths(const char* pref_name) {
    532   DCHECK(thread_checker_.CalledOnValidThread());
    533   DataReductionProxySettings::ContentLengthList content_lengths;
    534   const base::ListValue* list_value = GetLocalStatePrefs()->GetList(pref_name);
    535   if (list_value->GetSize() == kNumDaysInHistory) {
    536     for (size_t i = 0; i < kNumDaysInHistory; ++i) {
    537       content_lengths.push_back(GetInt64PrefValue(*list_value, i));
    538     }
    539   }
    540   return content_lengths;
    541 }
    542 
    543 void DataReductionProxySettings::GetContentLengths(
    544     unsigned int days,
    545     int64* original_content_length,
    546     int64* received_content_length,
    547     int64* last_update_time) {
    548   DCHECK(thread_checker_.CalledOnValidThread());
    549   DCHECK_LE(days, kNumDaysInHistory);
    550   PrefService* local_state = GetLocalStatePrefs();
    551   if (!local_state) {
    552     *original_content_length = 0L;
    553     *received_content_length = 0L;
    554     *last_update_time = 0L;
    555     return;
    556   }
    557 
    558   const base::ListValue* original_list =
    559       local_state->GetList(prefs::kDailyHttpOriginalContentLength);
    560   const base::ListValue* received_list =
    561       local_state->GetList(prefs::kDailyHttpReceivedContentLength);
    562 
    563   if (original_list->GetSize() != kNumDaysInHistory ||
    564       received_list->GetSize() != kNumDaysInHistory) {
    565     *original_content_length = 0L;
    566     *received_content_length = 0L;
    567     *last_update_time = 0L;
    568     return;
    569   }
    570 
    571   int64 orig = 0L;
    572   int64 recv = 0L;
    573   // Include days from the end of the list going backwards.
    574   for (size_t i = kNumDaysInHistory - days;
    575        i < kNumDaysInHistory; ++i) {
    576     orig += GetInt64PrefValue(*original_list, i);
    577     recv += GetInt64PrefValue(*received_list, i);
    578   }
    579   *original_content_length = orig;
    580   *received_content_length = recv;
    581   *last_update_time =
    582       local_state->GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate);
    583 }
    584 
    585 // static
    586 base::string16 DataReductionProxySettings::AuthHashForSalt(
    587     int64 salt,
    588     const std::string& key) {
    589   std::string salted_key =
    590       base::StringPrintf("%lld%s%lld",
    591                          static_cast<long long>(salt),
    592                          key.c_str(),
    593                          static_cast<long long>(salt));
    594   return base::UTF8ToUTF16(base::MD5String(salted_key));
    595 }
    596 
    597 net::URLFetcher* DataReductionProxySettings::GetBaseURLFetcher(
    598     const GURL& gurl,
    599     int load_flags) {
    600 
    601   net::URLFetcher* fetcher = net::URLFetcher::Create(gurl,
    602                                                      net::URLFetcher::GET,
    603                                                      this);
    604   fetcher->SetLoadFlags(load_flags);
    605   DCHECK(url_request_context_getter_);
    606   fetcher->SetRequestContext(url_request_context_getter_);
    607   // Configure max retries to be at most kMaxRetries times for 5xx errors.
    608   static const int kMaxRetries = 5;
    609   fetcher->SetMaxRetriesOn5xx(kMaxRetries);
    610   fetcher->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries);
    611   return fetcher;
    612 }
    613 
    614 
    615 net::URLFetcher*
    616 DataReductionProxySettings::GetURLFetcherForAvailabilityCheck() {
    617   return GetBaseURLFetcher(params_->probe_url(),
    618                            net::LOAD_DISABLE_CACHE | net::LOAD_BYPASS_PROXY);
    619 }
    620 
    621 
    622 void DataReductionProxySettings::ProbeWhetherDataReductionProxyIsAvailable() {
    623   net::URLFetcher* fetcher = GetURLFetcherForAvailabilityCheck();
    624   if (!fetcher)
    625     return;
    626   fetcher_.reset(fetcher);
    627   fetcher_->Start();
    628 }
    629 
    630 net::URLFetcher* DataReductionProxySettings::GetURLFetcherForWarmup() {
    631   return GetBaseURLFetcher(params_->warmup_url(), net::LOAD_DISABLE_CACHE);
    632 }
    633 
    634 void DataReductionProxySettings::WarmProxyConnection() {
    635   net::URLFetcher* fetcher = GetURLFetcherForWarmup();
    636   if (!fetcher)
    637     return;
    638   warmup_fetcher_.reset(fetcher);
    639   warmup_fetcher_->Start();
    640 }
    641 
    642 }  // namespace data_reduction_proxy
    643