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