// 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 #include #include #include #include "base/bind.h" #include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/guid.h" #include "base/location.h" #include "base/optional.h" #include "base/path_service.h" #include "base/strings/strcat.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/test/bind_test_util.h" #include "base/test/scoped_feature_list.h" #include "base/threading/thread_restrictions.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/content_settings/cookie_settings_factory.h" #include "chrome/browser/net/profile_network_context_service.h" #include "chrome/browser/net/profile_network_context_service_factory.h" #include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/common/webui_url_constants.h" #include "chrome/test/base/in_process_browser_test.h" #include "components/content_settings/core/browser/cookie_settings.h" #include "components/content_settings/core/common/pref_names.h" #include "components/language/core/browser/pref_names.h" #include "components/network_session_configurator/common/network_switches.h" #include "components/policy/core/browser/browser_policy_connector.h" #include "components/policy/core/common/mock_configuration_policy_provider.h" #include "components/policy/core/common/policy_map.h" #include "components/policy/policy_constants.h" #include "components/prefs/pref_service.h" #include "components/proxy_config/proxy_config_dictionary.h" #include "components/proxy_config/proxy_config_pref_names.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/network_service_instance.h" #include "content/public/browser/storage_partition.h" #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "content/public/common/network_service_util.h" #include "content/public/common/url_constants.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/simple_url_loader_test_helper.h" #include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/system/data_pipe_utils.h" #include "net/base/address_list.h" #include "net/base/filename_util.h" #include "net/base/host_port_pair.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_options.h" #include "net/cookies/cookie_util.h" #include "net/dns/mock_host_resolver.h" #include "net/dns/public/resolve_error_info.h" #include "net/http/http_response_headers.h" #include "net/reporting/reporting_policy.h" #include "net/ssl/ssl_config.h" #include "net/ssl/ssl_server_config.h" #include "net/test/embedded_test_server/controllable_http_response.h" #include "net/test/embedded_test_server/default_handlers.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/embedded_test_server_connection_listener.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" #include "net/test/gtest_util.h" #include "net/test/spawned_test_server/spawned_test_server.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/url_request/url_request.h" #include "services/network/public/cpp/features.h" #include "services/network/public/cpp/network_connection_tracker.h" #include "services/network/public/cpp/simple_url_loader.h" #include "services/network/public/mojom/cookie_manager.mojom.h" #include "services/network/public/mojom/host_resolver.mojom.h" #include "services/network/public/mojom/network_service.mojom.h" #include "services/network/public/mojom/url_loader.mojom.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "services/network/test/test_dns_util.h" #include "services/network/test/test_url_loader_client.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" #if defined(OS_MACOSX) #include "base/mac/mac_util.h" #endif #if BUILDFLAG(ENABLE_EXTENSIONS) #include "chrome/browser/extensions/chrome_test_extension_loader.h" #include "extensions/browser/browsertest_util.h" #include "extensions/test/test_extension_dir.h" #endif namespace { constexpr char kHostname[] = "foo.test"; constexpr char kAddress[] = "5.8.13.21"; const char kCacheRandomPath[] = "/cacherandom"; // Path using a ControllableHttpResponse that's part of the test fixture. const char kControllablePath[] = "/controllable"; enum class NetworkServiceState { kEnabled, // Similar to |kEnabled|, but will simulate a crash and run tests again the // restarted Network Service process. kRestarted, }; enum class NetworkContextType { kSystem, kSafeBrowsing, kProfile, kIncognitoProfile, kOnDiskApp, kInMemoryApp, kOnDiskAppWithIncognitoProfile, }; // This list should be kept in sync with the NetworkContextType enum. const NetworkContextType kNetworkContextTypes[] = { NetworkContextType::kSystem, NetworkContextType::kSafeBrowsing, NetworkContextType::kProfile, NetworkContextType::kIncognitoProfile, NetworkContextType::kOnDiskApp, NetworkContextType::kInMemoryApp, NetworkContextType::kOnDiskAppWithIncognitoProfile, }; struct TestCase { NetworkServiceState network_service_state; NetworkContextType network_context_type; }; // Waits for the network connection type to be the specified value. class ConnectionTypeWaiter : public network::NetworkConnectionTracker::NetworkConnectionObserver { public: ConnectionTypeWaiter() : tracker_(content::GetNetworkConnectionTracker()) { tracker_->AddNetworkConnectionObserver(this); } ~ConnectionTypeWaiter() override { tracker_->RemoveNetworkConnectionObserver(this); } void Wait(network::mojom::ConnectionType expected_type) { auto current_type = network::mojom::ConnectionType::CONNECTION_UNKNOWN; network::NetworkConnectionTracker::ConnectionTypeCallback callback = base::BindOnce(&ConnectionTypeWaiter::OnConnectionChanged, base::Unretained(this)); while (!tracker_->GetConnectionType(¤t_type, std::move(callback)) || current_type != expected_type) { run_loop_ = std::make_unique( base::RunLoop::Type::kNestableTasksAllowed); run_loop_->Run(); } } private: // network::NetworkConnectionTracker::NetworkConnectionObserver: void OnConnectionChanged(network::mojom::ConnectionType type) override { if (run_loop_) run_loop_->Quit(); } network::NetworkConnectionTracker* tracker_; std::unique_ptr run_loop_; }; // Tests the system, profile, and incognito profile NetworkContexts. class NetworkContextConfigurationBrowserTest : public InProcessBrowserTest, public testing::WithParamInterface { public: // Backing storage types that can used for various things (HTTP cache, // cookies, etc). enum class StorageType { kNone, kMemory, kDisk, }; enum class CookieType { kFirstParty, kThirdParty, }; enum class CookiePersistenceType { kSession, kPersistent, }; NetworkContextConfigurationBrowserTest() : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) { // Have to get a port before setting up the command line, but can only set // up the connection listener after there's a main thread, so can't start // the test server here. EXPECT_TRUE(embedded_test_server()->InitializeAndListen()); EXPECT_TRUE(https_server()->InitializeAndListen()); } // Returns a cacheable response (10 hours) that is some random text. static std::unique_ptr HandleCacheRandom( const net::test_server::HttpRequest& request) { if (request.relative_url != kCacheRandomPath) return nullptr; std::unique_ptr response = std::make_unique(); response->set_content(base::GenerateGUID()); response->set_content_type("text/plain"); response->AddCustomHeader("Cache-Control", "max-age=60000"); return std::move(response); } ~NetworkContextConfigurationBrowserTest() override {} void SetUpInProcessBrowserTestFixture() override { EXPECT_CALL(provider_, IsInitializationComplete(testing::_)) .WillRepeatedly(testing::Return(true)); policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_); } void SetUpOnMainThread() override { // Used in a bunch of proxy tests. Should not resolve. host_resolver()->AddSimulatedFailure("does.not.resolve.test"); host_resolver()->AddRule(kHostname, kAddress); controllable_http_response_ = std::make_unique( embedded_test_server(), kControllablePath); embedded_test_server()->RegisterRequestHandler(base::BindRepeating( &NetworkContextConfigurationBrowserTest::HandleCacheRandom)); embedded_test_server()->StartAcceptingConnections(); net::test_server::RegisterDefaultHandlers(https_server()); https_server()->StartAcceptingConnections(); if (is_incognito()) incognito_ = CreateIncognitoBrowser(); SimulateNetworkServiceCrashIfNecessary(); #if defined(OS_CHROMEOS) // On ChromeOS the connection type comes from a fake Shill service, which // is configured with a fake ethernet connection asynchronously. Wait for // the connection type to be available to avoid getting notified of the // connection change halfway through the test. ConnectionTypeWaiter().Wait( network::mojom::ConnectionType::CONNECTION_ETHERNET); #endif } // Returns true if the NetworkContext being tested is associated with an // incognito profile. bool is_incognito() const { return GetParam().network_context_type == NetworkContextType::kIncognitoProfile || GetParam().network_context_type == NetworkContextType::kOnDiskAppWithIncognitoProfile; } void TearDownOnMainThread() override { // Have to destroy this before the main message loop is torn down. Need to // leave the embedded test server up for tests that use // |live_during_shutdown_simple_loader_|. It's safe to destroy the // ControllableHttpResponse before the test server. controllable_http_response_.reset(); } // Returns, as a string, a PAC script that will use the EmbeddedTestServer as // a proxy. std::string GetPacScript() const { return base::StringPrintf( "function FindProxyForURL(url, host){ return 'PROXY %s;' }", net::HostPortPair::FromURL(embedded_test_server()->base_url()) .ToString() .c_str()); } net::EmbeddedTestServer* https_server() { return &https_server_; } content::StoragePartition* GetStoragePartition() { return GetStoragePartitionForContextType(GetParam().network_context_type); } content::StoragePartition* GetStoragePartitionForContextType( NetworkContextType network_context_type) { const GURL kOnDiskUrl("chrome-guest://foo/persist"); const GURL kInMemoryUrl("chrome-guest://foo/"); switch (network_context_type) { case NetworkContextType::kSystem: case NetworkContextType::kSafeBrowsing: NOTREACHED() << "Network context has no storage partition"; return nullptr; case NetworkContextType::kProfile: return content::BrowserContext::GetDefaultStoragePartition( browser()->profile()); case NetworkContextType::kIncognitoProfile: DCHECK(incognito_); return content::BrowserContext::GetDefaultStoragePartition( incognito_->profile()); case NetworkContextType::kOnDiskApp: return content::BrowserContext::GetStoragePartitionForSite( browser()->profile(), kOnDiskUrl); case NetworkContextType::kInMemoryApp: return content::BrowserContext::GetStoragePartitionForSite( browser()->profile(), kInMemoryUrl); case NetworkContextType::kOnDiskAppWithIncognitoProfile: DCHECK(incognito_); return content::BrowserContext::GetStoragePartitionForSite( incognito_->profile(), kOnDiskUrl); } NOTREACHED(); return nullptr; } network::mojom::URLLoaderFactory* loader_factory() { return GetLoaderFactoryForContextType(GetParam().network_context_type); } network::mojom::URLLoaderFactory* GetLoaderFactoryForContextType( NetworkContextType network_context_type) { switch (network_context_type) { case NetworkContextType::kSystem: return g_browser_process->system_network_context_manager() ->GetURLLoaderFactory(); case NetworkContextType::kSafeBrowsing: return g_browser_process->safe_browsing_service() ->GetURLLoaderFactory() .get(); case NetworkContextType::kProfile: case NetworkContextType::kIncognitoProfile: case NetworkContextType::kOnDiskApp: case NetworkContextType::kInMemoryApp: case NetworkContextType::kOnDiskAppWithIncognitoProfile: return GetStoragePartitionForContextType(network_context_type) ->GetURLLoaderFactoryForBrowserProcess() .get(); } NOTREACHED(); return nullptr; } network::mojom::NetworkContext* network_context() { return GetNetworkContextForContextType(GetParam().network_context_type); } network::mojom::NetworkContext* GetNetworkContextForContextType( NetworkContextType network_context_type) { switch (network_context_type) { case NetworkContextType::kSystem: return g_browser_process->system_network_context_manager() ->GetContext(); case NetworkContextType::kSafeBrowsing: return g_browser_process->safe_browsing_service()->GetNetworkContext(); case NetworkContextType::kProfile: case NetworkContextType::kIncognitoProfile: case NetworkContextType::kOnDiskApp: case NetworkContextType::kInMemoryApp: case NetworkContextType::kOnDiskAppWithIncognitoProfile: return GetStoragePartitionForContextType(network_context_type) ->GetNetworkContext(); } NOTREACHED(); return nullptr; } StorageType GetHttpCacheType() const { switch (GetParam().network_context_type) { case NetworkContextType::kSystem: case NetworkContextType::kSafeBrowsing: return StorageType::kNone; case NetworkContextType::kProfile: case NetworkContextType::kOnDiskApp: return StorageType::kDisk; case NetworkContextType::kIncognitoProfile: case NetworkContextType::kInMemoryApp: case NetworkContextType::kOnDiskAppWithIncognitoProfile: return StorageType::kMemory; } NOTREACHED(); return StorageType::kNone; } StorageType GetCookieStorageType() const { switch (GetParam().network_context_type) { case NetworkContextType::kSystem: case NetworkContextType::kIncognitoProfile: case NetworkContextType::kInMemoryApp: case NetworkContextType::kOnDiskAppWithIncognitoProfile: return StorageType::kMemory; case NetworkContextType::kSafeBrowsing: case NetworkContextType::kProfile: case NetworkContextType::kOnDiskApp: return StorageType::kDisk; } NOTREACHED(); return StorageType::kNone; } // Returns the pref service with most prefs related to the NetworkContext // being tested. PrefService* GetPrefService() { switch (GetParam().network_context_type) { case NetworkContextType::kSystem: case NetworkContextType::kSafeBrowsing: return g_browser_process->local_state(); case NetworkContextType::kProfile: case NetworkContextType::kInMemoryApp: case NetworkContextType::kOnDiskApp: return browser()->profile()->GetPrefs(); case NetworkContextType::kIncognitoProfile: case NetworkContextType::kOnDiskAppWithIncognitoProfile: // Incognito actually uses the non-incognito prefs, so this should end // up being the same pref store as in the KProfile case. return browser()->profile()->GetOffTheRecordProfile()->GetPrefs(); } } // Sets the proxy preference on a PrefService based on the NetworkContextType, // and waits for it to be applied. void SetProxyPref(const net::HostPortPair& host_port_pair) { GetPrefService()->Set(proxy_config::prefs::kProxy, ProxyConfigDictionary::CreateFixedServers( host_port_pair.ToString(), std::string())); // Wait for the new ProxyConfig to be passed over the pipe. Needed because // Mojo doesn't guarantee ordering of events on different Mojo pipes, and // requests are sent on a separate pipe from ProxyConfigs. switch (GetParam().network_context_type) { case NetworkContextType::kSystem: case NetworkContextType::kSafeBrowsing: g_browser_process->system_network_context_manager() ->FlushProxyConfigMonitorForTesting(); break; case NetworkContextType::kProfile: case NetworkContextType::kInMemoryApp: case NetworkContextType::kOnDiskApp: ProfileNetworkContextServiceFactory::GetForContext(browser()->profile()) ->FlushProxyConfigMonitorForTesting(); break; case NetworkContextType::kIncognitoProfile: case NetworkContextType::kOnDiskAppWithIncognitoProfile: ProfileNetworkContextServiceFactory::GetForContext( browser()->profile()->GetOffTheRecordProfile()) ->FlushProxyConfigMonitorForTesting(); break; } } // Sends a request and expects it to be handled by embedded_test_server() // acting as a proxy; void TestProxyConfigured(bool expect_success) { std::unique_ptr request = std::make_unique(); // This URL should be directed to the test server because of the proxy. request->url = GURL("http://does.not.resolve.test:1872/echo"); content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); if (expect_success) { EXPECT_EQ(net::OK, simple_loader->NetError()); ASSERT_TRUE(simple_loader_helper.response_body()); EXPECT_EQ(*simple_loader_helper.response_body(), "Echo"); } else { EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, simple_loader->NetError()); ASSERT_FALSE(simple_loader_helper.response_body()); } } // Makes a request that hangs, and will live until browser shutdown. void MakeLongLivedRequestThatHangsUntilShutdown() { std::unique_ptr request = std::make_unique(); request->url = embedded_test_server()->GetURL(kControllablePath); live_during_shutdown_simple_loader_ = network::SimpleURLLoader::Create( std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); live_during_shutdown_simple_loader_helper_ = std::make_unique(); live_during_shutdown_simple_loader_ ->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), live_during_shutdown_simple_loader_helper_->GetCallback()); // Don't actually care about controlling the response, just need to wait // until it sees the request, to make sure that a URLRequest has been // created to potentially leak. Since the |controllable_http_response_| is // not used to send a response to the request, the request just hangs until // the NetworkContext is destroyed (Or the test server is shut down, but the // NetworkContext should be destroyed before that happens, in this test). controllable_http_response_->WaitForRequest(); } // Sends a request to the test server's echoheader URL and sets // |header_value_out| to the value of the specified response header. Returns // false if the request fails. If non-null, uses |request| to make the // request, after setting its |url| value. bool FetchHeaderEcho(const std::string& header_name, std::string* header_value_out, std::unique_ptr request = nullptr) WARN_UNUSED_RESULT { if (!request) request = std::make_unique(); request->url = embedded_test_server()->GetURL( base::StrCat({"/echoheader?", header_name})); content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); if (simple_loader_helper.response_body()) { *header_value_out = *simple_loader_helper.response_body(); return true; } return false; } // |server| should be |TYPE_HTTPS| if the cookie is third-party, because // SameSite=None cookies must be Secure. void SetCookie(CookieType cookie_type, CookiePersistenceType cookie_expiration_type, net::EmbeddedTestServer* server) { std::unique_ptr request = std::make_unique(); std::string cookie_line = "cookie"; if (cookie_expiration_type == CookiePersistenceType::kPersistent) cookie_line += ";max-age=3600"; // Third party (i.e. SameSite=None) cookies must be secure. if (cookie_type == CookieType::kThirdParty) cookie_line += ";SameSite=None;Secure"; request->url = server->GetURL("/set-cookie?" + cookie_line); url::Origin origin; if (cookie_type == CookieType::kThirdParty) origin = url::Origin::Create(GURL("http://example.com")); else origin = url::Origin::Create(server->base_url()); request->site_for_cookies = net::SiteForCookies::FromOrigin(origin); request->trusted_params = network::ResourceRequest::TrustedParams(); request->trusted_params->network_isolation_key = net::NetworkIsolationKey(origin, origin); content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); EXPECT_EQ(net::OK, simple_loader->NetError()); } void FlushNetworkInterface() { switch (GetParam().network_context_type) { case NetworkContextType::kSystem: g_browser_process->system_network_context_manager() ->FlushNetworkInterfaceForTesting(); break; case NetworkContextType::kSafeBrowsing: g_browser_process->safe_browsing_service() ->FlushNetworkInterfaceForTesting(); break; case NetworkContextType::kProfile: case NetworkContextType::kIncognitoProfile: case NetworkContextType::kInMemoryApp: case NetworkContextType::kOnDiskApp: case NetworkContextType::kOnDiskAppWithIncognitoProfile: GetStoragePartition()->FlushNetworkInterfaceForTesting(); break; } } Profile* GetProfile() { switch (GetParam().network_context_type) { case NetworkContextType::kSystem: case NetworkContextType::kSafeBrowsing: case NetworkContextType::kProfile: case NetworkContextType::kInMemoryApp: case NetworkContextType::kOnDiskApp: return browser()->profile(); case NetworkContextType::kIncognitoProfile: case NetworkContextType::kOnDiskAppWithIncognitoProfile: DCHECK(incognito_); return incognito_->profile(); } } // Gets all cookies for given URL, as a single string. std::string GetCookies(const GURL& url) { return GetCookiesForContextType(GetParam().network_context_type, url); } std::string GetCookiesForContextType(NetworkContextType network_context_type, const GURL& url) { std::string cookies; base::RunLoop run_loop; mojo::Remote cookie_manager; GetNetworkContextForContextType(network_context_type) ->GetCookieManager(cookie_manager.BindNewPipeAndPassReceiver()); cookie_manager->GetCookieList( url, net::CookieOptions::MakeAllInclusive(), base::BindOnce( [](std::string* cookies_out, base::RunLoop* run_loop, const net::CookieStatusList& cookies, const net::CookieStatusList& excluded_cookies) { *cookies_out = net::CanonicalCookie::BuildCookieLine(cookies); run_loop->Quit(); }, &cookies, &run_loop)); run_loop.Run(); return cookies; } void ForEachOtherContext( base::RepeatingCallback callback) { // Create Incognito Profile if needed. if (!incognito_) incognito_ = CreateIncognitoBrowser(); // True if the |network_context_type| corresponding to GetParam() has been // found. Used to verify that kNetworkContextTypes is kept up to date, and // contains no duplicates. bool found_matching_type = false; for (const auto network_context_type : kNetworkContextTypes) { if (network_context_type == GetParam().network_context_type) { EXPECT_FALSE(found_matching_type); found_matching_type = true; continue; } callback.Run(network_context_type); } EXPECT_TRUE(found_matching_type); } bool IsRestartStateWithInProcessNetworkService() { return GetParam().network_service_state == NetworkServiceState::kRestarted && content::IsInProcessNetworkService(); } void UpdateChromePolicy(const policy::PolicyMap& policy_map) { provider_.UpdateChromePolicy(policy_map); } enum class WayToEnableSSLConfig { kViaPrefs, kViaPolicy }; // This helper function enables the kSSLVersionMin pref and tests that this // pref is respected. kSSLVersionMin can be set in two ways: over prefs // directly or over a policy. |way_to_enable| is used to determine the way to // set the pref. void TestEnablingSSLVersionMin(WayToEnableSSLConfig way_to_enable) { // Start a TLS 1.0 server. net::EmbeddedTestServer ssl_server(net::EmbeddedTestServer::TYPE_HTTPS); net::SSLServerConfig ssl_config; ssl_config.version_min = net::SSL_PROTOCOL_VERSION_TLS1; ssl_config.version_max = net::SSL_PROTOCOL_VERSION_TLS1; ssl_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config); ssl_server.AddDefaultHandlers(GetChromeTestDataDir()); ASSERT_TRUE(ssl_server.Start()); std::unique_ptr request = std::make_unique(); request->url = ssl_server.GetURL("/echo"); content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); ASSERT_TRUE(simple_loader_helper.response_body()); EXPECT_EQ(*simple_loader_helper.response_body(), "Echo"); if (way_to_enable == WayToEnableSSLConfig::kViaPrefs) { // Disallow TLS 1.0 via prefs. g_browser_process->local_state()->SetString(prefs::kSSLVersionMin, switches::kSSLVersionTLSv11); } else { // Disallow TLS 1.0 via policy. policy::PolicyMap values; values.Set(policy::key::kSSLVersionMin, policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_MACHINE, policy::POLICY_SOURCE_CLOUD, std::make_unique(switches::kSSLVersionTLSv11), nullptr); base::RunLoop run_loop; PrefChangeRegistrar pref_change_registrar; pref_change_registrar.Init(g_browser_process->local_state()); pref_change_registrar.Add(prefs::kSSLVersionMin, run_loop.QuitClosure()); UpdateChromePolicy(values); run_loop.Run(); } g_browser_process->system_network_context_manager() ->FlushSSLConfigManagerForTesting(); // With the new prefs, requests to the server should be blocked. request = std::make_unique(); request->url = ssl_server.GetURL("/echo"); content::SimpleURLLoaderTestHelper simple_loader_helper2; simple_loader = network::SimpleURLLoader::Create( std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper2.GetCallback()); simple_loader_helper2.WaitForCallback(); EXPECT_FALSE(simple_loader_helper2.response_body()); EXPECT_EQ(net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH, simple_loader->NetError()); } private: void SimulateNetworkServiceCrashIfNecessary() { if (GetParam().network_service_state != NetworkServiceState::kRestarted || content::IsInProcessNetworkService()) { return; } // Make sure |network_context()| is working as expected. Use '/echoheader' // instead of '/echo' to avoid a disk_cache bug. // See https://crbug.com/792255. int net_error = content::LoadBasicRequest( network_context(), embedded_test_server()->GetURL("/echoheader"), 0, 0, net::LOAD_BYPASS_PROXY); EXPECT_THAT(net_error, net::test::IsOk()); // Crash the NetworkService process. Existing interfaces should receive // error notifications at some point. SimulateNetworkServiceCrash(); // Flush the interface to make sure the error notification was received. FlushNetworkInterface(); } Browser* incognito_ = nullptr; base::test::ScopedFeatureList feature_list_; net::EmbeddedTestServer https_server_; std::unique_ptr controllable_http_response_; policy::MockConfigurationPolicyProvider provider_; // Used in tests that need a live request during browser shutdown. std::unique_ptr live_during_shutdown_simple_loader_; std::unique_ptr live_during_shutdown_simple_loader_helper_; DISALLOW_COPY_AND_ASSIGN(NetworkContextConfigurationBrowserTest); }; IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, SecureCookiesAllowedForChromeScheme) { if (IsRestartStateWithInProcessNetworkService()) return; // TODO(crbug.com/1007320): This does not work under SameSiteByDefaultCookies, // (and also does not work for SameSite cookies, in general). This is not // easily fixable, so disable the test for now. if (net::cookie_util::IsSameSiteByDefaultCookiesEnabled()) return; // Cookies are only allowed for chrome:// schemes requesting a secure origin, // so create an HTTPS server. net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); net::test_server::RegisterDefaultHandlers(&https_server); ASSERT_TRUE(https_server.Start()); if (GetPrefService()->FindPreference(prefs::kBlockThirdPartyCookies)) GetPrefService()->SetBoolean(prefs::kBlockThirdPartyCookies, true); SetCookie(CookieType::kFirstParty, CookiePersistenceType::kPersistent, embedded_test_server()); std::unique_ptr request = std::make_unique(); request->url = https_server.GetURL("/echoheader?Cookie"); url::Origin origin = url::Origin::Create(GURL(chrome::kChromeUIPrintURL)); request->site_for_cookies = net::SiteForCookies::FromOrigin(origin); request->trusted_params = network::ResourceRequest::TrustedParams(); request->trusted_params->network_isolation_key = net::NetworkIsolationKey(origin, origin); content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); EXPECT_EQ(200, simple_loader->ResponseInfo()->headers->response_code()); ASSERT_TRUE(simple_loader_helper.response_body()); EXPECT_EQ("cookie", *simple_loader_helper.response_body()); } #if BUILDFLAG(ENABLE_EXTENSIONS) std::unique_ptr EchoCookieHeader( const net::test_server::HttpRequest& request) { auto response = std::make_unique(); auto it = request.headers.find("Cookie"); if (it != request.headers.end()) response->set_content(it->second); response->AddCustomHeader("Access-Control-Allow-Origin", "*"); return response; } IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, ThirdPartyCookiesAllowedForExtensions) { if (IsRestartStateWithInProcessNetworkService()) return; // Loading an extension only makes sense for profile contexts. if (GetParam().network_context_type != NetworkContextType::kProfile && GetParam().network_context_type != NetworkContextType::kIncognitoProfile) { return; } net::EmbeddedTestServer test_server; net::test_server::RegisterDefaultHandlers(&test_server); test_server.RegisterRequestHandler(base::BindRepeating(&EchoCookieHeader)); ASSERT_TRUE(test_server.Start()); GetPrefService()->SetBoolean(prefs::kBlockThirdPartyCookies, true); SetCookie(CookieType::kFirstParty, CookiePersistenceType::kPersistent, embedded_test_server()); extensions::TestExtensionDir extension_dir; extension_dir.WriteManifest(R"({ "name": "Cookie Test", "manifest_version": 2, "version": "1.0", "background": { "scripts": ["background.js"] }, "incognito": "split", "permissions": [""] })"); extension_dir.WriteFile(FILE_PATH_LITERAL("background.js"), ""); extensions::ChromeTestExtensionLoader loader(GetProfile()); loader.set_allow_incognito_access(true); scoped_refptr extension = loader.LoadExtension(extension_dir.UnpackedPath()); ASSERT_TRUE(extension); // This request will show up as cross-site because the chrome-extension URL // won't match the test_server domain (127.0.0.1), but because we set // |attach_same_site_cookies| to true for extension-initiated requests, this // will actually be able to get the cookie. GURL url = test_server.GetURL("/echocookieheader"); std::string script = R"((url => { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onload = () => domAutomationController.send(xhr.responseText); xhr.send(); }))"; std::string result = extensions::browsertest_util::ExecuteScriptInBackgroundPage( GetProfile(), extension->id(), script + "('" + url.spec() + "')"); EXPECT_EQ("cookie", result); } #endif IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, BasicRequest) { if (IsRestartStateWithInProcessNetworkService()) return; std::unique_ptr request = std::make_unique(); request->url = embedded_test_server()->GetURL("/echo"); content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); ASSERT_TRUE(simple_loader->ResponseInfo()); ASSERT_TRUE(simple_loader->ResponseInfo()->headers); EXPECT_EQ(200, simple_loader->ResponseInfo()->headers->response_code()); ASSERT_TRUE(simple_loader_helper.response_body()); EXPECT_EQ("Echo", *simple_loader_helper.response_body()); } // Make sure a cache is used when expected. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, Cache) { if (IsRestartStateWithInProcessNetworkService()) return; // Crashing the network service may corrupt the disk cache, so skip this test // in tests that crash the network service and use an on-disk cache. if (GetParam().network_service_state == NetworkServiceState::kRestarted && GetHttpCacheType() == StorageType::kDisk) { return; } // Make a request whose response should be cached. GURL request_url = embedded_test_server()->GetURL("/cachetime"); url::Origin request_origin = url::Origin::Create(embedded_test_server()->base_url()); std::unique_ptr request = std::make_unique(); request->url = request_url; request->trusted_params = network::ResourceRequest::TrustedParams(); request->trusted_params->network_isolation_key = net::NetworkIsolationKey(request_origin, request_origin); content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); ASSERT_TRUE(simple_loader_helper.response_body()); EXPECT_GT(simple_loader_helper.response_body()->size(), 0u); // Stop the server. ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); // Make the request again, and make sure it's cached or not, according to // expectations. Reuse the content::ResourceRequest, but nothing else. std::unique_ptr request2 = std::make_unique(); request2->url = request_url; request2->trusted_params = network::ResourceRequest::TrustedParams(); request2->trusted_params->network_isolation_key = net::NetworkIsolationKey(request_origin, request_origin); content::SimpleURLLoaderTestHelper simple_loader_helper2; std::unique_ptr simple_loader2 = network::SimpleURLLoader::Create(std::move(request2), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader2->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper2.GetCallback()); simple_loader_helper2.WaitForCallback(); if (GetHttpCacheType() == StorageType::kNone) { // If there's no cache, and no server running, the request should have // failed. EXPECT_FALSE(simple_loader_helper2.response_body()); EXPECT_EQ(net::ERR_CONNECTION_REFUSED, simple_loader2->NetError()); } else { // Otherwise, the request should have succeeded, and returned the same // result as before. ASSERT_TRUE(simple_loader_helper2.response_body()); EXPECT_EQ(*simple_loader_helper.response_body(), *simple_loader_helper2.response_body()); } } // Make sure that NetworkContexts can't access each other's disk caches. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, CacheIsolation) { if (IsRestartStateWithInProcessNetworkService()) return; // Make a request whose response should be cached. GURL request_url = embedded_test_server()->GetURL("/cachetime"); std::unique_ptr request = std::make_unique(); request->url = request_url; content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); ASSERT_TRUE(simple_loader_helper.response_body()); EXPECT_GT(simple_loader_helper.response_body()->size(), 0u); // Stop the server. ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); // Make the request again, for each other network context, and make sure the // response is not cached. ForEachOtherContext( base::BindLambdaForTesting([&](NetworkContextType network_context_type) { std::unique_ptr request2 = std::make_unique(); request2->url = request_url; content::SimpleURLLoaderTestHelper simple_loader_helper2; std::unique_ptr simple_loader2 = network::SimpleURLLoader::Create(std::move(request2), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader2->DownloadToStringOfUnboundedSizeUntilCrashAndDie( GetLoaderFactoryForContextType(network_context_type), simple_loader_helper2.GetCallback()); simple_loader_helper2.WaitForCallback(); EXPECT_FALSE(simple_loader_helper2.response_body()); EXPECT_EQ(net::ERR_CONNECTION_REFUSED, simple_loader2->NetError()); })); } // Make sure an on-disk cache is used when expected. PRE_DiskCache populates the // cache. DiskCache then makes sure the cache entry is still there (Or not) as // expected. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, PRE_DiskCache) { if (IsRestartStateWithInProcessNetworkService()) return; // Save test URL to disk, so it can be used in the next test (Test server uses // a random port, so need to know the port to try and retrieve it from the // cache in the next test). The profile directory is preserved between the // PRE_DiskCache and DiskCache run, so can just keep a file there. GURL test_url = embedded_test_server()->GetURL(kCacheRandomPath); url::Origin test_origin = url::Origin::Create(test_url); base::ScopedAllowBlockingForTesting allow_blocking; base::FilePath save_url_file_path = browser()->profile()->GetPath().Append( FILE_PATH_LITERAL("url_for_test.txt")); // Make a request whose response should be cached. std::unique_ptr request = std::make_unique(); request->url = test_url; request->trusted_params = network::ResourceRequest::TrustedParams(); request->trusted_params->network_isolation_key = net::NetworkIsolationKey(test_origin, test_origin); content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); EXPECT_EQ(net::OK, simple_loader->NetError()); ASSERT_TRUE(simple_loader_helper.response_body()); EXPECT_FALSE(simple_loader_helper.response_body()->empty()); // Write the URL and expected response to a file. std::string file_data = test_url.spec() + "\n" + *simple_loader_helper.response_body(); ASSERT_EQ( static_cast(file_data.length()), base::WriteFile(save_url_file_path, file_data.data(), file_data.size())); EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); } // Check if the URL loaded in PRE_DiskCache is still in the cache, across a // browser restart. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, DiskCache) { if (IsRestartStateWithInProcessNetworkService()) return; // Crashing the network service may corrupt the disk cache, so skip this phase // in tests that crash the network service and use an on-disk cache. if (GetParam().network_service_state == NetworkServiceState::kRestarted && GetHttpCacheType() == StorageType::kDisk) { return; } // Load URL from the above test body to disk. base::ScopedAllowBlockingForTesting allow_blocking; base::FilePath save_url_file_path = browser()->profile()->GetPath().Append( FILE_PATH_LITERAL("url_for_test.txt")); std::string file_data; ASSERT_TRUE(ReadFileToString(save_url_file_path, &file_data)); size_t newline_pos = file_data.find('\n'); ASSERT_NE(newline_pos, std::string::npos); GURL test_url = GURL(file_data.substr(0, newline_pos)); ASSERT_TRUE(test_url.is_valid()) << test_url.possibly_invalid_spec(); url::Origin test_origin = url::Origin::Create(test_url); std::string original_response = file_data.substr(newline_pos + 1); // Request the same test URL as may have been cached by PRE_DiskCache. std::unique_ptr request = std::make_unique(); request->url = test_url; request->trusted_params = network::ResourceRequest::TrustedParams(); request->trusted_params->network_isolation_key = net::NetworkIsolationKey(test_origin, test_origin); content::SimpleURLLoaderTestHelper simple_loader_helper; request->load_flags = net::LOAD_ONLY_FROM_CACHE; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); // The request should only succeed if there is an on-disk cache. if (GetHttpCacheType() != StorageType::kDisk) { EXPECT_FALSE(simple_loader_helper.response_body()); } else { DCHECK_NE(GetParam().network_service_state, NetworkServiceState::kRestarted); ASSERT_TRUE(simple_loader_helper.response_body()); EXPECT_EQ(original_response, *simple_loader_helper.response_body()); } } // Make sure that NetworkContexts have separate DNS caches. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, DnsCacheIsolation) { net::NetworkIsolationKey network_isolation_key = net::NetworkIsolationKey::CreateTransient(); net::HostPortPair host_port_pair(kHostname, 0); network::mojom::ResolveHostParametersPtr params = network::mojom::ResolveHostParameters::New(); // Use A queries, to avoid running into issues with the IPv6 probe, the // results of which can change during runtime, and can affect the DNS cache // key. params->dns_query_type = net::DnsQueryType ::A; // Resolve |host_port_pair|, which should succeed and put it in the // NetworkContext's cache. network::DnsLookupResult result = network::BlockingDnsLookup(network_context(), host_port_pair, std::move(params), network_isolation_key); EXPECT_EQ(net::OK, result.error); ASSERT_TRUE(result.resolved_addresses.has_value()); ASSERT_EQ(1u, result.resolved_addresses->size()); EXPECT_EQ(kAddress, result.resolved_addresses.value()[0].ToStringWithoutPort()); // Make a cache-only request for the same hostname, for each other network // context, and make sure no result is returned. ForEachOtherContext( base::BindLambdaForTesting([&](NetworkContextType network_context_type) { params = network::mojom::ResolveHostParameters::New(); params->dns_query_type = net::DnsQueryType ::A; // Cache only lookup. params->cache_usage = network::mojom::ResolveHostParameters::CacheUsage::STALE_ALLOWED; params->source = net::HostResolverSource::LOCAL_ONLY; network::DnsLookupResult result = network::BlockingDnsLookup( GetNetworkContextForContextType(network_context_type), host_port_pair, std::move(params), network_isolation_key); EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, result.error); })); // Do a cache-only lookup using the original network context, which should // return the same result it initially did. params = network::mojom::ResolveHostParameters::New(); // Cache only lookup. params->dns_query_type = net::DnsQueryType ::A; params->source = net::HostResolverSource::LOCAL_ONLY; params->cache_usage = network::mojom::ResolveHostParameters::CacheUsage::STALE_ALLOWED; result = network::BlockingDnsLookup(network_context(), host_port_pair, std::move(params), network_isolation_key); EXPECT_EQ(net::OK, result.error); ASSERT_TRUE(result.resolved_addresses.has_value()); ASSERT_EQ(1u, result.resolved_addresses->size()); EXPECT_EQ(kAddress, result.resolved_addresses.value()[0].ToStringWithoutPort()); } // Visits a URL with an HSTS header, and makes sure it is respected. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, PRE_Hsts) { if (IsRestartStateWithInProcessNetworkService()) return; net::test_server::EmbeddedTestServer ssl_server( net::test_server::EmbeddedTestServer::TYPE_HTTPS); ssl_server.SetSSLConfig( net::test_server::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN); ssl_server.AddDefaultHandlers(GetChromeTestDataDir()); ASSERT_TRUE(ssl_server.Start()); // Make a request whose response has an STS header. std::unique_ptr request = std::make_unique(); request->url = ssl_server.GetURL( "/set-header?Strict-Transport-Security: max-age%3D600000"); content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); EXPECT_EQ(net::OK, simple_loader->NetError()); ASSERT_TRUE(simple_loader->ResponseInfo()->headers); EXPECT_TRUE(simple_loader->ResponseInfo()->headers->HasHeaderValue( "Strict-Transport-Security", "max-age=600000")); // Make a cache-only request to make sure the HSTS entry is respected. Using a // cache-only request both prevents the result from being cached, and makes // the check identical to the one in the next test, which is run after the // test server has been shut down. GURL exected_ssl_url = ssl_server.base_url(); GURL::Replacements replacements; replacements.SetSchemeStr("http"); GURL start_url = exected_ssl_url.ReplaceComponents(replacements); request = std::make_unique(); request->url = start_url; request->load_flags = net::LOAD_ONLY_FROM_CACHE; content::SimpleURLLoaderTestHelper simple_loader_helper2; simple_loader = network::SimpleURLLoader::Create( std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper2.GetCallback()); simple_loader_helper2.WaitForCallback(); EXPECT_FALSE(simple_loader_helper2.response_body()); EXPECT_EQ(exected_ssl_url, simple_loader->GetFinalURL()); // Write the URL with HSTS information to a file, so it can be loaded in the // next test. Have to use a file for this, since the server's port is random. base::ScopedAllowBlockingForTesting allow_blocking; base::FilePath save_url_file_path = browser()->profile()->GetPath().Append( FILE_PATH_LITERAL("url_for_test.txt")); std::string file_data = start_url.spec(); ASSERT_EQ( static_cast(file_data.length()), base::WriteFile(save_url_file_path, file_data.data(), file_data.size())); } // Checks if the HSTS information from the last test is still available after a // restart. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, Hsts) { if (IsRestartStateWithInProcessNetworkService()) return; // The network service must be cleanly shut down to guarantee HSTS information // is flushed to disk, but that currently generally doesn't happen. See // https://crbug.com/820996. if (GetHttpCacheType() == StorageType::kDisk) { return; } base::ScopedAllowBlockingForTesting allow_blocking; base::FilePath save_url_file_path = browser()->profile()->GetPath().Append( FILE_PATH_LITERAL("url_for_test.txt")); std::string file_data; ASSERT_TRUE(ReadFileToString(save_url_file_path, &file_data)); GURL start_url = GURL(file_data); // Unfortunately, loading HSTS information is loaded asynchronously from // disk, so there's no way to guarantee it has loaded by the time a // request is made. As a result, may have to try multiple times to verify that // cached HSTS information has been loaded, when it's stored on disk. while (true) { std::unique_ptr request = std::make_unique(); request->url = start_url; request->load_flags = net::LOAD_ONLY_FROM_CACHE; content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); EXPECT_FALSE(simple_loader_helper.response_body()); // HSTS information is currently stored on disk if-and-only-if there's an // on-disk HTTP cache. if (GetHttpCacheType() == StorageType::kDisk) { GURL::Replacements replacements; replacements.SetSchemeStr("https"); GURL expected_https_url = start_url.ReplaceComponents(replacements); // The file may not have been loaded yet, so if the cached HSTS // information was not respected, try again. if (expected_https_url != simple_loader->GetFinalURL()) continue; EXPECT_EQ(expected_https_url, simple_loader->GetFinalURL()); break; } else { EXPECT_EQ(start_url, simple_loader->GetFinalURL()); break; } } } // Check that the SSLConfig is hooked up. PRE_SSLConfig checks that changing // local_state() after start modifies the SSLConfig, SSLConfig makes sure the // (now modified) initial value of local_state() is respected. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, PRE_SSLConfig) { if (IsRestartStateWithInProcessNetworkService()) return; TestEnablingSSLVersionMin(WayToEnableSSLConfig::kViaPrefs); } IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, SSLConfig) { if (IsRestartStateWithInProcessNetworkService()) return; // Start a TLS 1.0 server. net::EmbeddedTestServer ssl_server(net::EmbeddedTestServer::TYPE_HTTPS); net::SSLServerConfig ssl_config; ssl_config.version_min = net::SSL_PROTOCOL_VERSION_TLS1; ssl_config.version_max = net::SSL_PROTOCOL_VERSION_TLS1; ssl_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config); ASSERT_TRUE(ssl_server.Start()); // Making a request should fail, since PRE_SSLConfig saved a pref to disallow // TLS 1.0. std::unique_ptr request = std::make_unique(); request->url = ssl_server.GetURL("/echo"); content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); EXPECT_FALSE(simple_loader_helper.response_body()); EXPECT_EQ(net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH, simple_loader->NetError()); } // This test does the same as // 'NetworkContextConfigurationBrowserTest.PRE_SSLConfig' but with the // difference that the SSLVersionMin is set via a policy (not via the prefs). IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, SSLVersionMinSetViaPolicy) { if (IsRestartStateWithInProcessNetworkService()) return; TestEnablingSSLVersionMin(WayToEnableSSLConfig::kViaPolicy); } IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, ProxyConfig) { if (IsRestartStateWithInProcessNetworkService()) return; SetProxyPref(embedded_test_server()->host_port_pair()); TestProxyConfigured(/*expect_success=*/true); } // This test should not end in an AssertNoURLLRequests CHECK. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, ShutdownWithLiveRequest) { if (IsRestartStateWithInProcessNetworkService()) return; MakeLongLivedRequestThatHangsUntilShutdown(); } IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, UserAgentAndLanguagePrefs) { if (IsRestartStateWithInProcessNetworkService()) return; // The system and SafeBrowsing network contexts aren't associated with any // profile, so changing the language settings for the profile's main network // context won't affect what they send. bool system = (GetParam().network_context_type == NetworkContextType::kSystem || GetParam().network_context_type == NetworkContextType::kSafeBrowsing); // echoheader returns "None" when the header isn't there in the first place. const char kNoAcceptLanguage[] = "None"; std::string accept_language, user_agent; // Check default. ASSERT_TRUE(FetchHeaderEcho("accept-language", &accept_language)); EXPECT_EQ(system ? kNoAcceptLanguage : "en-US,en;q=0.9", accept_language); ASSERT_TRUE(FetchHeaderEcho("user-agent", &user_agent)); EXPECT_EQ(::GetUserAgent(), user_agent); // Now change the profile a different language, and see if the headers // get updated. browser()->profile()->GetPrefs()->SetString(language::prefs::kAcceptLanguages, "uk"); FlushNetworkInterface(); std::string accept_language2, user_agent2; ASSERT_TRUE(FetchHeaderEcho("accept-language", &accept_language2)); EXPECT_EQ(system ? kNoAcceptLanguage : "uk", accept_language2); ASSERT_TRUE(FetchHeaderEcho("user-agent", &user_agent2)); EXPECT_EQ(::GetUserAgent(), user_agent2); // Try a more complicated one, with multiple languages. browser()->profile()->GetPrefs()->SetString(language::prefs::kAcceptLanguages, "uk, en_US"); FlushNetworkInterface(); std::string accept_language3, user_agent3; ASSERT_TRUE(FetchHeaderEcho("accept-language", &accept_language3)); EXPECT_EQ(system ? kNoAcceptLanguage : "uk,en_US;q=0.9", accept_language3); ASSERT_TRUE(FetchHeaderEcho("user-agent", &user_agent3)); EXPECT_EQ(::GetUserAgent(), user_agent3); } // First part of testing enable referrers. Check that referrers are enabled by // default at browser start, and referrers are indeed sent. Then disable // referrers, and make sure that they aren't set. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, PRE_EnableReferrers) { if (IsRestartStateWithInProcessNetworkService()) return; const GURL kReferrer("http://referrer/"); // Referrers should be enabled by default. EXPECT_TRUE(GetPrefService()->GetBoolean(prefs::kEnableReferrers)); // Send a request, make sure the referrer is sent. std::string referrer; std::unique_ptr request = std::make_unique(); request->referrer = kReferrer; ASSERT_TRUE(FetchHeaderEcho("referer", &referrer, std::move(request))); // SafeBrowsing never sends the referrer since it doesn't need to. if (GetParam().network_context_type == NetworkContextType::kSafeBrowsing) { EXPECT_EQ("None", referrer); } else { EXPECT_EQ(kReferrer.spec(), referrer); } // Disable referrers, and flush the NetworkContext mojo interface it's set on, // to avoid any races with the URLLoaderFactory pipe. GetPrefService()->SetBoolean(prefs::kEnableReferrers, false); FlushNetworkInterface(); // Send a request and make sure its referer is not sent. std::string referrer2; std::unique_ptr request2 = std::make_unique(); request2->referrer = kReferrer; ASSERT_TRUE(FetchHeaderEcho("referer", &referrer2, std::move(request2))); EXPECT_EQ("None", referrer2); } // Second part of enable referrer test. Referrer should still be disabled. Make // sure that disable referrers option is respected after startup, as to just // after changing it. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, EnableReferrers) { if (IsRestartStateWithInProcessNetworkService()) return; const GURL kReferrer("http://referrer/"); // The preference is expected to be reset in incognito mode. if (is_incognito()) { EXPECT_TRUE(GetPrefService()->GetBoolean(prefs::kEnableReferrers)); return; } // Referrers should still be disabled. EXPECT_FALSE(GetPrefService()->GetBoolean(prefs::kEnableReferrers)); // Send a request and make sure its referer is not sent. std::string referrer; std::unique_ptr request = std::make_unique(); request->referrer = kReferrer; ASSERT_TRUE(FetchHeaderEcho("referer", &referrer, std::move(request))); EXPECT_EQ("None", referrer); } // Make sure that sending referrers that violate the referrer policy results in // errors. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, PolicyViolatingReferrers) { if (IsRestartStateWithInProcessNetworkService()) return; std::unique_ptr request = std::make_unique(); request->url = embedded_test_server()->GetURL("/echoheader?Referer"); request->referrer = GURL("http://referrer/"); request->referrer_policy = net::URLRequest::NO_REFERRER; content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); if (GetParam().network_context_type == NetworkContextType::kSafeBrowsing) { // Safebrowsing ignores referrers so the requests succeed. EXPECT_EQ(net::OK, simple_loader->NetError()); ASSERT_TRUE(simple_loader_helper.response_body()); EXPECT_EQ("None", *simple_loader_helper.response_body()); } else { // In all other cases, the invalid referrer causes the request to fail. EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, simple_loader->NetError()); } } // Makes sure cookies are enabled by default, and saved to disk / not saved to // disk as expected. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, PRE_CookiesEnabled) { if (IsRestartStateWithInProcessNetworkService()) return; EXPECT_TRUE(GetCookies(embedded_test_server()->base_url()).empty()); SetCookie(CookieType::kFirstParty, CookiePersistenceType::kPersistent, embedded_test_server()); EXPECT_FALSE(GetCookies(embedded_test_server()->base_url()).empty()); } IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, CookiesEnabled) { if (IsRestartStateWithInProcessNetworkService()) return; #if defined(OS_MACOSX) // TODO(https://crbug.com/880496): Fix and reenable test. if (base::mac::IsOS10_11()) return; #endif // Check that the cookie from the first stage of the test was / was not // preserved between browser restarts, as expected. bool has_cookies = !GetCookies(embedded_test_server()->base_url()).empty(); EXPECT_EQ(GetCookieStorageType() == StorageType::kDisk, has_cookies); } IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, CookieIsolation) { if (IsRestartStateWithInProcessNetworkService()) return; SetCookie(CookieType::kFirstParty, CookiePersistenceType::kPersistent, embedded_test_server()); EXPECT_FALSE(GetCookies(embedded_test_server()->base_url()).empty()); ForEachOtherContext( base::BindLambdaForTesting([&](NetworkContextType network_context_type) { EXPECT_TRUE(GetCookiesForContextType(network_context_type, embedded_test_server()->base_url()) .empty()); })); } IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, PRE_ThirdPartyCookiesBlocked) { if (IsRestartStateWithInProcessNetworkService()) return; // The system and SafeBrowsing network contexts don't support the third party // cookie blocking options, since they have no notion of third parties. bool system = GetParam().network_context_type == NetworkContextType::kSystem || GetParam().network_context_type == NetworkContextType::kSafeBrowsing; if (system) return; GetPrefService()->SetBoolean(prefs::kBlockThirdPartyCookies, true); SetCookie(CookieType::kThirdParty, CookiePersistenceType::kSession, https_server()); EXPECT_TRUE(GetCookies(https_server()->base_url()).empty()); } IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, ThirdPartyCookiesBlocked) { if (IsRestartStateWithInProcessNetworkService()) return; // The system and SafeBrowsing network contexts don't support the third party // cookie blocking options, since they have no notion of third parties. bool system = GetParam().network_context_type == NetworkContextType::kSystem || GetParam().network_context_type == NetworkContextType::kSafeBrowsing; if (system) return; // The preference is expected to be reset in incognito mode. if (is_incognito()) { EXPECT_FALSE(GetPrefService()->GetBoolean(prefs::kBlockThirdPartyCookies)); return; } // The kBlockThirdPartyCookies pref should carry over to the next session. EXPECT_TRUE(GetPrefService()->GetBoolean(prefs::kBlockThirdPartyCookies)); SetCookie(CookieType::kThirdParty, CookiePersistenceType::kSession, https_server()); EXPECT_TRUE(GetCookies(https_server()->base_url()).empty()); // Set pref to false, third party cookies should be allowed now. GetPrefService()->SetBoolean(prefs::kBlockThirdPartyCookies, false); // Set a third-party cookie. It should actually get set this time. SetCookie(CookieType::kThirdParty, CookiePersistenceType::kSession, https_server()); EXPECT_FALSE(GetCookies(https_server()->base_url()).empty()); } IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, PRE_CookieSettings) { if (IsRestartStateWithInProcessNetworkService()) return; // The system and SafeBrowsing network contexts don't respect cookie blocking // options, which are per-profile. bool system = GetParam().network_context_type == NetworkContextType::kSystem || GetParam().network_context_type == NetworkContextType::kSafeBrowsing; if (system) return; CookieSettingsFactory::GetForProfile(browser()->profile()) ->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK); FlushNetworkInterface(); SetCookie(CookieType::kFirstParty, CookiePersistenceType::kSession, embedded_test_server()); EXPECT_TRUE(GetCookies(embedded_test_server()->base_url()).empty()); } IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, CookieSettings) { if (IsRestartStateWithInProcessNetworkService()) return; // The system and SafeBrowsing network contexts don't respect cookie blocking // options, which are per-profile. bool system = GetParam().network_context_type == NetworkContextType::kSystem || GetParam().network_context_type == NetworkContextType::kSafeBrowsing; if (system) return; // The content settings should carry over to the next session. SetCookie(CookieType::kFirstParty, CookiePersistenceType::kSession, embedded_test_server()); EXPECT_TRUE(GetCookies(embedded_test_server()->base_url()).empty()); // Set default setting to allow, cookies should be set now. CookieSettingsFactory::GetForProfile(browser()->profile()) ->SetDefaultCookieSetting(CONTENT_SETTING_ALLOW); FlushNetworkInterface(); SetCookie(CookieType::kFirstParty, CookiePersistenceType::kSession, embedded_test_server()); EXPECT_FALSE(GetCookies(embedded_test_server()->base_url()).empty()); } // Make sure file uploads work. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, UploadFile) { if (IsRestartStateWithInProcessNetworkService()) return; std::unique_ptr request = std::make_unique(); request->method = "POST"; request->url = embedded_test_server()->GetURL("/echo"); content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); base::FilePath dir_test_data; base::PathService::Get(chrome::DIR_TEST_DATA, &dir_test_data); base::FilePath path = dir_test_data.Append(base::FilePath(FILE_PATH_LITERAL("simple.html"))); simple_loader->AttachFileForUpload(path, "text/html"); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); ASSERT_TRUE(simple_loader->ResponseInfo()); ASSERT_TRUE(simple_loader->ResponseInfo()->headers); EXPECT_EQ(200, simple_loader->ResponseInfo()->headers->response_code()); ASSERT_TRUE(simple_loader_helper.response_body()); base::ScopedAllowBlockingForTesting allow_blocking; std::string expected_response; base::ReadFileToString(path, &expected_response); EXPECT_EQ(expected_response.c_str(), *simple_loader_helper.response_body()); } class NetworkContextConfigurationFixedPortBrowserTest : public NetworkContextConfigurationBrowserTest { public: NetworkContextConfigurationFixedPortBrowserTest() {} ~NetworkContextConfigurationFixedPortBrowserTest() override {} void SetUpCommandLine(base::CommandLine* command_line) override { command_line->AppendSwitchASCII( switches::kTestingFixedHttpPort, base::StringPrintf("%u", embedded_test_server()->port())); LOG(WARNING) << base::StringPrintf("%u", embedded_test_server()->port()); } }; // Test that the command line switch makes it to the network service and is // respected. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationFixedPortBrowserTest, TestingFixedPort) { if (IsRestartStateWithInProcessNetworkService()) return; std::unique_ptr request = std::make_unique(); // This URL does not use the port the embedded test server is using. The // command line switch should make it result in the request being directed to // the test server anyways. request->url = GURL("http://127.0.0.1/echo"); content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); EXPECT_EQ(net::OK, simple_loader->NetError()); ASSERT_TRUE(simple_loader_helper.response_body()); EXPECT_EQ(*simple_loader_helper.response_body(), "Echo"); } class NetworkContextConfigurationProxyOnStartBrowserTest : public NetworkContextConfigurationBrowserTest { public: NetworkContextConfigurationProxyOnStartBrowserTest() {} ~NetworkContextConfigurationProxyOnStartBrowserTest() override {} void SetUpCommandLine(base::CommandLine* command_line) override { command_line->AppendSwitchASCII( switches::kProxyServer, embedded_test_server()->host_port_pair().ToString()); } private: DISALLOW_COPY_AND_ASSIGN(NetworkContextConfigurationProxyOnStartBrowserTest); }; // Test that when there's a proxy configuration at startup, the initial requests // use that configuration. IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationProxyOnStartBrowserTest, TestInitialProxyConfig) { if (IsRestartStateWithInProcessNetworkService()) return; TestProxyConfigured(/*expect_success=*/true); } // Make sure the system URLRequestContext can handle fetching PAC scripts from // http URLs. class NetworkContextConfigurationHttpPacBrowserTest : public NetworkContextConfigurationBrowserTest { public: NetworkContextConfigurationHttpPacBrowserTest() : pac_test_server_(net::test_server::EmbeddedTestServer::TYPE_HTTP) {} ~NetworkContextConfigurationHttpPacBrowserTest() override {} void SetUpCommandLine(base::CommandLine* command_line) override { pac_test_server_.RegisterRequestHandler(base::Bind( &NetworkContextConfigurationHttpPacBrowserTest::HandlePacRequest, GetPacScript())); EXPECT_TRUE(pac_test_server_.Start()); command_line->AppendSwitchASCII(switches::kProxyPacUrl, pac_test_server_.base_url().spec().c_str()); } static std::unique_ptr HandlePacRequest( const std::string& pac_script, const net::test_server::HttpRequest& request) { std::unique_ptr response = std::make_unique(); response->set_content(pac_script); return response; } private: net::test_server::EmbeddedTestServer pac_test_server_; DISALLOW_COPY_AND_ASSIGN(NetworkContextConfigurationHttpPacBrowserTest); }; IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationHttpPacBrowserTest, HttpPac) { if (IsRestartStateWithInProcessNetworkService()) return; TestProxyConfigured(/*expect_success=*/true); } // Make sure the system URLRequestContext can handle fetching PAC scripts from // file URLs. class NetworkContextConfigurationFilePacBrowserTest : public NetworkContextConfigurationBrowserTest { public: NetworkContextConfigurationFilePacBrowserTest() {} ~NetworkContextConfigurationFilePacBrowserTest() override {} void SetUpCommandLine(base::CommandLine* command_line) override { const char kPacFileName[] = "foo.pac"; ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); base::FilePath pac_file_path = temp_dir_.GetPath().AppendASCII(kPacFileName); std::string pac_script = GetPacScript(); ASSERT_EQ( static_cast(pac_script.size()), base::WriteFile(pac_file_path, pac_script.c_str(), pac_script.size())); command_line->AppendSwitchASCII( switches::kProxyPacUrl, net::FilePathToFileURL(pac_file_path).spec()); } private: base::ScopedTempDir temp_dir_; DISALLOW_COPY_AND_ASSIGN(NetworkContextConfigurationFilePacBrowserTest); }; IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationFilePacBrowserTest, FilePac) { if (IsRestartStateWithInProcessNetworkService()) return; TestProxyConfigured(false); } // Make sure the system URLRequestContext can handle fetching PAC scripts from // data URLs. class NetworkContextConfigurationDataPacBrowserTest : public NetworkContextConfigurationBrowserTest { public: NetworkContextConfigurationDataPacBrowserTest() {} ~NetworkContextConfigurationDataPacBrowserTest() override {} void SetUpCommandLine(base::CommandLine* command_line) override { std::string contents; // Read in kPACScript contents. command_line->AppendSwitchASCII(switches::kProxyPacUrl, "data:," + GetPacScript()); } private: DISALLOW_COPY_AND_ASSIGN(NetworkContextConfigurationDataPacBrowserTest); }; IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationDataPacBrowserTest, DataPac) { if (IsRestartStateWithInProcessNetworkService()) return; TestProxyConfigured(/*expect_success=*/true); } // Make sure the system URLRequestContext can handle fetching PAC scripts from // ftp URLs. Unlike the other PAC tests, this test uses a PAC script that // results in an error, since the spawned test server is designed so that it can // run remotely (So can't just write a script to a local file and have the // server serve it). // // TODO(https://crbug.com/333943): Remove these tests when FTP support is // removed. class NetworkContextConfigurationFtpPacBrowserTest : public NetworkContextConfigurationBrowserTest { public: NetworkContextConfigurationFtpPacBrowserTest() : ftp_server_(net::SpawnedTestServer::TYPE_FTP, GetChromeTestDataDir()) { scoped_feature_list_.InitAndEnableFeature(features::kFtpProtocol); EXPECT_TRUE(ftp_server_.Start()); } ~NetworkContextConfigurationFtpPacBrowserTest() override {} void SetUpCommandLine(base::CommandLine* command_line) override { command_line->AppendSwitchASCII( switches::kProxyPacUrl, ftp_server_.GetURL("bad_server.pac").spec().c_str()); } private: net::SpawnedTestServer ftp_server_; base::test::ScopedFeatureList scoped_feature_list_; DISALLOW_COPY_AND_ASSIGN(NetworkContextConfigurationFtpPacBrowserTest); }; IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationFtpPacBrowserTest, FtpPac) { if (IsRestartStateWithInProcessNetworkService()) return; std::unique_ptr request = std::make_unique(); // This URL should be directed to the test server because of the proxy. request->url = GURL("http://does.not.resolve.test:1872/echo"); content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); simple_loader_helper.WaitForCallback(); EXPECT_EQ(net::ERR_PROXY_CONNECTION_FAILED, simple_loader->NetError()); } class NetworkContextConfigurationProxySettingsBrowserTest : public NetworkContextConfigurationHttpPacBrowserTest { public: const size_t kDefaultMaxConnectionsPerProxy = 32; NetworkContextConfigurationProxySettingsBrowserTest() = default; ~NetworkContextConfigurationProxySettingsBrowserTest() override = default; void SetUpOnMainThread() override { embedded_test_server()->RegisterRequestHandler(base::BindRepeating( &NetworkContextConfigurationProxySettingsBrowserTest::TrackConnections, base::Unretained(this))); expected_connections_loop_ptr_.store(nullptr); NetworkContextConfigurationHttpPacBrowserTest::SetUpOnMainThread(); } virtual size_t GetExpectedMaxConnectionsPerProxy() const { return kDefaultMaxConnectionsPerProxy; } std::unique_ptr TrackConnections( const net::test_server::HttpRequest& request) { if (!base::StartsWith(request.relative_url, "/hung", base::CompareCase::INSENSITIVE_ASCII)) return nullptr; // Record the number of connections we're seeing. CHECK(observed_request_urls_.find(request.GetURL().spec()) == observed_request_urls_.end()); observed_request_urls_.emplace(request.GetURL().spec()); CHECK_GE(GetExpectedMaxConnectionsPerProxy(), observed_request_urls_.size()); // Once we've seen at least as many connections as we expect, we can quit // the loop on the main test thread. The test may choose to wait for // longer to see if there are any additional unexpected connections. if (GetExpectedMaxConnectionsPerProxy() == observed_request_urls_.size() && expected_connections_loop_ptr_.load() != nullptr) { expected_connections_loop_ptr_.load()->Quit(); } // To test the number of connections per proxy, we'll hang all responses. return std::make_unique(); } void RunMaxConnectionsPerProxyTest() { // At this point in the test, we've set up a proxy that points to our // embedded test server. We've also set things up to hang all incoming // requests and record how many concurrent connections we have running. To // detect the maximum number of requests per proxy, we now just have to // attempt to make as many requests as possible to ensure we don't see an // incorrect number of concurrent requests. // First of all, we're going to want to wait for at least as many // connections as we expect. base::RunLoop expected_connections_run_loop; expected_connections_loop_ptr_.store(&expected_connections_run_loop); std::vector> loaders( GetExpectedMaxConnectionsPerProxy()); for (unsigned int i = 0; i < GetExpectedMaxConnectionsPerProxy() + 1; ++i) { std::unique_ptr request = std::make_unique(); request->url = embedded_test_server()->GetURL(base::StringPrintf("foo%u.test", i), base::StringPrintf("/hung_%u", i)); content::SimpleURLLoaderTestHelper simple_loader_helper; std::unique_ptr simple_loader = network::SimpleURLLoader::Create(std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), simple_loader_helper.GetCallback()); loaders.emplace_back(std::move(simple_loader)); } expected_connections_run_loop.Run(); // Then wait for any remaining connections that we should NOT get. base::RunLoop ugly_100ms_wait; base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, ugly_100ms_wait.QuitClosure(), base::TimeDelta::FromMilliseconds(100)); ugly_100ms_wait.Run(); // Stop the server. ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); } private: std::atomic expected_connections_loop_ptr_{nullptr}; // In RunMaxConnectionsPerProxyTest(), we'll make several network requests // that hang. These hung requests are assumed to last for the duration of the // test. This member, which is only accessed from the server's IO thread, // records each observed request to ensure we see only as many connections as // we expect. std::unordered_set observed_request_urls_; DISALLOW_COPY_AND_ASSIGN(NetworkContextConfigurationProxySettingsBrowserTest); }; IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationProxySettingsBrowserTest, MaxConnectionsPerProxy) { RunMaxConnectionsPerProxyTest(); } class NetworkContextConfigurationManagedProxySettingsBrowserTest : public NetworkContextConfigurationProxySettingsBrowserTest { public: const size_t kTestMaxConnectionsPerProxy = 37; NetworkContextConfigurationManagedProxySettingsBrowserTest() = default; ~NetworkContextConfigurationManagedProxySettingsBrowserTest() override = default; void SetUpInProcessBrowserTestFixture() override { NetworkContextConfigurationProxySettingsBrowserTest:: SetUpInProcessBrowserTestFixture(); policy::PolicyMap policies; policies.Set(policy::key::kMaxConnectionsPerProxy, policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_MACHINE, policy::POLICY_SOURCE_CLOUD, std::make_unique( static_cast(kTestMaxConnectionsPerProxy)), /*external_data_fetcher=*/nullptr); UpdateChromePolicy(policies); } size_t GetExpectedMaxConnectionsPerProxy() const override { return kTestMaxConnectionsPerProxy; } private: DISALLOW_COPY_AND_ASSIGN( NetworkContextConfigurationManagedProxySettingsBrowserTest); }; IN_PROC_BROWSER_TEST_P( NetworkContextConfigurationManagedProxySettingsBrowserTest, MaxConnectionsPerProxy) { RunMaxConnectionsPerProxyTest(); } // Used to test that we persist Reporting clients and NEL policies to disk, but // only when appropriate. class NetworkContextConfigurationReportingAndNelBrowserTest : public NetworkContextConfigurationBrowserTest { public: struct RequestState { content::SimpleURLLoaderTestHelper helper; std::unique_ptr loader; }; NetworkContextConfigurationReportingAndNelBrowserTest() : https_server_(net::test_server::EmbeddedTestServer::TYPE_HTTPS) { // Set up an SSL certificate so we can make requests to "https://localhost" https_server_.SetSSLConfig( net::test_server::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN); // Only start the server if we actually need it in the test (i.e., we'll // call StartAcceptingConnections somewhere in the test). if (!IsRestartStateWithInProcessNetworkService() && AreReportingAndNelEnabled()) { EXPECT_TRUE(https_server_.InitializeAndListen()); } // Make report delivery happen instantly. net::ReportingPolicy policy; policy.delivery_interval = base::TimeDelta::FromSeconds(0); net::ReportingPolicy::UsePolicyForTesting(policy); } std::unique_ptr NewSimpleRequest(const GURL& url) { auto request_state = std::make_unique(); std::unique_ptr request = std::make_unique(); request->url = url; request_state->loader = network::SimpleURLLoader::Create( std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS); request_state->loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( loader_factory(), request_state->helper.GetCallback()); return request_state; } void SetUpCommandLine(base::CommandLine* command_line) override { command_line->AppendSwitch(switches::kShortReportingDelay); // This switch will cause traffic to *any* port to go to https_server_, // regardless of which arbitrary port https_server_ decides to run on. // NEL and Reporting policies are only valid for a single origin. if (!IsRestartStateWithInProcessNetworkService() && AreReportingAndNelEnabled()) { command_line->AppendSwitchASCII(switches::kTestingFixedHttpsPort, base::StringPrintf("%u", port())); } } net::EmbeddedTestServer* http_server() { return &https_server_; } int port() const { return https_server_.port(); } static GURL GetCollectorURL() { return GURL("https://localhost/upload"); } static std::string GetReportToHeader() { return "Report-To: {\"endpoints\":[{\"url\":\"" + GetCollectorURL().spec() + "\"}],\"max_age\":86400}\r\n"; } static std::string GetNELHeader() { return "NEL: " "{\"report_to\":\"default\",\"max_age\":86400,\"success_fraction\":" "1.0}\r\n"; } void RespondWithHeaders(net::test_server::ControllableHttpResponse* resp) { resp->WaitForRequest(); resp->Send("HTTP/1.1 200 OK\r\n"); resp->Send(GetReportToHeader()); resp->Send(GetNELHeader()); resp->Send("\r\n"); resp->Done(); } void RespondWithoutHeaders(net::test_server::ControllableHttpResponse* resp) { resp->WaitForRequest(); resp->Send("HTTP/1.1 200 OK\r\n"); resp->Send("\r\n"); resp->Done(); } bool AreReportingAndNelEnabled() const { switch (GetParam().network_context_type) { case NetworkContextType::kSystem: case NetworkContextType::kSafeBrowsing: return false; case NetworkContextType::kProfile: case NetworkContextType::kIncognitoProfile: case NetworkContextType::kOnDiskApp: case NetworkContextType::kInMemoryApp: case NetworkContextType::kOnDiskAppWithIncognitoProfile: return true; } } bool ExpectPersistenceEnabled() const { switch (GetParam().network_context_type) { case NetworkContextType::kSystem: case NetworkContextType::kSafeBrowsing: case NetworkContextType::kIncognitoProfile: case NetworkContextType::kInMemoryApp: case NetworkContextType::kOnDiskAppWithIncognitoProfile: return false; case NetworkContextType::kProfile: case NetworkContextType::kOnDiskApp: return true; } } private: net::EmbeddedTestServer https_server_; }; namespace { constexpr char kReportingEnabledURL[] = "https://localhost/page"; constexpr char kCrossOriginReportingEnabledURL[] = "https://localhost:444/page"; } // namespace IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationReportingAndNelBrowserTest, PRE_PersistReportingAndNel) { if (IsRestartStateWithInProcessNetworkService() || !AreReportingAndNelEnabled()) { return; } net::test_server::ControllableHttpResponse original_response(http_server(), "/page"); net::test_server::ControllableHttpResponse upload_response(http_server(), "/upload"); http_server()->StartAcceptingConnections(); // Make a request to /page and respond with Report-To and NEL headers, which // will turn on NEL for the localhost:443 origin. std::unique_ptr request = NewSimpleRequest(GURL(kReportingEnabledURL)); RespondWithHeaders(&original_response); request->helper.WaitForCallback(); // Wait for a request to /upload, which should happen because the previous // request precipitated a NEL report. upload_response.WaitForRequest(); EXPECT_EQ(net::test_server::METHOD_POST, upload_response.http_request()->method); } IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationReportingAndNelBrowserTest, PersistReportingAndNel) { if (IsRestartStateWithInProcessNetworkService() || !AreReportingAndNelEnabled()) { return; } net::test_server::ControllableHttpResponse original_response(http_server(), "/page"); net::test_server::ControllableHttpResponse cross_origin_response( http_server(), "/page"); net::test_server::ControllableHttpResponse upload_response(http_server(), "/upload"); http_server()->StartAcceptingConnections(); // Make a request that will only precipitate a NEL report if we loaded a NEL // policy from the store. std::unique_ptr request = NewSimpleRequest(GURL(kReportingEnabledURL)); RespondWithoutHeaders(&original_response); request->helper.WaitForCallback(); // Make another request that will generate another upload to the same // collector. If the previous request didn't generate a NEL report (e.g., // because persistence is disabled) then this'll be first upload to the NEL // collector. Note that because this upload is to a different origin than the // request, Reporting will make a CORS preflight request, which is what we // look for. std::unique_ptr cross_origin_request = NewSimpleRequest(GURL(kCrossOriginReportingEnabledURL)); RespondWithHeaders(&cross_origin_response); cross_origin_request->helper.WaitForCallback(); // Wait for a request to /upload, which should happen because the previous // requests precipitated NEL reports. // // We assume that Reporting/NEL will send reports in the order we made the // requests above, which seems to be the case today but may not necessarily // true in general. upload_response.WaitForRequest(); if (ExpectPersistenceEnabled()) { // A NEL upload about https://localhost EXPECT_EQ(net::test_server::METHOD_POST, upload_response.http_request()->method); } else { // A CORS preflight request before a cross-origin NEL upload about // https://localhost:444 EXPECT_EQ(net::test_server::METHOD_OPTIONS, upload_response.http_request()->method); } } // Instantiates tests with a prefix indicating which NetworkContext is being // tested, and a suffix of "/0" if the network service is disabled, "/1" if it's // enabled, and "/2" if it's enabled and restarted. #define TEST_CASES(network_context_type) \ TestCase({NetworkServiceState::kEnabled, network_context_type}), \ TestCase({NetworkServiceState::kRestarted, network_context_type}) #if BUILDFLAG(ENABLE_EXTENSIONS) #define INSTANTIATE_EXTENSION_TESTS(TestFixture) \ INSTANTIATE_TEST_SUITE_P( \ OnDiskApp, TestFixture, \ ::testing::Values(TEST_CASES(NetworkContextType::kOnDiskApp))); \ \ INSTANTIATE_TEST_SUITE_P( \ InMemoryApp, TestFixture, \ ::testing::Values(TEST_CASES(NetworkContextType::kInMemoryApp))); \ \ INSTANTIATE_TEST_SUITE_P( \ OnDiskAppWithIncognitoProfile, TestFixture, \ ::testing::Values( \ TEST_CASES(NetworkContextType::kOnDiskAppWithIncognitoProfile))); #else // !BUILDFLAG(ENABLE_EXTENSIONS) #define INSTANTIATE_EXTENSION_TESTS(TestFixture) #endif // !BUILDFLAG(ENABLE_EXTENSIONS) #define INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE(TestFixture) \ INSTANTIATE_EXTENSION_TESTS(TestFixture) \ INSTANTIATE_TEST_SUITE_P( \ SystemNetworkContext, TestFixture, \ ::testing::Values(TEST_CASES(NetworkContextType::kSystem))); \ \ INSTANTIATE_TEST_SUITE_P( \ SafeBrowsingNetworkContext, TestFixture, \ ::testing::Values(TEST_CASES(NetworkContextType::kSafeBrowsing))); \ \ INSTANTIATE_TEST_SUITE_P( \ ProfileMainNetworkContext, TestFixture, \ ::testing::Values(TEST_CASES(NetworkContextType::kProfile))); \ \ INSTANTIATE_TEST_SUITE_P( \ IncognitoProfileMainNetworkContext, TestFixture, \ ::testing::Values(TEST_CASES(NetworkContextType::kIncognitoProfile))) INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE(NetworkContextConfigurationBrowserTest); INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE( NetworkContextConfigurationFixedPortBrowserTest); INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE( NetworkContextConfigurationProxyOnStartBrowserTest); INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE( NetworkContextConfigurationHttpPacBrowserTest); INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE( NetworkContextConfigurationFilePacBrowserTest); INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE( NetworkContextConfigurationDataPacBrowserTest); INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE( NetworkContextConfigurationFtpPacBrowserTest); INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE( NetworkContextConfigurationProxySettingsBrowserTest); INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE( NetworkContextConfigurationManagedProxySettingsBrowserTest); INSTANTIATE_TEST_CASES_FOR_TEST_FIXTURE( NetworkContextConfigurationReportingAndNelBrowserTest); } // namespace