| // 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 "base/test/scoped_feature_list.h" |
| #include "build/build_config.h" |
| #include "content/browser/storage_partition_impl.h" |
| #include "content/browser/url_loader_factory_getter.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/network_service_instance.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/common/content_features.h" |
| #include "content/public/common/simple_url_loader.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/content_browser_test.h" |
| #include "content/public/test/content_browser_test_utils.h" |
| #include "content/public/test/simple_url_loader_test_helper.h" |
| #include "content/shell/browser/shell.h" |
| #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" |
| #include "services/network/public/interfaces/network_service.mojom.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| network::mojom::NetworkContextPtr CreateNetworkContext() { |
| network::mojom::NetworkContextPtr network_context; |
| network::mojom::NetworkContextParamsPtr context_params = |
| network::mojom::NetworkContextParams::New(); |
| GetNetworkService()->CreateNetworkContext(mojo::MakeRequest(&network_context), |
| std::move(context_params)); |
| return network_context; |
| } |
| |
| int LoadBasicRequestOnIOThread( |
| URLLoaderFactoryGetter* url_loader_factory_getter, |
| const GURL& url) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| auto request = std::make_unique<network::ResourceRequest>(); |
| request->url = url; |
| |
| SimpleURLLoaderTestHelper simple_loader_helper; |
| // Wait for callback on UI thread to avoid nesting IO message loops. |
| simple_loader_helper.SetRunLoopQuitThread(BrowserThread::UI); |
| |
| std::unique_ptr<content::SimpleURLLoader> simple_loader = |
| content::SimpleURLLoader::Create(std::move(request), |
| TRAFFIC_ANNOTATION_FOR_TESTS); |
| |
| // |URLLoaderFactoryGetter::GetNetworkFactory()| can only be accessed on IO |
| // thread. |
| BrowserThread::PostTask( |
| BrowserThread::IO, FROM_HERE, |
| base::BindOnce( |
| [](content::SimpleURLLoader* loader, |
| URLLoaderFactoryGetter* factory_getter, |
| SimpleURLLoader::BodyAsStringCallback body_as_string_callback) { |
| loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( |
| factory_getter->GetNetworkFactory(), |
| std::move(body_as_string_callback)); |
| }, |
| base::Unretained(simple_loader.get()), |
| base::Unretained(url_loader_factory_getter), |
| simple_loader_helper.GetCallback())); |
| |
| simple_loader_helper.WaitForCallback(); |
| return simple_loader->NetError(); |
| } |
| |
| } // namespace |
| |
| // This test source has been excluded from Android as Android doesn't have |
| // out-of-process Network Service. |
| class NetworkServiceRestartBrowserTest : public ContentBrowserTest { |
| public: |
| NetworkServiceRestartBrowserTest() { |
| scoped_feature_list_.InitAndEnableFeature(features::kNetworkService); |
| EXPECT_TRUE(embedded_test_server()->Start()); |
| } |
| |
| GURL GetTestURL() const { |
| // Use '/echoheader' instead of '/echo' to avoid a disk_cache bug. |
| // See https://crbug.com/792255. |
| return embedded_test_server()->GetURL("/echoheader"); |
| } |
| |
| BrowserContext* browser_context() { |
| return shell()->web_contents()->GetBrowserContext(); |
| } |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| |
| DISALLOW_COPY_AND_ASSIGN(NetworkServiceRestartBrowserTest); |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, |
| NetworkServiceProcessRecovery) { |
| network::mojom::NetworkContextPtr network_context = CreateNetworkContext(); |
| EXPECT_EQ(net::OK, LoadBasicRequest(network_context.get(), GetTestURL())); |
| EXPECT_TRUE(network_context.is_bound()); |
| EXPECT_FALSE(network_context.encountered_error()); |
| |
| // Crash the NetworkService process. Existing interfaces should receive error |
| // notifications at some point. |
| SimulateNetworkServiceCrash(); |
| // |network_context| will receive an error notification, but it's not |
| // guaranteed to have arrived at this point. Flush the pointer to make sure |
| // the notification has been received. |
| network_context.FlushForTesting(); |
| EXPECT_TRUE(network_context.is_bound()); |
| EXPECT_TRUE(network_context.encountered_error()); |
| // Make sure we could get |net::ERR_FAILED| with an invalid |network_context|. |
| EXPECT_EQ(net::ERR_FAILED, |
| LoadBasicRequest(network_context.get(), GetTestURL())); |
| |
| // NetworkService should restart automatically and return valid interface. |
| network::mojom::NetworkContextPtr network_context2 = CreateNetworkContext(); |
| EXPECT_EQ(net::OK, LoadBasicRequest(network_context2.get(), GetTestURL())); |
| EXPECT_TRUE(network_context2.is_bound()); |
| EXPECT_FALSE(network_context2.encountered_error()); |
| } |
| |
| // Make sure |StoragePartitionImpl::GetNetworkContext()| returns valid interface |
| // after crash. |
| IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, |
| StoragePartitionImplGetNetworkContext) { |
| StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( |
| BrowserContext::GetDefaultStoragePartition(browser_context())); |
| |
| network::mojom::NetworkContext* old_network_context = |
| partition->GetNetworkContext(); |
| EXPECT_EQ(net::OK, LoadBasicRequest(old_network_context, GetTestURL())); |
| |
| // 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. |
| partition->FlushNetworkInterfaceForTesting(); |
| |
| // |partition->GetNetworkContext()| should return a valid new pointer after |
| // crash. |
| EXPECT_NE(old_network_context, partition->GetNetworkContext()); |
| EXPECT_EQ(net::OK, |
| LoadBasicRequest(partition->GetNetworkContext(), GetTestURL())); |
| } |
| |
| // Make sure |URLLoaderFactoryGetter| returns valid interface after crash. |
| IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, |
| URLLoaderFactoryGetterGetNetworkFactory) { |
| StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( |
| BrowserContext::GetDefaultStoragePartition(browser_context())); |
| scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter = |
| partition->url_loader_factory_getter(); |
| EXPECT_EQ(net::OK, LoadBasicRequestOnIOThread(url_loader_factory_getter.get(), |
| GetTestURL())); |
| // 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. |
| partition->FlushNetworkInterfaceForTesting(); |
| url_loader_factory_getter->FlushNetworkInterfaceOnIOThreadForTesting(); |
| |
| // |url_loader_factory_getter| should be able to get a valid new pointer after |
| // crash. |
| EXPECT_EQ(net::OK, LoadBasicRequestOnIOThread(url_loader_factory_getter.get(), |
| GetTestURL())); |
| } |
| |
| // Make sure basic navigation works after crash. |
| IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, |
| NavigationURLLoaderBasic) { |
| StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( |
| BrowserContext::GetDefaultStoragePartition(browser_context())); |
| |
| EXPECT_TRUE( |
| NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"))); |
| |
| // 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. |
| partition->FlushNetworkInterfaceForTesting(); |
| partition->url_loader_factory_getter() |
| ->FlushNetworkInterfaceOnIOThreadForTesting(); |
| |
| EXPECT_TRUE( |
| NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html"))); |
| } |
| |
| } // namespace content |