| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h" |
| |
| #include <stddef.h> |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/macros.h" |
| #include "base/metrics/field_trial.h" |
| #include "base/metrics/histogram.h" |
| #include "base/metrics/histogram_base.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/optional.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_piece.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/task/lazy_task_runner.h" |
| #include "base/task_runner_util.h" |
| #include "base/time/default_tick_clock.h" |
| #include "build/build_config.h" |
| #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h" |
| #include "components/data_reduction_proxy/core/browser/network_properties_manager.h" |
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_bypass_protocol.h" |
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h" |
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h" |
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" |
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h" |
| #include "components/variations/variations_associated_data.h" |
| #include "net/base/host_port_pair.h" |
| #include "net/base/load_flags.h" |
| #include "net/base/network_change_notifier.h" |
| #include "net/base/network_interfaces.h" |
| #include "net/base/proxy_server.h" |
| #include "net/nqe/effective_connection_type.h" |
| #include "net/proxy_resolution/proxy_resolution_service.h" |
| #include "services/network/public/cpp/shared_url_loader_factory.h" |
| |
| #if defined(OS_ANDROID) |
| #include "net/android/network_library.h" |
| #endif // OS_ANDROID |
| |
| using base::FieldTrialList; |
| |
| namespace { |
| |
| #if defined(OS_CHROMEOS) |
| // SequencedTaskRunner to get the network id. A SequencedTaskRunner is used |
| // rather than parallel tasks to avoid having many threads getting the network |
| // id concurrently. |
| base::LazySequencedTaskRunner g_get_network_id_task_runner = |
| LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER( |
| base::TaskTraits(base::ThreadPool(), |
| base::MayBlock(), |
| base::TaskPriority::BEST_EFFORT, |
| base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)); |
| #endif |
| |
| // Values of the UMA DataReductionProxy.NetworkChangeEvents histograms. |
| // This enum must remain synchronized with the enum of the same |
| // name in metrics/histograms/histograms.xml. |
| enum DataReductionProxyNetworkChangeEvent { |
| // The client IP address changed. |
| DEPRECATED_IP_CHANGED = 0, |
| // [Deprecated] Proxy is disabled because a VPN is running. |
| DEPRECATED_DISABLED_ON_VPN = 1, |
| // There was a network change. |
| NETWORK_CHANGED = 2, |
| CHANGE_EVENT_COUNT = NETWORK_CHANGED + 1 |
| |
| }; |
| |
| // Key of the UMA DataReductionProxy.ProbeURL histogram. |
| const char kUMAProxyProbeURL[] = "DataReductionProxy.ProbeURL"; |
| |
| // Key of the UMA DataReductionProxy.ProbeURLNetError histogram. |
| const char kUMAProxyProbeURLNetError[] = "DataReductionProxy.ProbeURLNetError"; |
| |
| // Record a network change event. |
| void RecordNetworkChangeEvent(DataReductionProxyNetworkChangeEvent event) { |
| UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.NetworkChangeEvents", event, |
| CHANGE_EVENT_COUNT); |
| } |
| |
| // Records UMA containing the result of requesting the secure proxy check. |
| void RecordSecureProxyCheckFetchResult( |
| data_reduction_proxy::SecureProxyCheckFetchResult result) { |
| UMA_HISTOGRAM_ENUMERATION( |
| kUMAProxyProbeURL, result, |
| data_reduction_proxy::SECURE_PROXY_CHECK_FETCH_RESULT_COUNT); |
| } |
| |
| enum class WarmupURLFetchAttemptEvent { |
| kFetchInitiated = 0, |
| kConnectionTypeNone = 1, |
| kProxyNotEnabledByUser = 2, |
| kWarmupURLFetchingDisabled = 3, |
| kCount |
| }; |
| |
| void RecordWarmupURLFetchAttemptEvent( |
| WarmupURLFetchAttemptEvent warmup_url_fetch_event) { |
| DCHECK_GT(WarmupURLFetchAttemptEvent::kCount, warmup_url_fetch_event); |
| UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.WarmupURL.FetchAttemptEvent", |
| warmup_url_fetch_event, |
| WarmupURLFetchAttemptEvent::kCount); |
| } |
| |
| // Returns the current connection type if known, otherwise returns |
| // CONNECTION_UNKNOWN. |
| network::mojom::ConnectionType GetConnectionType( |
| network::NetworkConnectionTracker* network_connection_tracker) { |
| auto connection_type = network::mojom::ConnectionType::CONNECTION_UNKNOWN; |
| network_connection_tracker->GetConnectionType(&connection_type, |
| base::DoNothing()); |
| return connection_type; |
| } |
| |
| std::string DoGetCurrentNetworkID( |
| network::NetworkConnectionTracker* network_connection_tracker) { |
| // It is possible that the connection type changed between when |
| // GetConnectionType() was called and when the API to determine the |
| // network name was called. Check if that happened and retry until the |
| // connection type stabilizes. This is an imperfect solution but should |
| // capture majority of cases, and should not significantly affect estimates |
| // (that are approximate to begin with). |
| |
| while (true) { |
| auto connection_type = GetConnectionType(network_connection_tracker); |
| std::string ssid_mccmnc; |
| |
| switch (connection_type) { |
| case network::mojom::ConnectionType::CONNECTION_UNKNOWN: |
| case network::mojom::ConnectionType::CONNECTION_NONE: |
| case network::mojom::ConnectionType::CONNECTION_BLUETOOTH: |
| case network::mojom::ConnectionType::CONNECTION_ETHERNET: |
| break; |
| case network::mojom::ConnectionType::CONNECTION_WIFI: |
| // Get WiFi SSID only on Android since calling it on non-Android |
| // platforms may result in hung IO loop. See https://crbg.com/896296. |
| #if defined(OS_ANDROID) |
| ssid_mccmnc = net::GetWifiSSID(); |
| #endif |
| break; |
| case network::mojom::ConnectionType::CONNECTION_2G: |
| case network::mojom::ConnectionType::CONNECTION_3G: |
| case network::mojom::ConnectionType::CONNECTION_4G: |
| #if defined(OS_ANDROID) |
| ssid_mccmnc = net::android::GetTelephonyNetworkOperator(); |
| #endif |
| break; |
| } |
| |
| if (connection_type == GetConnectionType(network_connection_tracker)) { |
| if (connection_type >= network::mojom::ConnectionType::CONNECTION_2G && |
| connection_type <= network::mojom::ConnectionType::CONNECTION_4G) { |
| // No need to differentiate cellular connections by the exact |
| // connection type. |
| return "cell," + ssid_mccmnc; |
| } |
| return base::NumberToString(static_cast<int>(connection_type)) + "," + |
| ssid_mccmnc; |
| } |
| } |
| NOTREACHED(); |
| } |
| |
| } // namespace |
| |
| namespace data_reduction_proxy { |
| |
| DataReductionProxyConfig::DataReductionProxyConfig( |
| scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, |
| scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
| network::NetworkConnectionTracker* network_connection_tracker, |
| std::unique_ptr<DataReductionProxyConfigValues> config_values, |
| DataReductionProxyConfigurator* configurator) |
| : unreachable_(false), |
| enabled_by_user_(false), |
| config_values_(std::move(config_values)), |
| io_task_runner_(io_task_runner), |
| ui_task_runner_(ui_task_runner), |
| network_connection_tracker_(network_connection_tracker), |
| configurator_(configurator), |
| connection_type_(network::mojom::ConnectionType::CONNECTION_UNKNOWN), |
| network_properties_manager_(nullptr) { |
| DCHECK(io_task_runner_); |
| DCHECK(network_connection_tracker_); |
| DCHECK(configurator); |
| |
| // Constructed on the UI thread, but should be checked on the IO thread. |
| thread_checker_.DetachFromThread(); |
| } |
| |
| DataReductionProxyConfig::~DataReductionProxyConfig() { |
| network_connection_tracker_->RemoveNetworkConnectionObserver(this); |
| } |
| |
| void DataReductionProxyConfig::InitializeOnIOThread( |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| WarmupURLFetcher::CreateCustomProxyConfigCallback |
| create_custom_proxy_config_callback, |
| NetworkPropertiesManager* manager, |
| const std::string& user_agent) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| network_properties_manager_ = manager; |
| network_properties_manager_->ResetWarmupURLFetchMetrics(); |
| |
| if (!params::IsIncludedInHoldbackFieldTrial()) { |
| secure_proxy_checker_.reset(new SecureProxyChecker(url_loader_factory)); |
| warmup_url_fetcher_.reset(new WarmupURLFetcher( |
| create_custom_proxy_config_callback, |
| base::BindRepeating( |
| &DataReductionProxyConfig::HandleWarmupFetcherResponse, |
| base::Unretained(this)), |
| base::BindRepeating(&DataReductionProxyConfig::GetHttpRttEstimate, |
| base::Unretained(this)), |
| ui_task_runner_, user_agent)); |
| } |
| |
| AddDefaultProxyBypassRules(); |
| |
| network_connection_tracker_->AddNetworkConnectionObserver(this); |
| network_connection_tracker_->GetConnectionType( |
| &connection_type_, |
| base::BindOnce(&DataReductionProxyConfig::OnConnectionChanged, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void DataReductionProxyConfig::OnNewClientConfigFetched() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| ReloadConfig(); |
| // Call ResetWarmupURLFetchMetrics to reset the counts since the list of |
| // proxies may have changed. |
| network_properties_manager_->ResetWarmupURLFetchMetrics(); |
| FetchWarmupProbeURL(); |
| } |
| |
| void DataReductionProxyConfig::ReloadConfig() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| DCHECK(configurator_); |
| |
| if (enabled_by_user_ && !params::IsIncludedInHoldbackFieldTrial() && |
| !config_values_->proxies_for_http().empty()) { |
| configurator_->Enable(*network_properties_manager_, |
| config_values_->proxies_for_http()); |
| } else { |
| configurator_->Disable(); |
| } |
| } |
| |
| base::Optional<DataReductionProxyTypeInfo> |
| DataReductionProxyConfig::FindConfiguredDataReductionProxy( |
| const net::ProxyServer& proxy_server) const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| return config_values_->FindConfiguredDataReductionProxy(proxy_server); |
| } |
| |
| net::ProxyList DataReductionProxyConfig::GetAllConfiguredProxies() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| return config_values_->GetAllConfiguredProxies(); |
| } |
| |
| bool DataReductionProxyConfig::AreProxiesBypassed( |
| const net::ProxyRetryInfoMap& retry_map, |
| const net::ProxyConfig::ProxyRules& proxy_rules, |
| bool is_https, |
| base::TimeDelta* min_retry_delay) const { |
| // Data reduction proxy config is Type::PROXY_LIST_PER_SCHEME. |
| if (proxy_rules.type != net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME) |
| return false; |
| |
| if (is_https) |
| return false; |
| |
| const net::ProxyList* proxies = |
| proxy_rules.MapUrlSchemeToProxyList(url::kHttpScheme); |
| |
| if (!proxies) |
| return false; |
| |
| base::TimeDelta min_delay = base::TimeDelta::Max(); |
| bool bypassed = false; |
| |
| for (const net::ProxyServer& proxy : proxies->GetAll()) { |
| if (!proxy.is_valid() || proxy.is_direct()) |
| continue; |
| |
| base::TimeDelta delay; |
| if (FindConfiguredDataReductionProxy(proxy)) { |
| if (!IsProxyBypassed(retry_map, proxy, &delay)) |
| return false; |
| if (delay < min_delay) |
| min_delay = delay; |
| bypassed = true; |
| } |
| } |
| |
| if (min_retry_delay && bypassed) |
| *min_retry_delay = min_delay; |
| |
| return bypassed; |
| } |
| |
| bool DataReductionProxyConfig::IsProxyBypassed( |
| const net::ProxyRetryInfoMap& retry_map, |
| const net::ProxyServer& proxy_server, |
| base::TimeDelta* retry_delay) const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| return IsProxyBypassedAtTime(retry_map, proxy_server, GetTicksNow(), |
| retry_delay); |
| } |
| |
| bool DataReductionProxyConfig::ContainsDataReductionProxy( |
| const net::ProxyConfig::ProxyRules& proxy_rules) const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| // Data Reduction Proxy configurations are always Type::PROXY_LIST_PER_SCHEME. |
| if (proxy_rules.type != net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME) |
| return false; |
| |
| const net::ProxyList* http_proxy_list = |
| proxy_rules.MapUrlSchemeToProxyList("http"); |
| if (http_proxy_list && !http_proxy_list->IsEmpty() && |
| // Sufficient to check only the first proxy. |
| FindConfiguredDataReductionProxy(http_proxy_list->Get())) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| void DataReductionProxyConfig::SetProxyConfig(bool enabled, bool at_startup) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| enabled_by_user_ = enabled; |
| network_properties_manager_->OnChangeInNetworkID(GetCurrentNetworkID()); |
| |
| ReloadConfig(); |
| |
| if (enabled_by_user_) { |
| HandleCaptivePortal(); |
| |
| // Check if the proxy has been restricted explicitly by the carrier. |
| // It is safe to use base::Unretained here, since it gets executed |
| // synchronously on the IO thread, and |this| outlives |
| // |secure_proxy_checker_|. |
| SecureProxyCheck( |
| base::Bind(&DataReductionProxyConfig::HandleSecureProxyCheckResponse, |
| base::Unretained(this))); |
| } |
| network_properties_manager_->ResetWarmupURLFetchMetrics(); |
| FetchWarmupProbeURL(); |
| } |
| |
| void DataReductionProxyConfig::HandleCaptivePortal() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| bool is_captive_portal = GetIsCaptivePortal(); |
| if (is_captive_portal == network_properties_manager_->IsCaptivePortal()) |
| return; |
| network_properties_manager_->SetIsCaptivePortal(is_captive_portal); |
| ReloadConfig(); |
| } |
| |
| bool DataReductionProxyConfig::GetIsCaptivePortal() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| #if defined(OS_ANDROID) |
| return net::android::GetIsCaptivePortal(); |
| #endif // OS_ANDROID |
| return false; |
| } |
| |
| void DataReductionProxyConfig::UpdateConfigForTesting( |
| bool enabled, |
| bool secure_proxies_allowed, |
| bool insecure_proxies_allowed) { |
| enabled_by_user_ = enabled; |
| network_properties_manager_->ResetWarmupURLFetchMetrics(); |
| network_properties_manager_->SetIsSecureProxyDisallowedByCarrier( |
| !secure_proxies_allowed); |
| if (!insecure_proxies_allowed != |
| network_properties_manager_->HasWarmupURLProbeFailed( |
| false /* secure_proxy */, true /* is_core_proxy */)) { |
| network_properties_manager_->SetHasWarmupURLProbeFailed( |
| false /* secure_proxy */, true /* is_core_proxy */, |
| !insecure_proxies_allowed); |
| } |
| } |
| |
| void DataReductionProxyConfig::SetNetworkPropertiesManagerForTesting( |
| NetworkPropertiesManager* manager) { |
| network_properties_manager_ = manager; |
| } |
| |
| base::Optional<DataReductionProxyServer> |
| DataReductionProxyConfig::GetProxyConnectionToProbe() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| const std::vector<DataReductionProxyServer>& proxies = |
| DataReductionProxyConfig::GetProxiesForHttp(); |
| |
| for (const DataReductionProxyServer& proxy_server : proxies) { |
| // First find a proxy server that has never been probed before. Proxies that |
| // have been probed before successfully do not need to be probed. On the |
| // other hand, proxies that have been probed before unsuccessfully are |
| // already disabled, and so they need not be probed immediately. |
| bool is_secure_proxy = proxy_server.IsSecureProxy(); |
| bool is_core_proxy = proxy_server.IsCoreProxy(); |
| if (!network_properties_manager_->HasWarmupURLProbeFailed(is_secure_proxy, |
| is_core_proxy) && |
| network_properties_manager_->ShouldFetchWarmupProbeURL(is_secure_proxy, |
| is_core_proxy)) { |
| return proxy_server; |
| } |
| } |
| |
| for (const DataReductionProxyServer& proxy_server : proxies) { |
| // Now find any proxy server that can be probed. This would return proxies |
| // that were probed before, the result was unsuccessful, but they have not |
| // yet hit the maximum probe retry limit. |
| bool is_secure_proxy = proxy_server.IsSecureProxy(); |
| bool is_core_proxy = proxy_server.IsCoreProxy(); |
| if (network_properties_manager_->ShouldFetchWarmupProbeURL(is_secure_proxy, |
| is_core_proxy)) { |
| return proxy_server; |
| } |
| } |
| |
| // No more proxies left to probe. |
| return base::nullopt; |
| } |
| |
| void DataReductionProxyConfig::HandleWarmupFetcherResponse( |
| const net::ProxyServer& proxy_server, |
| WarmupURLFetcher::FetchResult success_response) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| DCHECK(IsFetchInFlight()); |
| |
| base::Optional<DataReductionProxyTypeInfo> proxy_type_info = |
| FindConfiguredDataReductionProxy(proxy_server); |
| |
| // Check the proxy server used. |
| if (!proxy_type_info && proxy_server.is_valid() && |
| !proxy_server.is_direct()) { |
| // No need to do anything here since the warmup fetch went through |
| // a non-datasaver proxy. |
| return; |
| } |
| |
| bool is_secure_proxy = false; |
| bool is_core_proxy = false; |
| |
| if (proxy_type_info) { |
| DCHECK(proxy_server.is_valid()); |
| DCHECK(!proxy_server.is_direct()); |
| is_secure_proxy = proxy_server.is_https() || proxy_server.is_quic(); |
| is_core_proxy = proxy_type_info->proxy_servers[proxy_type_info->proxy_index] |
| .IsCoreProxy(); |
| |
| // The proxy server through which the warmup URL was fetched should match |
| // the proxy server for which the warmup URL is in-flight. |
| DCHECK(GetInFlightWarmupProxyDetails()); |
| DCHECK_EQ(is_secure_proxy, GetInFlightWarmupProxyDetails()->first); |
| DCHECK_EQ(is_core_proxy, GetInFlightWarmupProxyDetails()->second); |
| } else { |
| DCHECK(!proxy_server.is_valid() || proxy_server.is_direct()); |
| // When the probe times out or if the warmup URL was fetched via DIRECT |
| // proxy, the data reduction proxy information may not be set. Fill-in the |
| // missing data using the proxy that was being probed. |
| is_secure_proxy = warmup_url_fetch_in_flight_secure_proxy_; |
| is_core_proxy = warmup_url_fetch_in_flight_core_proxy_; |
| } |
| |
| if (is_secure_proxy && is_core_proxy) { |
| UMA_HISTOGRAM_BOOLEAN( |
| "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." |
| "SecureProxy.Core", |
| success_response == WarmupURLFetcher::FetchResult::kSuccessful); |
| } else if (is_secure_proxy && !is_core_proxy) { |
| UMA_HISTOGRAM_BOOLEAN( |
| "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." |
| "SecureProxy.NonCore", |
| success_response == WarmupURLFetcher::FetchResult::kSuccessful); |
| } else if (!is_secure_proxy && is_core_proxy) { |
| UMA_HISTOGRAM_BOOLEAN( |
| "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." |
| "InsecureProxy.Core", |
| success_response == WarmupURLFetcher::FetchResult::kSuccessful); |
| } else { |
| UMA_HISTOGRAM_BOOLEAN( |
| "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." |
| "InsecureProxy.NonCore", |
| success_response == WarmupURLFetcher::FetchResult::kSuccessful); |
| } |
| |
| bool warmup_url_failed_past = |
| network_properties_manager_->HasWarmupURLProbeFailed(is_secure_proxy, |
| is_core_proxy); |
| |
| network_properties_manager_->SetHasWarmupURLProbeFailed( |
| is_secure_proxy, is_core_proxy, |
| success_response != |
| WarmupURLFetcher::FetchResult::kSuccessful /* warmup failed */); |
| |
| if (warmup_url_failed_past != |
| network_properties_manager_->HasWarmupURLProbeFailed(is_secure_proxy, |
| is_core_proxy)) { |
| ReloadConfig(); |
| } |
| |
| // May probe other proxy types that have not been probed yet, or may retry |
| // probe of proxy types that has failed but the maximum probe limit has not |
| // been reached yet. This method may have been called by warmup URL fetcher. |
| // FetchWarmupProbeURL() may itself call warmup URL fetcher. Posting the call |
| // here avoids recursive calls to the warmup URL fetcher. |
| io_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&DataReductionProxyConfig::FetchWarmupProbeURL, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void DataReductionProxyConfig::HandleSecureProxyCheckResponse( |
| const std::string& response, |
| int net_status, |
| int http_response_code) { |
| bool success_response = |
| base::StartsWith(response, "OK", base::CompareCase::SENSITIVE); |
| |
| if (net_status != net::OK) { |
| if (net_status == net::ERR_INTERNET_DISCONNECTED) { |
| RecordSecureProxyCheckFetchResult(INTERNET_DISCONNECTED); |
| return; |
| } |
| // TODO(bengr): Remove once we understand the reasons secure proxy checks |
| // are failing. Secure proxy check errors are either due to fetcher-level |
| // errors or modified responses. This only tracks the former. |
| base::UmaHistogramSparse(kUMAProxyProbeURLNetError, std::abs(net_status)); |
| } |
| |
| bool secure_proxy_allowed_past = |
| !network_properties_manager_->IsSecureProxyDisallowedByCarrier(); |
| network_properties_manager_->SetIsSecureProxyDisallowedByCarrier( |
| !success_response); |
| if (!enabled_by_user_) |
| return; |
| |
| if (!network_properties_manager_->IsSecureProxyDisallowedByCarrier() != |
| secure_proxy_allowed_past) |
| ReloadConfig(); |
| |
| // Record the result. |
| if (secure_proxy_allowed_past && |
| !network_properties_manager_->IsSecureProxyDisallowedByCarrier()) { |
| RecordSecureProxyCheckFetchResult(SUCCEEDED_PROXY_ALREADY_ENABLED); |
| } else if (secure_proxy_allowed_past && |
| network_properties_manager_->IsSecureProxyDisallowedByCarrier()) { |
| RecordSecureProxyCheckFetchResult(FAILED_PROXY_DISABLED); |
| } else if (!secure_proxy_allowed_past && |
| !network_properties_manager_->IsSecureProxyDisallowedByCarrier()) { |
| RecordSecureProxyCheckFetchResult(SUCCEEDED_PROXY_ENABLED); |
| } else { |
| DCHECK(!secure_proxy_allowed_past && |
| network_properties_manager_->IsSecureProxyDisallowedByCarrier()); |
| RecordSecureProxyCheckFetchResult(FAILED_PROXY_ALREADY_DISABLED); |
| } |
| } |
| |
| void DataReductionProxyConfig::OnConnectionChanged( |
| network::mojom::ConnectionType type) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| connection_type_ = type; |
| RecordNetworkChangeEvent(NETWORK_CHANGED); |
| |
| #if defined(OS_CHROMEOS) |
| if (get_network_id_asynchronously_) { |
| base::PostTaskAndReplyWithResult( |
| g_get_network_id_task_runner.Get().get(), FROM_HERE, |
| base::BindOnce(&DoGetCurrentNetworkID, |
| base::Unretained(network_connection_tracker_)), |
| base::BindOnce(&DataReductionProxyConfig::ContinueNetworkChanged, |
| weak_factory_.GetWeakPtr())); |
| return; |
| } |
| #endif // defined(OS_CHROMEOS) |
| |
| ContinueNetworkChanged(GetCurrentNetworkID()); |
| } |
| |
| void DataReductionProxyConfig::ContinueNetworkChanged( |
| const std::string& network_id) { |
| network_properties_manager_->OnChangeInNetworkID(network_id); |
| |
| ReloadConfig(); |
| |
| FetchWarmupProbeURL(); |
| |
| if (enabled_by_user_) { |
| HandleCaptivePortal(); |
| // It is safe to use base::Unretained here, since it gets executed |
| // synchronously on the IO thread, and |this| outlives |
| // |secure_proxy_checker_|. |
| SecureProxyCheck( |
| base::Bind(&DataReductionProxyConfig::HandleSecureProxyCheckResponse, |
| base::Unretained(this))); |
| } |
| } |
| |
| void DataReductionProxyConfig::AddDefaultProxyBypassRules() { |
| DCHECK(configurator_); |
| // Under the hood we use an instance of ProxyBypassRules to evaluate these |
| // rules. ProxyBypassRules implicitly bypasses localhost, loopback, and |
| // link-local addresses, so it is not necessary to explicitly add them here. |
| // See ProxyBypassRules::MatchesImplicitRules() for details. |
| configurator_->SetBypassRules( |
| // Hostnames with no dot in them. |
| "<local>," |
| |
| // WebSockets |
| "ws://*," |
| "wss://*," |
| |
| // RFC6890 current network (only valid as source address). |
| "0.0.0.0/8," |
| |
| // RFC1918 private addresses. |
| "10.0.0.0/8," |
| "172.16.0.0/12," |
| "192.168.0.0/16," |
| |
| // RFC3513 unspecified address. |
| "::/128," |
| |
| // RFC4193 private addresses. |
| "fc00::/7," |
| |
| // IPV6 probe addresses. |
| "*-ds.metric.gstatic.com," |
| "*-v4.metric.gstatic.com"); |
| } |
| |
| void DataReductionProxyConfig::SecureProxyCheck( |
| SecureProxyCheckerCallback fetcher_callback) { |
| if (params::IsIncludedInHoldbackFieldTrial()) |
| return; |
| |
| secure_proxy_checker_->CheckIfSecureProxyIsAllowed(fetcher_callback); |
| } |
| |
| void DataReductionProxyConfig::FetchWarmupProbeURL() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| if (params::IsIncludedInHoldbackFieldTrial()) |
| return; |
| |
| if (!enabled_by_user_) { |
| RecordWarmupURLFetchAttemptEvent( |
| WarmupURLFetchAttemptEvent::kProxyNotEnabledByUser); |
| return; |
| } |
| |
| if (!params::FetchWarmupProbeURLEnabled()) { |
| RecordWarmupURLFetchAttemptEvent( |
| WarmupURLFetchAttemptEvent::kWarmupURLFetchingDisabled); |
| return; |
| } |
| |
| if (connection_type_ == network::mojom::ConnectionType::CONNECTION_NONE) { |
| RecordWarmupURLFetchAttemptEvent( |
| WarmupURLFetchAttemptEvent::kConnectionTypeNone); |
| return; |
| } |
| |
| base::Optional<DataReductionProxyServer> warmup_proxy = |
| GetProxyConnectionToProbe(); |
| |
| if (!warmup_proxy) |
| return; |
| |
| // Refetch the warmup URL when it has failed. |
| warmup_url_fetch_in_flight_secure_proxy_ = warmup_proxy->IsSecureProxy(); |
| warmup_url_fetch_in_flight_core_proxy_ = warmup_proxy->IsCoreProxy(); |
| |
| size_t previous_attempt_counts = GetWarmupURLFetchAttemptCounts(); |
| |
| network_properties_manager_->OnWarmupFetchInitiated( |
| warmup_url_fetch_in_flight_secure_proxy_, |
| warmup_url_fetch_in_flight_core_proxy_); |
| |
| RecordWarmupURLFetchAttemptEvent(WarmupURLFetchAttemptEvent::kFetchInitiated); |
| |
| warmup_url_fetcher_->FetchWarmupURL(previous_attempt_counts, |
| warmup_proxy.value()); |
| } |
| |
| size_t DataReductionProxyConfig::GetWarmupURLFetchAttemptCounts() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| return network_properties_manager_->GetWarmupURLFetchAttemptCounts( |
| warmup_url_fetch_in_flight_secure_proxy_, |
| warmup_url_fetch_in_flight_core_proxy_); |
| } |
| |
| void DataReductionProxyConfig::OnRTTOrThroughputEstimatesComputed( |
| base::TimeDelta http_rtt) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| http_rtt_ = http_rtt; |
| } |
| |
| base::Optional<base::TimeDelta> DataReductionProxyConfig::GetHttpRttEstimate() |
| const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| return http_rtt_; |
| } |
| |
| bool DataReductionProxyConfig::enabled_by_user_and_reachable() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| return enabled_by_user_ && !unreachable_; |
| } |
| |
| base::TimeTicks DataReductionProxyConfig::GetTicksNow() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| return base::TimeTicks::Now(); |
| } |
| |
| net::ProxyConfig DataReductionProxyConfig::ProxyConfigIgnoringHoldback() const { |
| if (!enabled_by_user_ || config_values_->proxies_for_http().empty()) |
| return net::ProxyConfig::CreateDirect(); |
| return configurator_->CreateProxyConfig(false /* probe_url_config */, |
| *network_properties_manager_, |
| config_values_->proxies_for_http()); |
| } |
| |
| std::vector<DataReductionProxyServer> |
| DataReductionProxyConfig::GetProxiesForHttp() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| if (!enabled_by_user_) |
| return std::vector<DataReductionProxyServer>(); |
| |
| return config_values_->proxies_for_http(); |
| } |
| |
| std::string DataReductionProxyConfig::GetCurrentNetworkID() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| return DoGetCurrentNetworkID(network_connection_tracker_); |
| } |
| |
| const NetworkPropertiesManager& |
| DataReductionProxyConfig::GetNetworkPropertiesManager() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| return *network_properties_manager_; |
| } |
| |
| bool DataReductionProxyConfig::IsFetchInFlight() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| if (!warmup_url_fetcher_) |
| return false; |
| return warmup_url_fetcher_->IsFetchInFlight(); |
| } |
| |
| base::Optional<std::pair<bool /* is_secure_proxy */, bool /*is_core_proxy */>> |
| DataReductionProxyConfig::GetInFlightWarmupProxyDetails() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| if (!IsFetchInFlight()) |
| return base::nullopt; |
| |
| return std::make_pair(warmup_url_fetch_in_flight_secure_proxy_, |
| warmup_url_fetch_in_flight_core_proxy_); |
| } |
| |
| #if defined(OS_CHROMEOS) |
| void DataReductionProxyConfig::EnableGetNetworkIdAsynchronously() { |
| get_network_id_asynchronously_ = true; |
| } |
| #endif // defined(OS_CHROMEOS) |
| |
| } // namespace data_reduction_proxy |