blob: e89881ec6f50dca57f38a520c975c0706c00f726 [file] [log] [blame]
// 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_io_data.h"
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
#include "components/data_reduction_proxy/core/browser/network_properties_manager.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_storage_delegate.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
#include "components/previews/core/previews_decider.h"
#include "net/base/load_flags.h"
#include "net/http/http_request_headers.h"
#include "net/url_request/http_user_agent_settings.h"
#include "net/url_request/static_http_user_agent_settings.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_builder.h"
#include "net/url_request/url_request_context_getter.h"
namespace data_reduction_proxy {
// A |net::URLRequestContextGetter| which uses only vanilla HTTP/HTTPS for
// performing requests. This is used by the secure proxy check to prevent the
// use of SPDY and QUIC which may be used by the primary request contexts.
class BasicHTTPURLRequestContextGetter : public net::URLRequestContextGetter {
public:
BasicHTTPURLRequestContextGetter(
const std::string& user_agent,
const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner);
// Overridden from net::URLRequestContextGetter:
net::URLRequestContext* GetURLRequestContext() override;
scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
const override;
private:
~BasicHTTPURLRequestContextGetter() override;
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
std::unique_ptr<net::HttpUserAgentSettings> user_agent_settings_;
std::unique_ptr<net::URLRequestContext> url_request_context_;
DISALLOW_COPY_AND_ASSIGN(BasicHTTPURLRequestContextGetter);
};
BasicHTTPURLRequestContextGetter::BasicHTTPURLRequestContextGetter(
const std::string& user_agent,
const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner)
: network_task_runner_(network_task_runner),
user_agent_settings_(
new net::StaticHttpUserAgentSettings(std::string(), user_agent)) {
}
net::URLRequestContext*
BasicHTTPURLRequestContextGetter::GetURLRequestContext() {
if (!url_request_context_) {
net::URLRequestContextBuilder builder;
builder.set_proxy_resolution_service(net::ProxyResolutionService::CreateDirect());
builder.SetSpdyAndQuicEnabled(false, false);
url_request_context_ = builder.Build();
}
return url_request_context_.get();
}
scoped_refptr<base::SingleThreadTaskRunner>
BasicHTTPURLRequestContextGetter::GetNetworkTaskRunner() const {
return network_task_runner_;
}
BasicHTTPURLRequestContextGetter::~BasicHTTPURLRequestContextGetter() {
}
DataReductionProxyIOData::DataReductionProxyIOData(
Client client,
PrefService* prefs,
net::NetLog* net_log,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
bool enabled,
const std::string& user_agent,
const std::string& channel)
: client_(client),
net_log_(net_log),
io_task_runner_(io_task_runner),
ui_task_runner_(ui_task_runner),
data_use_observer_(nullptr),
enabled_(enabled),
url_request_context_getter_(nullptr),
basic_url_request_context_getter_(
new BasicHTTPURLRequestContextGetter(user_agent, io_task_runner)),
channel_(channel),
effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
weak_factory_(this) {
DCHECK(net_log);
DCHECK(io_task_runner_);
DCHECK(ui_task_runner_);
std::unique_ptr<DataReductionProxyParams> params(
new DataReductionProxyParams());
event_creator_.reset(new DataReductionProxyEventCreator(this));
configurator_.reset(
new DataReductionProxyConfigurator(net_log, event_creator_.get()));
bool use_config_client =
params::IsConfigClientEnabled() && client_ != Client::CRONET_ANDROID;
DataReductionProxyMutableConfigValues* raw_mutable_config = nullptr;
if (use_config_client) {
std::unique_ptr<DataReductionProxyMutableConfigValues> mutable_config =
std::make_unique<DataReductionProxyMutableConfigValues>();
raw_mutable_config = mutable_config.get();
config_.reset(new DataReductionProxyConfig(
io_task_runner, net_log, std::move(mutable_config), configurator_.get(),
event_creator_.get()));
} else {
config_.reset(new DataReductionProxyConfig(
io_task_runner, net_log, std::move(params), configurator_.get(),
event_creator_.get()));
}
// It is safe to use base::Unretained here, since it gets executed
// synchronously on the IO thread, and |this| outlives the caller (since the
// caller is owned by |this|.
bypass_stats_.reset(new DataReductionProxyBypassStats(
config_.get(), base::Bind(&DataReductionProxyIOData::SetUnreachable,
base::Unretained(this))));
request_options_.reset(
new DataReductionProxyRequestOptions(client_, config_.get()));
request_options_->Init();
// It is safe to use base::Unretained here, since it gets executed
// synchronously on the IO thread, and |this| outlives the caller (since the
// caller is owned by |this|.
request_options_->SetUpdateHeaderCallback(
base::BindRepeating(&DataReductionProxyIOData::UpdateProxyRequestHeaders,
base::Unretained(this)));
if (use_config_client) {
// It is safe to use base::Unretained here, since it gets executed
// synchronously on the IO thread, and |this| outlives the caller (since the
// caller is owned by |this|.
config_client_.reset(new DataReductionProxyConfigServiceClient(
std::move(params), GetBackoffPolicy(), request_options_.get(),
raw_mutable_config, config_.get(), event_creator_.get(), this, net_log_,
base::Bind(&DataReductionProxyIOData::StoreSerializedConfig,
base::Unretained(this))));
}
proxy_delegate_.reset(new DataReductionProxyDelegate(
config_.get(), configurator_.get(), event_creator_.get(),
bypass_stats_.get(), net_log_));
network_properties_manager_.reset(new NetworkPropertiesManager(
base::DefaultClock::GetInstance(), prefs, ui_task_runner_));
}
DataReductionProxyIOData::DataReductionProxyIOData(
PrefService* prefs,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
: client_(Client::UNKNOWN),
net_log_(nullptr),
io_task_runner_(io_task_runner),
ui_task_runner_(ui_task_runner),
url_request_context_getter_(nullptr),
effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
weak_factory_(this) {
DCHECK(ui_task_runner_);
DCHECK(io_task_runner_);
network_properties_manager_.reset(new NetworkPropertiesManager(
base::DefaultClock::GetInstance(), prefs, ui_task_runner_));
}
DataReductionProxyIOData::~DataReductionProxyIOData() {
// Guaranteed to be destroyed on IO thread if the IO thread is still
// available at the time of destruction. If the IO thread is unavailable,
// then the destruction will happen on the UI thread.
}
void DataReductionProxyIOData::ShutdownOnUIThread() {
DCHECK(ui_task_runner_->BelongsToCurrentThread());
network_properties_manager_->ShutdownOnUIThread();
}
void DataReductionProxyIOData::SetDataReductionProxyService(
base::WeakPtr<DataReductionProxyService> data_reduction_proxy_service) {
DCHECK(ui_task_runner_->BelongsToCurrentThread());
service_ = data_reduction_proxy_service;
url_request_context_getter_ = service_->url_request_context_getter();
// Using base::Unretained is safe here, unless the browser is being shut down
// before the Initialize task can be executed. The task is only created as
// part of class initialization.
if (io_task_runner_->BelongsToCurrentThread()) {
InitializeOnIOThread();
return;
}
io_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&DataReductionProxyIOData::InitializeOnIOThread,
base::Unretained(this)));
}
void DataReductionProxyIOData::InitializeOnIOThread() {
DCHECK(io_task_runner_->BelongsToCurrentThread());
DCHECK(network_properties_manager_);
config_->InitializeOnIOThread(basic_url_request_context_getter_.get(),
url_request_context_getter_,
network_properties_manager_.get());
bypass_stats_->InitializeOnIOThread();
proxy_delegate_->InitializeOnIOThread(this);
if (config_client_)
config_client_->InitializeOnIOThread(url_request_context_getter_);
if (ui_task_runner_->BelongsToCurrentThread()) {
service_->SetIOData(weak_factory_.GetWeakPtr());
return;
}
ui_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&DataReductionProxyService::SetIOData, service_,
weak_factory_.GetWeakPtr()));
}
bool DataReductionProxyIOData::IsEnabled() const {
DCHECK(io_task_runner_->BelongsToCurrentThread());
return enabled_;
}
void DataReductionProxyIOData::SetPingbackReportingFraction(
float pingback_reporting_fraction) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
ui_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&DataReductionProxyService::SetPingbackReportingFraction,
service_, pingback_reporting_fraction));
}
void DataReductionProxyIOData::DeleteBrowsingHistory(const base::Time start,
const base::Time end) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
network_properties_manager_->DeleteHistory();
}
void DataReductionProxyIOData::OnCacheCleared(const base::Time start,
const base::Time end) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
network_properties_manager_->DeleteHistory();
}
std::unique_ptr<net::URLRequestInterceptor>
DataReductionProxyIOData::CreateInterceptor() {
DCHECK(io_task_runner_->BelongsToCurrentThread());
return std::make_unique<DataReductionProxyInterceptor>(
config_.get(), config_client_.get(), bypass_stats_.get(),
event_creator_.get());
}
std::unique_ptr<DataReductionProxyNetworkDelegate>
DataReductionProxyIOData::CreateNetworkDelegate(
std::unique_ptr<net::NetworkDelegate> wrapped_network_delegate,
bool track_proxy_bypass_statistics) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
std::unique_ptr<DataReductionProxyNetworkDelegate> network_delegate(
new DataReductionProxyNetworkDelegate(
std::move(wrapped_network_delegate), config_.get(),
request_options_.get(), configurator_.get()));
if (track_proxy_bypass_statistics)
network_delegate->InitIODataAndUMA(this, bypass_stats_.get());
return network_delegate;
}
std::unique_ptr<DataReductionProxyDelegate>
DataReductionProxyIOData::CreateProxyDelegate() const {
DCHECK(io_task_runner_->BelongsToCurrentThread());
return std::make_unique<DataReductionProxyDelegate>(
config_.get(), configurator_.get(), event_creator_.get(),
bypass_stats_.get(), net_log_);
}
// TODO(kundaji): Rename this method to something more descriptive.
// Bug http://crbug/488190.
void DataReductionProxyIOData::SetProxyPrefs(bool enabled, bool at_startup) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
DCHECK(url_request_context_getter_->GetURLRequestContext()->proxy_resolution_service());
enabled_ = enabled;
config_->SetProxyConfig(enabled, at_startup);
if (config_client_) {
config_client_->SetEnabled(enabled);
if (enabled)
config_client_->RetrieveConfig();
}
// If Data Saver is disabled, reset data reduction proxy state.
if (!enabled) {
net::ProxyResolutionService* proxy_resolution_service =
url_request_context_getter_->GetURLRequestContext()->proxy_resolution_service();
proxy_resolution_service->ClearBadProxiesCache();
bypass_stats_->ClearRequestCounts();
bypass_stats_->NotifyUnavailabilityIfChanged();
}
}
void DataReductionProxyIOData::SetDataReductionProxyConfiguration(
const std::string& serialized_config) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
if (config_client_)
config_client_->ApplySerializedConfig(serialized_config);
}
bool DataReductionProxyIOData::ShouldAcceptServerPreview(
const net::URLRequest& request,
previews::PreviewsDecider* previews_decider) {
DCHECK(previews_decider);
DCHECK((request.load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED) != 0);
if (!config_ || !request.url().SchemeIsHTTPOrHTTPS()) {
return false;
}
return config_->ShouldAcceptServerPreview(request, *previews_decider);
}
void DataReductionProxyIOData::UpdateDataUseForHost(int64_t network_bytes,
int64_t original_bytes,
const std::string& host) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
ui_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&DataReductionProxyService::UpdateDataUseForHost, service_,
network_bytes, original_bytes, host));
}
void DataReductionProxyIOData::UpdateContentLengths(
int64_t data_used,
int64_t original_size,
bool data_reduction_proxy_enabled,
DataReductionProxyRequestType request_type,
const std::string& mime_type,
bool is_user_traffic,
data_use_measurement::DataUseUserData::DataUseContentType content_type,
int32_t service_hash_code) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
ui_task_runner_->PostTask(
FROM_HERE,
base::BindRepeating(&DataReductionProxyService::UpdateContentLengths,
service_, data_used, original_size,
data_reduction_proxy_enabled, request_type, mime_type,
is_user_traffic, content_type, service_hash_code));
}
void DataReductionProxyIOData::AddEvent(std::unique_ptr<base::Value> event) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
ui_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&DataReductionProxyService::AddEvent, service_,
std::move(event)));
}
void DataReductionProxyIOData::AddEnabledEvent(
std::unique_ptr<base::Value> event,
bool enabled) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
ui_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&DataReductionProxyService::AddEnabledEvent,
service_, std::move(event), enabled));
}
void DataReductionProxyIOData::AddEventAndSecureProxyCheckState(
std::unique_ptr<base::Value> event,
SecureProxyCheckState state) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
ui_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&DataReductionProxyService::AddEventAndSecureProxyCheckState,
service_, std::move(event), state));
}
void DataReductionProxyIOData::AddAndSetLastBypassEvent(
std::unique_ptr<base::Value> event,
int64_t expiration_ticks) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
ui_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&DataReductionProxyService::AddAndSetLastBypassEvent,
service_, std::move(event), expiration_ticks));
}
void DataReductionProxyIOData::SetUnreachable(bool unreachable) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
ui_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&DataReductionProxyService::SetUnreachable,
service_, unreachable));
}
void DataReductionProxyIOData::SetInt64Pref(const std::string& pref_path,
int64_t value) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
ui_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&DataReductionProxyService::SetInt64Pref,
service_, pref_path, value));
}
void DataReductionProxyIOData::SetStringPref(const std::string& pref_path,
const std::string& value) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
ui_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&DataReductionProxyService::SetStringPref,
service_, pref_path, value));
}
void DataReductionProxyIOData::StoreSerializedConfig(
const std::string& serialized_config) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
SetStringPref(prefs::kDataReductionProxyConfig, serialized_config);
SetInt64Pref(prefs::kDataReductionProxyLastConfigRetrievalTime,
(base::Time::Now() - base::Time()).InMicroseconds());
}
void DataReductionProxyIOData::SetDataUseAscriber(
data_use_measurement::DataUseAscriber* data_use_ascriber) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
DCHECK(data_use_ascriber);
data_use_observer_.reset(
new DataReductionProxyDataUseObserver(this, data_use_ascriber));
// Disable data use ascriber when data saver is not enabled.
if (!IsEnabled()) {
data_use_ascriber->DisableAscriber();
}
}
void DataReductionProxyIOData::SetPreviewsDecider(
previews::PreviewsDecider* previews_decider) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
DCHECK(previews_decider);
previews_decider_ = previews_decider;
}
void DataReductionProxyIOData::UpdateProxyRequestHeaders(
net::HttpRequestHeaders headers) {
ui_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&DataReductionProxyService::SetProxyRequestHeaders,
service_, std::move(headers)));
}
void DataReductionProxyIOData::OnEffectiveConnectionTypeChanged(
net::EffectiveConnectionType type) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
effective_connection_type_ = type;
}
void DataReductionProxyIOData::OnRTTOrThroughputEstimatesComputed(
base::TimeDelta http_rtt) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
config_->OnRTTOrThroughputEstimatesComputed(http_rtt);
}
net::EffectiveConnectionType
DataReductionProxyIOData::GetEffectiveConnectionType() const {
DCHECK(io_task_runner_->BelongsToCurrentThread());
return effective_connection_type_;
}
} // namespace data_reduction_proxy