| // Copyright 2017 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 "content/network/network_context.h" |
| |
| #include "base/command_line.h" |
| #include "base/files/file_util.h" |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/rand_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/task_scheduler/post_task.h" |
| #include "base/task_scheduler/task_traits.h" |
| #include "build/build_config.h" |
| #include "components/network_session_configurator/browser/network_session_configurator.h" |
| #include "components/network_session_configurator/common/network_switches.h" |
| #include "components/prefs/json_pref_store.h" |
| #include "components/prefs/pref_registry_simple.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/prefs/pref_service_factory.h" |
| #include "content/network/cache_url_loader.h" |
| #include "content/network/http_server_properties_pref_delegate.h" |
| #include "content/network/network_service_impl.h" |
| #include "content/network/network_service_url_loader_factory.h" |
| #include "content/network/restricted_cookie_manager.h" |
| #include "content/network/throttling/network_conditions.h" |
| #include "content/network/throttling/throttling_controller.h" |
| #include "content/network/throttling/throttling_network_transaction_factory.h" |
| #include "content/network/url_loader.h" |
| #include "content/public/common/content_client.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/network/ignore_errors_cert_verifier.h" |
| #include "mojo/public/cpp/bindings/strong_binding.h" |
| #include "net/dns/host_resolver.h" |
| #include "net/dns/mapped_host_resolver.h" |
| #include "net/http/http_network_session.h" |
| #include "net/http/http_server_properties.h" |
| #include "net/http/http_server_properties_manager.h" |
| #include "net/http/http_transaction_factory.h" |
| #include "net/proxy/proxy_config.h" |
| #include "net/proxy/proxy_config_service_fixed.h" |
| #include "net/url_request/url_request_context.h" |
| #include "net/url_request/url_request_context_builder.h" |
| |
| namespace content { |
| |
| NetworkContext::NetworkContext(NetworkServiceImpl* network_service, |
| mojom::NetworkContextRequest request, |
| mojom::NetworkContextParamsPtr params) |
| : network_service_(network_service), |
| params_(std::move(params)), |
| binding_(this, std::move(request)) { |
| owned_url_request_context_ = MakeURLRequestContext(params_.get()); |
| url_request_context_ = owned_url_request_context_.get(); |
| cookie_manager_ = |
| std::make_unique<CookieManager>(url_request_context_->cookie_store()); |
| network_service_->RegisterNetworkContext(this); |
| binding_.set_connection_error_handler(base::BindOnce( |
| &NetworkContext::OnConnectionError, base::Unretained(this))); |
| } |
| |
| // TODO(mmenke): Share URLRequestContextBulder configuration between two |
| // constructors. Can only share them once consumer code is ready for its |
| // corresponding options to be overwritten. |
| NetworkContext::NetworkContext( |
| NetworkServiceImpl* network_service, |
| mojom::NetworkContextRequest request, |
| mojom::NetworkContextParamsPtr params, |
| std::unique_ptr<net::URLRequestContextBuilder> builder) |
| : network_service_(network_service), |
| params_(std::move(params)), |
| binding_(this, std::move(request)) { |
| if (params_ && params_->http_cache_path) { |
| // Only sample 0.1% of NetworkContexts that get created. |
| if (base::RandUint64() % 1000 == 0) |
| disk_checker_ = std::make_unique<DiskChecker>(*params_->http_cache_path); |
| } |
| network_service_->RegisterNetworkContext(this); |
| ApplyContextParamsToBuilder(builder.get(), params_.get()); |
| owned_url_request_context_ = builder->Build(); |
| url_request_context_ = owned_url_request_context_.get(); |
| cookie_manager_ = |
| std::make_unique<CookieManager>(url_request_context_->cookie_store()); |
| } |
| |
| NetworkContext::NetworkContext(mojom::NetworkContextRequest request, |
| net::URLRequestContext* url_request_context) |
| : network_service_(nullptr), |
| binding_(this, std::move(request)), |
| cookie_manager_(std::make_unique<CookieManager>( |
| url_request_context->cookie_store())) { |
| url_request_context_ = url_request_context; |
| } |
| |
| NetworkContext::~NetworkContext() { |
| // Call each URLLoader and ask it to release its net::URLRequest, as the |
| // corresponding net::URLRequestContext is going away with this |
| // NetworkContext. The loaders can be deregistering themselves in Cleanup(), |
| // so have to be careful. |
| while (!url_loaders_.empty()) |
| (*url_loaders_.begin())->Cleanup(); |
| |
| // May be nullptr in tests. |
| if (network_service_) |
| network_service_->DeregisterNetworkContext(this); |
| } |
| |
| std::unique_ptr<NetworkContext> NetworkContext::CreateForTesting() { |
| return base::WrapUnique(new NetworkContext); |
| } |
| |
| void NetworkContext::RegisterURLLoader(URLLoader* url_loader) { |
| DCHECK(url_loaders_.count(url_loader) == 0); |
| url_loaders_.insert(url_loader); |
| } |
| |
| void NetworkContext::DeregisterURLLoader(URLLoader* url_loader) { |
| size_t removed_count = url_loaders_.erase(url_loader); |
| DCHECK(removed_count); |
| } |
| |
| void NetworkContext::CreateURLLoaderFactory( |
| mojom::URLLoaderFactoryRequest request, |
| uint32_t process_id) { |
| loader_factory_bindings_.AddBinding( |
| std::make_unique<NetworkServiceURLLoaderFactory>(this, process_id), |
| std::move(request)); |
| } |
| |
| void NetworkContext::HandleViewCacheRequest(const GURL& url, |
| mojom::URLLoaderClientPtr client) { |
| StartCacheURLLoader(url, url_request_context_, std::move(client)); |
| } |
| |
| void NetworkContext::GetCookieManager( |
| network::mojom::CookieManagerRequest request) { |
| cookie_manager_->AddRequest(std::move(request)); |
| } |
| |
| void NetworkContext::GetRestrictedCookieManager( |
| network::mojom::RestrictedCookieManagerRequest request, |
| int32_t render_process_id, |
| int32_t render_frame_id) { |
| // TODO(crbug.com/729800): RestrictedCookieManager should own its bindings |
| // and NetworkContext should own the RestrictedCookieManager |
| // instances. |
| mojo::MakeStrongBinding(std::make_unique<RestrictedCookieManager>( |
| url_request_context_->cookie_store(), |
| render_process_id, render_frame_id), |
| std::move(request)); |
| } |
| |
| void NetworkContext::DisableQuic() { |
| url_request_context_->http_transaction_factory()->GetSession()->DisableQuic(); |
| } |
| |
| void NetworkContext::Cleanup() { |
| // The NetworkService is going away, so have to destroy the |
| // net::URLRequestContext held by this NetworkContext. |
| delete this; |
| } |
| |
| NetworkContext::NetworkContext() |
| : network_service_(nullptr), |
| params_(mojom::NetworkContextParams::New()), |
| binding_(this) { |
| owned_url_request_context_ = MakeURLRequestContext(params_.get()); |
| url_request_context_ = owned_url_request_context_.get(); |
| } |
| |
| void NetworkContext::OnConnectionError() { |
| // Don't delete |this| in response to connection errors when it was created by |
| // CreateForTesting. |
| if (network_service_) |
| delete this; |
| } |
| |
| NetworkContext::DiskChecker::DiskChecker(const base::FilePath& cache_path) |
| : cache_path_(cache_path) { |
| timer_.Start(FROM_HERE, base::TimeDelta::FromHours(24), |
| base::Bind(&DiskChecker::CheckDiskSize, base::Unretained(this))); |
| |
| // Check disk size at startup, hopefully before the HTTPCache has been cleared |
| // from the previous run. |
| CheckDiskSize(); |
| } |
| |
| void NetworkContext::DiskChecker::CheckDiskSize() { |
| base::PostTaskWithTraits( |
| FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, |
| base::Bind(&DiskChecker::CheckDiskSizeOnBackgroundThread, cache_path_)); |
| } |
| |
| void NetworkContext::DiskChecker::CheckDiskSizeOnBackgroundThread( |
| const base::FilePath& cache_path) { |
| int64_t size = base::ComputeDirectorySize(cache_path); |
| UMA_HISTOGRAM_MEMORY_LARGE_MB("Net.DiskCache.Size", size / 1024 / 1024); |
| } |
| |
| NetworkContext::DiskChecker::~DiskChecker() = default; |
| |
| std::unique_ptr<net::URLRequestContext> NetworkContext::MakeURLRequestContext( |
| mojom::NetworkContextParams* network_context_params) { |
| net::URLRequestContextBuilder builder; |
| const base::CommandLine* command_line = |
| base::CommandLine::ForCurrentProcess(); |
| |
| if (command_line->HasSwitch(switches::kHostResolverRules)) { |
| std::unique_ptr<net::HostResolver> host_resolver( |
| net::HostResolver::CreateDefaultResolver(nullptr)); |
| std::unique_ptr<net::MappedHostResolver> remapped_host_resolver( |
| new net::MappedHostResolver(std::move(host_resolver))); |
| remapped_host_resolver->SetRulesFromString( |
| command_line->GetSwitchValueASCII(switches::kHostResolverRules)); |
| builder.set_host_resolver(std::move(remapped_host_resolver)); |
| } |
| builder.set_accept_language("en-us,en"); |
| builder.set_user_agent(GetContentClient()->GetUserAgent()); |
| |
| if (command_line->HasSwitch(switches::kProxyServer)) { |
| net::ProxyConfig config; |
| config.proxy_rules().ParseFromString( |
| command_line->GetSwitchValueASCII(switches::kProxyServer)); |
| std::unique_ptr<net::ProxyConfigService> fixed_config_service = |
| std::make_unique<net::ProxyConfigServiceFixed>(config); |
| builder.set_proxy_config_service(std::move(fixed_config_service)); |
| } else { |
| builder.set_proxy_service(net::ProxyService::CreateDirect()); |
| } |
| |
| std::unique_ptr<net::CertVerifier> cert_verifier = |
| net::CertVerifier::CreateDefault(); |
| builder.SetCertVerifier( |
| content::IgnoreErrorsCertVerifier::MaybeWrapCertVerifier( |
| *command_line, nullptr, std::move(cert_verifier))); |
| |
| ApplyContextParamsToBuilder(&builder, network_context_params); |
| |
| return builder.Build(); |
| } |
| |
| void NetworkContext::ApplyContextParamsToBuilder( |
| net::URLRequestContextBuilder* builder, |
| mojom::NetworkContextParams* network_context_params) { |
| // |network_service_| may be nullptr in tests. |
| if (network_service_) |
| builder->set_net_log(network_service_->net_log()); |
| |
| builder->set_enable_brotli(network_context_params->enable_brotli); |
| if (network_context_params->context_name) |
| builder->set_name(*network_context_params->context_name); |
| |
| if (!network_context_params->http_cache_enabled) { |
| builder->DisableHttpCache(); |
| } else { |
| net::URLRequestContextBuilder::HttpCacheParams cache_params; |
| cache_params.max_size = network_context_params->http_cache_max_size; |
| if (!network_context_params->http_cache_path) { |
| cache_params.type = |
| net::URLRequestContextBuilder::HttpCacheParams::IN_MEMORY; |
| } else { |
| cache_params.path = *network_context_params->http_cache_path; |
| cache_params.type = network_session_configurator::ChooseCacheType( |
| *base::CommandLine::ForCurrentProcess()); |
| } |
| |
| builder->EnableHttpCache(cache_params); |
| } |
| |
| if (network_context_params->http_server_properties_path) { |
| scoped_refptr<JsonPrefStore> json_pref_store(new JsonPrefStore( |
| *network_context_params->http_server_properties_path, |
| base::CreateSequencedTaskRunnerWithTraits( |
| {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN, |
| base::TaskPriority::BACKGROUND}))); |
| PrefServiceFactory pref_service_factory; |
| pref_service_factory.set_user_prefs(json_pref_store); |
| pref_service_factory.set_async(true); |
| scoped_refptr<PrefRegistrySimple> pref_registry(new PrefRegistrySimple()); |
| HttpServerPropertiesPrefDelegate::RegisterPrefs(pref_registry.get()); |
| pref_service_ = pref_service_factory.Create(pref_registry.get()); |
| |
| builder->SetHttpServerProperties( |
| std::make_unique<net::HttpServerPropertiesManager>( |
| std::make_unique<HttpServerPropertiesPrefDelegate>( |
| pref_service_.get()), |
| network_service_->net_log())); |
| } |
| |
| builder->set_data_enabled(network_context_params->enable_data_url_support); |
| #if !BUILDFLAG(DISABLE_FILE_SUPPORT) |
| builder->set_file_enabled(network_context_params->enable_file_url_support); |
| #else // BUILDFLAG(DISABLE_FILE_SUPPORT) |
| DCHECK(!network_context_params->enable_file_url_support); |
| #endif |
| #if !BUILDFLAG(DISABLE_FTP_SUPPORT) |
| builder->set_ftp_enabled(network_context_params->enable_ftp_url_support); |
| #else // BUILDFLAG(DISABLE_FTP_SUPPORT) |
| DCHECK(!network_context_params->enable_ftp_url_support); |
| #endif |
| |
| net::HttpNetworkSession::Params session_params; |
| bool is_quic_force_disabled = false; |
| if (network_service_ && network_service_->quic_disabled()) |
| is_quic_force_disabled = true; |
| |
| network_session_configurator::ParseCommandLineAndFieldTrials( |
| *base::CommandLine::ForCurrentProcess(), is_quic_force_disabled, |
| network_context_params->quic_user_agent_id, &session_params); |
| |
| session_params.http_09_on_non_default_ports_enabled = |
| network_context_params->http_09_on_non_default_ports_enabled; |
| |
| builder->set_http_network_session_params(session_params); |
| builder->SetCreateHttpTransactionFactoryCallback( |
| base::BindOnce([](net::HttpNetworkSession* session) |
| -> std::unique_ptr<net::HttpTransactionFactory> { |
| return std::make_unique<ThrottlingNetworkTransactionFactory>(session); |
| })); |
| } |
| |
| void NetworkContext::ClearNetworkingHistorySince( |
| base::Time time, |
| base::OnceClosure completion_callback) { |
| // TODO(mmenke): Neither of these methods waits until the changes have been |
| // commited to disk. They probably should, as most similar methods net/ |
| // exposes do. |
| |
| // Completes synchronously. |
| url_request_context_->transport_security_state()->DeleteAllDynamicDataSince( |
| time); |
| |
| url_request_context_->http_server_properties()->Clear(); |
| std::move(completion_callback).Run(); |
| } |
| |
| void NetworkContext::SetNetworkConditions( |
| const std::string& profile_id, |
| mojom::NetworkConditionsPtr conditions) { |
| std::unique_ptr<NetworkConditions> network_conditions; |
| if (conditions) { |
| network_conditions.reset(new NetworkConditions( |
| conditions->offline, conditions->latency.InMillisecondsF(), |
| conditions->download_throughput, conditions->upload_throughput)); |
| } |
| ThrottlingController::SetConditions(profile_id, |
| std::move(network_conditions)); |
| } |
| |
| } // namespace content |