Home | History | Annotate | Download | only in spdyproxy
      1 // Copyright 2013 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 "chrome/browser/net/spdyproxy/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 "chrome/browser/browser_process.h"
     19 #include "chrome/browser/prefs/proxy_prefs.h"
     20 #include "chrome/browser/profiles/profile.h"
     21 #include "chrome/browser/profiles/profile_manager.h"
     22 #include "chrome/common/chrome_switches.h"
     23 #include "chrome/common/pref_names.h"
     24 #include "crypto/random.h"
     25 #include "net/base/auth.h"
     26 #include "net/base/host_port_pair.h"
     27 #include "net/base/load_flags.h"
     28 #include "net/base/net_errors.h"
     29 #include "net/http/http_auth.h"
     30 #include "net/http/http_auth_cache.h"
     31 #include "net/http/http_network_session.h"
     32 #include "net/http/http_response_headers.h"
     33 #include "net/url_request/url_fetcher.h"
     34 #include "net/url_request/url_fetcher_delegate.h"
     35 #include "net/url_request/url_request_status.h"
     36 #include "url/gurl.h"
     37 
     38 using base::FieldTrialList;
     39 using base::StringPrintf;
     40 
     41 namespace {
     42 
     43 // Key of the UMA DataReductionProxy.StartupState histogram.
     44 const char kUMAProxyStartupStateHistogram[] =
     45     "DataReductionProxy.StartupState";
     46 // Values of the UMA DataReductionProxy.StartupState histogram.
     47 enum ProxyStartupState {
     48   PROXY_NOT_AVAILABLE = 0,
     49   PROXY_DISABLED,
     50   PROXY_ENABLED,
     51   PROXY_STARTUP_STATE_COUNT,
     52 };
     53 
     54 // Key of the UMA DataReductionProxy.ProbeURL histogram.
     55 const char kUMAProxyProbeURL[] = "DataReductionProxy.ProbeURL";
     56 // Values of the UMA DataReductionProxy.ProbeURL histogram.
     57 // This enum must remain synchronized with DataReductionProxyProbeURLFetchResult
     58 // in metrics/histograms/histograms.xml.
     59 enum ProbeURLFetchResult {
     60   // The probe failed because the internet was disconnected.
     61   INTERNET_DISCONNECTED = 0,
     62 
     63   // The probe failed for any other reason, and as a result, the proxy was
     64   // disabled.
     65   FAILED_PROXY_DISABLED,
     66 
     67   // The probe failed, but the proxy was already disabled.
     68   FAILED_PROXY_ALREADY_DISABLED,
     69 
     70   // THe probe succeeded, and as a result the proxy was enabled.
     71   SUCCEEDED_PROXY_ENABLED,
     72 
     73   // The probe succeeded, but the proxy was already enabled.
     74   SUCCEEDED_PROXY_ALREADY_ENABLED,
     75 
     76   // This must always be last.
     77   FETCH_RESULT_COUNT
     78 };
     79 
     80 void RecordProbeURLFetchResult(ProbeURLFetchResult result) {
     81   UMA_HISTOGRAM_ENUMERATION(kUMAProxyProbeURL, result, FETCH_RESULT_COUNT);
     82 }
     83 
     84 const char kEnabled[] = "Enabled";
     85 
     86 // TODO(marq): Factor this string out into a constant here and in
     87 //             http_auth_handler_spdyproxy.
     88 const char kAuthenticationRealmName[] = "SpdyProxy";
     89 
     90 int64 GetInt64PrefValue(const ListValue& list_value, size_t index) {
     91   int64 val = 0;
     92   std::string pref_value;
     93   bool rv = list_value.GetString(index, &pref_value);
     94   DCHECK(rv);
     95   if (rv) {
     96     rv = base::StringToInt64(pref_value, &val);
     97     DCHECK(rv);
     98   }
     99   return val;
    100 }
    101 
    102 bool IsProxyOriginSetOnCommandLine() {
    103   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    104   return command_line.HasSwitch(switches::kSpdyProxyAuthOrigin);
    105 }
    106 
    107 }  // namespace
    108 
    109 DataReductionProxySettings::DataReductionProxySettings()
    110     : restricted_by_carrier_(false),
    111       enabled_by_user_(false) {
    112 }
    113 
    114 DataReductionProxySettings::~DataReductionProxySettings() {
    115   if (IsDataReductionProxyAllowed())
    116     spdy_proxy_auth_enabled_.Destroy();
    117 }
    118 
    119 void DataReductionProxySettings::InitPrefMembers() {
    120   spdy_proxy_auth_enabled_.Init(
    121       prefs::kSpdyProxyAuthEnabled,
    122       GetOriginalProfilePrefs(),
    123       base::Bind(&DataReductionProxySettings::OnProxyEnabledPrefChange,
    124                  base::Unretained(this)));
    125 }
    126 
    127 void DataReductionProxySettings::InitDataReductionProxySettings() {
    128   InitPrefMembers();
    129 
    130   // Disable the proxy if it is not allowed to be used.
    131   if (!IsDataReductionProxyAllowed())
    132     return;
    133 
    134   AddDefaultProxyBypassRules();
    135   net::NetworkChangeNotifier::AddIPAddressObserver(this);
    136 
    137   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    138 
    139   // Setting the kEnableSpdyProxyAuth switch has the same effect as enabling
    140   // the feature via settings, in that once set, the preference will be sticky
    141   // across instances of Chrome. Disabling the feature can only be done through
    142   // the settings menu.
    143   RecordDataReductionInit();
    144   if (spdy_proxy_auth_enabled_.GetValue() ||
    145       command_line.HasSwitch(switches::kEnableSpdyProxyAuth)) {
    146     MaybeActivateDataReductionProxy(true);
    147   } else {
    148     // This is logged so we can use this information in user feedback.
    149     LogProxyState(false /* enabled */,
    150                   false /* restricted */,
    151                   true /* at startup */);
    152   }
    153 }
    154 
    155 // static
    156 void DataReductionProxySettings::InitDataReductionProxySession(
    157     net::HttpNetworkSession* session) {
    158 // This is a no-op unless the authentication parameters are compiled in.
    159 // (even though values for them may be specified on the command line).
    160 // Authentication will still work if the command line parameters are used,
    161 // however there will be a round-trip overhead for each challenge/response
    162 // (typically once per session).
    163 #if defined(SPDY_PROXY_AUTH_ORIGIN) && defined(SPDY_PROXY_AUTH_VALUE)
    164   DCHECK(session);
    165   net::HttpAuthCache* auth_cache = session->http_auth_cache();
    166   DCHECK(auth_cache);
    167   InitDataReductionAuthentication(auth_cache);
    168 #endif  // defined(SPDY_PROXY_AUTH_ORIGIN) && defined(SPDY_PROXY_AUTH_VALUE)
    169 }
    170 
    171 // static
    172 void DataReductionProxySettings::InitDataReductionAuthentication(
    173     net::HttpAuthCache* auth_cache) {
    174   DCHECK(auth_cache);
    175   int64 timestamp =
    176       (base::Time::Now() - base::Time::UnixEpoch()).InMilliseconds() / 1000;
    177 
    178   DataReductionProxyList proxies = GetDataReductionProxies();
    179   for (DataReductionProxyList::iterator it = proxies.begin();
    180       it != proxies.end(); ++it) {
    181     GURL auth_origin = (*it).GetOrigin();
    182     int32 rand[3];
    183     crypto::RandBytes(rand, 3 * sizeof(rand[0]));
    184 
    185     std::string realm =
    186         base::StringPrintf("%s%lld", kAuthenticationRealmName, timestamp);
    187     std::string challenge = base::StringPrintf(
    188         "%s realm=\"%s\", ps=\"%lld-%u-%u-%u\"", kAuthenticationRealmName,
    189         realm.data(), timestamp, rand[0], rand[1], rand[2]);
    190     base::string16 password = AuthHashForSalt(timestamp);
    191 
    192     DVLOG(1) << "origin: [" << auth_origin << "] realm: [" << realm
    193         << "] challenge: [" << challenge << "] password: [" << password << "]";
    194 
    195     net::AuthCredentials credentials(base::string16(), password);
    196     // |HttpAuthController| searches this cache by origin and path, the latter
    197     // being '/' in the case of the data reduction proxy.
    198     auth_cache->Add(auth_origin,
    199                     realm,
    200                     net::HttpAuth::AUTH_SCHEME_SPDYPROXY,
    201                     challenge,
    202                     credentials,
    203                     std::string("/"));
    204   }
    205 }
    206 
    207 void DataReductionProxySettings::AddHostPatternToBypass(
    208     const std::string& pattern) {
    209   bypass_rules_.push_back(pattern);
    210 }
    211 
    212 void DataReductionProxySettings::AddURLPatternToBypass(
    213     const std::string& pattern) {
    214   size_t pos = pattern.find("/");
    215   if (pattern.find("/", pos + 1) == pos + 1)
    216     pos = pattern.find("/", pos + 2);
    217 
    218   std::string host_pattern;
    219   if (pos != std::string::npos)
    220     host_pattern = pattern.substr(0, pos);
    221   else
    222     host_pattern = pattern;
    223 
    224   AddHostPatternToBypass(host_pattern);
    225 }
    226 
    227 // static
    228 bool DataReductionProxySettings::IsDataReductionProxyAllowed() {
    229   return IsProxyOriginSetOnCommandLine() ||
    230       (FieldTrialList::FindFullName("DataCompressionProxyRollout") == kEnabled);
    231 }
    232 
    233 // static
    234 bool DataReductionProxySettings::IsDataReductionProxyPromoAllowed() {
    235   return IsProxyOriginSetOnCommandLine() ||
    236       (IsDataReductionProxyAllowed() &&
    237         FieldTrialList::FindFullName("DataCompressionProxyPromoVisibility") ==
    238             kEnabled);
    239 }
    240 
    241 // static
    242 bool DataReductionProxySettings::IsPreconnectHintingAllowed() {
    243   if (!IsDataReductionProxyAllowed())
    244     return false;
    245   return FieldTrialList::FindFullName("DataCompressionProxyPreconnectHints") ==
    246       kEnabled;
    247 }
    248 
    249 // static
    250 bool DataReductionProxySettings::WasFetchedViaProxy(
    251     const net::HttpResponseHeaders* headers) {
    252   const char kChromeProxyViaValue[] = "1.1 Chrome Compression Proxy";
    253   void* iter = NULL;
    254   std::string value;
    255   while (headers->EnumerateHeader(&iter, "via", &value))
    256     if (value == kChromeProxyViaValue) return true;
    257   return false;
    258 }
    259 
    260 // static
    261 std::string DataReductionProxySettings::GetDataReductionProxyOrigin() {
    262   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    263   if (command_line.HasSwitch(switches::kSpdyProxyAuthOrigin))
    264     return command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthOrigin);
    265 #if defined(SPDY_PROXY_AUTH_ORIGIN)
    266   return SPDY_PROXY_AUTH_ORIGIN;
    267 #else
    268   return std::string();
    269 #endif
    270 }
    271 
    272 // static
    273 std::string DataReductionProxySettings::GetDataReductionProxyFallback() {
    274   // Regardless of what else is defined, only return a value if the main proxy
    275   // origin is defined.
    276   if (GetDataReductionProxyOrigin().empty())
    277     return std::string();
    278   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    279   if (command_line.HasSwitch(switches::kSpdyProxyAuthFallback))
    280     return command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthFallback);
    281 #if defined(DATA_REDUCTION_FALLBACK_HOST)
    282   return DATA_REDUCTION_FALLBACK_HOST;
    283 #else
    284   return std::string();
    285 #endif
    286 }
    287 
    288 bool DataReductionProxySettings::IsAcceptableAuthChallenge(
    289     net::AuthChallengeInfo* auth_info) {
    290   // Challenge realm must start with the authentication realm name.
    291   std::string realm_prefix =
    292       auth_info->realm.substr(0, strlen(kAuthenticationRealmName));
    293   if (realm_prefix != kAuthenticationRealmName)
    294     return false;
    295 
    296   // The challenger must be one of the configured proxies.
    297   DataReductionProxyList proxies = GetDataReductionProxies();
    298   for (DataReductionProxyList::iterator it = proxies.begin();
    299        it != proxies.end(); ++it) {
    300     net::HostPortPair origin_host = net::HostPortPair::FromURL(*it);
    301     if (origin_host.Equals(auth_info->challenger))
    302       return true;
    303   }
    304   return false;
    305 }
    306 
    307 base::string16 DataReductionProxySettings::GetTokenForAuthChallenge(
    308     net::AuthChallengeInfo* auth_info) {
    309   if (auth_info->realm.length() > strlen(kAuthenticationRealmName)) {
    310     int64 salt;
    311     std::string realm_suffix =
    312         auth_info->realm.substr(strlen(kAuthenticationRealmName));
    313     if (base::StringToInt64(realm_suffix, &salt)) {
    314       return AuthHashForSalt(salt);
    315     } else {
    316       DVLOG(1) << "Unable to parse realm name " << auth_info->realm
    317                << "into an int for salting.";
    318       return base::string16();
    319     }
    320   } else {
    321     return base::string16();
    322   }
    323 }
    324 
    325 bool DataReductionProxySettings::IsDataReductionProxyEnabled() {
    326   return spdy_proxy_auth_enabled_.GetValue();
    327 }
    328 
    329 bool DataReductionProxySettings::IsDataReductionProxyManaged() {
    330   return spdy_proxy_auth_enabled_.IsManaged();
    331 }
    332 
    333 // static
    334 DataReductionProxySettings::DataReductionProxyList
    335 DataReductionProxySettings::GetDataReductionProxies() {
    336   DataReductionProxyList proxies;
    337   std::string proxy = GetDataReductionProxyOrigin();
    338   std::string fallback = GetDataReductionProxyFallback();
    339 
    340   if (!proxy.empty())
    341     proxies.push_back(GURL(proxy));
    342 
    343   if (!fallback.empty()) {
    344     // Sanity check: fallback isn't the only proxy.
    345     DCHECK(!proxies.empty());
    346     proxies.push_back(GURL(fallback));
    347   }
    348 
    349   return proxies;
    350 }
    351 
    352 void DataReductionProxySettings::SetDataReductionProxyEnabled(bool enabled) {
    353   // Prevent configuring the proxy when it is not allowed to be used.
    354   if (!IsDataReductionProxyAllowed())
    355     return;
    356 
    357   spdy_proxy_auth_enabled_.SetValue(enabled);
    358   OnProxyEnabledPrefChange();
    359 }
    360 
    361 int64 DataReductionProxySettings::GetDataReductionLastUpdateTime() {
    362   PrefService* local_state = GetLocalStatePrefs();
    363   int64 last_update_internal =
    364       local_state->GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate);
    365   base::Time last_update = base::Time::FromInternalValue(last_update_internal);
    366   return static_cast<int64>(last_update.ToJsTime());
    367 }
    368 
    369 DataReductionProxySettings::ContentLengthList
    370 DataReductionProxySettings::GetDailyOriginalContentLengths() {
    371   return GetDailyContentLengths(prefs::kDailyHttpOriginalContentLength);
    372 }
    373 
    374 DataReductionProxySettings::ContentLengthList
    375 DataReductionProxySettings::GetDailyReceivedContentLengths() {
    376   return GetDailyContentLengths(prefs::kDailyHttpReceivedContentLength);
    377 }
    378 
    379 void DataReductionProxySettings::OnURLFetchComplete(
    380     const net::URLFetcher* source) {
    381   net::URLRequestStatus status = source->GetStatus();
    382   if (status.status() == net::URLRequestStatus::FAILED &&
    383       status.error() == net::ERR_INTERNET_DISCONNECTED) {
    384     RecordProbeURLFetchResult(INTERNET_DISCONNECTED);
    385     return;
    386   }
    387 
    388   std::string response;
    389   source->GetResponseAsString(&response);
    390 
    391   if ("OK" == response.substr(0, 2)) {
    392     DVLOG(1) << "The data reduction proxy is unrestricted.";
    393 
    394     if (enabled_by_user_) {
    395       if (restricted_by_carrier_) {
    396         // The user enabled the proxy, but sometime previously in the session,
    397         // the network operator had blocked the canary and restricted the user.
    398         // The current network doesn't block the canary, so don't restrict the
    399         // proxy configurations.
    400         SetProxyConfigs(true /* enabled */,
    401                         false /* restricted */,
    402                         false /* at_startup */);
    403         RecordProbeURLFetchResult(SUCCEEDED_PROXY_ENABLED);
    404       } else {
    405         RecordProbeURLFetchResult(SUCCEEDED_PROXY_ALREADY_ENABLED);
    406       }
    407     }
    408     restricted_by_carrier_ = false;
    409     return;
    410   }
    411   DVLOG(1) << "The data reduction proxy is restricted to the configured "
    412            << "fallback proxy.";
    413 
    414   if (enabled_by_user_) {
    415     if (!restricted_by_carrier_) {
    416       // Restrict the proxy.
    417       SetProxyConfigs(true /* enabled */,
    418                       true /* restricted */,
    419                       false /* at_startup */);
    420       RecordProbeURLFetchResult(FAILED_PROXY_DISABLED);
    421     } else {
    422       RecordProbeURLFetchResult(FAILED_PROXY_ALREADY_DISABLED);
    423     }
    424   }
    425   restricted_by_carrier_ = true;
    426 }
    427 
    428 void DataReductionProxySettings::OnIPAddressChanged() {
    429   if (enabled_by_user_) {
    430     DCHECK(IsDataReductionProxyAllowed());
    431     ProbeWhetherDataReductionProxyIsAvailable();
    432   }
    433 }
    434 
    435 void DataReductionProxySettings::OnProxyEnabledPrefChange() {
    436   if (!DataReductionProxySettings::IsDataReductionProxyAllowed())
    437     return;
    438   MaybeActivateDataReductionProxy(false);
    439 }
    440 
    441 void DataReductionProxySettings::AddDefaultProxyBypassRules() {
    442   // localhost
    443   AddHostPatternToBypass("<local>");
    444   // RFC1918 private addresses.
    445   AddHostPatternToBypass("10.0.0.0/8");
    446   AddHostPatternToBypass("172.16.0.0/12");
    447   AddHostPatternToBypass("192.168.0.0/16");
    448   // RFC4193 private addresses.
    449   AddHostPatternToBypass("fc00::/7");
    450   // IPV6 probe addresses.
    451   AddHostPatternToBypass("*-ds.metric.gstatic.com");
    452   AddHostPatternToBypass("*-v4.metric.gstatic.com");
    453 }
    454 
    455 void DataReductionProxySettings::LogProxyState(
    456     bool enabled, bool restricted, bool at_startup) {
    457   // This must stay a LOG(WARNING); the output is used in processing customer
    458   // feedback.
    459   const char kAtStartup[] = "at startup";
    460   const char kByUser[] = "by user action";
    461   const char kOn[] = "ON";
    462   const char kOff[] = "OFF";
    463   const char kRestricted[] = "(Restricted)";
    464   const char kUnrestricted[] = "(Unrestricted)";
    465 
    466   std::string annotated_on =
    467       kOn + std::string(" ") + (restricted ? kRestricted : kUnrestricted);
    468 
    469   LOG(WARNING) << "SPDY proxy " << (enabled ? annotated_on : kOff)
    470                << " " << (at_startup ? kAtStartup : kByUser);
    471 }
    472 
    473 PrefService* DataReductionProxySettings::GetOriginalProfilePrefs() {
    474   return g_browser_process->profile_manager()->GetLastUsedProfile()->
    475       GetOriginalProfile()->GetPrefs();
    476 }
    477 
    478 PrefService* DataReductionProxySettings::GetLocalStatePrefs() {
    479   return g_browser_process->local_state();
    480 }
    481 
    482 void DataReductionProxySettings::ResetDataReductionStatistics() {
    483   PrefService* prefs = GetLocalStatePrefs();
    484   if (!prefs)
    485     return;
    486   ListPrefUpdate original_update(prefs, prefs::kDailyHttpOriginalContentLength);
    487   ListPrefUpdate received_update(prefs, prefs::kDailyHttpReceivedContentLength);
    488   original_update->Clear();
    489   received_update->Clear();
    490   for (size_t i = 0; i < spdyproxy::kNumDaysInHistory; ++i) {
    491     original_update->AppendString(base::Int64ToString(0));
    492     received_update->AppendString(base::Int64ToString(0));
    493   }
    494 }
    495 
    496 void DataReductionProxySettings::MaybeActivateDataReductionProxy(
    497     bool at_startup) {
    498   PrefService* prefs = GetOriginalProfilePrefs();
    499 
    500   // TODO(marq): Consider moving this so stats are wiped the first time the
    501   // proxy settings are actually (not maybe) turned on.
    502   if (spdy_proxy_auth_enabled_.GetValue() &&
    503       !prefs->GetBoolean(prefs::kSpdyProxyAuthWasEnabledBefore)) {
    504     prefs->SetBoolean(prefs::kSpdyProxyAuthWasEnabledBefore, true);
    505     ResetDataReductionStatistics();
    506   }
    507 
    508   std::string proxy = GetDataReductionProxyOrigin();
    509   // Configure use of the data reduction proxy if it is enabled and the proxy
    510   // origin is non-empty.
    511   enabled_by_user_= spdy_proxy_auth_enabled_.GetValue() && !proxy.empty();
    512   SetProxyConfigs(enabled_by_user_, restricted_by_carrier_, at_startup);
    513 
    514   // Check if the proxy has been restricted explicitly by the carrier.
    515   if (enabled_by_user_)
    516     ProbeWhetherDataReductionProxyIsAvailable();
    517 }
    518 
    519 void DataReductionProxySettings::SetProxyConfigs(
    520     bool enabled, bool restricted, bool at_startup) {
    521   // If |restricted| is true and there is no defined fallback proxy.
    522   // treat this as a disable.
    523   std::string fallback = GetDataReductionProxyFallback();
    524   if (fallback.empty() && enabled && restricted)
    525       enabled = false;
    526 
    527   LogProxyState(enabled, restricted, at_startup);
    528   PrefService* prefs = GetOriginalProfilePrefs();
    529   DCHECK(prefs);
    530   DictionaryPrefUpdate update(prefs, prefs::kProxy);
    531   base::DictionaryValue* dict = update.Get();
    532   if (enabled) {
    533     std::string proxy_list;
    534     if (restricted) {
    535       DCHECK(!fallback.empty());
    536       proxy_list = fallback;
    537     } else {
    538       proxy_list = GetDataReductionProxyOrigin() +
    539           (fallback.empty() ? "" : "," + fallback);
    540     }
    541 
    542     std::string proxy_server_config = "http=" + proxy_list + ",direct://;";
    543     dict->SetString("server", proxy_server_config);
    544     dict->SetString("mode",
    545                     ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS));
    546     dict->SetString("bypass_list", JoinString(bypass_rules_, ", "));
    547   } else {
    548     dict->SetString("mode", ProxyModeToString(ProxyPrefs::MODE_SYSTEM));
    549     dict->SetString("server", "");
    550     dict->SetString("bypass_list", "");
    551   }
    552 }
    553 
    554 // Metrics methods
    555 void DataReductionProxySettings::RecordDataReductionInit() {
    556   ProxyStartupState state = PROXY_NOT_AVAILABLE;
    557   if (IsDataReductionProxyAllowed())
    558     state = IsDataReductionProxyEnabled() ? PROXY_ENABLED : PROXY_DISABLED;
    559   UMA_HISTOGRAM_ENUMERATION(kUMAProxyStartupStateHistogram,
    560                             state,
    561                             PROXY_STARTUP_STATE_COUNT);
    562 }
    563 
    564 DataReductionProxySettings::ContentLengthList
    565 DataReductionProxySettings::GetDailyContentLengths(const char* pref_name) {
    566   DataReductionProxySettings::ContentLengthList content_lengths;
    567   const ListValue* list_value = GetLocalStatePrefs()->GetList(pref_name);
    568   if (list_value->GetSize() == spdyproxy::kNumDaysInHistory) {
    569     for (size_t i = 0; i < spdyproxy::kNumDaysInHistory; ++i) {
    570       content_lengths.push_back(GetInt64PrefValue(*list_value, i));
    571     }
    572   }
    573   return content_lengths;
    574  }
    575 
    576 void DataReductionProxySettings::GetContentLengths(
    577     unsigned int days,
    578     int64* original_content_length,
    579     int64* received_content_length,
    580     int64* last_update_time) {
    581   DCHECK_LE(days, spdyproxy::kNumDaysInHistory);
    582   PrefService* local_state = GetLocalStatePrefs();
    583   if (!local_state) {
    584     *original_content_length = 0L;
    585     *received_content_length = 0L;
    586     *last_update_time = 0L;
    587     return;
    588   }
    589 
    590   const ListValue* original_list =
    591       local_state->GetList(prefs::kDailyHttpOriginalContentLength);
    592   const ListValue* received_list =
    593       local_state->GetList(prefs::kDailyHttpReceivedContentLength);
    594 
    595   if (original_list->GetSize() != spdyproxy::kNumDaysInHistory ||
    596       received_list->GetSize() != spdyproxy::kNumDaysInHistory) {
    597     *original_content_length = 0L;
    598     *received_content_length = 0L;
    599     *last_update_time = 0L;
    600     return;
    601   }
    602 
    603   int64 orig = 0L;
    604   int64 recv = 0L;
    605   // Include days from the end of the list going backwards.
    606   for (size_t i = spdyproxy::kNumDaysInHistory - days;
    607        i < spdyproxy::kNumDaysInHistory; ++i) {
    608     orig += GetInt64PrefValue(*original_list, i);
    609     recv += GetInt64PrefValue(*received_list, i);
    610   }
    611   *original_content_length = orig;
    612   *received_content_length = recv;
    613   *last_update_time =
    614       local_state->GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate);
    615 }
    616 
    617 std::string DataReductionProxySettings::GetProxyCheckURL() {
    618   if (!IsDataReductionProxyAllowed())
    619     return std::string();
    620   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    621   if (command_line.HasSwitch(switches::kDataReductionProxyProbeURL)) {
    622     return command_line.GetSwitchValueASCII(
    623         switches::kDataReductionProxyProbeURL);
    624   }
    625 #if defined(DATA_REDUCTION_PROXY_PROBE_URL)
    626   return DATA_REDUCTION_PROXY_PROBE_URL;
    627 #else
    628   return std::string();
    629 #endif
    630 }
    631 
    632 // static
    633 base::string16 DataReductionProxySettings::AuthHashForSalt(int64 salt) {
    634   if (!IsDataReductionProxyAllowed())
    635     return base::string16();
    636 
    637   std::string key;
    638 
    639   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    640   if (command_line.HasSwitch(switches::kSpdyProxyAuthOrigin)) {
    641     // If an origin is provided via a switch, then only consider the value
    642     // that is provided by a switch. Do not use the preprocessor constant.
    643     // Don't expose SPDY_PROXY_AUTH_VALUE to a proxy passed in via the command
    644     // line.
    645     if (!command_line.HasSwitch(switches::kSpdyProxyAuthValue))
    646       return base::string16();
    647     key = command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthValue);
    648   } else {
    649 #if defined(SPDY_PROXY_AUTH_VALUE)
    650     key = SPDY_PROXY_AUTH_VALUE;
    651 #else
    652     return base::string16();
    653 #endif
    654   }
    655 
    656   DCHECK(!key.empty());
    657 
    658   std::string salted_key =
    659       base::StringPrintf("%lld%s%lld", salt, key.c_str(), salt);
    660   return UTF8ToUTF16(base::MD5String(salted_key));
    661 }
    662 
    663 net::URLFetcher* DataReductionProxySettings::GetURLFetcher() {
    664   std::string url = GetProxyCheckURL();
    665   if (url.empty())
    666     return NULL;
    667   net::URLFetcher* fetcher = net::URLFetcher::Create(GURL(url),
    668                                                      net::URLFetcher::GET,
    669                                                      this);
    670   fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE | net::LOAD_BYPASS_PROXY);
    671   Profile* profile = g_browser_process->profile_manager()->
    672       GetDefaultProfile();
    673   fetcher->SetRequestContext(profile->GetRequestContext());
    674   // Configure max retries to be at most kMaxRetries times for 5xx errors.
    675   static const int kMaxRetries = 5;
    676   fetcher->SetMaxRetriesOn5xx(kMaxRetries);
    677   return fetcher;
    678 }
    679 
    680 void
    681 DataReductionProxySettings::ProbeWhetherDataReductionProxyIsAvailable() {
    682   net::URLFetcher* fetcher = GetURLFetcher();
    683   if (!fetcher)
    684     return;
    685   fetcher_.reset(fetcher);
    686   fetcher_->Start();
    687 }
    688