Add diagnostics_writer.cc to the list of files allowed to printf.
[chromium-blink-merge.git] / components / data_reduction_proxy / browser / data_reduction_proxy_settings.cc
blob60ec9c1c321256cbdc25b92b8d4922a2dd8ba31d
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.
5 #include "components/data_reduction_proxy/browser/data_reduction_proxy_settings.h"
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/metrics/sparse_histogram.h"
12 #include "base/prefs/pref_member.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/prefs/scoped_user_pref_update.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "components/data_reduction_proxy/browser/data_reduction_proxy_auth_request_handler.h"
20 #include "components/data_reduction_proxy/browser/data_reduction_proxy_configurator.h"
21 #include "components/data_reduction_proxy/browser/data_reduction_proxy_params.h"
22 #include "components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.h"
23 #include "components/data_reduction_proxy/common/data_reduction_proxy_pref_names.h"
24 #include "components/data_reduction_proxy/common/data_reduction_proxy_switches.h"
25 #include "net/base/host_port_pair.h"
26 #include "net/base/load_flags.h"
27 #include "net/base/net_errors.h"
28 #include "net/base/net_util.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"
38 using base::StringPrintf;
40 namespace {
41 // Values of the UMA DataReductionProxy.NetworkChangeEvents histograms.
42 // This enum must remain synchronized with the enum of the same
43 // name in metrics/histograms/histograms.xml.
44 enum DataReductionProxyNetworkChangeEvent {
45 IP_CHANGED = 0, // The client IP address changed.
46 DISABLED_ON_VPN = 1, // The proxy is disabled because a VPN is running.
47 CHANGE_EVENT_COUNT = 2 // This must always be last.
50 // Key of the UMA DataReductionProxy.StartupState histogram.
51 const char kUMAProxyStartupStateHistogram[] =
52 "DataReductionProxy.StartupState";
54 // Key of the UMA DataReductionProxy.ProbeURL histogram.
55 const char kUMAProxyProbeURL[] = "DataReductionProxy.ProbeURL";
57 // Key of the UMA DataReductionProxy.ProbeURLNetError histogram.
58 const char kUMAProxyProbeURLNetError[] = "DataReductionProxy.ProbeURLNetError";
60 // Record a network change event.
61 void RecordNetworkChangeEvent(DataReductionProxyNetworkChangeEvent event) {
62 UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.NetworkChangeEvents",
63 event,
64 CHANGE_EVENT_COUNT);
67 int64 GetInt64PrefValue(const base::ListValue& list_value, size_t index) {
68 int64 val = 0;
69 std::string pref_value;
70 bool rv = list_value.GetString(index, &pref_value);
71 DCHECK(rv);
72 if (rv) {
73 rv = base::StringToInt64(pref_value, &val);
74 DCHECK(rv);
76 return val;
79 bool IsEnabledOnCommandLine() {
80 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
81 return command_line.HasSwitch(
82 data_reduction_proxy::switches::kEnableDataReductionProxy);
85 } // namespace
87 namespace data_reduction_proxy {
89 DataReductionProxySettings::DataReductionProxySettings(
90 DataReductionProxyParams* params)
91 : restricted_by_carrier_(false),
92 enabled_by_user_(false),
93 disabled_on_vpn_(false),
94 unreachable_(false),
95 prefs_(NULL),
96 local_state_prefs_(NULL),
97 url_request_context_getter_(NULL) {
98 DCHECK(params);
99 params_.reset(params);
102 DataReductionProxySettings::~DataReductionProxySettings() {
103 if (params_->allowed())
104 spdy_proxy_auth_enabled_.Destroy();
107 void DataReductionProxySettings::InitPrefMembers() {
108 DCHECK(thread_checker_.CalledOnValidThread());
109 spdy_proxy_auth_enabled_.Init(
110 prefs::kDataReductionProxyEnabled,
111 GetOriginalProfilePrefs(),
112 base::Bind(&DataReductionProxySettings::OnProxyEnabledPrefChange,
113 base::Unretained(this)));
114 data_reduction_proxy_alternative_enabled_.Init(
115 prefs::kDataReductionProxyAltEnabled,
116 GetOriginalProfilePrefs(),
117 base::Bind(
118 &DataReductionProxySettings::OnProxyAlternativeEnabledPrefChange,
119 base::Unretained(this)));
122 void DataReductionProxySettings::InitDataReductionProxySettings(
123 PrefService* prefs,
124 PrefService* local_state_prefs,
125 net::URLRequestContextGetter* url_request_context_getter) {
126 DCHECK(thread_checker_.CalledOnValidThread());
127 DCHECK(prefs);
128 DCHECK(local_state_prefs);
129 DCHECK(url_request_context_getter);
130 prefs_ = prefs;
131 local_state_prefs_ = local_state_prefs;
132 url_request_context_getter_ = url_request_context_getter;
133 InitPrefMembers();
134 RecordDataReductionInit();
136 // Disable the proxy if it is not allowed to be used.
137 if (!params_->allowed())
138 return;
140 AddDefaultProxyBypassRules();
141 net::NetworkChangeNotifier::AddIPAddressObserver(this);
143 // We set or reset the proxy pref at startup.
144 MaybeActivateDataReductionProxy(true);
147 void DataReductionProxySettings::InitDataReductionProxySettings(
148 PrefService* prefs,
149 PrefService* local_state_prefs,
150 net::URLRequestContextGetter* url_request_context_getter,
151 scoped_ptr<DataReductionProxyConfigurator> configurator) {
152 InitDataReductionProxySettings(prefs,
153 local_state_prefs,
154 url_request_context_getter);
155 SetProxyConfigurator(configurator.Pass());
158 void DataReductionProxySettings::SetOnDataReductionEnabledCallback(
159 const base::Callback<void(bool)>& on_data_reduction_proxy_enabled) {
160 on_data_reduction_proxy_enabled_ = on_data_reduction_proxy_enabled;
161 on_data_reduction_proxy_enabled_.Run(IsDataReductionProxyEnabled());
164 void DataReductionProxySettings::SetProxyConfigurator(
165 scoped_ptr<DataReductionProxyConfigurator> configurator) {
166 DCHECK(configurator);
167 configurator_ = configurator.Pass();
170 bool DataReductionProxySettings::IsDataReductionProxyEnabled() {
171 return spdy_proxy_auth_enabled_.GetValue() || IsEnabledOnCommandLine();
174 bool
175 DataReductionProxySettings::IsDataReductionProxyAlternativeEnabled() const {
176 return data_reduction_proxy_alternative_enabled_.GetValue();
179 bool DataReductionProxySettings::IsDataReductionProxyManaged() {
180 return spdy_proxy_auth_enabled_.IsManaged();
183 void DataReductionProxySettings::SetDataReductionProxyEnabled(bool enabled) {
184 DCHECK(thread_checker_.CalledOnValidThread());
185 // Prevent configuring the proxy when it is not allowed to be used.
186 if (!params_->allowed())
187 return;
189 if (spdy_proxy_auth_enabled_.GetValue() != enabled) {
190 spdy_proxy_auth_enabled_.SetValue(enabled);
191 OnProxyEnabledPrefChange();
195 void DataReductionProxySettings::SetDataReductionProxyAlternativeEnabled(
196 bool enabled) {
197 DCHECK(thread_checker_.CalledOnValidThread());
198 // Prevent configuring the proxy when it is not allowed to be used.
199 if (!params_->alternative_allowed())
200 return;
201 if (data_reduction_proxy_alternative_enabled_.GetValue() != enabled) {
202 data_reduction_proxy_alternative_enabled_.SetValue(enabled);
203 OnProxyAlternativeEnabledPrefChange();
207 int64 DataReductionProxySettings::GetDataReductionLastUpdateTime() {
208 DCHECK(thread_checker_.CalledOnValidThread());
209 PrefService* local_state = GetLocalStatePrefs();
210 int64 last_update_internal =
211 local_state->GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate);
212 base::Time last_update = base::Time::FromInternalValue(last_update_internal);
213 return static_cast<int64>(last_update.ToJsTime());
216 DataReductionProxySettings::ContentLengthList
217 DataReductionProxySettings::GetDailyOriginalContentLengths() {
218 DCHECK(thread_checker_.CalledOnValidThread());
219 return GetDailyContentLengths(prefs::kDailyHttpOriginalContentLength);
222 void DataReductionProxySettings::SetUnreachable(bool unreachable) {
223 unreachable_ = unreachable;
226 bool DataReductionProxySettings::IsDataReductionProxyUnreachable() {
227 DCHECK(thread_checker_.CalledOnValidThread());
228 return unreachable_;
231 DataReductionProxySettings::ContentLengthList
232 DataReductionProxySettings::GetDailyReceivedContentLengths() {
233 DCHECK(thread_checker_.CalledOnValidThread());
234 return GetDailyContentLengths(prefs::kDailyHttpReceivedContentLength);
237 void DataReductionProxySettings::OnURLFetchComplete(
238 const net::URLFetcher* source) {
239 DCHECK(thread_checker_.CalledOnValidThread());
241 // The purpose of sending a request for the warmup URL is to warm the
242 // connection to the data_reduction_proxy. The result is ignored.
243 if (source == warmup_fetcher_.get())
244 return;
246 DCHECK(source == fetcher_.get());
247 net::URLRequestStatus status = source->GetStatus();
248 if (status.status() == net::URLRequestStatus::FAILED) {
249 if (status.error() == net::ERR_INTERNET_DISCONNECTED) {
250 RecordProbeURLFetchResult(INTERNET_DISCONNECTED);
251 return;
253 // TODO(bengr): Remove once we understand the reasons probes are failing.
254 // Probe errors are either due to fetcher-level errors or modified
255 // responses. This only tracks the former.
256 UMA_HISTOGRAM_SPARSE_SLOWLY(
257 kUMAProxyProbeURLNetError, std::abs(status.error()));
260 std::string response;
261 source->GetResponseAsString(&response);
263 if ("OK" == response.substr(0, 2)) {
264 DVLOG(1) << "The data reduction proxy is unrestricted.";
266 if (enabled_by_user_) {
267 if (restricted_by_carrier_) {
268 // The user enabled the proxy, but sometime previously in the session,
269 // the network operator had blocked the canary and restricted the user.
270 // The current network doesn't block the canary, so don't restrict the
271 // proxy configurations.
272 SetProxyConfigs(true /* enabled */,
273 IsDataReductionProxyAlternativeEnabled(),
274 false /* restricted */,
275 false /* at_startup */);
276 RecordProbeURLFetchResult(SUCCEEDED_PROXY_ENABLED);
277 } else {
278 RecordProbeURLFetchResult(SUCCEEDED_PROXY_ALREADY_ENABLED);
281 restricted_by_carrier_ = false;
282 return;
284 DVLOG(1) << "The data reduction proxy is restricted to the configured "
285 << "fallback proxy.";
286 if (enabled_by_user_) {
287 if (!restricted_by_carrier_) {
288 // Restrict the proxy.
289 SetProxyConfigs(true /* enabled */,
290 IsDataReductionProxyAlternativeEnabled(),
291 true /* restricted */,
292 false /* at_startup */);
293 RecordProbeURLFetchResult(FAILED_PROXY_DISABLED);
294 } else {
295 RecordProbeURLFetchResult(FAILED_PROXY_ALREADY_DISABLED);
298 restricted_by_carrier_ = true;
301 PrefService* DataReductionProxySettings::GetOriginalProfilePrefs() {
302 DCHECK(thread_checker_.CalledOnValidThread());
303 return prefs_;
306 PrefService* DataReductionProxySettings::GetLocalStatePrefs() {
307 DCHECK(thread_checker_.CalledOnValidThread());
308 return local_state_prefs_;
311 void DataReductionProxySettings::AddDefaultProxyBypassRules() {
312 // localhost
313 DCHECK(configurator_);
314 configurator_->AddHostPatternToBypass("<local>");
315 // RFC1918 private addresses.
316 configurator_->AddHostPatternToBypass("10.0.0.0/8");
317 configurator_->AddHostPatternToBypass("172.16.0.0/12");
318 configurator_->AddHostPatternToBypass("192.168.0.0/16");
319 // RFC4193 private addresses.
320 configurator_->AddHostPatternToBypass("fc00::/7");
321 // IPV6 probe addresses.
322 configurator_->AddHostPatternToBypass("*-ds.metric.gstatic.com");
323 configurator_->AddHostPatternToBypass("*-v4.metric.gstatic.com");
326 void DataReductionProxySettings::LogProxyState(
327 bool enabled, bool restricted, bool at_startup) {
328 // This must stay a LOG(WARNING); the output is used in processing customer
329 // feedback.
330 const char kAtStartup[] = "at startup";
331 const char kByUser[] = "by user action";
332 const char kOn[] = "ON";
333 const char kOff[] = "OFF";
334 const char kRestricted[] = "(Restricted)";
335 const char kUnrestricted[] = "(Unrestricted)";
337 std::string annotated_on =
338 kOn + std::string(" ") + (restricted ? kRestricted : kUnrestricted);
340 LOG(WARNING) << "SPDY proxy " << (enabled ? annotated_on : kOff)
341 << " " << (at_startup ? kAtStartup : kByUser);
344 void DataReductionProxySettings::OnIPAddressChanged() {
345 DCHECK(thread_checker_.CalledOnValidThread());
346 if (enabled_by_user_) {
347 DCHECK(params_->allowed());
348 RecordNetworkChangeEvent(IP_CHANGED);
349 if (DisableIfVPN())
350 return;
351 ProbeWhetherDataReductionProxyIsAvailable();
352 WarmProxyConnection();
356 void DataReductionProxySettings::OnProxyEnabledPrefChange() {
357 DCHECK(thread_checker_.CalledOnValidThread());
358 if (!on_data_reduction_proxy_enabled_.is_null())
359 on_data_reduction_proxy_enabled_.Run(IsDataReductionProxyEnabled());
360 if (!params_->allowed())
361 return;
362 MaybeActivateDataReductionProxy(false);
365 void DataReductionProxySettings::OnProxyAlternativeEnabledPrefChange() {
366 DCHECK(thread_checker_.CalledOnValidThread());
367 if (!params_->alternative_allowed())
368 return;
369 MaybeActivateDataReductionProxy(false);
372 void DataReductionProxySettings::ResetDataReductionStatistics() {
373 DCHECK(thread_checker_.CalledOnValidThread());
374 PrefService* prefs = GetLocalStatePrefs();
375 if (!prefs)
376 return;
377 ListPrefUpdate original_update(prefs, prefs::kDailyHttpOriginalContentLength);
378 ListPrefUpdate received_update(prefs, prefs::kDailyHttpReceivedContentLength);
379 original_update->Clear();
380 received_update->Clear();
381 for (size_t i = 0; i < kNumDaysInHistory; ++i) {
382 original_update->AppendString(base::Int64ToString(0));
383 received_update->AppendString(base::Int64ToString(0));
387 void DataReductionProxySettings::MaybeActivateDataReductionProxy(
388 bool at_startup) {
389 DCHECK(thread_checker_.CalledOnValidThread());
390 PrefService* prefs = GetOriginalProfilePrefs();
391 // TODO(marq): Consider moving this so stats are wiped the first time the
392 // proxy settings are actually (not maybe) turned on.
393 if (spdy_proxy_auth_enabled_.GetValue() &&
394 !prefs->GetBoolean(prefs::kDataReductionProxyWasEnabledBefore)) {
395 prefs->SetBoolean(prefs::kDataReductionProxyWasEnabledBefore, true);
396 ResetDataReductionStatistics();
398 // Configure use of the data reduction proxy if it is enabled.
399 enabled_by_user_= IsDataReductionProxyEnabled();
400 SetProxyConfigs(enabled_by_user_ && !disabled_on_vpn_,
401 IsDataReductionProxyAlternativeEnabled(),
402 restricted_by_carrier_,
403 at_startup);
405 // Check if the proxy has been restricted explicitly by the carrier.
406 if (enabled_by_user_ && !disabled_on_vpn_) {
407 ProbeWhetherDataReductionProxyIsAvailable();
408 WarmProxyConnection();
412 void DataReductionProxySettings::SetProxyConfigs(bool enabled,
413 bool alternative_enabled,
414 bool restricted,
415 bool at_startup) {
416 DCHECK(thread_checker_.CalledOnValidThread());
417 DCHECK(configurator_);
419 LogProxyState(enabled, restricted, at_startup);
420 // The alternative is only configured if the standard configuration is
421 // is enabled.
422 if (enabled & !params_->holdback()) {
423 if (alternative_enabled) {
424 configurator_->Enable(restricted,
425 !params_->fallback_allowed(),
426 params_->alt_origin().spec(),
427 params_->alt_fallback_origin().spec(),
428 params_->ssl_origin().spec());
429 } else {
430 configurator_->Enable(restricted,
431 !params_->fallback_allowed(),
432 params_->origin().spec(),
433 params_->fallback_origin().spec(),
434 std::string());
436 } else {
437 configurator_->Disable();
441 // Metrics methods
442 void DataReductionProxySettings::RecordDataReductionInit() {
443 DCHECK(thread_checker_.CalledOnValidThread());
444 ProxyStartupState state = PROXY_NOT_AVAILABLE;
445 if (params_->allowed()) {
446 if (IsDataReductionProxyEnabled())
447 state = PROXY_ENABLED;
448 else
449 state = PROXY_DISABLED;
452 RecordStartupState(state);
455 void DataReductionProxySettings::RecordProbeURLFetchResult(
456 ProbeURLFetchResult result) {
457 UMA_HISTOGRAM_ENUMERATION(kUMAProxyProbeURL,
458 result,
459 PROBE_URL_FETCH_RESULT_COUNT);
462 void DataReductionProxySettings::RecordStartupState(ProxyStartupState state) {
463 UMA_HISTOGRAM_ENUMERATION(kUMAProxyStartupStateHistogram,
464 state,
465 PROXY_STARTUP_STATE_COUNT);
468 void DataReductionProxySettings::GetNetworkList(
469 net::NetworkInterfaceList* interfaces,
470 int policy) {
471 net::GetNetworkList(interfaces, policy);
474 void DataReductionProxySettings::ResetParamsForTest(
475 DataReductionProxyParams* params) {
476 params_.reset(params);
479 DataReductionProxySettings::ContentLengthList
480 DataReductionProxySettings::GetDailyContentLengths(const char* pref_name) {
481 DCHECK(thread_checker_.CalledOnValidThread());
482 DataReductionProxySettings::ContentLengthList content_lengths;
483 const base::ListValue* list_value = GetLocalStatePrefs()->GetList(pref_name);
484 if (list_value->GetSize() == kNumDaysInHistory) {
485 for (size_t i = 0; i < kNumDaysInHistory; ++i) {
486 content_lengths.push_back(GetInt64PrefValue(*list_value, i));
489 return content_lengths;
492 void DataReductionProxySettings::GetContentLengths(
493 unsigned int days,
494 int64* original_content_length,
495 int64* received_content_length,
496 int64* last_update_time) {
497 DCHECK(thread_checker_.CalledOnValidThread());
498 DCHECK_LE(days, kNumDaysInHistory);
499 PrefService* local_state = GetLocalStatePrefs();
500 if (!local_state) {
501 *original_content_length = 0L;
502 *received_content_length = 0L;
503 *last_update_time = 0L;
504 return;
507 const base::ListValue* original_list =
508 local_state->GetList(prefs::kDailyHttpOriginalContentLength);
509 const base::ListValue* received_list =
510 local_state->GetList(prefs::kDailyHttpReceivedContentLength);
512 if (original_list->GetSize() != kNumDaysInHistory ||
513 received_list->GetSize() != kNumDaysInHistory) {
514 *original_content_length = 0L;
515 *received_content_length = 0L;
516 *last_update_time = 0L;
517 return;
520 int64 orig = 0L;
521 int64 recv = 0L;
522 // Include days from the end of the list going backwards.
523 for (size_t i = kNumDaysInHistory - days;
524 i < kNumDaysInHistory; ++i) {
525 orig += GetInt64PrefValue(*original_list, i);
526 recv += GetInt64PrefValue(*received_list, i);
528 *original_content_length = orig;
529 *received_content_length = recv;
530 *last_update_time =
531 local_state->GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate);
534 net::URLFetcher* DataReductionProxySettings::GetBaseURLFetcher(
535 const GURL& gurl,
536 int load_flags) {
538 net::URLFetcher* fetcher = net::URLFetcher::Create(gurl,
539 net::URLFetcher::GET,
540 this);
541 fetcher->SetLoadFlags(load_flags);
542 DCHECK(url_request_context_getter_);
543 fetcher->SetRequestContext(url_request_context_getter_);
544 // Configure max retries to be at most kMaxRetries times for 5xx errors.
545 static const int kMaxRetries = 5;
546 fetcher->SetMaxRetriesOn5xx(kMaxRetries);
547 fetcher->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries);
548 return fetcher;
552 net::URLFetcher*
553 DataReductionProxySettings::GetURLFetcherForAvailabilityCheck() {
554 return GetBaseURLFetcher(params_->probe_url(),
555 net::LOAD_DISABLE_CACHE | net::LOAD_BYPASS_PROXY);
559 void DataReductionProxySettings::ProbeWhetherDataReductionProxyIsAvailable() {
560 net::URLFetcher* fetcher = GetURLFetcherForAvailabilityCheck();
561 if (!fetcher)
562 return;
563 fetcher_.reset(fetcher);
564 fetcher_->Start();
567 net::URLFetcher* DataReductionProxySettings::GetURLFetcherForWarmup() {
568 return GetBaseURLFetcher(params_->warmup_url(), net::LOAD_DISABLE_CACHE);
571 void DataReductionProxySettings::WarmProxyConnection() {
572 net::URLFetcher* fetcher = GetURLFetcherForWarmup();
573 if (!fetcher)
574 return;
575 warmup_fetcher_.reset(fetcher);
576 warmup_fetcher_->Start();
579 bool DataReductionProxySettings::DisableIfVPN() {
580 net::NetworkInterfaceList network_interfaces;
581 GetNetworkList(&network_interfaces, 0);
582 // VPNs use a "tun" interface, so the presence of a "tun" interface indicates
583 // a VPN is in use.
584 // TODO(kundaji): Verify this works on Windows.
585 const std::string vpn_interface_name_prefix = "tun";
586 for (size_t i = 0; i < network_interfaces.size(); ++i) {
587 std::string interface_name = network_interfaces[i].name;
588 if (LowerCaseEqualsASCII(
589 interface_name.begin(),
590 interface_name.begin() + vpn_interface_name_prefix.size(),
591 vpn_interface_name_prefix.c_str())) {
592 SetProxyConfigs(false,
593 IsDataReductionProxyAlternativeEnabled(),
594 false,
595 false);
596 disabled_on_vpn_ = true;
597 RecordNetworkChangeEvent(DISABLED_ON_VPN);
598 return true;
601 if (disabled_on_vpn_) {
602 SetProxyConfigs(enabled_by_user_,
603 IsDataReductionProxyAlternativeEnabled(),
604 restricted_by_carrier_,
605 false);
607 disabled_on_vpn_ = false;
608 return false;
611 } // namespace data_reduction_proxy