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