| // Copyright 2017 The Chromium Authors |
| // 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 <algorithm> |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <tuple> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/barrier_closure.h" |
| #include "base/base64.h" |
| #include "base/build_time.h" |
| #include "base/callback_list.h" |
| #include "base/check.h" |
| #include "base/check_op.h" |
| #include "base/command_line.h" |
| #include "base/containers/flat_set.h" |
| #include "base/containers/to_vector.h" |
| #include "base/containers/unique_ptr_adapters.h" |
| #include "base/dcheck_is_on.h" |
| #include "base/feature_list.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/sequence_checker.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/task/current_thread.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/task/task_traits.h" |
| #include "base/task/thread_pool.h" |
| #include "base/time/time.h" |
| #include "base/types/optional_util.h" |
| #include "build/build_config.h" |
| #include "build/chromecast_buildflags.h" |
| #include "components/cookie_config/cookie_store_util.h" |
| #include "components/domain_reliability/monitor.h" |
| #include "components/ip_protection/common/ip_protection_core_host_remote.h" |
| #include "components/ip_protection/common/ip_protection_core_impl_mojo.h" |
| #include "components/ip_protection/common/ip_protection_proxy_delegate.h" |
| #include "components/network_session_configurator/browser/network_session_configurator.h" |
| #include "components/network_session_configurator/common/network_switches.h" |
| #include "components/os_crypt/async/common/encryptor.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 "components/url_matcher/url_matcher.h" |
| #include "components/url_matcher/url_util.h" |
| #include "mojo/public/cpp/bindings/pending_receiver.h" |
| #include "net/base/features.h" |
| #include "net/base/isolation_info.h" |
| #include "net/base/load_flags.h" |
| #include "net/base/net_errors.h" |
| #include "net/base/network_anonymization_key.h" |
| #include "net/base/network_delegate.h" |
| #include "net/base/network_isolation_key.h" |
| #include "net/base/port_util.h" |
| #include "net/base/reconnect_notifier.h" |
| #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| #include "net/cert/caching_cert_verifier.h" |
| #include "net/cert/cert_verifier.h" |
| #include "net/cert/coalescing_cert_verifier.h" |
| #include "net/cookies/cookie_access_delegate.h" |
| #include "net/cookies/cookie_constants.h" |
| #include "net/cookies/cookie_monster.h" |
| #include "net/cookies/cookie_setting_override.h" |
| #include "net/device_bound_sessions/session_service.h" |
| #include "net/dns/host_cache.h" |
| #include "net/dns/mapped_host_resolver.h" |
| #include "net/extras/sqlite/cookie_crypto_delegate.h" |
| #include "net/extras/sqlite/sqlite_persistent_cookie_store.h" |
| #include "net/first_party_sets/first_party_set_metadata.h" |
| #include "net/http/http_auth.h" |
| #include "net/http/http_auth_handler_factory.h" |
| #include "net/http/http_auth_preferences.h" |
| #include "net/http/http_auth_scheme.h" |
| #include "net/http/http_cache.h" |
| #include "net/http/http_network_layer.h" |
| #include "net/http/http_network_session.h" |
| #include "net/http/http_request_headers.h" |
| #include "net/http/http_server_properties.h" |
| #include "net/http/http_transaction_factory.h" |
| #include "net/log/net_log_source_type.h" |
| #include "net/net_buildflags.h" |
| #include "net/proxy_resolution/configured_proxy_resolution_service.h" |
| #include "net/proxy_resolution/proxy_config.h" |
| #include "net/shared_dictionary/shared_dictionary_isolation_key.h" |
| #include "net/storage_access_api/status.h" |
| #include "net/traffic_annotation/network_traffic_annotation.h" |
| #include "net/url_request/static_http_user_agent_settings.h" |
| #include "net/url_request/url_request.h" |
| #include "net/url_request/url_request_context.h" |
| #include "net/url_request/url_request_context_builder.h" |
| #include "services/network/brokered_client_socket_factory.h" |
| #include "services/network/connection_change_observer.h" |
| #include "services/network/cookie_manager.h" |
| #include "services/network/data_remover_util.h" |
| #include "services/network/device_bound_session_manager.h" |
| #include "services/network/devtools_durable_msg_collector.h" |
| #include "services/network/disk_cache/mojo_backend_file_operations_factory.h" |
| #include "services/network/host_resolver.h" |
| #include "services/network/http_auth_cache_proxy_copier.h" |
| #include "services/network/http_server_properties_pref_delegate.h" |
| #include "services/network/ignore_errors_cert_verifier.h" |
| #include "services/network/is_browser_initiated.h" |
| #include "services/network/known_legacy_scope_domains_delegate.h" |
| #include "services/network/net_log_exporter.h" |
| #include "services/network/network_service.h" |
| #include "services/network/network_service_network_delegate.h" |
| #include "services/network/network_service_proxy_delegate.h" |
| #include "services/network/oblivious_http_request_handler.h" |
| #include "services/network/prefetch_cache.h" |
| #include "services/network/prefetch_matching_url_loader_factory.h" |
| #include "services/network/prefetch_url_loader_client.h" |
| #include "services/network/proxy_config_service_mojo.h" |
| #include "services/network/proxy_lookup_request.h" |
| #include "services/network/proxy_resolving_socket_factory_mojo.h" |
| #include "services/network/public/cpp/cert_verifier/mojo_cert_verifier.h" |
| #include "services/network/public/cpp/content_security_policy/content_security_policy.h" |
| #include "services/network/public/cpp/network_switches.h" |
| #include "services/network/public/cpp/parsed_headers.h" |
| #include "services/network/public/cpp/resource_request.h" |
| #include "services/network/public/cpp/simple_host_resolver.h" |
| #include "services/network/public/mojom/clear_data_filter.mojom.h" |
| #include "services/network/public/mojom/connection_change_observer_client.mojom-forward.h" |
| #include "services/network/public/mojom/cookie_encryption_provider.mojom.h" |
| #include "services/network/public/mojom/network_context.mojom.h" |
| #include "services/network/public/mojom/reporting_service.mojom.h" |
| #include "services/network/public/mojom/trust_tokens.mojom-forward.h" |
| #include "services/network/public/mojom/url_loader_factory.mojom.h" |
| #include "services/network/public/mojom/web_transport.mojom.h" |
| #include "services/network/resolve_host_request.h" |
| #include "services/network/resource_scheduler/resource_scheduler_client.h" |
| #include "services/network/restricted_cookie_manager.h" |
| #include "services/network/session_cleanup_cookie_store.h" |
| #include "services/network/shared_dictionary/shared_dictionary_constants.h" |
| #include "services/network/shared_dictionary/shared_dictionary_manager.h" |
| #include "services/network/shared_dictionary/shared_dictionary_storage.h" |
| #include "services/network/shared_resource_checker.h" |
| #include "services/network/ssl_config_service_mojo.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/trust_tokens/expiry_inspecting_record_expiry_delegate.h" |
| #include "services/network/trust_tokens/in_memory_trust_token_persister.h" |
| #include "services/network/trust_tokens/pending_trust_token_store.h" |
| #include "services/network/trust_tokens/sqlite_trust_token_persister.h" |
| #include "services/network/trust_tokens/suitable_trust_token_origin.h" |
| #include "services/network/trust_tokens/trust_token_parameterization.h" |
| #include "services/network/trust_tokens/trust_token_query_answerer.h" |
| #include "services/network/trust_tokens/trust_token_store.h" |
| #include "services/network/url_loader.h" |
| #include "services/network/url_request_context_builder_mojo.h" |
| #include "services/network/web_transport.h" |
| #include "url/gurl.h" |
| |
| #if BUILDFLAG(IS_CT_SUPPORTED) |
| // gn check does not account for BUILDFLAG(). So, for iOS builds, it will |
| // complain about a missing dependency on the target exposing this header. Add a |
| // nogncheck to stop it from yelling. |
| #include "components/certificate_transparency/chrome_require_ct_delegate.h" // nogncheck |
| #include "services/network/sct_auditing/sct_auditing_cache.h" |
| #include "services/network/sct_auditing/sct_auditing_handler.h" |
| #endif // BUILDFLAG(IS_CT_SUPPORTED) |
| |
| #if BUILDFLAG(ENABLE_WEBSOCKETS) |
| #include "services/network/websocket_factory.h" |
| #endif // BUILDFLAG(ENABLE_WEBSOCKETS) |
| |
| #if BUILDFLAG(ENABLE_REPORTING) |
| #include "net/base/http_user_agent_settings.h" |
| #include "net/extras/sqlite/sqlite_persistent_reporting_and_nel_store.h" |
| #include "net/network_error_logging/network_error_logging_service.h" |
| #include "net/reporting/reporting_browsing_data_remover.h" |
| #include "net/reporting/reporting_policy.h" |
| #include "net/reporting/reporting_service.h" |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| |
| #if BUILDFLAG(ENABLE_MDNS) |
| #include "services/network/mdns_responder.h" |
| #endif // BUILDFLAG(ENABLE_MDNS) |
| |
| #if BUILDFLAG(IS_P2P_ENABLED) |
| #include "services/network/p2p/socket_manager.h" |
| #endif // BUILDFLAG(IS_P2P_ENABLED) |
| |
| #if BUILDFLAG(IS_ANDROID) |
| #include "base/android/application_status_listener.h" |
| #endif // BUILDFLAG(IS_ANDROID) |
| |
| 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::CertVerifyResult* verify_result, |
| net::CompletionOnceCallback 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, verify_result, std::move(callback), out_req, net_log); |
| } |
| void Verify2QwacBinding( |
| const std::string& binding, |
| const std::string& hostname, |
| const scoped_refptr<net::X509Certificate>& tls_cert, |
| base::OnceCallback<void(const scoped_refptr<net::X509Certificate>&)> |
| callback, |
| const net::NetLogWithSource& net_log) override { |
| if (!g_cert_verifier_for_testing) { |
| base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( |
| FROM_HERE, base::BindOnce(std::move(callback), nullptr)); |
| return; |
| } |
| g_cert_verifier_for_testing->Verify2QwacBinding( |
| binding, hostname, tls_cert, std::move(callback), net_log); |
| } |
| void SetConfig(const Config& config) override { |
| if (!g_cert_verifier_for_testing) { |
| return; |
| } |
| g_cert_verifier_for_testing->SetConfig(config); |
| } |
| void AddObserver(Observer* observer) override { |
| if (!g_cert_verifier_for_testing) { |
| return; |
| } |
| g_cert_verifier_for_testing->AddObserver(observer); |
| } |
| void RemoveObserver(Observer* observer) override { |
| if (!g_cert_verifier_for_testing) { |
| return; |
| } |
| g_cert_verifier_for_testing->RemoveObserver(observer); |
| } |
| }; |
| |
| // This implementation initializes an OSCryptAsync Encryptor instance and uses |
| // that. |
| class CookieOSCryptAsyncDelegate : public net::CookieCryptoDelegate { |
| public: |
| explicit CookieOSCryptAsyncDelegate( |
| mojo::PendingRemote<network::mojom::CookieEncryptionProvider> provider); |
| |
| CookieOSCryptAsyncDelegate(const CookieOSCryptAsyncDelegate&) = delete; |
| CookieOSCryptAsyncDelegate& operator=(const CookieOSCryptAsyncDelegate&) = |
| delete; |
| |
| void Init(base::OnceClosure callback) override; |
| bool EncryptString(const std::string& plaintext, |
| std::string* ciphertext) override; |
| bool DecryptString(const std::string& ciphertext, |
| std::string* plaintext) override; |
| |
| private: |
| void InitCallback( |
| mojo::Remote<network::mojom::CookieEncryptionProvider> lifetime, |
| os_crypt_async::Encryptor encryptor); |
| |
| std::optional<os_crypt_async::Encryptor> instance_; |
| mojo::PendingRemote<network::mojom::CookieEncryptionProvider> provider_ |
| GUARDED_BY_CONTEXT(sequence_checker_); |
| base::OnceClosureList callbacks_ GUARDED_BY_CONTEXT(sequence_checker_); |
| bool is_initializing_ GUARDED_BY_CONTEXT(sequence_checker_) = false; |
| bool is_initialized_ GUARDED_BY_CONTEXT(sequence_checker_) = false; |
| |
| SEQUENCE_CHECKER(sequence_checker_); |
| |
| base::WeakPtrFactory<CookieOSCryptAsyncDelegate> weak_ptr_factory_{this}; |
| }; |
| |
| CookieOSCryptAsyncDelegate::CookieOSCryptAsyncDelegate( |
| mojo::PendingRemote<network::mojom::CookieEncryptionProvider> provider) |
| : provider_(std::move(provider)) { |
| DETACH_FROM_SEQUENCE(sequence_checker_); |
| } |
| |
| bool CookieOSCryptAsyncDelegate::EncryptString(const std::string& plaintext, |
| std::string* ciphertext) { |
| return instance_->EncryptString(plaintext, ciphertext); |
| } |
| |
| bool CookieOSCryptAsyncDelegate::DecryptString(const std::string& ciphertext, |
| std::string* plaintext) { |
| return instance_->DecryptString(ciphertext, plaintext); |
| } |
| |
| void CookieOSCryptAsyncDelegate::InitCallback( |
| mojo::Remote<network::mojom::CookieEncryptionProvider> lifetime, |
| os_crypt_async::Encryptor encryptor) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| instance_.emplace(std::move(encryptor)); |
| is_initialized_ = true; |
| callbacks_.Notify(); |
| } |
| |
| void CookieOSCryptAsyncDelegate::Init(base::OnceClosure callback) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (is_initialized_) { |
| std::move(callback).Run(); |
| return; |
| } |
| |
| // AddUnsafe is safe here because it's always called with a callback that is |
| // owned by a refcounted object. See SQLitePersistentCookieStore::Backend. |
| callbacks_.AddUnsafe(std::move(callback)); |
| |
| if (is_initializing_) { |
| return; |
| } |
| |
| is_initializing_ = true; |
| mojo::Remote<network::mojom::CookieEncryptionProvider> remote( |
| std::move(provider_)); |
| auto* raw_remote = remote.get(); |
| raw_remote->GetEncryptor( |
| base::BindOnce(&CookieOSCryptAsyncDelegate::InitCallback, |
| weak_ptr_factory_.GetWeakPtr(), std::move(remote))); |
| } |
| |
| // Predicate function to determine if the given |domain| matches the |
| // |filter_type| and |filter_domains| from a |mojom::ClearDataFilter|. |
| bool MatchesDomainFilter(mojom::ClearDataFilter_Type filter_type, |
| std::set<std::string> filter_domains, |
| const std::string& domain) { |
| bool found_domain = filter_domains.find(domain) != filter_domains.end(); |
| return (filter_type == mojom::ClearDataFilter_Type::DELETE_MATCHES) == |
| found_domain; |
| } |
| |
| // Returns a callback that checks if a domain matches the |filter|. |filter| |
| // must contain no origins. A null filter matches everything. |
| base::RepeatingCallback<bool(const std::string& host_name)> MakeDomainFilter( |
| mojom::ClearDataFilter* filter) { |
| if (!filter) { |
| return base::BindRepeating([](const std::string&) { return true; }); |
| } |
| |
| DCHECK(filter->origins.empty()) |
| << "Origin filtering not allowed in a domain-only filter"; |
| |
| std::set<std::string> filter_domains; |
| filter_domains.insert(filter->domains.begin(), filter->domains.end()); |
| return base::BindRepeating(&MatchesDomainFilter, filter->type, |
| std::move(filter_domains)); |
| } |
| |
| // Predicate function to determine if the given |origin| matches the |
| // |filter_type|, |filter_domains| and |filter_origins| from a |
| // |mojom::ClearDataFilter|. |
| bool MatchesOriginFilter(mojom::ClearDataFilter_Type filter_type, |
| std::set<std::string> filter_domains, |
| std::set<url::Origin> filter_origins, |
| const url::Origin& origin) { |
| std::string url_registrable_domain = |
| net::registry_controlled_domains::GetDomainAndRegistry( |
| origin, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); |
| bool found_domain = |
| (filter_domains.find(url_registrable_domain != "" |
| ? url_registrable_domain |
| : origin.host()) != filter_domains.end()); |
| |
| bool found_origin = (filter_origins.find(origin) != filter_origins.end()); |
| |
| return (filter_type == mojom::ClearDataFilter_Type::DELETE_MATCHES) == |
| (found_domain || found_origin); |
| } |
| |
| // Builds a generic Origin-matching predicate function based on |filter|. If |
| // |filter| is null, creates an always-true predicate. |
| base::RepeatingCallback<bool(const url::Origin&)> BuildOriginFilter( |
| mojom::ClearDataFilterPtr filter) { |
| if (!filter) { |
| return base::BindRepeating([](const url::Origin&) { return true; }); |
| } |
| |
| std::set<std::string> filter_domains; |
| filter_domains.insert(filter->domains.begin(), filter->domains.end()); |
| |
| std::set<url::Origin> filter_origins; |
| filter_origins.insert(filter->origins.begin(), filter->origins.end()); |
| |
| return base::BindRepeating(&MatchesOriginFilter, filter->type, |
| std::move(filter_domains), |
| std::move(filter_origins)); |
| } |
| |
| // Builds a generic URL-matching predicate function based on |filter|. |
| // If |filter| is null, creates an always-true predicate. |
| base::RepeatingCallback<bool(const GURL&)> BuildUrlFilter( |
| mojom::ClearDataFilterPtr filter) { |
| return filter ? BindDoesUrlMatchFilter(filter->type, filter->origins, |
| filter->domains) |
| : base::NullCallback(); |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| class NetworkContextApplicationStatusListener |
| : public base::android::ApplicationStatusListener { |
| public: |
| // Sets `get_callback` to be a callback that returns nullptr if the created |
| // NetworkContextApplicationStatusListener has been destroyed, and the |
| // listener itself, otherwise. It's a constructor argument to avoid needing |
| // a cast, moving this into the header, or other complexities around |
| // `app_status_listeners_` being a vector of the parent class. |
| explicit NetworkContextApplicationStatusListener( |
| disk_cache::ApplicationStatusListenerGetter& get_callback) { |
| get_callback = |
| base::BindRepeating(&NetworkContextApplicationStatusListener:: |
| ReturnAppStatusListenerIfAlive, |
| weak_ptr_factory_.GetWeakPtr()); |
| } |
| |
| // base::android::ApplicationStatusListener implementation: |
| void SetCallback(const ApplicationStateChangeCallback& callback) override { |
| DCHECK(!callback_); |
| DCHECK(callback); |
| callback_ = callback; |
| } |
| |
| void Notify(base::android::ApplicationState state) override { |
| if (callback_) { |
| callback_.Run(state); |
| } |
| } |
| |
| private: |
| static base::android::ApplicationStatusListener* |
| ReturnAppStatusListenerIfAlive( |
| base::WeakPtr<base::android::ApplicationStatusListener> listener) { |
| return listener.get(); |
| } |
| |
| ApplicationStateChangeCallback callback_; |
| base::WeakPtrFactory<base::android::ApplicationStatusListener> |
| weak_ptr_factory_{this}; |
| }; |
| |
| #endif // BUILDFLAG(IS_ANDROID) |
| |
| struct TestVerifyCertState { |
| net::CertVerifyResult result; |
| std::unique_ptr<net::CertVerifier::Request> request; |
| }; |
| |
| void TestVerifyCertCallback( |
| std::unique_ptr<TestVerifyCertState> request, |
| NetworkContext::VerifyCertificateForTestingCallback callback, |
| int result) { |
| std::move(callback).Run(result); |
| } |
| |
| std::string HashesToBase64String( |
| const absl::flat_hash_set<net::SHA256HashValue>& hashes) { |
| std::vector<std::string> strings; |
| strings.reserve(hashes.size()); |
| for (const auto& hash : hashes) { |
| strings.push_back(net::HashValue(hash).ToString()); |
| } |
| return base::JoinString(strings, ","); |
| } |
| |
| #if BUILDFLAG(IS_CT_SUPPORTED) |
| // SCTAuditingDelegate is an implementation of the delegate interface that is |
| // aware of per-NetworkContext details (to allow the cache to notify the |
| // associated NetworkContextClient of new reports, and to apply |
| // per-NetworkContext enabled/disabled status for the auditing feature). |
| class SCTAuditingDelegate : public net::SCTAuditingDelegate { |
| public: |
| explicit SCTAuditingDelegate(const base::WeakPtr<NetworkContext>& context); |
| ~SCTAuditingDelegate() override; |
| |
| // net::SCTAuditingDelegate: |
| void MaybeEnqueueReport( |
| const net::HostPortPair& host_port_pair, |
| const net::X509Certificate* validated_certificate_chain, |
| const net::SignedCertificateTimestampAndStatusList& |
| signed_certificate_timestamps) override; |
| |
| private: |
| base::WeakPtr<NetworkContext> context_; |
| }; |
| |
| SCTAuditingDelegate::SCTAuditingDelegate( |
| const base::WeakPtr<NetworkContext>& context) |
| : context_(context) {} |
| |
| SCTAuditingDelegate::~SCTAuditingDelegate() = default; |
| |
| void SCTAuditingDelegate::MaybeEnqueueReport( |
| const net::HostPortPair& host_port_pair, |
| const net::X509Certificate* validated_certificate_chain, |
| const net::SignedCertificateTimestampAndStatusList& |
| signed_certificate_timestamps) { |
| if (!context_) { |
| return; |
| } |
| context_->MaybeEnqueueSCTReport(host_port_pair, validated_certificate_chain, |
| signed_certificate_timestamps); |
| } |
| #endif // BUILDFLAG(IS_CT_SUPPORTED) |
| |
| // Obtains a full data file path from a NetworkContextFilePaths, a class member |
| // pointer to the data file. If valid, then returns true and places the full |
| // path into `full_path` otherwise returns false. |
| bool GetFullDataFilePath( |
| const mojom::NetworkContextFilePathsPtr& file_paths, |
| std::optional<base::FilePath> network::mojom::NetworkContextFilePaths::* |
| field_name, |
| base::FilePath& full_path) { |
| if (!file_paths) { |
| return false; |
| } |
| |
| std::optional<base::FilePath> relative_file_path = |
| file_paths.get()->*field_name; |
| if (!relative_file_path.has_value()) { |
| return false; |
| } |
| |
| // Path to a data file should always be a plain filename. |
| DCHECK_EQ(relative_file_path->BaseName(), *relative_file_path); |
| |
| full_path = |
| file_paths->data_directory.path().Append(relative_file_path->value()); |
| return true; |
| } |
| |
| // Produces URLLoaderFactoryParams suitable for a prefetch. Generally this |
| // should match the params that are used for subresource fetches to render |
| // processes. |
| mojom::URLLoaderFactoryParamsPtr CreateURLLoaderFactoryParamsForPrefetch() { |
| auto params = mojom::URLLoaderFactoryParams::New(); |
| params->process_id = mojom::kBrowserProcessId; |
| // We want to be able to use TrustedParams to set the IsolationInfo for each |
| // prefetch separately, so make it trusted. |
| // TODO(crbug.com/342445996): Maybe stop using TrustedParams and lock this |
| // down? |
| params->is_trusted = true; |
| |
| // This can be set to true by the content::switches::kDisableWebSecurity |
| // switch, but that's not available in the network service. The consequences |
| // of this being disabled should just be that prefetches fail where this flag |
| // would have taken effect. |
| // TODO(crbug.com/342445996): Pass this through from the caller. |
| // |
| // Android WebView also disables web security when the |
| // `allow_universal_access_from_file_urls` flag is set, however, WebView |
| // doesn't currently support prefetch anyway. |
| params->disable_web_security = false; |
| |
| // TODO(crbug.com/342445996): Find out if we need to set anything here. |
| params->client_security_state = mojom::ClientSecurityState::New(); |
| |
| // TODO(crbug.com/342445996): params->coep_reporter |
| |
| // --disable-web-security also disables Opaque Response Blocking (ORB). |
| params->is_orb_enabled = !params->disable_web_security; |
| |
| // TODO(crbug.com/342445996): trust_token_issuance_policy, |
| // trust_token_redemption_policy |
| |
| // TODO(crbug.com/342445996): Add observers as needed for DevTools support, |
| // etc. |
| |
| // TODO(crbug.com/342445996): params->cookie_setting_overrides |
| |
| params->debug_tag = "CreateURLLoaderFactoryParamsForPrefetch"; |
| |
| // TODO(crbug.com/342445996): params->require_cross_site_requests_for_cookies |
| |
| return params; |
| } |
| |
| // These values are persisted to logs. Entries should not be renumbered and |
| // numeric values should never be reused. |
| // |
| // LINT.IfChange(HSTSRedirectUpgradeReason) |
| enum class HSTSRedirectUpgradeReason { |
| kNotUpgradedNotHTTP = 0, |
| kNotUpgradedHSTSUnavailable = 1, |
| kNotUpgradedNoHSTSPin = 2, |
| kUpgraded = 3, |
| kMaxValue = kUpgraded, |
| }; |
| // LINT.ThenChange(//tools/metrics/histograms/metadata/net/enums.xml:HSTSRedirectUpgradeReason) |
| |
| void RecordHSTSPreconnectUpgradeReason(HSTSRedirectUpgradeReason reason) { |
| if (!base::FeatureList::IsEnabled( |
| net::features::kHstsTopLevelNavigationsOnly)) { |
| base::UmaHistogramEnumeration("Net.PreconnectHSTSUpgradesUrl", reason); |
| } |
| } |
| |
| } // namespace |
| |
| constexpr uint32_t NetworkContext::kMaxOutstandingRequestsPerProcess; |
| |
| NetworkContext::NetworkContextHttpAuthPreferences:: |
| NetworkContextHttpAuthPreferences(NetworkService* network_service) |
| : network_service_(network_service) {} |
| |
| NetworkContext::NetworkContextHttpAuthPreferences:: |
| ~NetworkContextHttpAuthPreferences() = default; |
| |
| #if BUILDFLAG(IS_LINUX) |
| bool NetworkContext::NetworkContextHttpAuthPreferences::AllowGssapiLibraryLoad() |
| const { |
| if (network_service_) { |
| network_service_->OnBeforeGssapiLibraryLoad(); |
| } |
| return net::HttpAuthPreferences::AllowGssapiLibraryLoad(); |
| } |
| #endif // BUILDFLAG(IS_LINUX) |
| |
| NetworkContext::PendingCertVerify::PendingCertVerify() = default; |
| NetworkContext::PendingCertVerify::~PendingCertVerify() = default; |
| |
| NetworkContext::NetworkContext( |
| NetworkService* network_service, |
| mojo::PendingReceiver<mojom::NetworkContext> receiver, |
| mojom::NetworkContextParamsPtr params, |
| OnConnectionCloseCallback on_connection_close_callback) |
| : NetworkContext(base::PassKey<NetworkContext>(), |
| network_service, |
| std::move(receiver), |
| std::move(params), |
| std::move(on_connection_close_callback), |
| OnURLRequestContextBuilderConfiguredCallback()) {} |
| |
| // net::NetworkDelegate that wraps |
| NetworkContext::NetworkContext( |
| base::PassKey<NetworkContext> pass_key, |
| NetworkService* network_service, |
| mojo::PendingReceiver<mojom::NetworkContext> receiver, |
| mojom::NetworkContextParamsPtr params, |
| OnConnectionCloseCallback on_connection_close_callback, |
| OnURLRequestContextBuilderConfiguredCallback |
| on_url_request_context_builder_configured) |
| : network_service_(network_service), |
| url_request_context_(nullptr), |
| #if BUILDFLAG(ENABLE_REPORTING) |
| is_observing_reporting_service_(false), |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| params_(std::move(params)), |
| on_connection_close_callback_(std::move(on_connection_close_callback)), |
| receiver_(this, std::move(receiver)), |
| first_party_sets_access_delegate_( |
| std::move(params_->first_party_sets_access_delegate_receiver), |
| std::move(params_->first_party_sets_access_delegate_params), |
| network_service_->first_party_sets_manager()), |
| cors_preflight_controller_(network_service), |
| http_auth_merged_preferences_(network_service), |
| ohttp_handler_(this), |
| prefetch_enabled_( |
| base::FeatureList::IsEnabled(features::kNetworkContextPrefetch) && |
| (params_->bound_network == net::handles::kInvalidNetworkHandle)), |
| cors_non_wildcard_request_headers_support_(base::FeatureList::IsEnabled( |
| features::kCorsNonWildcardRequestHeadersSupport)), |
| prefetch_cache_(prefetch_enabled_ ? std::make_unique<PrefetchCache>() |
| : nullptr) { |
| #if BUILDFLAG(IS_WIN) && DCHECK_IS_ON() |
| if (params_->file_paths) { |
| DCHECK(params_->win_permissions_set) |
| << "Permissions not set on files. Network context should be created " |
| "using CreateNetworkContextInNetworkService rather than directly on " |
| "the network service."; |
| } |
| #endif // BUILDFLAG(IS_WIN) && DCHECK_IS_ON() |
| |
| #if BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED) |
| if (params_->file_paths) { |
| if (params_->file_paths->http_cache_directory) { |
| EnsureMounted(&*params_->file_paths->http_cache_directory); |
| } |
| if (params_->file_paths->shared_dictionary_directory) { |
| EnsureMounted(&*params_->file_paths->shared_dictionary_directory); |
| } |
| EnsureMounted(¶ms_->file_paths->data_directory); |
| } |
| #endif // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED) |
| |
| if (params_->shared_dictionary_enabled) { |
| if (params_->file_paths && |
| params_->file_paths->shared_dictionary_directory && |
| !params_->file_paths->shared_dictionary_directory->path().empty()) { |
| #if BUILDFLAG(IS_ANDROID) |
| disk_cache::ApplicationStatusListenerGetter get_callback; |
| app_status_listeners_.push_back( |
| std::make_unique<NetworkContextApplicationStatusListener>( |
| get_callback)); |
| #endif // BUILDFLAG(IS_ANDROID) |
| // TODO(crbug.com/40255884): Set `file_operations_factory` to support |
| // sandboxed network service on Android. |
| shared_dictionary_manager_ = SharedDictionaryManager::CreateOnDisk( |
| params_->file_paths->shared_dictionary_directory->path().Append( |
| FILE_PATH_LITERAL("db")), |
| params_->file_paths->shared_dictionary_directory->path().Append( |
| FILE_PATH_LITERAL("cache")), |
| params_->shared_dictionary_cache_max_size, |
| shared_dictionary::kDictionaryMaxCountPerNetworkContext, |
| #if BUILDFLAG(IS_ANDROID) |
| std::move(get_callback), |
| #endif // BUILDFLAG(IS_ANDROID) |
| /*file_operations_factory=*/nullptr); |
| } else { |
| shared_dictionary_manager_ = SharedDictionaryManager::CreateInMemory( |
| params_->shared_dictionary_cache_max_size, |
| shared_dictionary::kDictionaryMaxCountPerNetworkContext); |
| } |
| } |
| |
| mojo::PendingRemote<mojom::URLLoaderFactory> |
| url_loader_factory_for_cert_net_fetcher; |
| mojo::PendingReceiver<mojom::URLLoaderFactory> |
| url_loader_factory_for_cert_net_fetcher_receiver = |
| url_loader_factory_for_cert_net_fetcher |
| .InitWithNewPipeAndPassReceiver(); |
| |
| scoped_refptr<SessionCleanupCookieStore> session_cleanup_cookie_store = |
| MakeSessionCleanupCookieStore(); |
| |
| url_request_context_owner_ = MakeURLRequestContext( |
| std::move(url_loader_factory_for_cert_net_fetcher), |
| session_cleanup_cookie_store, |
| std::move(on_url_request_context_builder_configured), |
| params_->bound_network); |
| url_request_context_ = url_request_context_owner_.url_request_context.get(); |
| |
| cookie_manager_ = std::make_unique<CookieManager>( |
| url_request_context_, &first_party_sets_access_delegate_, |
| std::move(session_cleanup_cookie_store), |
| std::move(params_->cookie_manager_params), |
| network_service_->tpcd_metadata_manager()); |
| |
| cookie_manager_->AddSettingsWillChangeCallback( |
| base::BindRepeating(&NetworkContext::OnCookieManagerSettingsChanged, |
| weak_factory_.GetWeakPtr())); |
| |
| shared_resource_checker_ = std::make_unique<SharedResourceChecker>( |
| cookie_manager_->cookie_settings()); |
| |
| network_service_->RegisterNetworkContext(this); |
| |
| // Only register for destruction if |this| will be wholly lifetime-managed |
| // by the NetworkService. In the other constructors, lifetime is shared with |
| // other consumers, and thus self-deletion is not safe and can result in |
| // double-frees. |
| receiver_.set_disconnect_handler(base::BindOnce( |
| &NetworkContext::OnConnectionError, base::Unretained(this))); |
| |
| socket_factory_ = std::make_unique<SocketFactory>( |
| url_request_context_->net_log(), url_request_context_); |
| #if BUILDFLAG(IS_WIN) |
| if (params_->socket_brokers) { |
| socket_factory_->BindSocketBroker( |
| std::move(params_->socket_brokers->server)); |
| } |
| #endif |
| resource_scheduler_ = std::make_unique<ResourceScheduler>(); |
| |
| if (params_->http_auth_static_network_context_params) { |
| http_auth_merged_preferences_.SetAllowDefaultCredentials( |
| params_->http_auth_static_network_context_params |
| ->allow_default_credentials); |
| } |
| |
| InitializeCorsParams(); |
| |
| #if BUILDFLAG(IS_CT_SUPPORTED) |
| if (params_->ct_policy) { |
| SetCTPolicy(std::move(params_->ct_policy)); |
| } |
| |
| base::FilePath sct_auditing_path; |
| GetFullDataFilePath(params_->file_paths, |
| &network::mojom::NetworkContextFilePaths:: |
| sct_auditing_pending_reports_file_name, |
| sct_auditing_path); |
| sct_auditing_handler_ = |
| std::make_unique<SCTAuditingHandler>(this, sct_auditing_path); |
| sct_auditing_handler()->SetMode(params_->sct_auditing_mode); |
| #endif // BUILDFLAG(IS_CT_SUPPORTED) |
| |
| #if BUILDFLAG(IS_ANDROID) |
| if (params_->cookie_manager) { |
| GetCookieManager(std::move(params_->cookie_manager)); |
| } |
| #endif // BUILDFLAG(IS_ANDROID) |
| |
| CreateURLLoaderFactoryForCertNetFetcher( |
| std::move(url_loader_factory_for_cert_net_fetcher_receiver)); |
| |
| SetBlockTrustTokens(params_->block_trust_tokens); |
| |
| if (params_ && params_->http_cache_file_operations_factory) { |
| http_cache_file_operations_factory_ = |
| base::MakeRefCounted<MojoBackendFileOperationsFactory>( |
| std::move(params_->http_cache_file_operations_factory)); |
| } |
| |
| if (prefetch_enabled_) { |
| InitializePrefetchURLLoaderFactory(); |
| } |
| |
| device_bound_session_manager_ = DeviceBoundSessionManager::Create( |
| url_request_context_->device_bound_session_service(), |
| cookie_manager_.get()); |
| } |
| |
| NetworkContext::NetworkContext( |
| NetworkService* network_service, |
| mojo::PendingReceiver<mojom::NetworkContext> receiver, |
| net::URLRequestContext* url_request_context, |
| const std::vector<std::string>& cors_exempt_header_list) |
| : network_service_(network_service), |
| url_request_context_(url_request_context), |
| #if BUILDFLAG(ENABLE_REPORTING) |
| is_observing_reporting_service_(false), |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| receiver_(this, std::move(receiver)), |
| first_party_sets_access_delegate_( |
| /*receiver=*/mojo::NullReceiver(), |
| /*params=*/nullptr, |
| /*manager=*/nullptr), |
| cookie_manager_(std::make_unique<CookieManager>( |
| url_request_context, |
| nullptr, |
| /*first_party_sets_access_delegate=*/nullptr, |
| /*params=*/nullptr, |
| /*tpcd_metadata_manager=*/nullptr)), |
| socket_factory_( |
| std::make_unique<SocketFactory>(url_request_context_->net_log(), |
| url_request_context)), |
| cors_preflight_controller_(network_service), |
| http_auth_merged_preferences_(network_service), |
| ohttp_handler_(this), |
| prefetch_enabled_( |
| base::FeatureList::IsEnabled(features::kNetworkContextPrefetch) && |
| (url_request_context_->bound_network() == |
| net::handles::kInvalidNetworkHandle)), |
| prefetch_cache_(prefetch_enabled_ ? std::make_unique<PrefetchCache>() |
| : nullptr) { |
| |
| shared_resource_checker_ = std::make_unique<SharedResourceChecker>( |
| cookie_manager_->cookie_settings()); |
| |
| // May be nullptr in tests. |
| if (network_service_) { |
| network_service_->RegisterNetworkContext(this); |
| } |
| resource_scheduler_ = std::make_unique<ResourceScheduler>(); |
| |
| for (const auto& key : cors_exempt_header_list) { |
| cors_exempt_header_list_.insert(key); |
| } |
| |
| if (prefetch_enabled_) { |
| InitializePrefetchURLLoaderFactory(); |
| } |
| } |
| |
| NetworkContext::~NetworkContext() { |
| is_destructing_ = true; |
| |
| // May be nullptr in tests. |
| if (network_service_) { |
| network_service_->DeregisterNetworkContext(this); |
| } |
| |
| if (domain_reliability_monitor_) { |
| domain_reliability_monitor_->Shutdown(); |
| } |
| // Because of the order of declaration in the class, |
| // domain_reliability_monitor_ will be destroyed before |
| // |url_loader_factories_| which could own URLLoader's whose destructor call |
| // back into this class and might use domain_reliability_monitor_. So we reset |
| // |domain_reliability_monitor_| here explicitly, instead of changing the |
| // order, because any work calling into |domain_reliability_monitor_| at |
| // shutdown would be unnecessary as the reports would be thrown out. |
| domain_reliability_monitor_.reset(); |
| |
| if (url_request_context_ && |
| url_request_context_->transport_security_state()) { |
| #if BUILDFLAG(IS_CT_SUPPORTED) |
| if (require_ct_delegate_) { |
| url_request_context_->transport_security_state()->SetRequireCTDelegate( |
| nullptr); |
| } |
| #endif // BUILDFLAG(IS_CT_SUPPORTED) |
| } |
| |
| #if BUILDFLAG(ENABLE_REPORTING) |
| if (is_observing_reporting_service_) { |
| DCHECK(url_request_context()); |
| // May be nullptr in tests. |
| if (url_request_context()->reporting_service()) { |
| url_request_context()->reporting_service()->RemoveReportingCacheObserver( |
| this); |
| } |
| } |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| |
| #if BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED) |
| if (!dismount_closures_.empty()) { |
| // Dismount all mounted directories after a generous delay, so that |
| // pending asynchronous IO tasks have a chance to complete before the |
| // directory is unmounted. |
| constexpr base::TimeDelta kDismountDelay = base::Minutes(5); |
| |
| for (auto& dismount_closure : dismount_closures_) { |
| std::ignore = base::ThreadPool::PostDelayedTask( |
| FROM_HERE, std::move(dismount_closure), kDismountDelay); |
| } |
| } |
| #endif // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED) |
| |
| // Clear `url_loader_factories_` before deleting the contents, as it can |
| // result in re-entrant calls to DestroyURLLoaderFactory(). |
| std::set<std::unique_ptr<PrefetchMatchingURLLoaderFactory>, |
| base::UniquePtrComparator> |
| url_loader_factories = std::move(url_loader_factories_); |
| } |
| |
| void NetworkContext::OnCookieManagerSettingsChanged() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| for (const std::unique_ptr<network::RestrictedCookieManager>& rcm : |
| restricted_cookie_managers_) { |
| rcm->OnCookieSettingsChanged(); |
| } |
| } |
| |
| // static |
| std::unique_ptr<NetworkContext> NetworkContext::CreateForTesting( |
| NetworkService* network_service, |
| mojo::PendingReceiver<mojom::NetworkContext> receiver, |
| mojom::NetworkContextParamsPtr params, |
| OnURLRequestContextBuilderConfiguredCallback |
| on_url_request_context_builder_configured) { |
| return std::make_unique<NetworkContext>( |
| base::PassKey<NetworkContext>(), network_service, std::move(receiver), |
| std::move(params), OnConnectionCloseCallback(), |
| std::move(on_url_request_context_builder_configured)); |
| } |
| |
| // static |
| void NetworkContext::SetCertVerifierForTesting( |
| net::CertVerifier* cert_verifier) { |
| g_cert_verifier_for_testing = cert_verifier; |
| } |
| |
| void NetworkContext::CreateURLLoaderFactory( |
| mojo::PendingReceiver<mojom::URLLoaderFactory> receiver, |
| mojom::URLLoaderFactoryParamsPtr params, |
| scoped_refptr<ResourceSchedulerClient> resource_scheduler_client) { |
| url_loader_factories_.emplace( |
| std::make_unique<PrefetchMatchingURLLoaderFactory>( |
| this, std::move(params), std::move(resource_scheduler_client), |
| std::move(receiver), &cors_origin_access_list_, |
| prefetch_cache_.get())); |
| } |
| |
| void NetworkContext::CreateURLLoaderFactoryForCertNetFetcher( |
| mojo::PendingReceiver<mojom::URLLoaderFactory> factory_receiver) { |
| // TODO(crbug.com/40695068): investigate changing these params. |
| auto url_loader_factory_params = mojom::URLLoaderFactoryParams::New(); |
| url_loader_factory_params->is_trusted = true; |
| url_loader_factory_params->process_id = mojom::kBrowserProcessId; |
| url_loader_factory_params->automatically_assign_isolation_info = true; |
| url_loader_factory_params->is_orb_enabled = false; |
| if (url_request_context()->bound_network() != |
| net::handles::kInvalidNetworkHandle) { |
| // This is done to maintain consistency with network-bound |
| // URLLoaderFactories used by multi-network CCT. See |
| // CorsURLLoaderFactory::IsCorsPreflighLoadOptionAllowed |
| // http://crrev.com/c/5899528. |
| url_loader_factory_params->disable_web_security = true; |
| } |
| CreateURLLoaderFactory(std::move(factory_receiver), |
| std::move(url_loader_factory_params)); |
| } |
| |
| void NetworkContext::ActivateDohProbes() { |
| DCHECK(url_request_context_->host_resolver()); |
| |
| doh_probes_request_.reset(); |
| doh_probes_request_ = |
| url_request_context_->host_resolver()->CreateDohProbeRequest(); |
| doh_probes_request_->Start(); |
| } |
| |
| void NetworkContext::SetClient( |
| mojo::PendingRemote<mojom::NetworkContextClient> client) { |
| client_.reset(); |
| client_.Bind(std::move(client)); |
| } |
| |
| void NetworkContext::CreateURLLoaderFactory( |
| mojo::PendingReceiver<mojom::URLLoaderFactory> receiver, |
| mojom::URLLoaderFactoryParamsPtr params) { |
| scoped_refptr<ResourceSchedulerClient> resource_scheduler_client = |
| base::MakeRefCounted<ResourceSchedulerClient>( |
| ResourceScheduler::ClientId::Create(), |
| IsBrowserInitiated(params->process_id == mojom::kBrowserProcessId), |
| resource_scheduler_.get(), |
| url_request_context_->network_quality_estimator()); |
| CreateURLLoaderFactory(std::move(receiver), std::move(params), |
| std::move(resource_scheduler_client)); |
| } |
| |
| void NetworkContext::ResetURLLoaderFactories() { |
| // Move all factories to a temporary vector so ClearBindings() does not |
| // invalidate the iterator if the factory gets deleted. |
| std::vector<PrefetchMatchingURLLoaderFactory*> factories; |
| factories.reserve(url_loader_factories_.size()); |
| for (const auto& factory : url_loader_factories_) { |
| if (!factory->ShouldIgnoreFactoryReset()) { |
| factories.push_back(factory.get()); |
| } |
| } |
| for (auto* factory : factories) { |
| factory->ClearBindings(); |
| } |
| } |
| |
| void NetworkContext::GetViaObliviousHttp( |
| mojom::ObliviousHttpRequestPtr request, |
| mojo::PendingRemote<mojom::ObliviousHttpClient> client) { |
| ohttp_handler_.StartRequest(std::move(request), std::move(client)); |
| } |
| |
| void NetworkContext::GetCookieManager( |
| mojo::PendingReceiver<mojom::CookieManager> receiver) { |
| cookie_manager_->AddReceiver(std::move(receiver)); |
| } |
| |
| void NetworkContext::GetRestrictedCookieManager( |
| mojo::PendingReceiver<mojom::RestrictedCookieManager> receiver, |
| mojom::RestrictedCookieManagerRole role, |
| const url::Origin& origin, |
| const net::IsolationInfo& isolation_info, |
| const net::CookieSettingOverrides& cookie_setting_overrides, |
| const net::CookieSettingOverrides& devtools_cookie_setting_overrides, |
| mojo::PendingRemote<mojom::CookieAccessObserver> cookie_observer) { |
| RestrictedCookieManager::ComputeFirstPartySetMetadata( |
| origin, url_request_context_->cookie_store(), isolation_info, |
| base::BindOnce(&NetworkContext::OnComputedFirstPartySetMetadata, |
| weak_factory_.GetWeakPtr(), std::move(receiver), role, |
| origin, isolation_info, cookie_setting_overrides, |
| devtools_cookie_setting_overrides, |
| std::move(cookie_observer))); |
| } |
| |
| void NetworkContext::OnRCMDisconnect( |
| const network::RestrictedCookieManager* rcm) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| auto it = restricted_cookie_managers_.find(rcm); |
| CHECK(it != restricted_cookie_managers_.end()); |
| restricted_cookie_managers_.erase(it); |
| } |
| |
| void NetworkContext::RemoveConnectionChangeObserver( |
| const net::ConnectionChangeNotifier::Observer* observer) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| auto it = connection_change_observers_.find(observer); |
| if (it != connection_change_observers_.end()) { |
| connection_change_observers_.erase(it); |
| } |
| } |
| |
| void NetworkContext::OnComputedFirstPartySetMetadata( |
| mojo::PendingReceiver<mojom::RestrictedCookieManager> receiver, |
| mojom::RestrictedCookieManagerRole role, |
| const url::Origin& origin, |
| const net::IsolationInfo& isolation_info, |
| const net::CookieSettingOverrides& cookie_setting_overrides, |
| const net::CookieSettingOverrides& devtools_cookie_setting_overrides, |
| mojo::PendingRemote<mojom::CookieAccessObserver> cookie_observer, |
| net::FirstPartySetMetadata first_party_set_metadata) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| std::unique_ptr<RestrictedCookieManager> ptr = |
| std::make_unique<RestrictedCookieManager>( |
| role, url_request_context_->cookie_store(), |
| cookie_manager_->cookie_settings(), origin, isolation_info, |
| cookie_setting_overrides, devtools_cookie_setting_overrides, |
| std::move(cookie_observer), std::move(first_party_set_metadata), |
| network_service_->metrics_updater()); |
| |
| auto callback = base::BindOnce(&NetworkContext::OnRCMDisconnect, |
| base::Unretained(this), ptr.get()); |
| ptr->InstallReceiver(std::move(receiver), std::move(callback)); |
| restricted_cookie_managers_.insert(std::move(ptr)); |
| } |
| |
| void NetworkContext::GetTrustTokenQueryAnswerer( |
| mojo::PendingReceiver<mojom::TrustTokenQueryAnswerer> receiver, |
| const url::Origin& top_frame_origin) { |
| // Only called when Trust Tokens is enabled, i.e. trust_token_store_ is |
| // non-null. |
| DCHECK(trust_token_store_); |
| DCHECK(network_service_); |
| |
| std::optional<SuitableTrustTokenOrigin> suitable_top_frame_origin = |
| SuitableTrustTokenOrigin::Create(top_frame_origin); |
| |
| const SynchronousTrustTokenKeyCommitmentGetter* const key_commitment_getter = |
| network_service_->trust_token_key_commitments(); |
| |
| // It's safe to dereference |suitable_top_frame_origin| here as, during the |
| // process of vending the TrustTokenQueryAnswerer, the browser ensures that |
| // the requesting context's top frame origin is suitable for Trust Tokens. |
| auto answerer = std::make_unique<TrustTokenQueryAnswerer>( |
| std::move(*suitable_top_frame_origin), trust_token_store_.get(), |
| key_commitment_getter); |
| |
| trust_token_query_answerers_.Add(std::move(answerer), std::move(receiver)); |
| } |
| |
| void NetworkContext::GetStoredTrustTokenCounts( |
| GetStoredTrustTokenCountsCallback callback) { |
| if (trust_token_store_) { |
| auto get_trust_token_counts_from_store = |
| [](NetworkContext::GetStoredTrustTokenCountsCallback callback, |
| TrustTokenStore* trust_token_store) { |
| std::vector<mojom::StoredTrustTokensForIssuerPtr> result; |
| for (auto& issuer_count_pair : |
| trust_token_store->GetStoredTrustTokenCounts()) { |
| result.push_back(mojom::StoredTrustTokensForIssuer::New( |
| std::move(issuer_count_pair.first), issuer_count_pair.second)); |
| } |
| std::move(callback).Run(std::move(result)); |
| }; |
| trust_token_store_->ExecuteOrEnqueue( |
| base::BindOnce(get_trust_token_counts_from_store, std::move(callback))); |
| } else { |
| // The Trust Tokens feature is disabled, return immediately with an empty |
| // vector. |
| std::move(callback).Run({}); |
| } |
| } |
| |
| void NetworkContext::GetPrivateStateTokenRedemptionRecords( |
| GetPrivateStateTokenRedemptionRecordsCallback callback) { |
| // The Trust Tokens feature is disabled, return immediately with an empty |
| // map. |
| if (!trust_token_store_) { |
| base::flat_map<url::Origin, std::vector<mojom::ToplevelRedemptionRecordPtr>> |
| empty_result; |
| std::move(callback).Run(std::move(empty_result)); |
| return; |
| } |
| auto get_redemption_records_from_store = |
| [](NetworkContext::GetPrivateStateTokenRedemptionRecordsCallback callback, |
| TrustTokenStore* trust_token_store) { |
| std::move(callback).Run(trust_token_store->GetRedemptionRecords()); |
| }; |
| trust_token_store_->ExecuteOrEnqueue( |
| base::BindOnce(get_redemption_records_from_store, std::move(callback))); |
| } |
| |
| void NetworkContext::DeleteStoredTrustTokens( |
| const url::Origin& issuer, |
| DeleteStoredTrustTokensCallback callback) { |
| if (!trust_token_store_) { |
| std::move(callback).Run( |
| mojom::DeleteStoredTrustTokensStatus::kFailureFeatureDisabled); |
| return; |
| } |
| |
| std::optional<SuitableTrustTokenOrigin> suitable_issuer_origin = |
| SuitableTrustTokenOrigin::Create(issuer); |
| if (!suitable_issuer_origin) { |
| std::move(callback).Run( |
| mojom::DeleteStoredTrustTokensStatus::kFailureInvalidOrigin); |
| return; |
| } |
| |
| trust_token_store_->ExecuteOrEnqueue(base::BindOnce( |
| [](SuitableTrustTokenOrigin issuer, |
| DeleteStoredTrustTokensCallback callback, TrustTokenStore* store) { |
| const bool did_delete_tokens = store->DeleteStoredTrustTokens(issuer); |
| const auto status = |
| did_delete_tokens |
| ? mojom::DeleteStoredTrustTokensStatus::kSuccessTokensDeleted |
| : mojom::DeleteStoredTrustTokensStatus::kSuccessNoTokensDeleted; |
| std::move(callback).Run(status); |
| }, |
| std::move(*suitable_issuer_origin), std::move(callback))); |
| } |
| |
| void NetworkContext::SetBlockTrustTokens(bool block) { |
| block_trust_tokens_ = block; |
| } |
| |
| void NetworkContext::SetTrackingProtectionContentSetting( |
| const ContentSettingsForOneType& settings) { |
| if (!ip_protection_core_) { |
| return; |
| } |
| ip_protection_core_->SetTrackingProtectionContentSetting(settings); |
| } |
| |
| void NetworkContext::OnProxyLookupComplete( |
| ProxyLookupRequest* proxy_lookup_request) { |
| auto it = proxy_lookup_requests_.find(proxy_lookup_request); |
| CHECK(it != proxy_lookup_requests_.end()); |
| proxy_lookup_requests_.erase(it); |
| } |
| |
| void NetworkContext::SetTLS13EarlyDataEnabled(bool enabled) { |
| url_request_context_->http_transaction_factory() |
| ->GetSession() |
| ->SetTLS13EarlyDataEnabled(enabled); |
| } |
| |
| void NetworkContext::DisableQuic() { |
| url_request_context_->http_transaction_factory()->GetSession()->DisableQuic(); |
| } |
| |
| void NetworkContext::DestroyURLLoaderFactory( |
| PrefetchMatchingURLLoaderFactory* url_loader_factory) { |
| if (is_destructing_) { |
| return; |
| } |
| auto it = url_loader_factories_.find(url_loader_factory); |
| CHECK(it != url_loader_factories_.end()); |
| url_loader_factories_.erase(it); |
| } |
| |
| void NetworkContext::Remove(WebTransport* transport) { |
| auto it = web_transports_.find(transport); |
| if (it != web_transports_.end()) { |
| web_transports_.erase(it); |
| } |
| } |
| |
| void NetworkContext::LoaderCreated(uint32_t process_id) { |
| loader_count_per_process_[process_id] += 1; |
| } |
| |
| void NetworkContext::LoaderDestroyed(uint32_t process_id) { |
| auto it = loader_count_per_process_.find(process_id); |
| CHECK(it != loader_count_per_process_.end()); |
| it->second -= 1; |
| if (it->second == 0) { |
| loader_count_per_process_.erase(it); |
| } |
| } |
| |
| bool NetworkContext::CanCreateLoader(uint32_t process_id) { |
| auto it = loader_count_per_process_.find(process_id); |
| uint32_t count = (it == loader_count_per_process_.end() ? 0 : it->second); |
| return count < max_loaders_per_process_; |
| } |
| |
| size_t NetworkContext::GetNumOutstandingResolveHostRequestsForTesting() const { |
| size_t sum = 0; |
| if (internal_host_resolver_) { |
| sum += internal_host_resolver_->GetNumOutstandingRequestsForTesting(); |
| } |
| for (const auto& host_resolver : host_resolvers_) { |
| sum += host_resolver->GetNumOutstandingRequestsForTesting(); // IN-TEST |
| } |
| return sum; |
| } |
| |
| bool NetworkContext::SkipReportingPermissionCheck() const { |
| #if BUILDFLAG(ENABLE_REPORTING) |
| return params_ && params_->skip_reporting_send_permission_check; |
| #else |
| return false; |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| } |
| |
| void NetworkContext::ClearTrustTokenData(mojom::ClearDataFilterPtr filter, |
| base::OnceClosure done) { |
| if (!trust_token_store_) { |
| std::move(done).Run(); |
| return; |
| } |
| trust_token_store_->ExecuteOrEnqueue(base::BindOnce( |
| [](mojom::ClearDataFilterPtr filter, base::OnceClosure done, |
| TrustTokenStore* store) { |
| std::ignore = store->ClearDataForFilter(std::move(filter)); |
| std::move(done).Run(); |
| }, |
| std::move(filter), std::move(done))); |
| } |
| |
| void NetworkContext::ClearTrustTokenSessionOnlyData( |
| ClearTrustTokenSessionOnlyDataCallback callback) { |
| // Only called when Private State Tokens is enabled, i.e., |
| // `trust_token_store_` is non-null. |
| DCHECK(trust_token_store_); |
| DCHECK(cookie_manager_); |
| |
| DeleteCookiePredicate cookie_predicate = |
| cookie_manager_->cookie_settings().CreateDeleteCookieOnExitPredicate(); |
| |
| auto store_predicate = base::BindRepeating( |
| [](DeleteCookiePredicate predicate, const std::string& origin) { |
| return predicate.Run(origin, net::CookieSourceScheme::kSecure); |
| }, |
| std::move(cookie_predicate)); |
| trust_token_store_->ExecuteOrEnqueue(base::BindOnce( |
| [](base::RepeatingCallback<bool(const std::string&)> pred, |
| ClearTrustTokenSessionOnlyDataCallback cb, TrustTokenStore* store) { |
| bool any_data_deleted = store->ClearDataForPredicate(std::move(pred)); |
| std::move(cb).Run(any_data_deleted); |
| }, |
| std::move(store_predicate), std::move(callback))); |
| } |
| |
| void NetworkContext::ClearNetworkingHistoryBetween( |
| base::Time start_time, |
| base::Time end_time, |
| base::OnceClosure completion_callback) { |
| #if BUILDFLAG(IS_CT_SUPPORTED) |
| auto barrier = base::BarrierClosure(3, std::move(completion_callback)); |
| sct_auditing_handler()->ClearPendingReports(barrier); |
| #else |
| auto barrier = base::BarrierClosure(2, std::move(completion_callback)); |
| #endif // BUIDLFLAG(IS_CT_SUPPORTED) |
| |
| url_request_context_->transport_security_state()->DeleteAllDynamicDataBetween( |
| start_time, end_time, barrier); |
| |
| // 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. |
| // May not be set in all tests. |
| if (network_qualities_pref_delegate_) { |
| network_qualities_pref_delegate_->ClearPrefs(); |
| } |
| |
| url_request_context_->http_server_properties()->Clear(barrier); |
| } |
| |
| void NetworkContext::ClearHttpCache(base::Time start_time, |
| base::Time end_time, |
| mojom::ClearDataFilterPtr filter, |
| ClearHttpCacheCallback callback) { |
| // It's safe to use Unretained below as the HttpCacheDataRemover is owned by |
| // |this| and guarantees it won't call its callback if deleted. |
| http_cache_data_removers_.push_back(HttpCacheDataRemover::CreateAndStart( |
| url_request_context_, std::move(filter), start_time, end_time, |
| base::BindOnce(&NetworkContext::OnHttpCacheCleared, |
| base::Unretained(this), std::move(callback)))); |
| } |
| |
| void NetworkContext::ComputeHttpCacheSize( |
| base::Time start_time, |
| base::Time end_time, |
| ComputeHttpCacheSizeCallback callback) { |
| // It's safe to use Unretained below as the HttpCacheDataCounter is owned by |
| // |this| and guarantees it won't call its callback if deleted. |
| http_cache_data_counters_.push_back(HttpCacheDataCounter::CreateAndStart( |
| url_request_context_, start_time, end_time, |
| base::BindOnce(&NetworkContext::OnHttpCacheSizeComputed, |
| base::Unretained(this), std::move(callback)))); |
| } |
| |
| void NetworkContext::NotifyBrowserIdle() { |
| net::HttpCache* htp_cache = |
| url_request_context_->http_transaction_factory()->GetCache(); |
| if (!htp_cache) { |
| return; |
| } |
| disk_cache::Backend* backend = htp_cache->GetCurrentBackend(); |
| if (!backend) { |
| return; |
| } |
| backend->OnBrowserIdle(); |
| } |
| |
| void NetworkContext::ClearCorsPreflightCache( |
| mojom::ClearDataFilterPtr filter, |
| ClearCorsPreflightCacheCallback callback) { |
| cors_preflight_controller_.ClearCorsPreflightCache(std::move(filter)); |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::ClearHostCache(mojom::ClearDataFilterPtr filter, |
| ClearHostCacheCallback callback) { |
| net::HostCache* host_cache = |
| url_request_context_->host_resolver()->GetHostCache(); |
| DCHECK(host_cache); |
| host_cache->ClearForHosts(MakeDomainFilter(filter.get())); |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::ClearHttpAuthCache(base::Time start_time, |
| base::Time end_time, |
| mojom::ClearDataFilterPtr filter, |
| ClearHttpAuthCacheCallback callback) { |
| net::HttpNetworkSession* http_session = |
| url_request_context_->http_transaction_factory()->GetSession(); |
| DCHECK(http_session); |
| |
| if (http_session->http_auth_cache()->ClearEntriesAddedBetween( |
| start_time, end_time, BuildUrlFilter(std::move(filter)))) { |
| // TODO(mmenke): Use another error code for this, as ERR_ABORTED has |
| // somewhat magical handling with respect to navigations. |
| http_session->CloseAllConnections(net::ERR_ABORTED, "Clearing auth cache"); |
| } |
| |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::ClearReportingCacheReports( |
| mojom::ClearDataFilterPtr filter, |
| ClearReportingCacheReportsCallback callback) { |
| #if BUILDFLAG(ENABLE_REPORTING) |
| net::ReportingService* reporting_service = |
| url_request_context_->reporting_service(); |
| if (reporting_service) { |
| if (filter) { |
| reporting_service->RemoveBrowsingData( |
| net::ReportingBrowsingDataRemover::DATA_TYPE_REPORTS, |
| BuildOriginFilter(std::move(filter))); |
| } else { |
| reporting_service->RemoveAllBrowsingData( |
| net::ReportingBrowsingDataRemover::DATA_TYPE_REPORTS); |
| } |
| } |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::ClearReportingCacheClients( |
| mojom::ClearDataFilterPtr filter, |
| ClearReportingCacheClientsCallback callback) { |
| #if BUILDFLAG(ENABLE_REPORTING) |
| net::ReportingService* reporting_service = |
| url_request_context_->reporting_service(); |
| if (reporting_service) { |
| if (filter) { |
| reporting_service->RemoveBrowsingData( |
| net::ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS, |
| BuildOriginFilter(std::move(filter))); |
| } else { |
| reporting_service->RemoveAllBrowsingData( |
| net::ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS); |
| } |
| } |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::ClearNetworkErrorLogging( |
| mojom::ClearDataFilterPtr filter, |
| ClearNetworkErrorLoggingCallback callback) { |
| #if BUILDFLAG(ENABLE_REPORTING) |
| net::NetworkErrorLoggingService* logging_service = |
| url_request_context_->network_error_logging_service(); |
| if (logging_service) { |
| if (filter) { |
| logging_service->RemoveBrowsingData(BuildOriginFilter(std::move(filter))); |
| } else { |
| logging_service->RemoveAllBrowsingData(); |
| } |
| } |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::SetDocumentReportingEndpoints( |
| const base::UnguessableToken& reporting_source, |
| const url::Origin& origin, |
| const net::IsolationInfo& isolation_info, |
| const base::flat_map<std::string, std::string>& endpoints) { |
| #if BUILDFLAG(ENABLE_REPORTING) |
| DCHECK(!reporting_source.is_empty()); |
| DCHECK_EQ(net::IsolationInfo::RequestType::kOther, |
| isolation_info.request_type()); |
| net::ReportingService* reporting_service = |
| url_request_context()->reporting_service(); |
| if (reporting_service) { |
| reporting_service->SetDocumentReportingEndpoints(reporting_source, origin, |
| isolation_info, endpoints); |
| } |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| } |
| |
| void NetworkContext::SetEnterpriseReportingEndpoints( |
| const base::flat_map<std::string, GURL>& endpoints) { |
| #if BUILDFLAG(ENABLE_REPORTING) |
| if (auto* reporting_service = url_request_context()->reporting_service()) { |
| reporting_service->SetEnterpriseReportingEndpoints(endpoints); |
| } |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| } |
| |
| void NetworkContext::SendReportsAndRemoveSource( |
| const base::UnguessableToken& reporting_source) { |
| #if BUILDFLAG(ENABLE_REPORTING) |
| DCHECK(!reporting_source.is_empty()); |
| net::ReportingService* reporting_service = |
| url_request_context()->reporting_service(); |
| if (reporting_service) { |
| reporting_service->SendReportsAndRemoveSource(reporting_source); |
| } |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| } |
| |
| void NetworkContext::QueueReport( |
| const std::string& type, |
| const std::string& group, |
| const GURL& url, |
| const std::optional<base::UnguessableToken>& reporting_source, |
| const net::NetworkAnonymizationKey& network_anonymization_key, |
| base::Value::Dict body) { |
| QueueReportInternal(type, group, url, reporting_source, |
| network_anonymization_key, std::move(body), |
| net::ReportingTargetType::kDeveloper); |
| } |
| |
| void NetworkContext::QueueEnterpriseReport(const std::string& type, |
| const std::string& group, |
| const GURL& url, |
| base::Value::Dict body) { |
| // Enterprise reports don't use a |reporting_source| or |
| // |network_anonymization_key|. Enterprise endpoints are profile-bound and not |
| // document-bound like web developer endpoints. |
| QueueReportInternal(type, group, url, /*reporting_source=*/std::nullopt, |
| net::NetworkAnonymizationKey(), std::move(body), |
| net::ReportingTargetType::kEnterprise); |
| } |
| |
| void NetworkContext::QueueReportInternal( |
| const std::string& type, |
| const std::string& group, |
| const GURL& url, |
| const std::optional<base::UnguessableToken>& reporting_source, |
| const net::NetworkAnonymizationKey& network_anonymization_key, |
| base::Value::Dict body, |
| net::ReportingTargetType target_type) { |
| #if BUILDFLAG(ENABLE_REPORTING) |
| // If |reporting_source| is provided, it must not be empty. |
| DCHECK(!(reporting_source.has_value() && reporting_source->is_empty())); |
| // Enterprise reports have an empty |network_anonymization_key|. |
| if (target_type == net::ReportingTargetType::kDeveloper && |
| require_network_anonymization_key_) { |
| DCHECK(!network_anonymization_key.IsEmpty()); |
| } |
| |
| // Get the ReportingService. |
| net::URLRequestContext* request_context = url_request_context(); |
| net::ReportingService* reporting_service = |
| request_context->reporting_service(); |
| // TODO(paulmeyer): Remove this once the network service ships everywhere. |
| if (!reporting_service) { |
| return; |
| } |
| |
| // Reporting is disallowed if network access is disabled for the nonce. |
| if (network_anonymization_key.GetNonce().has_value() && |
| !IsNetworkForNonceAndUrlAllowed( |
| network_anonymization_key.GetNonce().value(), url)) { |
| return; |
| } |
| |
| std::string reported_user_agent = ""; |
| if (request_context->http_user_agent_settings() != nullptr) { |
| reported_user_agent = |
| request_context->http_user_agent_settings()->GetUserAgent(); |
| } |
| |
| reporting_service->QueueReport( |
| url, reporting_source, network_anonymization_key, reported_user_agent, |
| group, type, std::move(body), 0 /* depth */, target_type); |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| } |
| |
| void NetworkContext::QueueSignedExchangeReport( |
| mojom::SignedExchangeReportPtr report, |
| const net::NetworkAnonymizationKey& network_anonymization_key) { |
| #if BUILDFLAG(ENABLE_REPORTING) |
| if (require_network_anonymization_key_) { |
| DCHECK(!network_anonymization_key.IsEmpty()); |
| } |
| |
| net::NetworkErrorLoggingService* logging_service = |
| url_request_context_->network_error_logging_service(); |
| if (!logging_service) { |
| return; |
| } |
| |
| // Reporting is disallowed if network access is disabled for the nonce. |
| if (network_anonymization_key.GetNonce().has_value() && |
| !IsNetworkForNonceAndUrlAllowed( |
| network_anonymization_key.GetNonce().value(), report->outer_url)) { |
| return; |
| } |
| |
| std::string user_agent; |
| if (url_request_context_->http_user_agent_settings() != nullptr) { |
| user_agent = |
| url_request_context_->http_user_agent_settings()->GetUserAgent(); |
| } |
| net::NetworkErrorLoggingService::SignedExchangeReportDetails details; |
| details.network_anonymization_key = network_anonymization_key; |
| details.success = report->success; |
| details.type = std::move(report->type); |
| details.outer_url = std::move(report->outer_url); |
| details.inner_url = std::move(report->inner_url); |
| details.cert_url = std::move(report->cert_url); |
| details.referrer = std::move(report->referrer); |
| details.server_ip_address = std::move(report->server_ip_address); |
| details.protocol = std::move(report->protocol); |
| details.method = std::move(report->method); |
| details.status_code = report->status_code; |
| details.elapsed_time = report->elapsed_time; |
| details.user_agent = std::move(user_agent); |
| logging_service->QueueSignedExchangeReport(std::move(details)); |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| } |
| |
| #if BUILDFLAG(ENABLE_REPORTING) |
| void NetworkContext::AddReportingApiObserver( |
| mojo::PendingRemote<network::mojom::ReportingApiObserver> observer) { |
| if (url_request_context() && url_request_context()->reporting_service()) { |
| if (!is_observing_reporting_service_) { |
| is_observing_reporting_service_ = true; |
| url_request_context()->reporting_service()->AddReportingCacheObserver( |
| this); |
| reporting_api_observers_.set_disconnect_handler( |
| base::BindRepeating(&NetworkContext::OnReportingObserverDisconnect, |
| weak_factory_.GetWeakPtr())); |
| } |
| auto id = reporting_api_observers_.Add(std::move(observer)); |
| |
| auto service_reports = |
| url_request_context()->reporting_service()->GetReports(); |
| for (const net::ReportingReport* service_report : service_reports) { |
| reporting_api_observers_.Get(id)->OnReportAdded(*service_report); |
| } |
| |
| base::flat_map<url::Origin, std::vector<net::ReportingEndpoint>> |
| endpoints_by_origin = url_request_context() |
| ->reporting_service() |
| ->GetV1ReportingEndpointsByOrigin(); |
| for (auto const& origin_and_endpoints : endpoints_by_origin) { |
| OnEndpointsUpdatedForOrigin(origin_and_endpoints.second); |
| } |
| } |
| } |
| |
| void NetworkContext::OnReportAdded(const net::ReportingReport* service_report) { |
| for (const auto& observer : reporting_api_observers_) { |
| observer->OnReportAdded(*service_report); |
| } |
| } |
| |
| void NetworkContext::OnEndpointsUpdatedForOrigin( |
| const std::vector<net::ReportingEndpoint>& endpoints) { |
| for (const auto& observer : reporting_api_observers_) { |
| observer->OnEndpointsUpdatedForOrigin(endpoints); |
| } |
| } |
| |
| void NetworkContext::OnReportUpdated( |
| const net::ReportingReport* service_report) { |
| for (const auto& observer : reporting_api_observers_) { |
| observer->OnReportUpdated(*service_report); |
| } |
| } |
| |
| void NetworkContext::OnReportingObserverDisconnect( |
| mojo::RemoteSetElementId /*mojo_id*/) { |
| if (!reporting_api_observers_.size()) { |
| DCHECK(url_request_context()); |
| DCHECK(url_request_context()->reporting_service()); |
| url_request_context()->reporting_service()->RemoveReportingCacheObserver( |
| this); |
| is_observing_reporting_service_ = false; |
| } |
| } |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| |
| void NetworkContext::ClearDomainReliability( |
| mojom::ClearDataFilterPtr filter, |
| DomainReliabilityClearMode mode, |
| ClearDomainReliabilityCallback callback) { |
| if (domain_reliability_monitor_) { |
| domain_reliability::DomainReliabilityClearMode dr_mode; |
| if (mode == |
| mojom::NetworkContext::DomainReliabilityClearMode::CLEAR_CONTEXTS) { |
| dr_mode = domain_reliability::CLEAR_CONTEXTS; |
| } else { |
| dr_mode = domain_reliability::CLEAR_BEACONS; |
| } |
| |
| domain_reliability_monitor_->ClearBrowsingData( |
| dr_mode, BuildOriginFilter(std::move(filter))); |
| } |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::CloseAllConnections(CloseAllConnectionsCallback callback) { |
| net::HttpNetworkSession* http_session = |
| url_request_context_->http_transaction_factory()->GetSession(); |
| DCHECK(http_session); |
| |
| // TODO(mmenke): Use another error code for this, as ERR_ABORTED has somewhat |
| // magical handling with respect to navigations. |
| http_session->CloseAllConnections(net::ERR_ABORTED, |
| "Embedder closing all connections"); |
| |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::CloseIdleConnections( |
| CloseIdleConnectionsCallback callback) { |
| net::HttpNetworkSession* http_session = |
| url_request_context_->http_transaction_factory()->GetSession(); |
| DCHECK(http_session); |
| |
| http_session->CloseIdleConnections("Embedder closing idle connections"); |
| |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::SetNetworkConditions( |
| const base::UnguessableToken& throttling_profile_id, |
| std::vector<mojom::MatchedNetworkConditionsPtr> conditions) { |
| std::vector<MatchedNetworkConditions> network_conditions; |
| for (auto& condition : conditions) { |
| network_conditions.emplace_back( |
| std::move(condition->pattern), |
| NetworkConditions{condition->conditions->offline, |
| condition->conditions->latency.InMillisecondsF(), |
| condition->conditions->download_throughput, |
| condition->conditions->upload_throughput, |
| condition->conditions->packet_loss, |
| condition->conditions->packet_queue_length, |
| condition->conditions->packet_reordering, |
| condition->conditions->rule_id}); |
| } |
| ThrottlingController::SetConditions(throttling_profile_id, |
| std::move(network_conditions)); |
| } |
| |
| void NetworkContext::OnDevToolsDurableMessageClientsDisconnected( |
| const base::UnguessableToken& throttling_profile_id) { |
| devtools_profile_to_durable_message_collectors_.erase(throttling_profile_id); |
| } |
| |
| void NetworkContext::EnableDurableMessageCollector( |
| const base::UnguessableToken& throttling_profile_id, |
| mojo::PendingReceiver<network::mojom::DurableMessageCollector> receiver) { |
| auto [it, inserted] = |
| devtools_profile_to_durable_message_collectors_.try_emplace( |
| throttling_profile_id); |
| if (inserted) { |
| auto disconnect_callback = base::BindOnce( |
| &NetworkContext::OnDevToolsDurableMessageClientsDisconnected, |
| base::Unretained(this), throttling_profile_id); |
| it->second = std::make_unique<DevtoolsDurableMessageCollector>( |
| std::move(disconnect_callback)); |
| } |
| |
| it->second->AddReceiver(std::move(receiver)); |
| } |
| |
| void NetworkContext::SetAcceptLanguage(const std::string& new_accept_language) { |
| // This may only be called on NetworkContexts created with the constructor |
| // that calls MakeURLRequestContext(). |
| DCHECK(user_agent_settings_); |
| user_agent_settings_->set_accept_language(new_accept_language); |
| } |
| |
| void NetworkContext::SetEnableReferrers(bool enable_referrers) { |
| // This may only be called on NetworkContexts created with the constructor |
| // that calls MakeURLRequestContext(). |
| DCHECK(network_delegate_); |
| network_delegate_->set_enable_referrers(enable_referrers); |
| } |
| |
| #if BUILDFLAG(IS_CT_SUPPORTED) |
| void NetworkContext::SetCTPolicy(mojom::CTPolicyPtr ct_policy) { |
| if (!require_ct_delegate_) { |
| return; |
| } |
| |
| require_ct_delegate_->UpdateCTPolicies(ct_policy->excluded_hosts, |
| ct_policy->excluded_spkis); |
| } |
| |
| void NetworkContext::MaybeEnqueueSCTReport( |
| const net::HostPortPair& host_port_pair, |
| const net::X509Certificate* validated_certificate_chain, |
| const net::SignedCertificateTimestampAndStatusList& |
| signed_certificate_timestamps) { |
| sct_auditing_handler()->MaybeEnqueueReport(host_port_pair, |
| validated_certificate_chain, |
| signed_certificate_timestamps); |
| } |
| |
| void NetworkContext::SetSCTAuditingMode(mojom::SCTAuditingMode mode) { |
| sct_auditing_handler()->SetMode(mode); |
| } |
| |
| void NetworkContext::CanSendSCTAuditingReport( |
| base::OnceCallback<void(bool)> callback) { |
| // If the NetworkContextClient hasn't been set yet or has disconnected for |
| // some reason, just return `false`. (One case where this could occur is when |
| // restarting SCTAuditingReporter instances loaded form disk at startup -- see |
| // crbug.com/1347180 for more details on that case.) |
| if (!client_) { |
| std::move(callback).Run(false); |
| return; |
| } |
| client_->OnCanSendSCTAuditingReport(std::move(callback)); |
| } |
| |
| void NetworkContext::OnNewSCTAuditingReportSent() { |
| client_->OnNewSCTAuditingReportSent(); |
| } |
| #endif // BUILDFLAG(IS_CT_SUPPORTED) |
| |
| void NetworkContext::CreateUDPSocket( |
| mojo::PendingReceiver<mojom::UDPSocket> receiver, |
| mojo::PendingRemote<mojom::UDPSocketListener> listener) { |
| socket_factory_->CreateUDPSocket(std::move(receiver), std::move(listener)); |
| } |
| |
| void NetworkContext::CreateRestrictedUDPSocket( |
| const net::IPEndPoint& addr, |
| mojom::RestrictedUDPSocketMode mode, |
| const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, |
| mojom::RestrictedUDPSocketParamsPtr params, |
| mojo::PendingReceiver<mojom::RestrictedUDPSocket> receiver, |
| mojo::PendingRemote<mojom::UDPSocketListener> listener, |
| bool allow_multicast, |
| CreateRestrictedUDPSocketCallback callback) { |
| // SimpleHostResolver is transitively owned by |this|. |
| socket_factory_->CreateRestrictedUDPSocket( |
| addr, mode, traffic_annotation, std::move(params), std::move(receiver), |
| std::move(listener), SimpleHostResolver::Create(this), allow_multicast, |
| std::move(callback)); |
| } |
| |
| void NetworkContext::CreateTCPServerSocket( |
| const net::IPEndPoint& local_addr, |
| mojom::TCPServerSocketOptionsPtr options, |
| const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, |
| mojo::PendingReceiver<mojom::TCPServerSocket> receiver, |
| CreateTCPServerSocketCallback callback) { |
| socket_factory_->CreateTCPServerSocket( |
| local_addr, std::move(options), |
| static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation), |
| std::move(receiver), std::move(callback)); |
| } |
| |
| void NetworkContext::CreateTCPConnectedSocket( |
| const std::optional<net::IPEndPoint>& local_addr, |
| const net::AddressList& remote_addr_list, |
| mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options, |
| const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, |
| mojo::PendingReceiver<mojom::TCPConnectedSocket> receiver, |
| mojo::PendingRemote<mojom::SocketObserver> observer, |
| CreateTCPConnectedSocketCallback callback) { |
| socket_factory_->CreateTCPConnectedSocket( |
| local_addr, remote_addr_list, std::move(tcp_connected_socket_options), |
| static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation), |
| std::move(receiver), std::move(observer), std::move(callback)); |
| } |
| |
| void NetworkContext::CreateTCPBoundSocket( |
| const net::IPEndPoint& local_addr, |
| const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, |
| mojo::PendingReceiver<mojom::TCPBoundSocket> receiver, |
| CreateTCPBoundSocketCallback callback) { |
| socket_factory_->CreateTCPBoundSocket( |
| local_addr, |
| static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation), |
| std::move(receiver), std::move(callback)); |
| } |
| |
| void NetworkContext::CreateProxyResolvingSocketFactory( |
| mojo::PendingReceiver<mojom::ProxyResolvingSocketFactory> receiver) { |
| proxy_resolving_socket_factories_.Add( |
| std::make_unique<ProxyResolvingSocketFactoryMojo>(url_request_context()), |
| std::move(receiver)); |
| } |
| |
| void NetworkContext::LookUpProxyForURL( |
| const GURL& url, |
| const net::NetworkAnonymizationKey& network_anonyization_key, |
| mojo::PendingRemote<mojom::ProxyLookupClient> proxy_lookup_client) { |
| DCHECK(proxy_lookup_client); |
| std::unique_ptr<ProxyLookupRequest> proxy_lookup_request( |
| std::make_unique<ProxyLookupRequest>(std::move(proxy_lookup_client), this, |
| network_anonyization_key)); |
| ProxyLookupRequest* proxy_lookup_request_ptr = proxy_lookup_request.get(); |
| proxy_lookup_requests_.insert(std::move(proxy_lookup_request)); |
| proxy_lookup_request_ptr->Start(url); |
| } |
| |
| void NetworkContext::ForceReloadProxyConfig( |
| ForceReloadProxyConfigCallback callback) { |
| net::ConfiguredProxyResolutionService* configured_proxy_resolution_service = |
| nullptr; |
| if (url_request_context() |
| ->proxy_resolution_service() |
| ->CastToConfiguredProxyResolutionService( |
| &configured_proxy_resolution_service)) { |
| configured_proxy_resolution_service->ForceReloadProxyConfig(); |
| } else { |
| LOG(WARNING) |
| << "NetworkContext::ForceReloadProxyConfig() had no effect, as the " |
| "underlying ProxyResolutionService does not support that concept."; |
| } |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::ClearBadProxiesCache( |
| ClearBadProxiesCacheCallback callback) { |
| url_request_context()->proxy_resolution_service()->ClearBadProxiesCache(); |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::CreateWebSocket( |
| const GURL& url, |
| const std::vector<std::string>& requested_protocols, |
| const net::SiteForCookies& site_for_cookies, |
| net::StorageAccessApiStatus storage_access_api_status, |
| const net::IsolationInfo& isolation_info, |
| std::vector<mojom::HttpHeaderPtr> additional_headers, |
| int32_t process_id, |
| const url::Origin& origin, |
| network::mojom::ClientSecurityStatePtr client_security_state, |
| uint32_t options, |
| const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, |
| mojo::PendingRemote<mojom::WebSocketHandshakeClient> handshake_client, |
| mojo::PendingRemote<mojom::URLLoaderNetworkServiceObserver> |
| url_loader_network_observer, |
| mojo::PendingRemote<mojom::WebSocketAuthenticationHandler> auth_handler, |
| mojo::PendingRemote<mojom::TrustedHeaderClient> header_client, |
| const std::optional<base::UnguessableToken>& throttling_profile_id) { |
| #if BUILDFLAG(ENABLE_WEBSOCKETS) |
| if (!websocket_factory_) { |
| websocket_factory_ = std::make_unique<WebSocketFactory>(this); |
| } |
| |
| DCHECK_GE(process_id, 0); |
| |
| websocket_factory_->CreateWebSocket( |
| url, requested_protocols, site_for_cookies, storage_access_api_status, |
| isolation_info, std::move(additional_headers), process_id, origin, |
| std::move(client_security_state), options, |
| static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation), |
| std::move(handshake_client), std::move(url_loader_network_observer), |
| std::move(auth_handler), std::move(header_client), throttling_profile_id); |
| #endif // BUILDFLAG(ENABLE_WEBSOCKETS) |
| } |
| |
| void NetworkContext::CreateWebTransport( |
| const GURL& url, |
| const url::Origin& origin, |
| const net::NetworkAnonymizationKey& key, |
| std::vector<mojom::WebTransportCertificateFingerprintPtr> fingerprints, |
| const std::vector<std::string>& application_protocols, |
| mojo::PendingRemote<mojom::WebTransportHandshakeClient> |
| pending_handshake_client, |
| mojo::PendingRemote<mojom::URLLoaderNetworkServiceObserver> |
| url_loader_network_observer, |
| mojom::ClientSecurityStatePtr client_security_state) { |
| if (!IsNetworkForNonceAndUrlAllowed( |
| key.GetNonce().value_or(base::UnguessableToken::Null()), url)) { |
| mojo::Remote<mojom::WebTransportHandshakeClient> remote_handshake_client( |
| std::move(pending_handshake_client)); |
| remote_handshake_client->OnHandshakeFailed( |
| net::WebTransportError(net::ERR_NETWORK_ACCESS_REVOKED)); |
| return; |
| } |
| web_transports_.insert(std::make_unique<WebTransport>( |
| url, origin, key, fingerprints, application_protocols, this, |
| std::move(pending_handshake_client), |
| std::move(url_loader_network_observer), |
| std::move(client_security_state))); |
| } |
| |
| void NetworkContext::CreateNetLogExporter( |
| mojo::PendingReceiver<mojom::NetLogExporter> receiver) { |
| net_log_exporter_receivers_.Add(std::make_unique<NetLogExporter>(this), |
| std::move(receiver)); |
| } |
| |
| void NetworkContext::ResolveHost( |
| mojom::HostResolverHostPtr host, |
| const net::NetworkAnonymizationKey& network_anonymization_key, |
| mojom::ResolveHostParametersPtr optional_parameters, |
| mojo::PendingRemote<mojom::ResolveHostClient> response_client) { |
| // Dns request is disallowed if network access is disabled for the nonce. |
| if (network_anonymization_key.GetNonce().has_value() && |
| !IsNetworkForNonceAndUrlAllowed( |
| /*nonce=*/network_anonymization_key.GetNonce().value(), |
| /*url=*/host->is_host_port_pair() |
| ? GURL(host->get_host_port_pair().ToString()) |
| : host->get_scheme_host_port().GetURL())) { |
| mojo::Remote<mojom::ResolveHostClient> remote_response_client( |
| std::move(response_client)); |
| remote_response_client->OnComplete( |
| net::ERR_NETWORK_ACCESS_REVOKED, |
| net::ResolveErrorInfo(net::ERR_NETWORK_ACCESS_REVOKED), |
| /*resolved_addresses=*/{}, |
| /*alternative_endpoints=*/{}); |
| return; |
| } |
| |
| if (!internal_host_resolver_) { |
| internal_host_resolver_ = std::make_unique<HostResolver>( |
| url_request_context_->host_resolver(), url_request_context_->net_log()); |
| } |
| internal_host_resolver_->ResolveHost( |
| std::move(host), network_anonymization_key, |
| std::move(optional_parameters), std::move(response_client)); |
| } |
| |
| void NetworkContext::CreateHostResolver( |
| const std::optional<net::DnsConfigOverrides>& config_overrides, |
| mojo::PendingReceiver<mojom::HostResolver> receiver) { |
| net::HostResolver* internal_resolver = url_request_context_->host_resolver(); |
| std::unique_ptr<net::HostResolver> private_internal_resolver; |
| |
| if (config_overrides && |
| config_overrides.value() != net::DnsConfigOverrides()) { |
| // If custom configuration is needed, create a separate internal resolver |
| // with the specified configuration overrides. Because we are using a non- |
| // standard resolver, disable the cache. |
| // |
| // TODO(crbug.com/40577881): Consider allowing per-resolve overrides, so the |
| // same net::HostResolver with the same scheduler and cache can be used with |
| // different overrides. But since this is only used for special cases for |
| // now, much easier to create entirely separate net::HostResolver instances. |
| net::HostResolver::ManagerOptions options; |
| options.insecure_dns_client_enabled = true; |
| // Assume additional types are unnecessary for these special cases. |
| options.additional_types_via_insecure_dns_enabled = false; |
| options.dns_config_overrides = config_overrides.value(); |
| private_internal_resolver = |
| network_service_->host_resolver_factory()->CreateStandaloneResolver( |
| url_request_context_->net_log(), std::move(options), |
| /* host_mapping_rules */ "", /* enable_caching */ false, |
| /* enable_stale */ false); |
| private_internal_resolver->SetRequestContext(url_request_context_); |
| internal_resolver = private_internal_resolver.get(); |
| } |
| |
| host_resolvers_.emplace(std::make_unique<HostResolver>( |
| std::move(receiver), |
| base::BindOnce(&NetworkContext::OnHostResolverShutdown, |
| base::Unretained(this)), |
| internal_resolver, std::move(private_internal_resolver), |
| url_request_context_->net_log())); |
| } |
| |
| void NetworkContext::VerifyCertInternal( |
| const scoped_refptr<net::X509Certificate>& certificate, |
| const net::HostPortPair& host_port, |
| const std::string& ocsp_result, |
| const std::string& sct_list, |
| CTVerificationMode ct_verification_mode, |
| VerifyCertCallback callback) { |
| uint64_t cert_verify_id = ++next_cert_verify_id_; |
| CHECK_NE(0u, next_cert_verify_id_); // The request ID should not wrap around. |
| auto pending_cert_verify = std::make_unique<PendingCertVerify>(); |
| pending_cert_verify->callback = std::move(callback); |
| pending_cert_verify->result = std::make_unique<net::CertVerifyResult>(); |
| pending_cert_verify->certificate = certificate; |
| pending_cert_verify->host_port = host_port; |
| net::CertVerifier* cert_verifier = |
| g_cert_verifier_for_testing ? g_cert_verifier_for_testing |
| : url_request_context_->cert_verifier(); |
| int flags = 0; |
| switch (ct_verification_mode) { |
| case CTVerificationMode::kTlsCertificate: |
| break; |
| case CTVerificationMode::kSignedExchange: |
| flags = net::CertVerifier::VERIFY_SXG_CT_REQUIREMENTS; |
| break; |
| } |
| int result = cert_verifier->Verify( |
| net::CertVerifier::RequestParams(certificate, host_port.host(), flags, |
| ocsp_result, sct_list), |
| pending_cert_verify->result.get(), |
| base::BindOnce(&NetworkContext::OnVerifyCertComplete, |
| base::Unretained(this), cert_verify_id), |
| &pending_cert_verify->request, |
| net::NetLogWithSource::Make(url_request_context_->net_log(), |
| net::NetLogSourceType::CERT_VERIFIER_JOB)); |
| cert_verifier_requests_[cert_verify_id] = std::move(pending_cert_verify); |
| |
| if (result != net::ERR_IO_PENDING) { |
| OnVerifyCertComplete(cert_verify_id, result); |
| } |
| } |
| |
| void NetworkContext::VerifyCert( |
| const scoped_refptr<net::X509Certificate>& certificate, |
| const net::HostPortPair& host_port, |
| const std::string& ocsp_result, |
| const std::string& sct_list, |
| VerifyCertCallback callback) { |
| VerifyCertInternal(certificate, host_port, ocsp_result, sct_list, |
| CTVerificationMode::kTlsCertificate, std::move(callback)); |
| } |
| |
| void NetworkContext::VerifyCertForSignedExchange( |
| const scoped_refptr<net::X509Certificate>& certificate, |
| const net::HostPortPair& host_port, |
| const std::string& ocsp_result, |
| const std::string& sct_list, |
| VerifyCertCallback callback) { |
| VerifyCertInternal(certificate, host_port, ocsp_result, sct_list, |
| CTVerificationMode::kSignedExchange, std::move(callback)); |
| } |
| |
| void NetworkContext::Verify2QwacCertBinding( |
| const std::string& binding, |
| const std::string& hostname, |
| const scoped_refptr<net::X509Certificate>& tls_certificate, |
| Verify2QwacCertBindingCallback callback) { |
| net::CertVerifier* cert_verifier = |
| g_cert_verifier_for_testing ? g_cert_verifier_for_testing |
| : url_request_context_->cert_verifier(); |
| cert_verifier->Verify2QwacBinding( |
| binding, hostname, tls_certificate, std::move(callback), |
| net::NetLogWithSource::Make( |
| url_request_context_->net_log(), |
| net::NetLogSourceType::CERT_VERIFIER_2QWAC_JOB)); |
| } |
| |
| void NetworkContext::NotifyExternalCacheHit(const GURL& url, |
| const std::string& http_method, |
| const net::NetworkIsolationKey& key, |
| bool include_credentials) { |
| net::HttpCache* cache = |
| url_request_context_->http_transaction_factory()->GetCache(); |
| if (!cache) { |
| return; |
| } |
| cache->OnExternalCacheHit(url, http_method, key, include_credentials); |
| } |
| |
| void NetworkContext::SetCorsOriginAccessListsForOrigin( |
| const url::Origin& source_origin, |
| std::vector<mojom::CorsOriginPatternPtr> allow_patterns, |
| std::vector<mojom::CorsOriginPatternPtr> block_patterns, |
| SetCorsOriginAccessListsForOriginCallback callback) { |
| cors_origin_access_list_.SetAllowListForOrigin(source_origin, allow_patterns); |
| cors_origin_access_list_.SetBlockListForOrigin(source_origin, block_patterns); |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::AddHSTS(const std::string& host, |
| base::Time expiry, |
| bool include_subdomains, |
| AddHSTSCallback callback) { |
| net::TransportSecurityState* state = |
| url_request_context_->transport_security_state(); |
| state->AddHSTS(host, expiry, include_subdomains); |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::IsHSTSActiveForHost(const std::string& host, |
| bool is_top_level_nav, |
| IsHSTSActiveForHostCallback callback) { |
| net::TransportSecurityState* security_state = |
| url_request_context_->transport_security_state(); |
| |
| if (!security_state) { |
| std::move(callback).Run(false); |
| return; |
| } |
| |
| std::move(callback).Run( |
| security_state->ShouldUpgradeToSSL(host, is_top_level_nav)); |
| } |
| |
| void NetworkContext::GetHSTSState(const std::string& domain, |
| GetHSTSStateCallback callback) { |
| base::Value::Dict result; |
| |
| if (base::IsStringASCII(domain)) { |
| net::TransportSecurityState* transport_security_state = |
| url_request_context()->transport_security_state(); |
| if (transport_security_state) { |
| net::TransportSecurityState::STSState static_sts_state; |
| net::TransportSecurityState::PKPState static_pkp_state; |
| bool found_sts_static = transport_security_state->GetStaticSTSState( |
| domain, &static_sts_state); |
| bool found_pkp_static = transport_security_state->GetStaticPKPState( |
| domain, &static_pkp_state); |
| if (found_sts_static || found_pkp_static) { |
| result.Set("static_upgrade_mode", |
| static_cast<int>(static_sts_state.upgrade_mode)); |
| result.Set("static_sts_include_subdomains", |
| static_sts_state.include_subdomains); |
| result.Set("static_sts_observed", |
| static_sts_state.last_observed.InSecondsFSinceUnixEpoch()); |
| result.Set("static_sts_expiry", |
| static_sts_state.expiry.InSecondsFSinceUnixEpoch()); |
| result.Set("static_pkp_include_subdomains", |
| static_pkp_state.include_subdomains); |
| result.Set("static_pkp_observed", |
| static_pkp_state.last_observed.InSecondsFSinceUnixEpoch()); |
| result.Set("static_pkp_expiry", |
| static_pkp_state.expiry.InSecondsFSinceUnixEpoch()); |
| result.Set("static_spki_hashes", |
| HashesToBase64String(static_pkp_state.spki_hashes)); |
| result.Set("static_sts_domain", static_sts_state.domain); |
| result.Set("static_pkp_domain", static_pkp_state.domain); |
| } |
| |
| net::TransportSecurityState::STSState dynamic_sts_state; |
| net::TransportSecurityState::PKPState dynamic_pkp_state; |
| bool found_sts_dynamic = transport_security_state->GetDynamicSTSState( |
| domain, &dynamic_sts_state); |
| |
| bool found_pkp_dynamic = transport_security_state->GetDynamicPKPState( |
| domain, &dynamic_pkp_state); |
| if (found_sts_dynamic) { |
| result.Set("dynamic_upgrade_mode", |
| static_cast<int>(dynamic_sts_state.upgrade_mode)); |
| result.Set("dynamic_sts_include_subdomains", |
| dynamic_sts_state.include_subdomains); |
| result.Set("dynamic_sts_observed", |
| dynamic_sts_state.last_observed.InSecondsFSinceUnixEpoch()); |
| result.Set("dynamic_sts_expiry", |
| dynamic_sts_state.expiry.InSecondsFSinceUnixEpoch()); |
| result.Set("dynamic_sts_domain", dynamic_sts_state.domain); |
| } |
| |
| if (found_pkp_dynamic) { |
| result.Set("dynamic_pkp_include_subdomains", |
| dynamic_pkp_state.include_subdomains); |
| result.Set("dynamic_pkp_observed", |
| dynamic_pkp_state.last_observed.InSecondsFSinceUnixEpoch()); |
| result.Set("dynamic_pkp_expiry", |
| dynamic_pkp_state.expiry.InSecondsFSinceUnixEpoch()); |
| result.Set("dynamic_spki_hashes", |
| HashesToBase64String(dynamic_pkp_state.spki_hashes)); |
| result.Set("dynamic_pkp_domain", dynamic_pkp_state.domain); |
| } |
| |
| result.Set("result", found_sts_static || found_pkp_static || |
| found_sts_dynamic || found_pkp_dynamic); |
| } else { |
| result.Set("error", "no TransportSecurityState active"); |
| } |
| } else { |
| result.Set("error", "non-ASCII domain name"); |
| } |
| |
| std::move(callback).Run(std::move(result)); |
| } |
| |
| void NetworkContext::DeleteDynamicDataForHost( |
| const std::string& host, |
| DeleteDynamicDataForHostCallback callback) { |
| net::TransportSecurityState* transport_security_state = |
| url_request_context()->transport_security_state(); |
| if (!transport_security_state) { |
| std::move(callback).Run(false); |
| return; |
| } |
| |
| std::move(callback).Run( |
| transport_security_state->DeleteDynamicDataForHost(host)); |
| } |
| |
| void NetworkContext::EnableStaticKeyPinningForTesting( |
| EnableStaticKeyPinningForTestingCallback callback) { |
| net::TransportSecurityState* state = |
| url_request_context_->transport_security_state(); |
| state->EnableStaticPinsForTesting(); |
| state->SetPinningListAlwaysTimelyForTesting(true); |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::VerifyCertificateForTesting( |
| const scoped_refptr<net::X509Certificate>& certificate, |
| const std::string& hostname, |
| const std::string& ocsp_response, |
| const std::string& sct_list, |
| VerifyCertificateForTestingCallback callback) { |
| net::CertVerifier* cert_verifier = url_request_context_->cert_verifier(); |
| |
| auto state = std::make_unique<TestVerifyCertState>(); |
| auto* request = &state->request; |
| auto* result = &state->result; |
| |
| cert_verifier->Verify( |
| net::CertVerifier::RequestParams(certificate.get(), hostname, 0, |
| ocsp_response, sct_list), |
| result, |
| base::BindOnce(TestVerifyCertCallback, std::move(state), |
| std::move(callback)), |
| request, |
| net::NetLogWithSource::Make(net::NetLog::Get(), |
| net::NetLogSourceType::NONE)); |
| } |
| |
| void NetworkContext::GetTrustAnchorIDsForTesting( |
| GetTrustAnchorIDsForTestingCallback callback) { |
| std::move(callback).Run( |
| base::ToVector(url_request_context_->ssl_config_service() |
| ->GetSSLContextConfig() |
| .trust_anchor_ids)); |
| } |
| |
| void NetworkContext::PreconnectSockets( |
| uint32_t num_streams, |
| const GURL& original_url, |
| mojom::CredentialsMode credentials_mode, |
| const net::NetworkAnonymizationKey& network_anonymization_key, |
| const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, |
| const std::optional<net::ConnectionKeepAliveConfig>& keepalive_config, |
| mojo::PendingRemote<mojom::ConnectionChangeObserverClient> |
| connection_change_observer_client) { |
| DCHECK(!require_network_anonymization_key_ || |
| !network_anonymization_key.IsEmpty()); |
| |
| GURL url = GetHSTSRedirectForPreconnect(original_url); |
| |
| // |PreconnectSockets| may receive arguments from the renderer, which is not |
| // guaranteed to validate them. |
| if (num_streams == 0) { |
| return; |
| } |
| |
| // Preconnect is disallowed if network access is disabled for the nonce. |
| if (network_anonymization_key.GetNonce().has_value() && |
| !IsNetworkForNonceAndUrlAllowed( |
| network_anonymization_key.GetNonce().value(), url)) { |
| return; |
| } |
| |
| std::string user_agent; |
| if (url_request_context_->http_user_agent_settings()) { |
| user_agent = |
| url_request_context_->http_user_agent_settings()->GetUserAgent(); |
| } |
| net::HttpRequestInfo request_info; |
| request_info.url = url; |
| request_info.method = net::HttpRequestHeaders::kGetMethod; |
| request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kUserAgent, |
| user_agent); |
| request_info.traffic_annotation = traffic_annotation; |
| |
| if (keepalive_config.has_value() || |
| connection_change_observer_client.is_valid()) { |
| request_info.connection_management_config = |
| net::ConnectionManagementConfig(); |
| request_info.connection_management_config->keep_alive_config = |
| keepalive_config; |
| if (connection_change_observer_client.is_valid()) { |
| auto change_observer = std::make_unique<ConnectionChangeObserver>( |
| std::move(connection_change_observer_client), this); |
| |
| request_info.connection_management_config->connection_change_observer = |
| change_observer.get(); |
| connection_change_observers_.insert(std::move(change_observer)); |
| } |
| } |
| |
| switch (credentials_mode) { |
| case mojom::CredentialsMode::kOmit: |
| request_info.load_flags = net::LOAD_DO_NOT_SAVE_COOKIES; |
| request_info.privacy_mode = net::PRIVACY_MODE_ENABLED; |
| break; |
| |
| case mojom::CredentialsMode::kSameOrigin: |
| // Not yet implemented. If you need this credentials mode please update |
| // this branch to set the correct request_info fields. |
| NOTREACHED() << "kSameOrigin not yet implemented"; |
| |
| case mojom::CredentialsMode::kInclude: |
| request_info.load_flags = net::LOAD_NORMAL; |
| request_info.privacy_mode = net::PRIVACY_MODE_DISABLED; |
| break; |
| |
| case mojom::CredentialsMode::kOmitBug_775438_Workaround: |
| request_info.load_flags = net::LOAD_DO_NOT_SAVE_COOKIES; |
| request_info.privacy_mode = |
| net::PRIVACY_MODE_ENABLED_WITHOUT_CLIENT_CERTS; |
| break; |
| } |
| |
| request_info.network_anonymization_key = network_anonymization_key; |
| |
| net::HttpTransactionFactory* factory = |
| url_request_context_->http_transaction_factory(); |
| net::HttpNetworkSession* session = factory->GetSession(); |
| net::HttpStreamFactory* http_stream_factory = session->http_stream_factory(); |
| http_stream_factory->PreconnectStreams( |
| base::saturated_cast<int32_t>(num_streams), request_info, |
| base::OnceClosure()); |
| } |
| |
| #if BUILDFLAG(IS_P2P_ENABLED) |
| void NetworkContext::CreateP2PSocketManager( |
| const net::NetworkAnonymizationKey& network_anonymization_key, |
| mojo::PendingRemote<mojom::P2PTrustedSocketManagerClient> client, |
| mojo::PendingReceiver<mojom::P2PTrustedSocketManager> |
| trusted_socket_manager, |
| mojo::PendingReceiver<mojom::P2PSocketManager> socket_manager_receiver) { |
| std::unique_ptr<P2PSocketManager> socket_manager = |
| std::make_unique<P2PSocketManager>( |
| network_anonymization_key, std::move(client), |
| std::move(trusted_socket_manager), std::move(socket_manager_receiver), |
| base::BindRepeating(&NetworkContext::DestroySocketManager, |
| base::Unretained(this)), |
| url_request_context_); |
| socket_managers_[socket_manager.get()] = std::move(socket_manager); |
| } |
| #endif // BUILDFLAG(IS_P2P_ENABLED) |
| |
| void NetworkContext::CreateMdnsResponder( |
| mojo::PendingReceiver<mojom::MdnsResponder> responder_receiver) { |
| #if BUILDFLAG(ENABLE_MDNS) |
| if (!mdns_responder_manager_) { |
| mdns_responder_manager_ = std::make_unique<MdnsResponderManager>(); |
| } |
| |
| mdns_responder_manager_->CreateMdnsResponder(std::move(responder_receiver)); |
| #else |
| NOTREACHED(); |
| #endif // BUILDFLAG(ENABLE_MDNS) |
| } |
| |
| void NetworkContext::AddDomainReliabilityContextForTesting( |
| const url::Origin& origin, |
| const GURL& upload_url, |
| AddDomainReliabilityContextForTestingCallback callback) { |
| auto config = std::make_unique<domain_reliability::DomainReliabilityConfig>(); |
| config->origin = origin; |
| config->include_subdomains = false; |
| config->collectors.push_back(std::make_unique<GURL>(upload_url)); |
| config->success_sample_rate = 1.0; |
| config->failure_sample_rate = 1.0; |
| domain_reliability_monitor_->AddContextForTesting(std::move(config)); |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::ForceDomainReliabilityUploadsForTesting( |
| ForceDomainReliabilityUploadsForTestingCallback callback) { |
| domain_reliability_monitor_->ForceUploadsForTesting(); |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::SetSplitAuthCacheByNetworkAnonymizationKey( |
| bool split_auth_cache_by_network_anonymization_key) { |
| url_request_context_->http_transaction_factory() |
| ->GetSession() |
| ->http_auth_cache() |
| ->SetKeyServerEntriesByNetworkAnonymizationKey( |
| split_auth_cache_by_network_anonymization_key); |
| } |
| |
| void NetworkContext::SaveHttpAuthCacheProxyEntries( |
| SaveHttpAuthCacheProxyEntriesCallback callback) { |
| net::HttpAuthCache* http_auth_cache = |
| url_request_context_->http_transaction_factory() |
| ->GetSession() |
| ->http_auth_cache(); |
| base::UnguessableToken cache_key = |
| network_service_->http_auth_cache_proxy_copier()->SaveHttpAuthCache( |
| *http_auth_cache); |
| std::move(callback).Run(cache_key); |
| } |
| |
| void NetworkContext::LoadHttpAuthCacheProxyEntries( |
| const base::UnguessableToken& cache_key, |
| LoadHttpAuthCacheProxyEntriesCallback callback) { |
| net::HttpAuthCache* http_auth_cache = |
| url_request_context_->http_transaction_factory() |
| ->GetSession() |
| ->http_auth_cache(); |
| network_service_->http_auth_cache_proxy_copier()->LoadHttpAuthCache( |
| cache_key, http_auth_cache); |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::AddAuthCacheEntry( |
| const net::AuthChallengeInfo& challenge, |
| const net::NetworkAnonymizationKey& network_anonymization_key, |
| const net::AuthCredentials& credentials, |
| AddAuthCacheEntryCallback callback) { |
| net::HttpAuthCache* http_auth_cache = |
| url_request_context_->http_transaction_factory() |
| ->GetSession() |
| ->http_auth_cache(); |
| http_auth_cache->Add(challenge.challenger, |
| challenge.is_proxy ? net::HttpAuth::AUTH_PROXY |
| : net::HttpAuth::AUTH_SERVER, |
| challenge.realm, |
| net::HttpAuth::StringToScheme(challenge.scheme), |
| network_anonymization_key, challenge.challenge, |
| credentials, challenge.path); |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::SetCorsNonWildcardRequestHeadersSupport(bool value) { |
| if (!base::FeatureList::IsEnabled( |
| features::kCorsNonWildcardRequestHeadersSupport)) { |
| return; |
| } |
| cors_non_wildcard_request_headers_support_ = |
| cors::NonWildcardRequestHeadersSupport(value); |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| void NetworkContext::LookupProxyAuthCredentials( |
| const net::ProxyServer& proxy_server, |
| const std::string& auth_scheme, |
| const std::string& realm, |
| LookupProxyAuthCredentialsCallback callback) { |
| net::HttpAuth::Scheme net_scheme = |
| net::HttpAuth::StringToScheme(base::ToLowerASCII(auth_scheme)); |
| if (net_scheme == net::HttpAuth::Scheme::AUTH_SCHEME_MAX) { |
| std::move(callback).Run(std::nullopt); |
| return; |
| } |
| net::HttpAuthCache* http_auth_cache = |
| url_request_context_->http_transaction_factory() |
| ->GetSession() |
| ->http_auth_cache(); |
| // TODO(crbug.com/40704785): Mapping proxy addresses to URLs is a |
| // lossy conversion, shouldn't do this. |
| const char* scheme = |
| proxy_server.is_secure_http_like() ? "https://" : "http://"; |
| url::SchemeHostPort scheme_host_port( |
| GURL(scheme + proxy_server.host_port_pair().ToString())); |
| if (!scheme_host_port.IsValid()) { |
| std::move(callback).Run(std::nullopt); |
| return; |
| } |
| |
| // Unlike server credentials, proxy credentials are not keyed on |
| // NetworkAnonymizationKey. |
| net::HttpAuthCache::Entry* entry = http_auth_cache->Lookup( |
| scheme_host_port, net::HttpAuth::AUTH_PROXY, realm, net_scheme, |
| net::NetworkAnonymizationKey()); |
| if (entry) { |
| std::move(callback).Run(entry->credentials()); |
| } else { |
| std::move(callback).Run(std::nullopt); |
| } |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| const net::HttpAuthPreferences* NetworkContext::GetHttpAuthPreferences() const { |
| return &http_auth_merged_preferences_; |
| } |
| |
| size_t NetworkContext::NumOpenWebTransports() const { |
| return std::ranges::count(web_transports_, false, &WebTransport::torn_down); |
| } |
| |
| bool NetworkContext::AllURLLoaderFactoriesAreBoundToNetworkForTesting( |
| net::handles::NetworkHandle target_network) const { |
| for (const auto& factory : url_loader_factories_) { |
| if (factory->GetBoundNetworkForTesting() != target_network) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| void NetworkContext::OnHttpAuthDynamicParamsChanged( |
| const mojom::HttpAuthDynamicParams* |
| http_auth_dynamic_network_service_params) { |
| http_auth_merged_preferences_.SetServerAllowlist( |
| http_auth_dynamic_network_service_params->server_allowlist); |
| http_auth_merged_preferences_.SetDelegateAllowlist( |
| http_auth_dynamic_network_service_params->delegate_allowlist); |
| http_auth_merged_preferences_.set_delegate_by_kdc_policy( |
| http_auth_dynamic_network_service_params->delegate_by_kdc_policy); |
| http_auth_merged_preferences_.set_negotiate_disable_cname_lookup( |
| http_auth_dynamic_network_service_params->negotiate_disable_cname_lookup); |
| http_auth_merged_preferences_.set_negotiate_enable_port( |
| http_auth_dynamic_network_service_params->enable_negotiate_port); |
| http_auth_merged_preferences_.set_basic_over_http_enabled( |
| http_auth_dynamic_network_service_params->basic_over_http_enabled); |
| #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) |
| http_auth_merged_preferences_.set_ntlm_v2_enabled( |
| http_auth_dynamic_network_service_params->ntlm_v2_enabled); |
| #endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) |
| |
| #if BUILDFLAG(IS_ANDROID) |
| http_auth_merged_preferences_.set_auth_android_negotiate_account_type( |
| http_auth_dynamic_network_service_params->android_negotiate_account_type); |
| #endif // BUILDFLAG(IS_ANDROID) |
| |
| #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) |
| http_auth_merged_preferences_.set_allow_gssapi_library_load( |
| http_auth_dynamic_network_service_params->allow_gssapi_library_load); |
| #endif // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) |
| if (http_auth_dynamic_network_service_params->allowed_schemes.has_value()) { |
| http_auth_merged_preferences_.set_allowed_schemes( |
| base::flat_set<std::string>( |
| http_auth_dynamic_network_service_params->allowed_schemes->begin(), |
| http_auth_dynamic_network_service_params->allowed_schemes->end())); |
| } else { |
| http_auth_merged_preferences_.set_allowed_schemes(std::nullopt); |
| } |
| |
| url_matcher_ = std::make_unique<url_matcher::URLMatcher>(); |
| url_matcher::util::AddAllowFiltersWithLimit( |
| url_matcher_.get(), http_auth_dynamic_network_service_params |
| ->patterns_allowed_to_use_all_schemes); |
| http_auth_merged_preferences_.set_http_auth_scheme_filter( |
| base::BindRepeating(&NetworkContext::IsAllowedToUseAllHttpAuthSchemes, |
| base::Unretained(this))); |
| } |
| |
| URLRequestContextOwner NetworkContext::MakeURLRequestContext( |
| mojo::PendingRemote<mojom::URLLoaderFactory> |
| url_loader_factory_for_cert_net_fetcher, |
| scoped_refptr<SessionCleanupCookieStore> session_cleanup_cookie_store, |
| OnURLRequestContextBuilderConfiguredCallback |
| on_url_request_context_builder_configured, |
| net::handles::NetworkHandle bound_network) { |
| URLRequestContextBuilderMojo builder; |
| const base::CommandLine* command_line = |
| base::CommandLine::ForCurrentProcess(); |
| |
| bool is_network_bound = bound_network != net::handles::kInvalidNetworkHandle; |
| if (is_network_bound) { |
| builder.BindToNetwork(bound_network); |
| } |
| |
| std::unique_ptr<net::CertVerifier> cert_verifier; |
| if (g_cert_verifier_for_testing) { |
| cert_verifier = std::make_unique<WrappedTestingCertVerifier>(); |
| } else { |
| DCHECK(params_->cert_verifier_params); |
| // base::Unretained() is safe below because |this| will own |
| // |cert_verifier|. |
| // TODO(crbug.com/40693524): this cert verifier should deal with |
| // disconnections if the CertVerifierService is run outside of the browser |
| // process. |
| cert_verifier = std::make_unique<cert_verifier::MojoCertVerifier>( |
| std::move(params_->cert_verifier_params->cert_verifier_service), |
| std::move(params_->cert_verifier_params |
| ->cert_verifier_service_client_receiver), |
| std::move(url_loader_factory_for_cert_net_fetcher), |
| base::BindRepeating( |
| &NetworkContext::CreateURLLoaderFactoryForCertNetFetcher, |
| base::Unretained(this))); |
| |
| // Whether the cert verifier is remote or in-process, we should wrap it in |
| // caching and coalescing layers to avoid extra verifications and IPCs. |
| cert_verifier = std::make_unique<net::CachingCertVerifier>( |
| std::make_unique<net::CoalescingCertVerifier>( |
| std::move(cert_verifier))); |
| } |
| |
| builder.SetCertVerifier(IgnoreErrorsCertVerifier::MaybeWrapCertVerifier( |
| *command_line, nullptr, std::move(cert_verifier))); |
| |
| #if BUILDFLAG(IS_CT_SUPPORTED) |
| builder.set_sct_auditing_delegate( |
| std::make_unique<SCTAuditingDelegate>(weak_factory_.GetWeakPtr())); |
| #endif // BUILDFLAG(IS_CT_SUPPORTED) |
| |
| std::unique_ptr<NetworkServiceNetworkDelegate> network_delegate = |
| std::make_unique<NetworkServiceNetworkDelegate>( |
| params_->enable_referrers, |
| params_->validate_referrer_policy_on_initial_request, |
| std::move(params_->proxy_error_client), this); |
| network_delegate_ = network_delegate.get(); |
| builder.set_network_delegate(std::move(network_delegate)); |
| |
| // Decide which ProxyDelegate to create. At most one of these will be the |
| // case for any given NetworkContext: either PrefetchProxy, handling its |
| // custom proxy configs, or IpProtection, using the proxy allowlist. |
| auto* mdl_manager = network_service_->masked_domain_list_manager(); |
| auto* prt_registry = network_service_->probabilistic_reveal_token_registry(); |
| bool requires_ipp_proxy_delegate = |
| (mdl_manager->IsEnabled() || |
| !net::features::kIpPrivacyUnconditionalProxyDomainList.Get().empty()) && |
| (params_->ip_protection_core_host || |
| net::features::kIpPrivacyAlwaysCreateCore.Get()); |
| if (requires_ipp_proxy_delegate) { |
| CHECK(!params_->initial_custom_proxy_config); |
| CHECK(!params_->custom_proxy_config_client_receiver); |
| scoped_refptr<ip_protection::IpProtectionCoreHostRemote> core_host_remote = |
| params_->ip_protection_core_host |
| ? base::MakeRefCounted<ip_protection::IpProtectionCoreHostRemote>( |
| std::move(params_->ip_protection_core_host)) |
| : nullptr; |
| auto ip_protection_core_impl = |
| std::make_unique<ip_protection::IpProtectionCoreImplMojo>( |
| std::move(params_->ip_protection_control), core_host_remote, |
| mdl_manager, prt_registry, params_->enable_ip_protection, |
| params_->ip_protection_incognito, |
| std::move(params_->initial_ip_protection_tokens), |
| params_->ip_protection_data_directory); |
| builder.set_proxy_delegate( |
| std::make_unique<ip_protection::IpProtectionProxyDelegate>( |
| ip_protection_core_impl.get())); |
| // Set tracking protection content settings if there are any provided. |
| ip_protection_core_impl->SetTrackingProtectionContentSetting( |
| params_->tracking_protection_content_settings); |
| |
| ip_protection_core_ = std::move(ip_protection_core_impl); |
| } else if (params_->initial_custom_proxy_config || |
| params_->custom_proxy_config_client_receiver) { |
| builder.set_proxy_delegate(std::make_unique<NetworkServiceProxyDelegate>( |
| std::move(params_->initial_custom_proxy_config), |
| std::move(params_->custom_proxy_config_client_receiver), |
| std::move(params_->custom_proxy_connection_observer_remote))); |
| } |
| |
| net::NetLog* net_log = nullptr; |
| if (network_service_) { |
| net_log = network_service_->net_log(); |
| builder.set_net_log(net_log); |
| if (!is_network_bound) { |
| // Network bound URLRequestContexts build and configure their own special |
| // HostResolverManager and HostResolver. So, don't inject the |
| // NetworkService one even if NetworkService is enabled. |
| builder.set_host_resolver_manager( |
| network_service_->host_resolver_manager()); |
| builder.set_host_resolver_factory( |
| network_service_->host_resolver_factory()); |
| } |
| builder.SetHttpAuthHandlerFactory( |
| network_service_->CreateHttpAuthHandlerFactory(this)); |
| builder.set_network_quality_estimator( |
| network_service_->network_quality_estimator()); |
| } |
| trust_token_store_ = std::make_unique<PendingTrustTokenStore>(); |
| |
| base::FilePath trust_token_path; |
| if (GetFullDataFilePath( |
| params_->file_paths, |
| &network::mojom::NetworkContextFilePaths::trust_token_database_name, |
| trust_token_path)) { |
| SQLiteTrustTokenPersister::CreateForFilePath( |
| base::ThreadPool::CreateSequencedTaskRunner( |
| {base::MayBlock(), kTrustTokenDatabaseTaskPriority, |
| base::TaskShutdownBehavior::BLOCK_SHUTDOWN}), |
| trust_token_path, kTrustTokenWriteBufferingWindow, |
| base::BindOnce(&NetworkContext::FinishConstructingTrustTokenStore, |
| weak_factory_.GetWeakPtr())); |
| } else { |
| trust_token_store_->OnStoreReady(std::make_unique<TrustTokenStore>( |
| std::make_unique<InMemoryTrustTokenPersister>(), |
| std::make_unique<ExpiryInspectingRecordExpiryDelegate>( |
| network_service()->trust_token_key_commitments()))); |
| } |
| |
| std::unique_ptr<net::StaticHttpUserAgentSettings> user_agent_settings = |
| std::make_unique<net::StaticHttpUserAgentSettings>( |
| params_->accept_language, params_->user_agent); |
| // Borrow an alias for future use before giving the builder ownership. |
| user_agent_settings_ = user_agent_settings.get(); |
| builder.set_http_user_agent_settings(std::move(user_agent_settings)); |
| |
| builder.set_enable_brotli(params_->enable_brotli); |
| builder.set_enable_zstd(params_->enable_zstd); |
| |
| if (params_->proxy_resolver_factory) { |
| builder.SetMojoProxyResolverFactory( |
| std::move(params_->proxy_resolver_factory)); |
| } |
| |
| #if BUILDFLAG(IS_WIN) |
| if (params_->system_proxy_resolver) { |
| builder.SetMojoWindowsSystemProxyResolver( |
| std::move(params_->system_proxy_resolver)); |
| } |
| #endif // BUILDFLAG(IS_WIN) |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| if (params_->dhcp_wpad_url_client) { |
| builder.SetDhcpWpadUrlClient(std::move(params_->dhcp_wpad_url_client)); |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| if (!params_->http_cache_enabled) { |
| builder.DisableHttpCache(); |
| } else { |
| net::URLRequestContextBuilder::HttpCacheParams cache_params; |
| cache_params.max_size = params_->http_cache_max_size; |
| // Checking both to see if there are any file paths at all, and if there is |
| // specifically an http_cache_directory filepath in order to avoid a |
| // potential nullptr dereference if we just checked that |
| // `params_->file_paths->http_cache_directory' existed. |
| if (!params_->file_paths || !params_->file_paths->http_cache_directory) { |
| cache_params.type = |
| net::URLRequestContextBuilder::HttpCacheParams::IN_MEMORY; |
| } else { |
| // Network-bound NetworkContexts should not persist state on disk. |
| CHECK(!is_network_bound); |
| |
| cache_params.path = params_->file_paths->http_cache_directory->path(); |
| if (params_->file_paths->no_vary_search_directory) { |
| cache_params.no_vary_search_path = |
| params_->file_paths->no_vary_search_directory->path(); |
| } |
| cache_params.type = network_session_configurator::ChooseCacheType(); |
| #if BUILDFLAG(IS_WIN) |
| // For enterprise users, we always use simple backend when encryption is |
| // enabled. |
| if (params_->enable_encrypted_http_cache) { |
| cache_params.type = |
| net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE; |
| } |
| #endif |
| if (params_->http_cache_file_operations_factory) { |
| cache_params.file_operations_factory = |
| base::MakeRefCounted<MojoBackendFileOperationsFactory>( |
| std::move(params_->http_cache_file_operations_factory)); |
| } |
| } |
| cache_params.reset_cache = params_->reset_http_cache_backend; |
| |
| #if BUILDFLAG(IS_ANDROID) |
| app_status_listeners_.push_back( |
| std::make_unique<NetworkContextApplicationStatusListener>( |
| cache_params.app_status_listener_getter)); |
| #endif // BUILDFLAG(IS_ANDROID) |
| builder.EnableHttpCache(cache_params); |
| } |
| |
| std::unique_ptr<SSLConfigServiceMojo> ssl_config_service = |
| std::make_unique<SSLConfigServiceMojo>( |
| std::move(params_->initial_ssl_config), |
| std::move(params_->ssl_config_client_receiver)); |
| SSLConfigServiceMojo* ssl_config_service_raw = ssl_config_service.get(); |
| builder.set_ssl_config_service(std::move(ssl_config_service)); |
| |
| if (!params_->initial_proxy_config && |
| !params_->proxy_config_client_receiver.is_valid()) { |
| params_->initial_proxy_config = |
| net::ProxyConfigWithAnnotation::CreateDirect(); |
| } |
| builder.set_proxy_config_service(std::make_unique<ProxyConfigServiceMojo>( |
| std::move(params_->proxy_config_client_receiver), |
| std::move(params_->initial_proxy_config), |
| std::move(params_->proxy_config_poller_client))); |
| builder.set_pac_quick_check_enabled(params_->pac_quick_check_enabled); |
| |
| std::unique_ptr<PrefService> pref_service; |
| |
| base::FilePath http_server_properties_file_name; |
| if (GetFullDataFilePath(params_->file_paths, |
| &network::mojom::NetworkContextFilePaths:: |
| http_server_properties_file_name, |
| http_server_properties_file_name)) { |
| // Network-bound NetworkContexts should not persist state on disk. |
| CHECK(!is_network_bound); |
| scoped_refptr<JsonPrefStore> json_pref_store(new JsonPrefStore( |
| http_server_properties_file_name, nullptr, |
| base::ThreadPool::CreateSequencedTaskRunner( |
| {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN, |
| base::TaskPriority::BEST_EFFORT}))); |
| 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()); |
| NetworkQualitiesPrefDelegate::RegisterPrefs(pref_registry.get()); |
| KnownLegacyScopeDomainsPrefDelegate::RegisterPrefs(pref_registry.get()); |
| pref_service = pref_service_factory.Create(pref_registry.get()); |
| |
| builder.SetHttpServerProperties(std::make_unique<net::HttpServerProperties>( |
| std::make_unique<HttpServerPropertiesPrefDelegate>(pref_service.get()), |
| net_log)); |
| |
| network_qualities_pref_delegate_ = |
| std::make_unique<NetworkQualitiesPrefDelegate>( |
| pref_service.get(), network_service_->network_quality_estimator()); |
| } |
| |
| if (session_cleanup_cookie_store) { |
| // If the pref service was registered and initialized use it. |
| // If not, use nullptr to indicate prefs aren't available. |
| std::unique_ptr<net::CookieMonster> cookie_store = |
| std::make_unique<net::CookieMonster>( |
| session_cleanup_cookie_store.get(), net_log, |
| pref_service |
| ? std::make_unique<KnownLegacyScopeDomainsPrefDelegate>( |
| pref_service.get()) |
| : nullptr); |
| if (params_->persist_session_cookies) { |
| cookie_store->SetPersistSessionCookies(true); |
| } |
| |
| builder.SetCookieStore(std::move(cookie_store)); |
| } |
| |
| base::FilePath transport_security_persister_file_name; |
| if (GetFullDataFilePath(params_->file_paths, |
| &network::mojom::NetworkContextFilePaths:: |
| transport_security_persister_file_name, |
| transport_security_persister_file_name)) { |
| // Network-bound NetworkContexts should not persist state on disk. |
| CHECK(!is_network_bound); |
| builder.set_transport_security_persister_file_path( |
| transport_security_persister_file_name); |
| } |
| builder.set_hsts_policy_bypass_list(params_->hsts_policy_bypass_list); |
| |
| #if BUILDFLAG(ENABLE_REPORTING) |
| bool reporting_enabled = base::FeatureList::IsEnabled(features::kReporting); |
| if (reporting_enabled) { |
| auto reporting_policy = net::ReportingPolicy::Create(); |
| if (params_->reporting_delivery_interval) { |
| reporting_policy->delivery_interval = |
| *params_->reporting_delivery_interval; |
| reporting_policy->endpoint_backoff_policy.initial_delay_ms = |
| params_->reporting_delivery_interval->InMilliseconds(); |
| } |
| builder.set_reporting_policy(std::move(reporting_policy)); |
| } else { |
| builder.set_reporting_policy(nullptr); |
| } |
| |
| bool nel_enabled = |
| base::FeatureList::IsEnabled(features::kNetworkErrorLogging); |
| builder.set_network_error_logging_enabled(nel_enabled); |
| |
| base::FilePath reporting_and_nel_store_database_name; |
| if (GetFullDataFilePath(params_->file_paths, |
| &network::mojom::NetworkContextFilePaths:: |
| reporting_and_nel_store_database_name, |
| reporting_and_nel_store_database_name) && |
| (reporting_enabled || nel_enabled)) { |
| // Network-bound NetworkContexts should not persist state on disk. |
| CHECK(!is_network_bound); |
| scoped_refptr<base::SequencedTaskRunner> client_task_runner = |
| base::SingleThreadTaskRunner::GetCurrentDefault(); |
| scoped_refptr<base::SequencedTaskRunner> background_task_runner = |
| base::ThreadPool::CreateSequencedTaskRunner( |
| {base::MayBlock(), |
| net::GetReportingAndNelStoreBackgroundSequencePriority(), |
| base::TaskShutdownBehavior::BLOCK_SHUTDOWN}); |
| std::unique_ptr<net::SQLitePersistentReportingAndNelStore> sqlite_store( |
| new net::SQLitePersistentReportingAndNelStore( |
| reporting_and_nel_store_database_name, client_task_runner, |
| background_task_runner)); |
| builder.set_persistent_reporting_and_nel_store(std::move(sqlite_store)); |
| } else { |
| builder.set_persistent_reporting_and_nel_store(nullptr); |
| } |
| |
| if (params_->enterprise_reporting_endpoints.has_value()) { |
| builder.set_enterprise_reporting_endpoints( |
| params_->enterprise_reporting_endpoints.value()); |
| } |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| |
| net::HttpNetworkSessionParams session_params; |
| bool is_quic_force_disabled = false; |
| if (network_service_ && network_service_->quic_disabled()) { |
| is_quic_force_disabled = true; |
| } |
| |
| auto quic_context = std::make_unique<net::QuicContext>(); |
| if (params_->quic_idle_connection_timeout_seconds && |
| params_->quic_idle_connection_timeout_seconds.value() >= 0) { |
| quic_context->params()->idle_connection_timeout = |
| base::Seconds(params_->quic_idle_connection_timeout_seconds.value()); |
| } |
| network_session_configurator::ParseCommandLineAndFieldTrials( |
| *base::CommandLine::ForCurrentProcess(), is_quic_force_disabled, |
| &session_params, quic_context->params()); |
| |
| session_params.disable_idle_sockets_close_on_memory_pressure = |
| params_->disable_idle_sockets_close_on_memory_pressure; |
| |
| session_params.key_auth_cache_server_entries_by_network_anonymization_key = |
| params_->split_auth_cache_by_network_anonymization_key; |
| |
| builder.set_http_network_session_params(session_params); |
| builder.set_quic_context(std::move(quic_context)); |
| |
| if (params_->shared_dictionary_enabled) { |
| builder.set_enable_shared_dictionary(true); |
| builder.set_enable_shared_zstd(true); |
| } |
| |
| builder.SetWrapHttpNetworkLayerCallback( |
| base::BindOnce([](std::unique_ptr<net::HttpNetworkLayer> network_layer) |
| -> std::unique_ptr<net::HttpTransactionFactory> { |
| return std::make_unique<ThrottlingNetworkTransactionFactory>( |
| std::move(network_layer)); |
| })); |
| |
| if (command_line->HasSwitch(switches::kHostResolverRules)) { |
| builder.set_host_mapping_rules( |
| command_line->GetSwitchValueASCII(switches::kHostResolverRules)); |
| } else if (command_line->HasSwitch(switches::kHostRules)) { |
| LOG(WARNING) |
| << "The --" << switches::kHostRules |
| << " command line switch is deprecated, and now has the same behavior " |
| "as --" |
| << switches::kHostResolverRules << ". Use --" |
| << switches::kHostResolverRules |
| << " directly to avoid this LOG message. If you get certificate error " |
| "where --" |
| << switches::kHostRules |
| << " previously did not give one, you need to ensure the server has a " |
| "valid certificate for the mapped hostname, not the destination " |
| "hostname."; |
| builder.set_host_mapping_rules( |
| command_line->GetSwitchValueASCII(switches::kHostRules)); |
| } |
| |
| #if BUILDFLAG(IS_WIN) |
| if (params_->socket_brokers) { |
| builder.set_client_socket_factory( |
| std::make_unique<BrokeredClientSocketFactory>( |
| std::move(params_->socket_brokers->client))); |
| } |
| #endif |
| |
| require_network_anonymization_key_ = |
| params_->require_network_anonymization_key; |
| |
| // If `require_network_anonymization_key_` is true, but the features that can |
| // trigger another URLRequest are not set to respect NetworkAnonymizationKeys, |
| // the URLRequests that they create might not have a NAK, so only set the |
| // corresponding value in the URLRequestContext to true at the URLRequest |
| // layer if all those features are set to respect NAK. The Domain Reliability |
| // feature, which is partitioned by NIK instead of NAK, triggers creation of |
| // URLRequests as well, so also check `net::HttpCache::IsSplitCacheEnabled()`. |
| if (require_network_anonymization_key_ && |
| net::NetworkAnonymizationKey::IsPartitioningEnabled() && |
| net::HttpCache::IsSplitCacheEnabled()) { |
| builder.set_require_network_anonymization_key(true); |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| builder.set_check_cleartext_permitted(params_->check_clear_text_permitted); |
| #endif // BUILDFLAG(IS_ANDROID) |
| |
| if (params_->cookie_deprecation_label.has_value()) { |
| builder.set_cookie_deprecation_label(*params_->cookie_deprecation_label); |
| } |
| |
| if (params_->device_bound_sessions_enabled) { |
| builder.set_has_device_bound_session_service(true); |
| |
| if (base::FeatureList::IsEnabled( |
| net::features::kPersistDeviceBoundSessions)) { |
| base::FilePath device_bound_sessions_file_path; |
| if (GetFullDataFilePath(params_->file_paths, |
| &network::mojom::NetworkContextFilePaths:: |
| device_bound_sessions_database_name, |
| device_bound_sessions_file_path)) { |
| // Network-bound NetworkContexts should not persist state on disk. |
| CHECK(!is_network_bound); |
| builder.set_device_bound_sessions_file_path( |
| device_bound_sessions_file_path); |
| } |
| } |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| builder.enable_stale_dns_resolver(params_->stale_dns_enabled); |
| #endif // BUILDFLAG(IS_ANDROID) |
| |
| if (on_url_request_context_builder_configured) { |
| std::move(on_url_request_context_builder_configured).Run(&builder); |
| } |
| auto result = |
| URLRequestContextOwner(std::move(pref_service), builder.Build()); |
| |
| // Subscribe the CertVerifier to configuration changes that are exposed via |
| // the mojom::SSLConfig, but which are not part of the |
| // net::SSLConfig[Service] interfaces. |
| ssl_config_service_raw->SetCertVerifierForConfiguring( |
| result.url_request_context->cert_verifier()); |
| |
| // Attach some things to the URLRequestContextBuilder's |
| // TransportSecurityState. Since no requests have been made yet, safe to do |
| // this even after the call to Build(). |
| |
| if (network_service_->pins_list_updated()) { |
| result.url_request_context->transport_security_state()->UpdatePinList( |
| network_service_->pinsets(), network_service_->host_pins(), |
| network_service_->pins_list_update_time()); |
| } |
| |
| #if BUILDFLAG(IS_CT_SUPPORTED) |
| if (params_->enforce_chrome_ct_policy) { |
| require_ct_delegate_ = base::MakeRefCounted< |
| certificate_transparency::ChromeRequireCTDelegate>(); |
| result.url_request_context->transport_security_state() |
| ->SetRequireCTDelegate(require_ct_delegate_); |
| } |
| #endif // BUILDFLAG(IS_CT_SUPPORTED) |
| |
| if (params_->enable_domain_reliability) { |
| domain_reliability_monitor_ = |
| std::make_unique<domain_reliability::DomainReliabilityMonitor>( |
| result.url_request_context.get(), |
| params_->domain_reliability_upload_reporter, |
| base::BindRepeating(&NetworkContext::CanUploadDomainReliability, |
| base::Unretained(this))); |
| domain_reliability_monitor_->AddBakedInConfigs(); |
| domain_reliability_monitor_->SetDiscardUploads( |
| params_->discard_domain_reliablity_uploads); |
| } |
| |
| return result; |
| } |
| |
| scoped_refptr<SessionCleanupCookieStore> |
| NetworkContext::MakeSessionCleanupCookieStore() const { |
| base::FilePath cookie_path; |
| if (!GetFullDataFilePath( |
| params_->file_paths, |
| &network::mojom::NetworkContextFilePaths::cookie_database_name, |
| cookie_path)) { |
| DCHECK(!params_->restore_old_session_cookies); |
| DCHECK(!params_->persist_session_cookies); |
| return nullptr; |
| } |
| scoped_refptr<base::SequencedTaskRunner> client_task_runner = |
| base::SingleThreadTaskRunner::GetCurrentDefault(); |
| scoped_refptr<base::SequencedTaskRunner> background_task_runner = |
| base::ThreadPool::CreateSequencedTaskRunner( |
| {base::MayBlock(), net::GetCookieStoreBackgroundSequencePriority(), |
| base::TaskShutdownBehavior::BLOCK_SHUTDOWN}); |
| |
| std::unique_ptr<net::CookieCryptoDelegate> crypto_delegate = nullptr; |
| |
| if (params_->enable_encrypted_cookies) { |
| if (params_->cookie_encryption_provider) { |
| crypto_delegate = std::make_unique<CookieOSCryptAsyncDelegate>( |
| std::move(params_->cookie_encryption_provider)); |
| } else { |
| #if !BUILDFLAG(IS_ANDROID) |
| // A cookie crypto delegate should not be created on Android to |
| // match the behavior of cookie_config::GetCookieCryptoDelegate(). |
| // See https://crbug.com/449652881 |
| NOTREACHED(); |
| #endif |
| } |
| } |
| |
| #if BUILDFLAG(IS_WIN) |
| const bool enable_exclusive_access = |
| network_service()->exclusive_cookie_database_locking(); |
| #else |
| const bool enable_exclusive_access = false; |
| #endif // BUILDFLAG(IS_WIN) |
| |
| scoped_refptr<net::SQLitePersistentCookieStore> sqlite_store( |
| new net::SQLitePersistentCookieStore( |
| cookie_path, client_task_runner, background_task_runner, |
| params_->restore_old_session_cookies, std::move(crypto_delegate), |
| enable_exclusive_access)); |
| |
| return base::MakeRefCounted<SessionCleanupCookieStore>(sqlite_store); |
| } |
| |
| void NetworkContext::OnHttpCacheCleared(ClearHttpCacheCallback callback, |
| HttpCacheDataRemover* remover) { |
| bool removed = false; |
| for (auto iter = http_cache_data_removers_.begin(); |
| iter != http_cache_data_removers_.end(); ++iter) { |
| if (iter->get() == remover) { |
| removed = true; |
| http_cache_data_removers_.erase(iter); |
| break; |
| } |
| } |
| DCHECK(removed); |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::OnHostResolverShutdown(HostResolver* resolver) { |
| auto found_resolver = host_resolvers_.find(resolver); |
| CHECK(found_resolver != host_resolvers_.end()); |
| host_resolvers_.erase(found_resolver); |
| } |
| |
| void NetworkContext::OnHttpCacheSizeComputed( |
| ComputeHttpCacheSizeCallback callback, |
| HttpCacheDataCounter* counter, |
| bool is_upper_limit, |
| int64_t result_or_error) { |
| std::erase_if(http_cache_data_counters_, base::MatchesUniquePtr(counter)); |
| std::move(callback).Run(is_upper_limit, result_or_error); |
| } |
| |
| void NetworkContext::OnConnectionError() { |
| // If owned by the network service, this call will delete |this|. |
| if (on_connection_close_callback_) { |
| std::move(on_connection_close_callback_).Run(this); |
| } |
| } |
| |
| GURL NetworkContext::GetHSTSRedirectForPreconnect(const GURL& original_url) { |
| // TODO(lilyhoughton) This needs to be gotten rid of once explicit |
| // construction with a URLRequestContext is no longer supported. |
| |
| if (!url_request_context_->transport_security_state()) { |
| RecordHSTSPreconnectUpgradeReason( |
| HSTSRedirectUpgradeReason::kNotUpgradedHSTSUnavailable); |
| return original_url; |
| } |
| |
| if (!original_url.SchemeIs(url::kHttpScheme)) { |
| RecordHSTSPreconnectUpgradeReason( |
| HSTSRedirectUpgradeReason::kNotUpgradedNotHTTP); |
| return original_url; |
| } |
| |
| // TODO(crbug.com/40725781); This currently doesn't allow for preconnect |
| // upgrades when kHstsTopLevelNavigationsOnly is enabled. Revisit this |
| // decision after analyzing Net.PreconnectHSTSUpgradesUrl metric. |
| // |
| // When kHstsTopLevelNavigationsOnly is enabled only top-level navigations |
| // will be eligable for HSTS upgrades (not sub-resource requests). |
| // Unfortunately we don't know at this point if this request is for a |
| // top-level navigation so we need to disallow HSTS upgrades for every |
| // preconnect. |
| if (!url_request_context_->transport_security_state()->ShouldUpgradeToSSL( |
| original_url.GetHost(), /*is_top_level_nav=*/false)) { |
| RecordHSTSPreconnectUpgradeReason( |
| HSTSRedirectUpgradeReason::kNotUpgradedNoHSTSPin); |
| return original_url; |
| } |
| |
| RecordHSTSPreconnectUpgradeReason(HSTSRedirectUpgradeReason::kUpgraded); |
| |
| GURL::Replacements replacements; |
| replacements.SetSchemeStr("https"); |
| return original_url.ReplaceComponents(replacements); |
| } |
| |
| #if BUILDFLAG(IS_P2P_ENABLED) |
| void NetworkContext::DestroySocketManager(P2PSocketManager* socket_manager) { |
| auto iter = socket_managers_.find(socket_manager); |
| CHECK(iter != socket_managers_.end()); |
| socket_managers_.erase(iter); |
| } |
| #endif // BUILDFLAG(IS_P2P_ENABLED) |
| |
| void NetworkContext::CanUploadDomainReliability( |
| const url::Origin& origin, |
| base::OnceCallback<void(bool)> callback) { |
| // If the NetworkContextClient hasn't been set yet or has disconnected for |
| // some reason, just return `false`. This could occur in the case of CCT for |
| // captive portal -- see crbug.com/446496025 for more details, do the similar |
| // check to CanSendSCTAuditingReport(). |
| if (!client_) { |
| std::move(callback).Run(false); |
| return; |
| } |
| client_->OnCanSendDomainReliabilityUpload( |
| origin, |
| base::BindOnce([](base::OnceCallback<void(bool)> callback, |
| bool allowed) { std::move(callback).Run(allowed); }, |
| std::move(callback))); |
| } |
| |
| void NetworkContext::OnVerifyCertComplete(uint64_t cert_verify_id, int result) { |
| auto iter = cert_verifier_requests_.find(cert_verify_id); |
| CHECK(iter != cert_verifier_requests_.end()); |
| |
| auto pending_cert_verify = std::move(iter->second); |
| cert_verifier_requests_.erase(iter); |
| |
| bool pkp_bypassed = false; |
| if (result == net::OK || |
| result == net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED) { |
| #if BUILDFLAG(IS_CT_SUPPORTED) |
| if (url_request_context_->sct_auditing_delegate()) { |
| url_request_context_->sct_auditing_delegate()->MaybeEnqueueReport( |
| pending_cert_verify->host_port, |
| pending_cert_verify->result->verified_cert.get(), |
| pending_cert_verify->result->scts); |
| } |
| #endif // BUILDFLAG(IS_CT_SUPPORTED) |
| net::TransportSecurityState::PKPStatus pin_validity = |
| url_request_context_->transport_security_state()->CheckPublicKeyPins( |
| pending_cert_verify->host_port.host(), |
| pending_cert_verify->result->is_issued_by_known_root, |
| pending_cert_verify->result->public_key_hashes); |
| switch (pin_validity) { |
| case net::TransportSecurityState::PKPStatus::VIOLATED: |
| pending_cert_verify->result->cert_status |= |
| net::CERT_STATUS_PINNED_KEY_MISSING; |
| result = net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN; |
| break; |
| case net::TransportSecurityState::PKPStatus::BYPASSED: |
| pkp_bypassed = true; |
| [[fallthrough]]; |
| case net::TransportSecurityState::PKPStatus::OK: |
| // Do nothing. |
| break; |
| } |
| } |
| |
| std::move(pending_cert_verify->callback) |
| .Run(result, *pending_cert_verify->result.get(), pkp_bypassed); |
| } |
| |
| #if BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED) |
| void NetworkContext::EnsureMounted(network::TransferableDirectory* directory) { |
| if (directory->NeedsMount()) { |
| dismount_closures_.push_back(directory->Mount()); |
| } |
| } |
| #endif // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED) |
| |
| void NetworkContext::InitializeCorsParams() { |
| for (const auto& pattern : params_->cors_origin_access_list) { |
| cors_origin_access_list_.SetAllowListForOrigin(pattern->source_origin, |
| pattern->allow_patterns); |
| cors_origin_access_list_.SetBlockListForOrigin(pattern->source_origin, |
| pattern->block_patterns); |
| } |
| for (const auto& key : params_->cors_exempt_header_list) { |
| cors_exempt_header_list_.insert(key); |
| } |
| |
| acam_preflight_spec_conformant_ = params_->acam_preflight_spec_conformant; |
| } |
| |
| void NetworkContext::FinishConstructingTrustTokenStore( |
| std::unique_ptr<SQLiteTrustTokenPersister> persister) { |
| trust_token_store_->OnStoreReady(std::make_unique<TrustTokenStore>( |
| std::move(persister), |
| std::make_unique<ExpiryInspectingRecordExpiryDelegate>( |
| network_service()->trust_token_key_commitments()))); |
| } |
| |
| bool NetworkContext::IsAllowedToUseAllHttpAuthSchemes( |
| const url::SchemeHostPort& scheme_host_port) { |
| DCHECK(url_matcher_); |
| return !url_matcher_->MatchURL(scheme_host_port.GetURL()).empty(); |
| } |
| |
| void NetworkContext::CreateTrustedUrlLoaderFactoryForNetworkService( |
| mojo::PendingReceiver<mojom::URLLoaderFactory> |
| url_loader_factory_pending_receiver) { |
| auto url_loader_factory_params = mojom::URLLoaderFactoryParams::New(); |
| url_loader_factory_params->is_trusted = true; |
| url_loader_factory_params->process_id = network::mojom::kBrowserProcessId; |
| CreateURLLoaderFactory(std::move(url_loader_factory_pending_receiver), |
| std::move(url_loader_factory_params)); |
| } |
| |
| void NetworkContext::SetSharedDictionaryCacheMaxSize(uint64_t cache_max_size) { |
| if (!shared_dictionary_manager_) { |
| return; |
| } |
| shared_dictionary_manager_->SetCacheMaxSize(cache_max_size); |
| } |
| |
| void NetworkContext::ClearSharedDictionaryCache( |
| base::Time start_time, |
| base::Time end_time, |
| mojom::ClearDataFilterPtr filter, |
| ClearSharedDictionaryCacheCallback callback) { |
| if (!shared_dictionary_manager_) { |
| std::move(callback).Run(); |
| return; |
| } |
| shared_dictionary_manager_->ClearData(start_time, end_time, |
| BuildUrlFilter(std::move(filter)), |
| std::move(callback)); |
| } |
| |
| void NetworkContext::ClearSharedDictionaryCacheForIsolationKey( |
| const net::SharedDictionaryIsolationKey& isolation_key, |
| ClearSharedDictionaryCacheForIsolationKeyCallback callback) { |
| if (!shared_dictionary_manager_) { |
| std::move(callback).Run(); |
| return; |
| } |
| shared_dictionary_manager_->ClearDataForIsolationKey(isolation_key, |
| std::move(callback)); |
| } |
| |
| void NetworkContext::GetSharedDictionaryUsageInfo( |
| GetSharedDictionaryUsageInfoCallback callback) { |
| if (!shared_dictionary_manager_) { |
| std::move(callback).Run({}); |
| return; |
| } |
| shared_dictionary_manager_->GetUsageInfo(std::move(callback)); |
| } |
| |
| void NetworkContext::GetSharedDictionaryInfo( |
| const net::SharedDictionaryIsolationKey& isolation_key, |
| GetSharedDictionaryInfoCallback callback) { |
| if (!shared_dictionary_manager_) { |
| std::move(callback).Run({}); |
| return; |
| } |
| shared_dictionary_manager_->GetSharedDictionaryInfo(isolation_key, |
| std::move(callback)); |
| } |
| |
| void NetworkContext::GetSharedDictionaryOriginsBetween( |
| base::Time start_time, |
| base::Time end_time, |
| GetSharedDictionaryOriginsBetweenCallback callback) { |
| if (!shared_dictionary_manager_) { |
| std::move(callback).Run({}); |
| return; |
| } |
| shared_dictionary_manager_->GetOriginsBetween(start_time, end_time, |
| std::move(callback)); |
| } |
| |
| void NetworkContext::PreloadSharedDictionaryInfoForDocument( |
| const std::vector<GURL>& urls, |
| mojo::PendingReceiver<mojom::PreloadedSharedDictionaryInfoHandle> |
| preload_handle) { |
| if (shared_dictionary_manager_) { |
| shared_dictionary_manager_->PreloadSharedDictionaryInfoForDocument( |
| urls, std::move(preload_handle)); |
| } |
| } |
| |
| void NetworkContext::HasPreloadedSharedDictionaryInfoForTesting( |
| HasPreloadedSharedDictionaryInfoForTestingCallback callback) { |
| std::move(callback).Run( |
| shared_dictionary_manager_ && |
| shared_dictionary_manager_->HasPreloadedSharedDictionaryInfo()); |
| } |
| |
| void NetworkContext::FlushCachedClientCertIfNeeded( |
| const net::HostPortPair& host, |
| const scoped_refptr<net::X509Certificate>& certificate) { |
| net::HttpNetworkSession* http_session = |
| url_request_context_->http_transaction_factory()->GetSession(); |
| DCHECK(http_session); |
| if (http_session->ssl_client_context()) { |
| http_session->ssl_client_context()->ClearClientCertificateIfNeeded( |
| host, certificate); |
| } |
| } |
| |
| void NetworkContext::FlushMatchingCachedClientCert( |
| const scoped_refptr<net::X509Certificate>& certificate) { |
| net::HttpNetworkSession* http_session = |
| url_request_context_->http_transaction_factory()->GetSession(); |
| DCHECK(http_session); |
| if (http_session->ssl_client_context()) { |
| http_session->ssl_client_context()->ClearMatchingClientCertificate( |
| certificate); |
| } |
| } |
| |
| void NetworkContext::SetCookieDeprecationLabel( |
| const std::optional<std::string>& label) { |
| CHECK(url_request_context_); |
| url_request_context_->set_cookie_deprecation_label(label); |
| } |
| |
| void NetworkContext::RevokeNetworkForNonces( |
| const std::vector<base::UnguessableToken>& nonces, |
| RevokeNetworkForNoncesCallback callback) { |
| for (const auto& nonce : nonces) { |
| network_revocation_nonces_.insert(nonce); |
| const std::set<GURL>& exemptions = network_revocation_exemptions_[nonce]; |
| for (const auto& factory : url_loader_factories_) { |
| factory->CancelRequestsIfNonceMatchesAndUrlNotExempted(nonce, exemptions); |
| } |
| #if BUILDFLAG(ENABLE_WEBSOCKETS) |
| if (websocket_factory_) { |
| websocket_factory_->RemoveIfNonceMatches(nonce); |
| } |
| #endif // BUILDFLAG(ENABLE_WEBSOCKETS) |
| for (const auto& transport : web_transports_) { |
| transport->CloseIfNonceMatches(nonce); |
| } |
| } |
| |
| if (callback) { |
| std::move(callback).Run(); |
| } |
| } |
| |
| void NetworkContext::ClearNonces( |
| const std::vector<base::UnguessableToken>& nonces) { |
| for (const auto& nonce : nonces) { |
| network_revocation_nonces_.erase(nonce); |
| network_revocation_exemptions_.erase(nonce); |
| } |
| } |
| |
| void NetworkContext::ExemptUrlFromNetworkRevocationForNonce( |
| const GURL& exempted_url, |
| const base::UnguessableToken& nonce, |
| ExemptUrlFromNetworkRevocationForNonceCallback callback) { |
| GURL url_without_filename = exempted_url.GetWithoutFilename(); |
| |
| if (url_without_filename.is_valid()) { |
| network_revocation_exemptions_[nonce].insert(url_without_filename); |
| } |
| |
| std::move(callback).Run(); |
| } |
| |
| void NetworkContext::Prefetch( |
| int32_t request_id, |
| uint32_t options, |
| const ResourceRequest& request, |
| const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) { |
| if (!prefetch_enabled_) { |
| return; |
| } |
| |
| PrefetchURLLoaderClient* client = prefetch_cache_->Emplace(request); |
| if (!client) { |
| // This is normal if we already have a prefetch in progress for the {NIK, |
| // URL} combination. |
| return; |
| } |
| |
| prefetch_url_loader_factory_remote_->CreateLoaderAndStart( |
| client->GetURLLoaderPendingReceiver(), request_id, options, request, |
| client->BindNewPipeAndPassRemote(), traffic_annotation); |
| } |
| |
| void NetworkContext::GetBoundNetworkForTesting( |
| GetBoundNetworkForTestingCallback callback) { |
| std::move(callback).Run(url_request_context()->bound_network()); |
| } |
| |
| void NetworkContext::GetDeviceBoundSessionManager( |
| mojo::PendingReceiver<network::mojom::DeviceBoundSessionManager> |
| device_bound_session_manager) { |
| if (device_bound_session_manager_) { |
| device_bound_session_manager_->AddReceiver( |
| std::move(device_bound_session_manager)); |
| } |
| } |
| |
| void NetworkContext::AddQuicHints( |
| const std::vector<url::SchemeHostPort>& origins, |
| const net::NetworkAnonymizationKey& network_anonymization_key) { |
| CHECK(url_request_context_); |
| |
| for (const auto& origin : origins) { |
| url::CanonHostInfo host_info; |
| std::string canonical_host( |
| net::CanonicalizeHost(origin.host(), &host_info)); |
| if (!host_info.IsIPAddress() && |
| !net::IsCanonicalizedHostCompliant(canonical_host)) { |
| LOG(ERROR) << "Invalid QUIC hint host: " << origin.host(); |
| continue; |
| } |
| |
| // The AlternativeService hostname can be used to signal a change of host. |
| // By passing in an empty host, the origin's host will be used. |
| net::AlternativeService alternative_service(net::NextProto::kProtoQUIC, "", |
| origin.port()); |
| |
| url::SchemeHostPort canonical_origin(url::kHttpsScheme, canonical_host, |
| origin.port()); |
| url_request_context_->http_server_properties()->SetQuicAlternativeService( |
| canonical_origin, network_anonymization_key, alternative_service, |
| base::Time::Max(), quic::ParsedQuicVersionVector()); |
| } |
| } |
| |
| void NetworkContext::GetIpProxyStatus(GetIpProxyStatusCallback callback) { |
| ip_protection::IpProxyStatus status = |
| ip_protection::IpProxyStatus::kUnavailable; |
| |
| if (!base::FeatureList::IsEnabled(net::features::kEnableIpProtectionProxy)) { |
| status = ip_protection::IpProxyStatus::kFeatureNotEnabled; |
| std::move(callback).Run(status); |
| return; |
| } |
| if (!base::FeatureList::IsEnabled(features::kMaskedDomainList)) { |
| status = ip_protection::IpProxyStatus::kMaskedDomainListNotEnabled; |
| std::move(callback).Run(status); |
| return; |
| } |
| if (ip_protection_core()) { |
| // ip_protection_core() should be null if either of the above features are |
| // disabled, so check beforehand |
| status = ip_protection_core()->GetIpProxyStatus(); |
| std::move(callback).Run(status); |
| return; |
| } |
| |
| std::move(callback).Run(status); |
| } |
| |
| void NetworkContext::SetBypassIpProtectionProxy(bool bypass_proxy) { |
| if (ip_protection_core()) { |
| ip_protection_core()->SetBypassProxy(bypass_proxy); |
| } |
| } |
| |
| bool NetworkContext::IsNetworkForNonceAndUrlAllowed( |
| const base::UnguessableToken& nonce, |
| const GURL& url) const { |
| // If network hasn't been revoked for the nonce, it's allowed. |
| if (!network_revocation_nonces_.contains(nonce)) { |
| return true; |
| } |
| // If network has been revoked for the nonce, but the url is exempted, it's |
| // allowed. |
| if (network_revocation_exemptions_.contains(nonce) && |
| network_revocation_exemptions_.find(nonce)->second.contains( |
| url.GetWithoutFilename())) { |
| return true; |
| } |
| // The nonce was revoked and the url isn't exempted. |
| return false; |
| } |
| |
| void NetworkContext::InitializePrefetchURLLoaderFactory() { |
| auto pending_receiver = |
| prefetch_url_loader_factory_remote_.BindNewPipeAndPassReceiver(); |
| CreateURLLoaderFactory(std::move(pending_receiver), |
| CreateURLLoaderFactoryParamsForPrefetch()); |
| } |
| |
| base::WeakPtr<DevtoolsDurableMessage> NetworkContext::MaybeCreateDurableMessage( |
| const std::optional<base::UnguessableToken>& throttling_profile_id, |
| const std::optional<std::string>& devtools_request_id) { |
| if (!throttling_profile_id.has_value() || !devtools_request_id.has_value()) { |
| return nullptr; |
| } |
| |
| auto collector_it = devtools_profile_to_durable_message_collectors_.find( |
| throttling_profile_id.value()); |
| if (collector_it == devtools_profile_to_durable_message_collectors_.end()) { |
| return nullptr; |
| } |
| |
| return collector_it->second->CreateDurableMessage( |
| devtools_request_id.value()); |
| } |
| |
| } // namespace network |