| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/public/test/network_service_test_helper.h" |
| |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/callback_helpers.h" |
| #include "base/command_line.h" |
| #include "base/environment.h" |
| #include "base/feature_list.h" |
| #include "base/logging.h" |
| #include "base/metrics/field_trial.h" |
| #include "base/process/process.h" |
| #include "base/task/current_thread.h" |
| #include "build/build_config.h" |
| #include "content/public/common/content_features.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/test/test_host_resolver.h" |
| #include "crypto/sha2.h" |
| #include "mojo/public/cpp/bindings/receiver_set.h" |
| #include "net/base/hash_value.h" |
| #include "net/base/ip_address.h" |
| #include "net/cert/ev_root_ca_metadata.h" |
| #include "net/cert/mock_cert_verifier.h" |
| #include "net/cert/test_root_certs.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/http/transport_security_state.h" |
| #include "net/http/transport_security_state_test_util.h" |
| #include "net/nqe/network_quality_estimator.h" |
| #include "net/test/cert_test_util.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "net/test/spawned_test_server/spawned_test_server.h" |
| #include "net/test/test_data_directory.h" |
| #include "sandbox/policy/sandbox_type.h" |
| #include "services/network/cookie_manager.h" |
| #include "services/network/host_resolver.h" |
| #include "services/network/network_context.h" |
| #include "services/network/network_service.h" |
| #include "services/network/public/cpp/features.h" |
| #include "services/network/public/mojom/network_change_manager.mojom.h" |
| #include "services/network/public/mojom/network_service.mojom.h" |
| |
| #if defined(OS_ANDROID) |
| #include "base/test/android/url_utils.h" |
| #include "base/test/test_support_android.h" |
| #endif |
| |
| namespace content { |
| namespace { |
| |
| #ifndef STATIC_ASSERT_ENUM |
| #define STATIC_ASSERT_ENUM(a, b) \ |
| static_assert(static_cast<int>(a) == static_cast<int>(b), \ |
| "mismatching enums: " #a) |
| #endif |
| |
| STATIC_ASSERT_ENUM(network::mojom::ResolverType::kResolverTypeFail, |
| net::RuleBasedHostResolverProc::Rule::kResolverTypeFail); |
| STATIC_ASSERT_ENUM(network::mojom::ResolverType::kResolverTypeSystem, |
| net::RuleBasedHostResolverProc::Rule::kResolverTypeSystem); |
| STATIC_ASSERT_ENUM( |
| network::mojom::ResolverType::kResolverTypeIPLiteral, |
| net::RuleBasedHostResolverProc::Rule::kResolverTypeIPLiteral); |
| |
| void CrashResolveHost(const std::string& host_to_crash, |
| const std::string& host) { |
| if (host_to_crash == host) |
| base::Process::TerminateCurrentProcessImmediately(1); |
| } |
| } // namespace |
| |
| class NetworkServiceTestHelper::NetworkServiceTestImpl |
| : public network::mojom::NetworkServiceTest, |
| public base::CurrentThread::DestructionObserver { |
| public: |
| NetworkServiceTestImpl() |
| : test_host_resolver_(new TestHostResolver()), |
| memory_pressure_listener_( |
| FROM_HERE, |
| base::DoNothing(), |
| base::BindRepeating(&NetworkServiceTestHelper:: |
| NetworkServiceTestImpl::OnMemoryPressure, |
| base::Unretained(this))) { |
| if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kUseMockCertVerifierForTesting)) { |
| mock_cert_verifier_ = std::make_unique<net::MockCertVerifier>(); |
| network::NetworkContext::SetCertVerifierForTesting( |
| mock_cert_verifier_.get()); |
| |
| // The default result may be set using a command line flag. |
| std::string default_result = |
| base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| switches::kMockCertVerifierDefaultResultForTesting); |
| int default_result_int = 0; |
| if (!default_result.empty() && |
| base::StringToInt(default_result, &default_result_int)) { |
| mock_cert_verifier_->set_default_result(default_result_int); |
| } |
| } |
| } |
| |
| ~NetworkServiceTestImpl() override { |
| network::NetworkContext::SetCertVerifierForTesting(nullptr); |
| } |
| |
| // network::mojom::NetworkServiceTest: |
| void AddRules(std::vector<network::mojom::RulePtr> rules, |
| AddRulesCallback callback) override { |
| // test_host_resolver_ may be empty if |
| // SetAllowNetworkAccessToHostResolutions was invoked. |
| DCHECK(test_host_resolver_); |
| auto* host_resolver = test_host_resolver_->host_resolver(); |
| for (const auto& rule : rules) { |
| switch (rule->resolver_type) { |
| case network::mojom::ResolverType::kResolverTypeFail: |
| host_resolver->AddSimulatedFailure(rule->host_pattern); |
| break; |
| case network::mojom::ResolverType::kResolverTypeFailTimeout: |
| host_resolver->AddSimulatedTimeoutFailure(rule->host_pattern); |
| break; |
| case network::mojom::ResolverType::kResolverTypeIPLiteral: { |
| net::IPAddress ip_address; |
| DCHECK(ip_address.AssignFromIPLiteral(rule->replacement)); |
| host_resolver->AddRuleWithFlags(rule->host_pattern, rule->replacement, |
| rule->host_resolver_flags, |
| rule->dns_aliases); |
| break; |
| } |
| case network::mojom::ResolverType::kResolverTypeDirectLookup: |
| host_resolver->AllowDirectLookup(rule->host_pattern); |
| break; |
| default: |
| host_resolver->AddRuleWithFlags(rule->host_pattern, rule->replacement, |
| rule->host_resolver_flags, |
| rule->dns_aliases); |
| break; |
| } |
| } |
| std::move(callback).Run(); |
| } |
| |
| void SimulateNetworkChange(network::mojom::ConnectionType type, |
| SimulateNetworkChangeCallback callback) override { |
| DCHECK(!net::NetworkChangeNotifier::CreateIfNeeded()); |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::ConnectionType(type)); |
| std::move(callback).Run(); |
| } |
| |
| void SimulateNetworkQualityChange( |
| net::EffectiveConnectionType type, |
| SimulateNetworkChangeCallback callback) override { |
| network::NetworkService::GetNetworkServiceForTesting() |
| ->network_quality_estimator() |
| ->SimulateNetworkQualityChangeForTesting(type); |
| std::move(callback).Run(); |
| } |
| |
| void SimulateCrash() override { |
| LOG(ERROR) << "Intentionally terminating current process to simulate" |
| " NetworkService crash for testing."; |
| // Use |TerminateCurrentProcessImmediately()| instead of |CHECK()| to avoid |
| // 'Fatal error' dialog on Windows debug. |
| base::Process::TerminateCurrentProcessImmediately(1); |
| } |
| |
| void MockCertVerifierSetDefaultResult( |
| int32_t default_result, |
| MockCertVerifierSetDefaultResultCallback callback) override { |
| mock_cert_verifier_->set_default_result(default_result); |
| std::move(callback).Run(); |
| } |
| |
| void MockCertVerifierAddResultForCertAndHost( |
| const scoped_refptr<net::X509Certificate>& cert, |
| const std::string& host_pattern, |
| const net::CertVerifyResult& verify_result, |
| int32_t rv, |
| MockCertVerifierAddResultForCertAndHostCallback callback) override { |
| mock_cert_verifier_->AddResultForCertAndHost(cert, host_pattern, |
| verify_result, rv); |
| std::move(callback).Run(); |
| } |
| |
| void SetRequireCT(RequireCT required, |
| SetRequireCTCallback callback) override { |
| net::TransportSecurityState::SetRequireCTForTesting( |
| required == NetworkServiceTest::RequireCT::REQUIRE); |
| std::move(callback).Run(); |
| } |
| |
| void SetTransportSecurityStateSource( |
| uint16_t reporting_port, |
| SetTransportSecurityStateSourceCallback callback) override { |
| if (reporting_port) { |
| transport_security_state_source_ = |
| std::make_unique<net::ScopedTransportSecurityStateSource>( |
| reporting_port); |
| } else { |
| transport_security_state_source_.reset(); |
| } |
| std::move(callback).Run(); |
| } |
| |
| void SetAllowNetworkAccessToHostResolutions( |
| SetAllowNetworkAccessToHostResolutionsCallback callback) override { |
| test_host_resolver_.reset(); |
| std::move(callback).Run(); |
| } |
| |
| void CrashOnResolveHost(const std::string& host) override { |
| network::HostResolver::SetResolveHostCallbackForTesting( |
| base::BindRepeating(CrashResolveHost, host)); |
| } |
| |
| void CrashOnGetCookieList() override { |
| network::CookieManager::CrashOnGetCookieList(); |
| } |
| |
| void GetLatestMemoryPressureLevel( |
| GetLatestMemoryPressureLevelCallback callback) override { |
| std::move(callback).Run(latest_memory_pressure_level_); |
| } |
| |
| void GetPeerToPeerConnectionsCountChange( |
| GetPeerToPeerConnectionsCountChangeCallback callback) override { |
| uint32_t count = network::NetworkService::GetNetworkServiceForTesting() |
| ->network_quality_estimator() |
| ->GetPeerToPeerConnectionsCountChange(); |
| |
| std::move(callback).Run(count); |
| } |
| |
| void GetFirstPartySetEntriesCount( |
| GetFirstPartySetEntriesCountCallback callback) override { |
| std::move(callback).Run( |
| network::NetworkService::GetNetworkServiceForTesting() |
| ->first_party_sets() |
| ->size()); |
| } |
| |
| void GetEnvironmentVariableValue( |
| const std::string& name, |
| GetEnvironmentVariableValueCallback callback) override { |
| std::string value; |
| base::Environment::Create()->GetVar(name, &value); |
| std::move(callback).Run(value); |
| } |
| |
| void Log(const std::string& message, LogCallback callback) override { |
| LOG(ERROR) << message; |
| std::move(callback).Run(); |
| } |
| |
| void ActivateFieldTrial(const std::string& field_trial_name) override { |
| base::FieldTrialList::FindFullName(field_trial_name); |
| } |
| |
| void SetEVPolicy(const std::vector<uint8_t>& fingerprint_sha256, |
| const std::string& policy_oid, |
| SetEVPolicyCallback callback) override { |
| CHECK_EQ(fingerprint_sha256.size(), crypto::kSHA256Length); |
| net::SHA256HashValue fingerprint_sha256_hash; |
| memcpy(&fingerprint_sha256_hash.data, fingerprint_sha256.data(), |
| crypto::kSHA256Length); |
| ev_test_policy_ = std::make_unique<net::ScopedTestEVPolicy>( |
| net::EVRootCAMetadata::GetInstance(), fingerprint_sha256_hash, |
| policy_oid.data()); |
| std::move(callback).Run(); |
| } |
| |
| void BindReceiver( |
| mojo::PendingReceiver<network::mojom::NetworkServiceTest> receiver) { |
| receivers_.Add(this, std::move(receiver)); |
| if (!registered_as_destruction_observer_) { |
| base::CurrentIOThread::Get()->AddDestructionObserver(this); |
| registered_as_destruction_observer_ = true; |
| } |
| } |
| |
| // base::CurrentThread::DestructionObserver: |
| void WillDestroyCurrentMessageLoop() override { |
| // Needs to be called on the IO thread. |
| receivers_.Clear(); |
| } |
| |
| private: |
| void OnMemoryPressure( |
| base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { |
| latest_memory_pressure_level_ = memory_pressure_level; |
| } |
| |
| bool registered_as_destruction_observer_ = false; |
| mojo::ReceiverSet<network::mojom::NetworkServiceTest> receivers_; |
| std::unique_ptr<TestHostResolver> test_host_resolver_; |
| std::unique_ptr<net::MockCertVerifier> mock_cert_verifier_; |
| std::unique_ptr<net::ScopedTransportSecurityStateSource> |
| transport_security_state_source_; |
| base::MemoryPressureListener memory_pressure_listener_; |
| base::MemoryPressureListener::MemoryPressureLevel |
| latest_memory_pressure_level_ = |
| base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; |
| std::unique_ptr<net::ScopedTestEVPolicy> ev_test_policy_; |
| |
| DISALLOW_COPY_AND_ASSIGN(NetworkServiceTestImpl); |
| }; |
| |
| NetworkServiceTestHelper::NetworkServiceTestHelper() |
| : network_service_test_impl_(new NetworkServiceTestImpl) {} |
| |
| NetworkServiceTestHelper::~NetworkServiceTestHelper() = default; |
| |
| void NetworkServiceTestHelper::RegisterNetworkBinders( |
| service_manager::BinderRegistry* registry) { |
| registry->AddInterface(base::BindRepeating( |
| &NetworkServiceTestHelper::BindNetworkServiceTestReceiver, |
| base::Unretained(this))); |
| |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| auto utility_sub_type = |
| command_line->GetSwitchValueASCII(switches::kUtilitySubType); |
| if (utility_sub_type == network::mojom::NetworkService::Name_) { |
| // Register the EmbeddedTestServer's certs, so that any SSL connections to |
| // it succeed. Only do this when file I/O is allowed in the current process. |
| #if defined(OS_ANDROID) |
| base::InitAndroidTestPaths(base::android::GetIsolatedTestRoot()); |
| #endif |
| |
| if (!command_line->HasSwitch(switches::kDisableTestCerts)) { |
| net::EmbeddedTestServer::RegisterTestCerts(); |
| net::SpawnedTestServer::RegisterTestCerts(); |
| |
| // Also add the QUIC test certificate. |
| net::TestRootCerts* root_certs = net::TestRootCerts::GetInstance(); |
| root_certs->AddFromFile( |
| net::GetTestCertsDirectory().AppendASCII("quic-root.pem")); |
| } |
| } |
| } |
| |
| void NetworkServiceTestHelper::BindNetworkServiceTestReceiver( |
| mojo::PendingReceiver<network::mojom::NetworkServiceTest> receiver) { |
| network_service_test_impl_->BindReceiver(std::move(receiver)); |
| } |
| |
| } // namespace content |