| // 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 "services/network/network_context.h" |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "base/command_line.h" |
| #include "base/logging.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/optional.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/cookie_config/cookie_store_util.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 "mojo/public/cpp/bindings/strong_binding.h" |
| #include "net/cookies/cookie_monster.h" |
| #include "net/dns/host_resolver.h" |
| #include "net/dns/mapped_host_resolver.h" |
| #include "net/extras/sqlite/sqlite_channel_id_store.h" |
| #include "net/extras/sqlite/sqlite_persistent_cookie_store.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_resolution/proxy_config.h" |
| #include "net/reporting/reporting_policy.h" |
| #include "net/ssl/channel_id_service.h" |
| #include "net/ssl/default_channel_id_store.h" |
| #include "net/url_request/url_request_context.h" |
| #include "net/url_request/url_request_context_builder.h" |
| #include "services/network/http_server_properties_pref_delegate.h" |
| #include "services/network/ignore_errors_cert_verifier.h" |
| #include "services/network/network_service.h" |
| #include "services/network/proxy_config_service_mojo.h" |
| #include "services/network/public/cpp/features.h" |
| #include "services/network/public/cpp/network_switches.h" |
| #include "services/network/resource_scheduler_client.h" |
| #include "services/network/restricted_cookie_manager.h" |
| #include "services/network/throttling/network_conditions.h" |
| #include "services/network/throttling/throttling_controller.h" |
| #include "services/network/throttling/throttling_network_transaction_factory.h" |
| #include "services/network/udp_socket_factory.h" |
| #include "services/network/url_loader.h" |
| #include "services/network/url_loader_factory.h" |
| #include "services/network/url_request_context_builder_mojo.h" |
| |
| namespace network { |
| |
| namespace { |
| |
| net::CertVerifier* g_cert_verifier_for_testing = nullptr; |
| |
| // A CertVerifier that forwards all requests to |g_cert_verifier_for_testing|. |
| // This is used to allow NetworkContexts to have their own |
| // std::unique_ptr<net::CertVerifier> while forwarding calls to the shared |
| // verifier. |
| class WrappedTestingCertVerifier : public net::CertVerifier { |
| public: |
| ~WrappedTestingCertVerifier() override = default; |
| |
| // CertVerifier implementation |
| int Verify(const RequestParams& params, |
| net::CRLSet* crl_set, |
| net::CertVerifyResult* verify_result, |
| const net::CompletionCallback& callback, |
| std::unique_ptr<Request>* out_req, |
| const net::NetLogWithSource& net_log) override { |
| verify_result->Reset(); |
| if (!g_cert_verifier_for_testing) |
| return net::ERR_FAILED; |
| return g_cert_verifier_for_testing->Verify(params, crl_set, verify_result, |
| callback, out_req, net_log); |
| } |
| }; |
| |
| } // namespace |
| |
| constexpr bool NetworkContext::enable_resource_scheduler_; |
| |
| NetworkContext::NetworkContext(NetworkService* network_service, |
| mojom::NetworkContextRequest request, |
| mojom::NetworkContextParamsPtr params) |
| : network_service_(network_service), |
| params_(std::move(params)), |
| binding_(this, std::move(request)) { |
| url_request_context_owner_ = MakeURLRequestContext(params_.get()); |
| url_request_context_getter_ = |
| url_request_context_owner_.url_request_context_getter; |
| cookie_manager_ = |
| std::make_unique<CookieManager>(GetURLRequestContext()->cookie_store()); |
| network_service_->RegisterNetworkContext(this); |
| binding_.set_connection_error_handler(base::BindOnce( |
| &NetworkContext::OnConnectionError, base::Unretained(this))); |
| resource_scheduler_ = |
| std::make_unique<ResourceScheduler>(enable_resource_scheduler_); |
| } |
| |
| // 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( |
| NetworkService* network_service, |
| mojom::NetworkContextRequest request, |
| mojom::NetworkContextParamsPtr params, |
| std::unique_ptr<URLRequestContextBuilderMojo> builder) |
| : network_service_(network_service), |
| params_(std::move(params)), |
| binding_(this, std::move(request)) { |
| url_request_context_owner_ = ApplyContextParamsToBuilder( |
| builder.get(), params_.get(), network_service->quic_disabled(), |
| network_service->net_log()); |
| url_request_context_getter_ = |
| url_request_context_owner_.url_request_context_getter; |
| network_service_->RegisterNetworkContext(this); |
| cookie_manager_ = |
| std::make_unique<CookieManager>(GetURLRequestContext()->cookie_store()); |
| resource_scheduler_ = |
| std::make_unique<ResourceScheduler>(enable_resource_scheduler_); |
| } |
| |
| NetworkContext::NetworkContext( |
| NetworkService* network_service, |
| mojom::NetworkContextRequest request, |
| scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) |
| : network_service_(network_service), |
| url_request_context_getter_(std::move(url_request_context_getter)), |
| binding_(this, std::move(request)), |
| cookie_manager_(std::make_unique<CookieManager>( |
| url_request_context_getter_->GetURLRequestContext() |
| ->cookie_store())) { |
| // May be nullptr in tests. |
| if (network_service_) |
| network_service_->RegisterNetworkContext(this); |
| resource_scheduler_ = |
| std::make_unique<ResourceScheduler>(enable_resource_scheduler_); |
| } |
| |
| NetworkContext::~NetworkContext() { |
| // May be nullptr in tests. |
| if (network_service_) |
| network_service_->DeregisterNetworkContext(this); |
| } |
| |
| std::unique_ptr<NetworkContext> NetworkContext::CreateForTesting() { |
| return base::WrapUnique( |
| new NetworkContext(mojom::NetworkContextParams::New())); |
| } |
| |
| void NetworkContext::SetCertVerifierForTesting( |
| net::CertVerifier* cert_verifier) { |
| g_cert_verifier_for_testing = cert_verifier; |
| } |
| |
| void NetworkContext::CreateURLLoaderFactory( |
| mojom::URLLoaderFactoryRequest request, |
| uint32_t process_id, |
| scoped_refptr<ResourceSchedulerClient> resource_scheduler_client) { |
| loader_factory_bindings_.AddBinding( |
| std::make_unique<URLLoaderFactory>(this, process_id, |
| std::move(resource_scheduler_client)), |
| std::move(request)); |
| } |
| |
| void NetworkContext::CreateURLLoaderFactory( |
| mojom::URLLoaderFactoryRequest request, |
| uint32_t process_id) { |
| scoped_refptr<ResourceSchedulerClient> resource_scheduler_client; |
| if (process_id != 0) { |
| // Zero process ID means it's from the browser process and we don't want |
| // to throttle the requests. |
| resource_scheduler_client = base::MakeRefCounted<ResourceSchedulerClient>( |
| process_id, ++current_resource_scheduler_client_id_, |
| resource_scheduler_.get(), |
| GetURLRequestContext()->network_quality_estimator()); |
| } |
| CreateURLLoaderFactory(std::move(request), process_id, |
| std::move(resource_scheduler_client)); |
| } |
| |
| void NetworkContext::GetCookieManager(mojom::CookieManagerRequest request) { |
| cookie_manager_->AddRequest(std::move(request)); |
| } |
| |
| void NetworkContext::GetRestrictedCookieManager( |
| 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>( |
| GetURLRequestContext()->cookie_store(), |
| render_process_id, render_frame_id), |
| std::move(request)); |
| } |
| |
| void NetworkContext::DisableQuic() { |
| GetURLRequestContext() |
| ->http_transaction_factory() |
| ->GetSession() |
| ->DisableQuic(); |
| } |
| |
| net::URLRequestContext* NetworkContext::GetURLRequestContext() { |
| return url_request_context_getter_->GetURLRequestContext(); |
| } |
| |
| void NetworkContext::Cleanup() { |
| // The NetworkService is going away, so have to destroy the |
| // net::URLRequestContext held by this NetworkContext. |
| delete this; |
| } |
| |
| NetworkContext::NetworkContext(mojom::NetworkContextParamsPtr params) |
| : network_service_(nullptr), params_(std::move(params)), binding_(this) { |
| url_request_context_owner_ = MakeURLRequestContext(params_.get()); |
| url_request_context_getter_ = |
| url_request_context_owner_.url_request_context_getter; |
| |
| resource_scheduler_ = |
| std::make_unique<ResourceScheduler>(enable_resource_scheduler_); |
| } |
| |
| void NetworkContext::OnConnectionError() { |
| // Don't delete |this| in response to connection errors when it was created by |
| // CreateForTesting. |
| if (network_service_) |
| delete this; |
| } |
| |
| URLRequestContextOwner NetworkContext::MakeURLRequestContext( |
| mojom::NetworkContextParams* network_context_params) { |
| URLRequestContextBuilderMojo 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(network_context_params->user_agent); |
| |
| // The cookie configuration is in this method, which is only used by the |
| // network process, and not ApplyContextParamsToBuilder which is used by the |
| // browser as well. This is because this code path doesn't handle encryption |
| // and other configuration done in QuotaPolicyCookieStore yet (and we still |
| // have to figure out which of the latter needs to move to the network |
| // process). TODO: http://crbug.com/789644 |
| if (network_context_params->cookie_path) { |
| DCHECK(network_context_params->channel_id_path); |
| net::CookieCryptoDelegate* crypto_delegate = nullptr; |
| |
| scoped_refptr<base::SequencedTaskRunner> client_task_runner = |
| base::MessageLoop::current()->task_runner(); |
| scoped_refptr<base::SequencedTaskRunner> background_task_runner = |
| base::CreateSequencedTaskRunnerWithTraits( |
| {base::MayBlock(), base::TaskPriority::BACKGROUND, |
| base::TaskShutdownBehavior::BLOCK_SHUTDOWN}); |
| |
| scoped_refptr<net::SQLiteChannelIDStore> channel_id_db = |
| new net::SQLiteChannelIDStore( |
| network_context_params->channel_id_path.value(), |
| background_task_runner); |
| std::unique_ptr<net::ChannelIDService> channel_id_service( |
| std::make_unique<net::ChannelIDService>( |
| new net::DefaultChannelIDStore(channel_id_db.get()))); |
| |
| scoped_refptr<net::SQLitePersistentCookieStore> sqlite_store( |
| new net::SQLitePersistentCookieStore( |
| network_context_params->cookie_path.value(), client_task_runner, |
| background_task_runner, |
| network_context_params->restore_old_session_cookies, |
| crypto_delegate)); |
| |
| std::unique_ptr<net::CookieMonster> cookie_store = |
| std::make_unique<net::CookieMonster>(sqlite_store.get(), |
| channel_id_service.get()); |
| if (network_context_params->persist_session_cookies) |
| cookie_store->SetPersistSessionCookies(true); |
| |
| cookie_store->SetChannelIDServiceID(channel_id_service->GetUniqueID()); |
| builder.SetCookieAndChannelIdStores(std::move(cookie_store), |
| std::move(channel_id_service)); |
| } else { |
| DCHECK(!network_context_params->restore_old_session_cookies); |
| DCHECK(!network_context_params->persist_session_cookies); |
| } |
| |
| if (g_cert_verifier_for_testing) { |
| builder.SetCertVerifier(std::make_unique<WrappedTestingCertVerifier>()); |
| } else { |
| std::unique_ptr<net::CertVerifier> cert_verifier = |
| net::CertVerifier::CreateDefault(); |
| builder.SetCertVerifier(IgnoreErrorsCertVerifier::MaybeWrapCertVerifier( |
| *command_line, nullptr, std::move(cert_verifier))); |
| } |
| |
| // |network_service_| may be nullptr in tests. |
| return ApplyContextParamsToBuilder( |
| &builder, network_context_params, |
| network_service_ ? network_service_->quic_disabled() : false, |
| network_service_ ? network_service_->net_log() : nullptr); |
| } |
| |
| URLRequestContextOwner NetworkContext::ApplyContextParamsToBuilder( |
| URLRequestContextBuilderMojo* builder, |
| mojom::NetworkContextParams* network_context_params, |
| bool quic_disabled, |
| net::NetLog* net_log) { |
| if (net_log) |
| builder->set_net_log(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->proxy_resolver_factory) { |
| builder->SetMojoProxyResolverFactory( |
| proxy_resolver::mojom::ProxyResolverFactoryPtr( |
| std::move(network_context_params->proxy_resolver_factory))); |
| } |
| |
| 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->initial_proxy_config && |
| !network_context_params->proxy_config_client_request.is_pending()) { |
| network_context_params->initial_proxy_config = |
| net::ProxyConfig::CreateDirect(); |
| } |
| builder->set_proxy_config_service(std::make_unique<ProxyConfigServiceMojo>( |
| std::move(network_context_params->proxy_config_client_request), |
| std::move(network_context_params->initial_proxy_config), |
| std::move(network_context_params->proxy_config_poller_client))); |
| |
| std::unique_ptr<PrefService> pref_service; |
| 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()), |
| 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 |
| |
| #if BUILDFLAG(ENABLE_REPORTING) |
| if (base::FeatureList::IsEnabled(features::kReporting)) |
| builder->set_reporting_policy(std::make_unique<net::ReportingPolicy>()); |
| else |
| builder->set_reporting_policy(nullptr); |
| |
| builder->set_network_error_logging_enabled( |
| base::FeatureList::IsEnabled(features::kNetworkErrorLogging)); |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| |
| net::HttpNetworkSession::Params session_params; |
| bool is_quic_force_disabled = false; |
| if (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); |
| })); |
| return URLRequestContextOwner(std::move(pref_service), builder->Build()); |
| } |
| |
| 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. |
| GetURLRequestContext()->transport_security_state()->DeleteAllDynamicDataSince( |
| time); |
| |
| GetURLRequestContext()->http_server_properties()->Clear( |
| std::move(completion_callback)); |
| } |
| |
| 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)); |
| } |
| |
| void NetworkContext::CreateUDPSocket(mojom::UDPSocketRequest request, |
| mojom::UDPSocketReceiverPtr receiver) { |
| if (!udp_socket_factory_) |
| udp_socket_factory_ = std::make_unique<UDPSocketFactory>(); |
| udp_socket_factory_->CreateUDPSocket(std::move(request), std::move(receiver)); |
| } |
| |
| void NetworkContext::AddHSTSForTesting(const std::string& host, |
| base::Time expiry, |
| bool include_subdomains, |
| AddHSTSForTestingCallback callback) { |
| net::TransportSecurityState* state = |
| GetURLRequestContext()->transport_security_state(); |
| state->AddHSTS(host, expiry, include_subdomains); |
| std::move(callback).Run(); |
| } |
| |
| } // namespace network |