| // 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/network_service.mojom.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" | 
 |  | 
 | namespace content { | 
 |  | 
 | namespace { | 
 |  | 
 | mojom::NetworkContextPtr CreateNetworkContext() { | 
 |   mojom::NetworkContextPtr network_context; | 
 |   mojom::NetworkContextParamsPtr context_params = | 
 |       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<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) { | 
 |   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. | 
 |   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())); | 
 |  | 
 |   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 |