text:
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/json/values_util.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "content/browser/storage_partition_impl.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/url_data_source.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/browser/web_ui_controller_factory.h"
#include "content/public/common/bindings_policy.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_utils.h"
#include "content/public/test/browser_test.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/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
#include "net/base/features.h"
#include "net/cookies/cookie_util.h"
#include "net/disk_cache/disk_cache.h"
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_response_headers.h"
#include "net/test/embedded_test_server/default_handlers.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/gtest_util.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/network_switches.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/mojom/network_service_test.mojom.h"
#include "services/network/test/udp_socket_test_util.h"
#include "sql/database.h"
#include "sql/sql_features.h"

#if BUILDFLAG(IS_ANDROID)
#include "base/android/application_status_listener.h"
#endif

#if BUILDFLAG(IS_WIN)
#include "sandbox/policy/features.h"
#endif

namespace content {

namespace {

class WebUITestWebUIControllerFactory : public WebUIControllerFactory {
 public:
  std::unique_ptr<WebUIController> CreateWebUIControllerForURL(
      WebUI* web_ui,
      const GURL& url) override {
    std::string foo(url.path());
    if (url.path() == "/nobinding/")
      web_ui->SetBindings(BINDINGS_POLICY_NONE);
    return HasWebUIScheme(url) ? std::make_unique<WebUIController>(web_ui)
                               : nullptr;
  }
  WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
                             const GURL& url) override {
    return HasWebUIScheme(url) ? reinterpret_cast<WebUI::TypeID>(1) : nullptr;
  }
  bool UseWebUIForURL(BrowserContext* browser_context,
                      const GURL& url) override {
    return HasWebUIScheme(url);
  }
};

class TestWebUIDataSource : public URLDataSource {
 public:
  TestWebUIDataSource() {}

  TestWebUIDataSource(const TestWebUIDataSource&) = delete;
  TestWebUIDataSource& operator=(const TestWebUIDataSource&) = delete;

  ~TestWebUIDataSource() override {}

  std::string GetSource() override { return "webui"; }

  void StartDataRequest(const GURL& url,
                        const WebContents::Getter& wc_getter,
                        URLDataSource::GotDataCallback callback) override {
    std::move(callback).Run(base::MakeRefCounted<base::RefCountedString>(
        std::string("Foo")));
  }

  std::string GetMimeType(const GURL& url) override { return "text/html"; }
};

class NetworkServiceBrowserTest : public ContentBrowserTest {
 public:
  NetworkServiceBrowserTest() {
    EXPECT_TRUE(embedded_test_server()->Start());
    EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());

    WebUIControllerFactory::RegisterFactory(&factory_);
  }

  NetworkServiceBrowserTest(const NetworkServiceBrowserTest&) = delete;
  NetworkServiceBrowserTest& operator=(const NetworkServiceBrowserTest&) =
      delete;

  bool ExecuteScript(const std::string& script) {
    bool xhr_result = false;
    // The JS call will fail if disallowed because the process will be killed.
    bool execute_result =
        ExecuteScriptAndExtractBool(shell(), script, &xhr_result);
    return xhr_result && execute_result;
  }

  bool FetchResource(const GURL& url, bool synchronous = false) {
    if (!url.is_valid())
      return false;
    std::string script = JsReplace(
        "var xhr = new XMLHttpRequest();"
        "xhr.open('GET', $1, $2);"
        "xhr.onload = function (e) {"
        "  if (xhr.readyState === 4) {"
        "    window.domAutomationController.send(xhr.status === 200);"
        "  }"
        "};"
        "xhr.onerror = function () {"
        "  window.domAutomationController.send(false);"
        "};"
        "try {"
        "  xhr.send(null);"
        "} catch (error) {"
        "  window.domAutomationController.send(false);"
        "}",
        url, !synchronous);
    return ExecuteScript(script);
  }

  bool CheckCanLoadHttp() {
    return FetchResource(embedded_test_server()->GetURL("/echo"));
  }

  void SetUpOnMainThread() override {
    URLDataSource::Add(shell()->web_contents()->GetBrowserContext(),
                       std::make_unique<TestWebUIDataSource>());
  }

  void SetUpCommandLine(base::CommandLine* command_line) override {
    // Since we assume exploited renderer process, it can bypass the same origin
    // policy at will. Simulate that by passing the disable-web-security flag.
    command_line->AppendSwitch(switches::kDisableWebSecurity);
    IsolateAllSitesForTesting(command_line);
  }

  base::FilePath GetCacheDirectory() { return temp_dir_.GetPath(); }

  base::FilePath GetCacheIndexDirectory() {
    return GetCacheDirectory()
        .AppendASCII("Cache_Data")
        .AppendASCII("index-dir");
  }

  void LoadURL(const GURL& url,
               network::mojom::URLLoaderFactory* loader_factory) {
    std::unique_ptr<network::ResourceRequest> request =
        std::make_unique<network::ResourceRequest>();
    request->url = url;
    url::Origin origin = url::Origin::Create(url);
    request->trusted_params = network::ResourceRequest::TrustedParams();
    request->trusted_params->isolation_info =
        net::IsolationInfo::CreateForInternalRequest(origin);
    request->site_for_cookies =
        request->trusted_params->isolation_info.site_for_cookies();

    SimpleURLLoaderTestHelper simple_loader_helper;
    std::unique_ptr<network::SimpleURLLoader> 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());
  }

 private:
  WebUITestWebUIControllerFactory factory_;
  base::ScopedTempDir temp_dir_;
};

// Verifies that WebUI pages with WebUI bindings can't make network requests.
IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest, WebUIBindingsNoHttp) {
  GURL test_url(GetWebUIURL("webui/"));
  EXPECT_TRUE(NavigateToURL(shell(), test_url));
  RenderProcessHostBadIpcMessageWaiter kill_waiter(
      shell()->web_contents()->GetPrimaryMainFrame()->GetProcess());
  ASSERT_FALSE(CheckCanLoadHttp());
  EXPECT_EQ(bad_message::RPH_MOJO_PROCESS_ERROR, kill_waiter.Wait());
}

// Verifies that WebUI pages without WebUI bindings can make network requests.
IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest, NoWebUIBindingsHttp) {
  GURL test_url(GetWebUIURL("webui/nobinding/"));
  EXPECT_TRUE(NavigateToURL(shell(), test_url));
  ASSERT_TRUE(CheckCanLoadHttp());
}

// Verifies the filesystem URLLoaderFactory's check, using
// ChildProcessSecurityPolicyImpl::CanRequestURL is properly rejected.
IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest,
                       FileSystemBindingsCorrectOrigin) {
  GURL test_url(GetWebUIURL("webui/nobinding/"));
  EXPECT_TRUE(NavigateToURL(shell(), test_url));

  // Note: must be filesystem scheme (obviously).
  //       file: is not a safe web scheme (see IsWebSafeScheme),
  //       and /etc/passwd fails the CanCommitURL check.
  GURL file_url("filesystem:file:///etc/passwd");
  EXPECT_FALSE(FetchResource(file_url));
}

IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest,
                       SimpleUrlLoader_NoAuthWhenNoWebContents) {
  auto request = std::make_unique<network::ResourceRequest>();
  request->url = embedded_test_server()->GetURL("/auth-basic?password=");
  auto loader = network::SimpleURLLoader::Create(std::move(request),
                                                 TRAFFIC_ANNOTATION_FOR_TESTS);
  auto loader_factory = shell()
                            ->web_contents()
                            ->GetBrowserContext()
                            ->GetDefaultStoragePartition()
                            ->GetURLLoaderFactoryForBrowserProcess();
  scoped_refptr<net::HttpResponseHeaders> headers;
  base::RunLoop loop;
  loader->DownloadHeadersOnly(
      loader_factory.get(),
      base::BindOnce(
          [](base::OnceClosure quit_closure,
             scoped_refptr<net::HttpResponseHeaders>* rh_out,
             scoped_refptr<net::HttpResponseHeaders> rh_in) {
            *rh_out = rh_in;
            std::move(quit_closure).Run();
          },
          loop.QuitClosure(), &headers));
  loop.Run();
  ASSERT_TRUE(headers.get());
  ASSERT_EQ(headers->response_code(), 401);
}

#if BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest,
                       HttpCacheWrittenToDiskOnApplicationStateChange) {
  base::ScopedAllowBlockingForTesting allow_blocking;

  // Create network context with cache pointing to the temp cache dir.
  mojo::Remote<network::mojom::NetworkContext> network_context;
  network::mojom::NetworkContextParamsPtr context_params =
      network::mojom::NetworkContextParams::New();
  context_params->cert_verifier_params = GetCertVerifierParams(
      cert_verifier::mojom::CertVerifierCreationParams::New());
  context_params->http_cache_directory = GetCacheDirectory();
  CreateNetworkContextInNetworkService(
      network_context.BindNewPipeAndPassReceiver(), std::move(context_params));

  network::mojom::URLLoaderFactoryParamsPtr params =
      network::mojom::URLLoaderFactoryParams::New();
  params->process_id = network::mojom::kBrowserProcessId;
  params->automatically_assign_isolation_info = true;
  params->is_corb_enabled = false;
  params->is_trusted = true;
  mojo::Remote<network::mojom::URLLoaderFactory> loader_factory;
  network_context->CreateURLLoaderFactory(
      loader_factory.BindNewPipeAndPassReceiver(), std::move(params));

  // Load a URL and check the cache index size.
  LoadURL(embedded_test_server()->GetURL("/cachetime"), loader_factory.get());
  int64_t directory_size = base::ComputeDirectorySize(GetCacheIndexDirectory());

  // Load another URL, cache index should not be written to disk yet.
  LoadURL(embedded_test_server()->GetURL("/cachetime?foo"),
          loader_factory.get());
  EXPECT_EQ(directory_size,
            base::ComputeDirectorySize(GetCacheIndexDirectory()));

  // After application state changes, cache index should be written to disk.
  base::android::ApplicationStatusListener::NotifyApplicationStateChange(
      base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES);
  base::RunLoop().RunUntilIdle();
  FlushNetworkServiceInstanceForTesting();
  disk_cache::FlushCacheThreadForTesting();

  EXPECT_GT(base::ComputeDirectorySize(GetCacheIndexDirectory()),
            directory_size);
}

class NetworkConnectionObserver
    : public network::NetworkConnectionTracker::NetworkConnectionObserver {
 public:
  NetworkConnectionObserver() {
    content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
    content::GetNetworkConnectionTracker()->GetConnectionType(
        &last_connection_type_,
        base::BindOnce(&NetworkConnectionObserver::OnConnectionChanged,
                       base::Unretained(this)));
  }

  ~NetworkConnectionObserver() override {
    content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(
        this);
  }

  void WaitForConnectionType(network::mojom::ConnectionType type) {
    type_to_wait_for_ = type;
    if (last_connection_type_ == type_to_wait_for_)
      return;

    run_loop_ = std::make_unique<base::RunLoop>();
    run_loop_->Run();
  }

  // network::NetworkConnectionTracker::NetworkConnectionObserver:
  void OnConnectionChanged(network::mojom::ConnectionType type) override {
    last_connection_type_ = type;
    if (run_loop_ && type_to_wait_for_ == type)
      run_loop_->Quit();
  }

 private:
  network::mojom::ConnectionType type_to_wait_for_ =
      network::mojom::ConnectionType::CONNECTION_UNKNOWN;
  network::mojom::ConnectionType last_connection_type_ =
      network::mojom::ConnectionType::CONNECTION_UNKNOWN;
  std::unique_ptr<base::RunLoop> run_loop_;
};

IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest,
                       ConnectionTypeChangeSyncedToNetworkProcess) {
  NetworkConnectionObserver observer;
  net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
      net::NetworkChangeNotifier::CONNECTION_WIFI);
  observer.WaitForConnectionType(
      network::mojom::ConnectionType::CONNECTION_WIFI);

  net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
      net::NetworkChangeNotifier::CONNECTION_ETHERNET);
  observer.WaitForConnectionType(
      network::mojom::ConnectionType::CONNECTION_ETHERNET);
}
#endif

IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest,
                       MemoryPressureSentToNetworkProcess) {
  if (IsInProcessNetworkService())
    return;

  mojo::Remote<network::mojom::NetworkServiceTest> network_service_test;
  GetNetworkService()->BindTestInterface(
      network_service_test.BindNewPipeAndPassReceiver());
  // TODO(crbug.com/901026): Make sure the network process is started to avoid a
  // deadlock on Android.
  network_service_test.FlushForTesting();

  mojo::ScopedAllowSyncCallForTesting allow_sync_call;
  base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level =
      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
  network_service_test->GetLatestMemoryPressureLevel(&memory_pressure_level);
  EXPECT_EQ(memory_pressure_level,
            base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE);

  base::MemoryPressureListener::NotifyMemoryPressure(
      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
  base::RunLoop().RunUntilIdle();
  FlushNetworkServiceInstanceForTesting();

  network_service_test->GetLatestMemoryPressureLevel(&memory_pressure_level);
  EXPECT_EQ(memory_pressure_level,
            base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
}

// Verifies that sync XHRs don't hang if the network service crashes.
IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest, SyncXHROnCrash) {
  if (IsInProcessNetworkService())
    return;

  net::EmbeddedTestServer http_server;
  http_server.AddDefaultHandlers(GetTestDataFilePath());
  http_server.RegisterRequestMonitor(base::BindLambdaForTesting(
      [&](const net::test_server::HttpRequest& request) {
        if (request.relative_url == "/hung") {
          GetUIThreadTaskRunner({})->PostTask(
              FROM_HERE,
              base::BindOnce(&BrowserTestBase::SimulateNetworkServiceCrash,
                             base::Unretained(this)));
        }
      }));
  EXPECT_TRUE(http_server.Start());

  EXPECT_TRUE(NavigateToURL(shell(), http_server.GetURL("/empty.html")));

  FetchResource(http_server.GetURL("/hung"), true);
  // If the renderer is hung the test will hang.
}

// Verifies that sync cookie calls don't hang if the network service crashes.
IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest, SyncCookieGetOnCrash) {
  if (IsInProcessNetworkService())
    return;

  mojo::Remote<network::mojom::NetworkServiceTest> network_service_test;
  GetNetworkService()->BindTestInterface(
      network_service_test.BindNewPipeAndPassReceiver());
  network_service_test->CrashOnGetCookieList();

  EXPECT_TRUE(
      NavigateToURL(shell(), embedded_test_server()->GetURL("/empty.html")));

  ASSERT_TRUE(
      content::ExecuteScript(shell()->web_contents(), "document.cookie"));
  // If the renderer is hung the test will hang.
}

// Tests that CORS is performed by the network service when |factory_override|
// is used.
IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest, FactoryOverride) {
  class TestURLLoaderFactory final : public network::mojom::URLLoaderFactory {
   public:
    void CreateLoaderAndStart(
        mojo::PendingReceiver<network::mojom::URLLoader> receiver,
        int32_t request_id,
        uint32_t options,
        const network::ResourceRequest& resource_request,
        mojo::PendingRemote<network::mojom::URLLoaderClient> pending_client,
        const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
        override {
      mojo::Remote<network::mojom::URLLoaderClient> client(
          std::move(pending_client));
      EXPECT_EQ(resource_request.url,
                GURL("https://www.example.com/hello.txt"));
      if (resource_request.method == "OPTIONS") {
        has_received_preflight_ = true;
        auto response = network::mojom::URLResponseHead::New();
        response->headers =
            base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
        response->headers->SetHeader("access-control-allow-origin",
                                     "https://www2.example.com");
        response->headers->SetHeader("access-control-allow-methods", "*");
        client->OnReceiveResponse(std::move(response),
                                  mojo::ScopedDataPipeConsumerHandle(),
                                  absl::nullopt);
      } else if (resource_request.method == "custom-method") {
        has_received_request_ = true;
        auto response = network::mojom::URLResponseHead::New();
        response->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
            "HTTP/1.1 202 Accepted");
        response->headers->SetHeader("access-control-allow-origin",
                                     "https://www2.example.com");
        client->OnReceiveResponse(std::move(response),
                                  mojo::ScopedDataPipeConsumerHandle(),
                                  absl::nullopt);
        client->OnComplete(network::URLLoaderCompletionStatus(net::OK));
      } else {
        client->OnComplete(
            network::URLLoaderCompletionStatus(net::ERR_INVALID_ARGUMENT));
      }
    }
    void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
        override {
      NOTREACHED();
    }

    bool has_received_preflight() const { return has_received_preflight_; }
    bool has_received_request() const { return has_received_request_; }

   private:
    bool has_received_preflight_ = false;
    bool has_received_request_ = false;
  };

  // Create a request that will trigger a CORS preflight request.
  auto request = std::make_unique<network::ResourceRequest>();
  request->url = GURL("https://www.example.com/hello.txt");
  request->mode = network::mojom::RequestMode::kCors;
  request->credentials_mode = network::mojom::CredentialsMode::kSameOrigin;
  request->method = "custom-method";
  request->request_initiator =
      url::Origin::Create(GURL("https://www2.example.com/"));

  // Inject TestURLLoaderFactory as the factory override.
  auto test_loader_factory = std::make_unique<TestURLLoaderFactory>();
  mojo::Receiver<network::mojom::URLLoaderFactory> test_loader_factory_receiver(
      test_loader_factory.get());
  mojo::Remote<network::mojom::URLLoaderFactory> loader_factory_remote;
  auto loader = network::SimpleURLLoader::Create(std::move(request),
                                                 TRAFFIC_ANNOTATION_FOR_TESTS);
  auto params = network::mojom::URLLoaderFactoryParams::New();
  params->process_id = 0;
  params->factory_override = network::mojom::URLLoaderFactoryOverride::New();
  params->factory_override->overriding_factory =
      test_loader_factory_receiver.BindNewPipeAndPassRemote();
  shell()
      ->web_contents()
      ->GetBrowserContext()
      ->GetDefaultStoragePartition()
      ->GetNetworkContext()
      ->CreateURLLoaderFactory(
          loader_factory_remote.BindNewPipeAndPassReceiver(),
          std::move(params));
  scoped_refptr<net::HttpResponseHeaders> headers;

  // Perform the request.
  base::RunLoop loop;
  loader->DownloadHeadersOnly(
      loader_factory_remote.get(),
      base::BindLambdaForTesting(
          [&](scoped_refptr<net::HttpResponseHeaders> passed_headers) {
            headers = passed_headers;
            loop.Quit();
          }));
  loop.Run();
  ASSERT_TRUE(headers.get());
  EXPECT_EQ(headers->response_code(), 202);
  EXPECT_TRUE(test_loader_factory->has_received_preflight());
  EXPECT_TRUE(test_loader_factory->has_received_request());
}

// Android doesn't support PRE_ tests.
// TODO(wfh): Enable this test when https://crbug.com/1257820 is fixed.
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
class NetworkServiceBrowserCacheResetTest : public NetworkServiceBrowserTest {
 public:
  NetworkServiceBrowserCacheResetTest() = default;

 protected:
  void StoreUrl(const GURL& url) {
    base::ScopedAllowBlockingForTesting allow_blocking;

    base::FilePath data_file =
        shell()->web_contents()->GetBrowserContext()->GetPath().Append(
            FILE_PATH_LITERAL("TestData"));
    std::string data;
    base::JSONWriter::Write(base::Value(url.spec()), &data);
    EXPECT_TRUE(base::WriteFile(data_file, data));
  }

  void RetrieveUrl(GURL& url) {
    base::ScopedAllowBlockingForTesting allow_blocking;

    base::FilePath data_file =
        shell()->web_contents()->GetBrowserContext()->GetPath().Append(
            FILE_PATH_LITERAL("TestData"));
    std::string data;
    EXPECT_TRUE(base::ReadFileToString(data_file, &data));
    auto json_data = base::JSONReader::Read(data);
    ASSERT_TRUE(json_data.has_value());
    url = GURL(json_data->GetString());
    EXPECT_TRUE(url.is_valid());
  }

  base::FilePath GetNetworkContextPath() {
    return shell()->web_contents()->GetBrowserContext()->GetPath().Append(
        FILE_PATH_LITERAL("TestContext"));
  }

  base::FilePath GetNetworkContextCachePath() {
    return GetNetworkContextPath().Append(FILE_PATH_LITERAL("Cache"));
  }

  // Creates a Network context and attempts to make a request to a resource that
  // is cacheable. Returns the net error code. If `load_only_from_cache` is
  // specified then the request will fail if the resource cannot be served from
  // the cache. `url` specifies the URL to connect to on the
  // embedded_test_server host which does not need to have a server actively
  // listening on it if `load_only_from_cache` is true.
  int MakeNetworkContentAndLoadUrl(bool reset_cache,
                                   bool load_only_from_cache,
                                   const GURL& url) {
    auto file_paths = network::mojom::NetworkContextFilePaths::New();
    base::FilePath context_path = GetNetworkContextPath();
    file_paths->data_directory = context_path.Append(FILE_PATH_LITERAL("Data"));
    file_paths->unsandboxed_data_path = context_path;
    file_paths->trigger_migration = true;

    network::mojom::NetworkContextParamsPtr context_params =
        network::mojom::NetworkContextParams::New();
    context_params->file_paths = std::move(file_paths);
    context_params->cert_verifier_params = GetCertVerifierParams(
        cert_verifier::mojom::CertVerifierCreationParams::New());
    context_params->reset_http_cache_backend = reset_cache;
    context_params->http_cache_enabled = true;
    context_params->http_cache_directory = GetNetworkContextCachePath();

    mojo::Remote<network::mojom::NetworkContext> network_context;
    content::CreateNetworkContextInNetworkService(
        network_context.BindNewPipeAndPassReceiver(),
        std::move(context_params));

    network::mojom::URLLoaderFactoryParamsPtr url_loader_params =
        network::mojom::URLLoaderFactoryParams::New();
    url_loader_params->process_id = network::mojom::kBrowserProcessId;
    url_loader_params->is_trusted = true;
    mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory;
    network_context->CreateURLLoaderFactory(
        url_loader_factory.BindNewPipeAndPassReceiver(),
        std::move(url_loader_params));

    std::unique_ptr<network::ResourceRequest> request =
        std::make_unique<network::ResourceRequest>();
    request->url = url;
    url::Origin origin = url::Origin::Create(url);
    request->trusted_params = network::ResourceRequest::TrustedParams();
    request->trusted_params->isolation_info =
        net::IsolationInfo::CreateForInternalRequest(origin);
    request->site_for_cookies =
        request->trusted_params->isolation_info.site_for_cookies();

    if (load_only_from_cache)
      request->load_flags |= net::LOAD_ONLY_FROM_CACHE;
    auto loader = network::SimpleURLLoader::Create(
        std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS);

    scoped_refptr<net::HttpResponseHeaders> headers;
    base::RunLoop loop;
    loader->DownloadHeadersOnly(
        url_loader_factory.get(),
        base::BindLambdaForTesting(
            [&](scoped_refptr<net::HttpResponseHeaders> passed_headers) {
              headers = passed_headers;
              loop.Quit();
            }));
    loop.Run();
    return loader->NetError();
  }

  void GetCacheFileInfo(base::File::Info& info) {
    base::FilePath ceontxt_path = GetNetworkContextPath();
    base::FileEnumerator cache_files(GetNetworkContextCachePath(), true,
                                     base::FileEnumerator::FILES);
    // Cache entries created.
    auto file_path = cache_files.Next();
    ASSERT_FALSE(file_path.empty());
    ASSERT_TRUE(base::GetFileInfo(file_path, &info));
  }
};

// Create a network context and make an HTTP request which causes cache entry to
// be created.
IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserCacheResetTest,
                       PRE_PRE_CacheResetTest) {
  GURL url = embedded_test_server()->GetURL("/echoheadercache");
  // Store the URL so the requests made by the subsequent parts of this test
  // are to the same origin. Otherwise, the embedded test server might be
  // operating on a different port causing incorrect cache misses.
  ASSERT_NO_FATAL_FAILURE(StoreUrl(url));

  EXPECT_THAT(MakeNetworkContentAndLoadUrl(
                  /*reset_cache=*/false, /*load_only_from_cache=*/false, url),
              net::test::IsOk());
}

// Using the same network context, make an HTTP request and verify that the
// cache entry is correctly used.
IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserCacheResetTest,
                       PRE_CacheResetTest) {
  GURL url;
  ASSERT_NO_FATAL_FAILURE(RetrieveUrl(url));

  EXPECT_THAT(MakeNetworkContentAndLoadUrl(/*reset_cache=*/false,
                                           /*load_only_from_cache=*/true, url),
              net::test::IsOk());
}

// Using the same network context, reset the cache backend and verify that cache
// miss is correctly reported.
IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserCacheResetTest, CacheResetTest) {
  GURL url;
  ASSERT_NO_FATAL_FAILURE(RetrieveUrl(url));

  EXPECT_THAT(MakeNetworkContentAndLoadUrl(/*reset_cache=*/true,
                                           /*load_only_from_cache=*/true, url),
              net::test::IsError(net::ERR_CACHE_MISS));
}

#if BUILDFLAG(IS_POSIX)
IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserCacheResetTest, CacheResetFailure) {
  base::ScopedAllowBlockingForTesting allow_blocking;
  const base::FilePath path = GetNetworkContextCachePath();

  GURL url = embedded_test_server()->GetURL("/echoheadercache");

  ASSERT_TRUE(base::CreateDirectory(path));
  // Make the directory inaccessible, to see what happens when resetting the
  // cache fails.
  ASSERT_TRUE(base::SetPosixFilePermissions(path, /*mode=*/0));

  EXPECT_THAT(MakeNetworkContentAndLoadUrl(/*reset_cache=*/true,
                                           /*load_only_from_cache=*/true, url),
              net::test::IsError(net::ERR_CACHE_MISS));
}
#endif  // BUILDFLAG(IS_POSIX)
#endif  // BUILDFLAG(IS_ANDROID)

// Cache data migration is not used for Fuchsia.
#if !BUILDFLAG(IS_FUCHSIA)

const base::FilePath::CharType kCheckpointFileName[] =
    FILE_PATH_LITERAL("NetworkDataMigrated");
constexpr char kCookieName[] = "Name";
constexpr char kCookieValue[] = "Value";

net::CookieList GetCookies(
    const mojo::Remote<network::mojom::CookieManager>& cookie_manager) {
  base::RunLoop run_loop;
  net::CookieList cookies_out;
  cookie_manager->GetAllCookies(
      base::BindLambdaForTesting([&](const net::CookieList& cookies) {
        cookies_out = cookies;
        run_loop.Quit();
      }));
  run_loop.Run();
  return cookies_out;
}

void SetCookie(
    const mojo::Remote<network::mojom::CookieManager>& cookie_manager) {
  base::Time t = base::Time::Now();
  auto cookie = net::CanonicalCookie::CreateUnsafeCookieForTesting(
      kCookieName, kCookieValue, "example.test", "/", t, t + base::Days(1),
      base::Time(), base::Time(), /*secure=*/true, /*http-only=*/false,
      net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_DEFAULT,
      /*=same_party=*/false);
  base::RunLoop run_loop;
  cookie_manager->SetCanonicalCookie(
      *cookie, net::cookie_util::SimulatedCookieSource(*cookie, "https"),
      net::CookieOptions(),
      base::BindLambdaForTesting(
          [&](net::CookieAccessResult result) { run_loop.Quit(); }));
  run_loop.Run();
}

void FlushCookies(
    const mojo::Remote<network::mojom::CookieManager>& cookie_manager) {
  base::RunLoop run_loop;
  cookie_manager->FlushCookieStore(
      base::BindLambdaForTesting([&]() { run_loop.Quit(); }));
  run_loop.Run();
}

mojo::PendingRemote<network::mojom::NetworkContext>
CreateNetworkContextForPaths(network::mojom::NetworkContextFilePathsPtr paths,
                             const base::FilePath& cache_path) {
  network::mojom::NetworkContextParamsPtr context_params =
      network::mojom::NetworkContextParams::New();
  context_params->file_paths = std::move(paths);
  context_params->cert_verifier_params = GetCertVerifierParams(
      cert_verifier::mojom::CertVerifierCreationParams::New());
  // Not passing in a key for simplicity, so disable encryption.
  context_params->enable_encrypted_cookies = false;
  context_params->http_cache_enabled = true;
  context_params->http_cache_directory = cache_path;
  mojo::PendingRemote<network::mojom::NetworkContext> network_context;
  content::CreateNetworkContextInNetworkService(
      network_context.InitWithNewPipeAndPassReceiver(),
      std::move(context_params));
  return network_context;
}

enum class FailureType {
  kNoFailures = 0,
  // A file exists with the same name as the target directory so it cannot be
  // created.
  kDirIsAFile = 1,
  // The target migration directory already exists.
  kDirAlreadyThere = 2,
  // A file called 'TestCookies' already exists in the migration target
  // directory.
  kCookieFileAlreadyThere = 3,
#if BUILDFLAG(IS_WIN)
  // The 'TestCookies' file in the destination directory is locked and cannot be
  // written to. This is only valid on Windows where files can actually be
  // locked.
  kDestCookieFileIsLocked = 4,
  // The 'TestCookies' file in the source directory is locked and cannot be read
  // from (during the migration). This failure is only valid on Windows where
  // files can actually be locked.
  kSourceCookieFileIsLocked = 5,
#endif  // BUILDFLAG(IS_WIN)
  // A file exists with the same name as the Cache dir. This will cause the
  // creation of the cache dir to fail, and cache to not function either
  // (although we don't test for that here).
  kCacheDirIsAFile = 6,
};

static const FailureType kFailureTypes[] = {
    FailureType::kNoFailures,
    FailureType::kDirIsAFile,
    FailureType::kDirAlreadyThere,
    FailureType::kCookieFileAlreadyThere,
#if BUILDFLAG(IS_WIN)
    FailureType::kDestCookieFileIsLocked,
    FailureType::kSourceCookieFileIsLocked,
#endif  // BUILDFLAG(IS_WIN)
    FailureType::kCacheDirIsAFile};

static const base::FilePath::CharType kCookieDatabaseName[] =
    FILE_PATH_LITERAL("TestCookies");
static const base::FilePath::CharType kNetworkSubpath[] =
    FILE_PATH_LITERAL("Network");

// Disable the following data migration tests on Android because the data
// migration logic is disabled and compiled out on this platform.
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_NetworkServiceDataMigrationBrowserTest \
  DISABLED_NetworkServiceDataMigrationBrowserTest
#define MAYBE_NetworkServiceDataMigrationBrowserTestWithFailures \
  DISABLED_NetworkServiceDataMigrationBrowserTestWithFailures
#else
#define MAYBE_NetworkServiceDataMigrationBrowserTest \
  NetworkServiceDataMigrationBrowserTest
#define MAYBE_NetworkServiceDataMigrationBrowserTestWithFailures \
  NetworkServiceDataMigrationBrowserTestWithFailures
#endif  // BUILDFLAG(IS_ANDROID)

// A class to test various behavior of network context data migration.
class MAYBE_NetworkServiceDataMigrationBrowserTest : public ContentBrowserTest {
 public:
  MAYBE_NetworkServiceDataMigrationBrowserTest() {
    // Migration only supports non-WAL sqlite databases. If this feature is
    // switched on by default before migration has been completed then the code
    // in MaybeGrantSandboxAccessToNetworkContextData will need to be updated.
    EXPECT_FALSE(
        base::FeatureList::IsEnabled(sql::features::kEnableWALModeByDefault));
#if BUILDFLAG(IS_WIN)
    // On Windows, the network sandbox needs to be disabled. This is because the
    // code that performs the migration on Windows DCHECKs if network sandbox is
    // enabled and migration is not requested, but this is used in the tests to
    // verify this behavior.
    win_network_sandbox_feature_.InitAndDisableFeature(
        sandbox::policy::features::kNetworkServiceSandbox);
#endif
  }

#if BUILDFLAG(IS_WIN)
 private:
  base::test::ScopedFeatureList win_network_sandbox_feature_;
#endif
};

// A parameterized test fixture that can simulate various failures in the
// migration step, and can also be run with either in-process or out-of-process
// network service.
class MAYBE_NetworkServiceDataMigrationBrowserTestWithFailures
    : public MAYBE_NetworkServiceDataMigrationBrowserTest,
      public ::testing::WithParamInterface<std::tuple<bool, FailureType>> {
 public:
  MAYBE_NetworkServiceDataMigrationBrowserTestWithFailures() {
    if (IsNetworkServiceRunningInProcess())
      network_service_in_process_feature_.InitAndEnableFeature(
          features::kNetworkServiceInProcess);
  }

 protected:
  bool IsNetworkServiceRunningInProcess() { return std::get<0>(GetParam()); }
  FailureType GetFailureType() { return std::get<1>(GetParam()); }

 private:
  base::test::ScopedFeatureList network_service_in_process_feature_;
};

// A function to verify that data files move during migration to sandboxed data
// dir. This function uses three directories to verify the behavior. It uses the
// cookies file to verify the migration occurs correctly.
//
// Testing takes place under the browser context path. First, a network context
// is created in temp dir 'one' and then a cookie is written and flushed to
// disk. This results in cookie files(s) being created on disk.
//
// BrowserContext/
// |- tempdir 'one'/ (`tempdir_one` FilePath)
// |  |- Cookies
// |  |- Cookies-journal
//
// The entire 'one' dir is then copied into a new 'two' temp folder to create
// the directory structure used for migration. This is so a second network
// context can be created in the same network service.
//
// BrowserContext/
// |- tempdir 'one'/
// |  |- Cookies
// |  |- Cookies-journal
// |- tempdir 'two'/ (`tempdir_two` FilePath)
// |  |- Cookies (copied from above)
// |  |- Cookies-journal (copied from above)
//
// A new network context is then created with `unsandboxed_data_path` set to
// root of tempdir 'two' and `data_directory` set to a directory underneath
// tempdir 'two' called 'Network' to initiate the migration. After a successful
// migration, the structure should look like this:
//
// BrowserContext/
// |- tempdir 'one'/
// |  |- Cookies
// |  |- Cookies-journal
// |- tempdir 'two'/
// |  |- Network/
// |  |  |- Cookies (migrated from tempdir 'two')
// |  |  |- Cookies-journal (migrated from tempdir 'two')
//
// This test injects various failures in the migration process to ensure that
// the network context still functions correctly if the Cookies file cannot be
// migrated.
void MigrationTestInternal(const base::FilePath& tempdir_one,
                           const base::FilePath& tempdir_two_parent,
                           FailureType failure_type) {
  EXPECT_FALSE(base::PathExists(tempdir_one.Append(kCookieDatabaseName)));

  auto file_paths = network::mojom::NetworkContextFilePaths::New();
  file_paths->data_directory = tempdir_one;
  file_paths->cookie_database_name = base::FilePath(kCookieDatabaseName);

  mojo::Remote<network::mojom::NetworkContext> network_context_one(
      CreateNetworkContextForPaths(
          std::move(file_paths),
          tempdir_one.Append(FILE_PATH_LITERAL("Cache"))));
  mojo::Remote<network::mojom::CookieManager> cookie_manager_one;
  network_context_one->GetCookieManager(
      cookie_manager_one.BindNewPipeAndPassReceiver());

  SetCookie(cookie_manager_one);
  FlushCookies(cookie_manager_one);

  // Verify that the cookie file exists in tempdir 'one'.
  EXPECT_TRUE(base::PathExists(tempdir_one.Append(kCookieDatabaseName)));

  // Now, copy the entire directory to tempdir 'two' to verify the migration.
  EXPECT_TRUE(base::CopyDirectory(tempdir_one, tempdir_two_parent, true));
  // base::CopyDirectory copies the directory into a new directory if the target
  // directory already exists, so fix up the directory name here.
  base::FilePath tempdir_two =
      tempdir_two_parent.Append(tempdir_one.BaseName());

  // Verify cookie file is there, copied across from the tempdir 'one'.
  EXPECT_TRUE(base::PathExists(tempdir_two.Append(kCookieDatabaseName)));
#if BUILDFLAG(IS_WIN)
  base::File longer_lived_file;
#endif

  switch (failure_type) {
    case FailureType::kNoFailures:
      break;
    case FailureType::kDirIsAFile: {
      // Create a file called 'Network' in the path. This will cause migration
      // to fail catastrophically as the directory cannot be created.
      base::File scoped_file(
          tempdir_two.Append(kNetworkSubpath),
          base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
      EXPECT_TRUE(scoped_file.IsValid());
    } break;
    case FailureType::kDirAlreadyThere:
      EXPECT_TRUE(base::CreateDirectory(tempdir_two.Append(kNetworkSubpath)));
      break;
    case FailureType::kCookieFileAlreadyThere: {
      EXPECT_TRUE(base::CreateDirectory(tempdir_two.Append(kNetworkSubpath)));
      // Touch a file in the new dir called the same as the cookie file. This
      // should be correctly overwritten by the migration code.
      base::File scoped_file(
          tempdir_two.Append(kNetworkSubpath).Append(kCookieDatabaseName),
          base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
      EXPECT_TRUE(scoped_file.IsValid());
    } break;
#if BUILDFLAG(IS_WIN)
    case FailureType::kDestCookieFileIsLocked:
      // Create a file called 'TestCookies' in the destination path and hold a
      // write lock on it so it can't be written to.
      EXPECT_TRUE(base::CreateDirectory(tempdir_two.Append(kNetworkSubpath)));
      longer_lived_file = base::File(
          tempdir_two.Append(kNetworkSubpath).Append(kCookieDatabaseName),
          base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
              base::File::FLAG_WIN_EXCLUSIVE_WRITE |
              base::File::FLAG_WIN_EXCLUSIVE_READ);
      EXPECT_TRUE(longer_lived_file.IsValid());
      break;
    case FailureType::kSourceCookieFileIsLocked:
      // Lock the Cookie file so it can't be read. This causes cookies to break
      // entirely, both the migration and the normal operation. The test can
      // merely verify that the migration fails and the failure is reported
      // correctly.
      longer_lived_file =
          base::File(tempdir_two.Append(kCookieDatabaseName),
                     base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE |
                         base::File::FLAG_WIN_EXCLUSIVE_WRITE |
                         base::File::FLAG_WIN_EXCLUSIVE_READ);
      EXPECT_TRUE(longer_lived_file.IsValid());
      break;
#endif  // BUILDFLAG(IS_WIN)
    case FailureType::kCacheDirIsAFile: {
      // Make the cache directory invalid by deleting it and making it a file,
      // so it can't be created or used.
      base::DeletePathRecursively(
          tempdir_two.Append(FILE_PATH_LITERAL("Cache")));
      base::File scoped_file(
          tempdir_two.Append(FILE_PATH_LITERAL("Cache")),
          base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
      EXPECT_TRUE(scoped_file.IsValid());
    } break;
  }
  // Create a new network context that will migrate the files from the tempdir
  // 'two' into the new 'Network' directory underneath.
  auto new_file_paths = network::mojom::NetworkContextFilePaths::New();
  // Data path is now a new 'Network' directory under the tempdir 'two'.
  new_file_paths->data_directory = tempdir_two.Append(kNetworkSubpath);
  new_file_paths->cookie_database_name = base::FilePath(kCookieDatabaseName);
  // Migrate data from the tempdir 'two' to the new path under 'Network'.
  new_file_paths->unsandboxed_data_path = tempdir_two;
  new_file_paths->trigger_migration = true;

  base::HistogramTester histogram_tester;
  mojo::Remote<network::mojom::NetworkContext> network_context_two(
      CreateNetworkContextForPaths(
          std::move(new_file_paths),
          tempdir_two.Append(FILE_PATH_LITERAL("Cache"))));
  mojo::Remote<network::mojom::CookieManager> cookie_manager_two;
  network_context_two->GetCookieManager(
      cookie_manager_two.BindNewPipeAndPassReceiver());
  net::CookieList cookies = GetCookies(cookie_manager_two);

  bool cookies_should_work = true;

  switch (failure_type) {
    case FailureType::kNoFailures:
    case FailureType::kDirAlreadyThere:
    case FailureType::kCookieFileAlreadyThere:
      // Cookie file should have moved from the original `unsandboxed_data_path`
      // to the new 'Network' path.
      EXPECT_FALSE(base::PathExists(tempdir_two.Append(kCookieDatabaseName)));
      // Into the new directory.
      EXPECT_TRUE(base::PathExists(
          tempdir_two.Append(kNetworkSubpath).Append(kCookieDatabaseName)));
      // If there was a journal file in the original `unsandboxed_data_path`,
      // check that it has also moved.
      if (base::PathExists(tempdir_one.Append(sql::Database::JournalPath(
              base::FilePath(kCookieDatabaseName))))) {
        EXPECT_FALSE(base::PathExists(tempdir_two.Append(
            sql::Database::JournalPath(base::FilePath(kCookieDatabaseName)))));
        EXPECT_TRUE(
            base::PathExists(tempdir_two.Append(kNetworkSubpath)
                                 .Append(sql::Database::JournalPath(
                                     base::FilePath(kCookieDatabaseName)))));
      }

      histogram_tester.ExpectUniqueSample("NetworkService.GrantSandboxResult",
                                          /*sample=kSuccess=*/0,
                                          /*expected_bucket_count=*/1);
      // Checkpoint file should have been placed into the migrated directory.
      EXPECT_TRUE(base::PathExists(
          tempdir_two.Append(kNetworkSubpath).Append(kCheckpointFileName)));
      break;
    case FailureType::kDirIsAFile:
      // Cookie file should still be in the original `unsandboxed_data_path` as
      // it could not be moved.
      EXPECT_TRUE(base::PathExists(tempdir_two.Append(kCookieDatabaseName)));
      EXPECT_FALSE(base::PathExists(
          tempdir_two.Append(kNetworkSubpath).Append(kCheckpointFileName)));
      histogram_tester.ExpectUniqueSample(
          "NetworkService.GrantSandboxToCacheResult", /*sample=kSuccess=*/0,
          /*expected_bucket_count=*/1);
      histogram_tester.ExpectUniqueSample(
          "NetworkService.GrantSandboxResult",
          /*sample=kFailedToCreateDataDirectory=*/2,
          /*expected_bucket_count=*/1);
      break;
#if BUILDFLAG(IS_WIN)
    case FailureType::kDestCookieFileIsLocked:
      // Cookie file should still be in the original `unsandboxed_data_path` as
      // it could not be moved as the destination was locked or not writable.
      EXPECT_TRUE(base::PathExists(tempdir_two.Append(kCookieDatabaseName)));
      // Source file is there, but locked.
      EXPECT_TRUE(base::PathExists(tempdir_two.Append(kCookieDatabaseName)));
      // And locked destination file is there, but cookies are working so they
      // must be backed by the original file.
      EXPECT_TRUE(
          base::PathExists(tempdir_two.Append(FILE_PATH_LITERAL("Network"))
                               .Append(kCookieDatabaseName)));
      EXPECT_FALSE(base::PathExists(
          tempdir_two.Append(kNetworkSubpath).Append(kCheckpointFileName)));
      {
        base::File attempt_to_open_locked_file(
            tempdir_two.Append(kNetworkSubpath).Append(kCookieDatabaseName),
            base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ);
        // Check that the file really is locked, so the cookies must be running
        // from the unsandboxed directory.
        EXPECT_FALSE(attempt_to_open_locked_file.IsValid());
      }
      histogram_tester.ExpectUniqueSample("NetworkService.GrantSandboxResult",
                                          /*sample=kFailedToCopyData=*/3,
                                          /*expected_bucket_count=*/1);
      break;
    case FailureType::kSourceCookieFileIsLocked:
      // Cookie file should still be in the original `unsandboxed_data_path` as
      // it could not be moved as the destination was locked or not writable.
      EXPECT_TRUE(base::PathExists(tempdir_two.Append(kCookieDatabaseName)));
      // File hasn't moved, so cookies must be backed by the original file.
      EXPECT_FALSE(base::PathExists(
          tempdir_two.Append(kNetworkSubpath).Append(kCookieDatabaseName)));
      EXPECT_FALSE(base::PathExists(
          tempdir_two.Append(kNetworkSubpath).Append(kCheckpointFileName)));
      histogram_tester.ExpectUniqueSample("NetworkService.GrantSandboxResult",
                                          /*sample=kFailedToCopyData=*/3,
                                          /*expected_bucket_count=*/1);
      // In this case the source cookie file can't be read by anything including
      // the migration code and the network context, so cookies should be
      // totally broken. :(
      cookies_should_work = false;
      break;
#endif  // BUILDFLAG(IS_WIN)
    case FailureType::kCacheDirIsAFile:
      histogram_tester.ExpectUniqueSample(
          "NetworkService.GrantSandboxToCacheResult",
          /*sample=kFailedToCreateCacheDirectory=*/1,
          /*expected_bucket_count=*/1);
      histogram_tester.ExpectUniqueSample("NetworkService.GrantSandboxResult",
                                          /*sample=kSuccess=*/0,
                                          /*expected_bucket_count=*/1);
      break;
  }
  if (!cookies_should_work)
    return;

  ASSERT_EQ(1u, cookies.size());
  EXPECT_EQ(kCookieName, cookies[0].Name());
  EXPECT_EQ(kCookieValue, cookies[0].Value());
}

IN_PROC_BROWSER_TEST_P(MAYBE_NetworkServiceDataMigrationBrowserTestWithFailures,
                       MigrateDataTest) {
  base::ScopedAllowBlockingForTesting allow_blocking;

  base::FilePath tempdir_one;
  EXPECT_TRUE(base::CreateTemporaryDirInDir(
      shell()->web_contents()->GetBrowserContext()->GetPath(),
      /*prefix=*/FILE_PATH_LITERAL("one"), &tempdir_one));
  base::FilePath tempdir_two;
  EXPECT_TRUE(base::CreateTemporaryDirInDir(
      shell()->web_contents()->GetBrowserContext()->GetPath(),
      /*prefix=*/FILE_PATH_LITERAL("two"), &tempdir_two));
  MigrationTestInternal(tempdir_one, tempdir_two, GetFailureType());
}

// This test is similar to the test above that uses two directories, but it uses
// a third directory to verify that if a migration is triggered and then later
// not triggered, then the data is still read from the new directory and not the
// old one.
IN_PROC_BROWSER_TEST_F(MAYBE_NetworkServiceDataMigrationBrowserTest,
                       MigrateThenNoMigrate) {
  base::ScopedAllowBlockingForTesting allow_blocking;

  base::FilePath tempdir_one;
  EXPECT_TRUE(base::CreateTemporaryDirInDir(
      shell()->web_contents()->GetBrowserContext()->GetPath(),
      /*prefix=*/FILE_PATH_LITERAL("one"), &tempdir_one));
  base::FilePath tempdir_two;
  EXPECT_TRUE(base::CreateTemporaryDirInDir(
      shell()->web_contents()->GetBrowserContext()->GetPath(),
      /*prefix=*/FILE_PATH_LITERAL("two"), &tempdir_two));
  // Migrate within tempdir_two.
  MigrationTestInternal(tempdir_one, tempdir_two, FailureType::kNoFailures);
  // base::CopyDirectory copies the directory into a new directory if the target
  // directory already exists, so fix up the directory name here.
  base::FilePath real_tempdir_two = tempdir_two.Append(tempdir_one.BaseName());
  // Double check that the migration happened.
  EXPECT_TRUE(base::PathExists(
      real_tempdir_two.Append(kNetworkSubpath).Append(kCookieDatabaseName)));
  // Create a third testing directory, and copy the migrated data from
  // tempdir_two into it.
  base::FilePath tempdir_three;
  EXPECT_TRUE(base::CreateTemporaryDirInDir(
      shell()->web_contents()->GetBrowserContext()->GetPath(),
      /*prefix=*/FILE_PATH_LITERAL("three"), &tempdir_three));
  EXPECT_TRUE(base::CopyDirectory(real_tempdir_two, tempdir_three, true));
  // base::CopyDirectory copies the directory into a new directory if the target
  // directory already exists, so fix up the directory name here.
  base::FilePath real_tempdir_three =
      tempdir_three.Append(real_tempdir_two.BaseName());
  // Double check the directory was copied right.
  EXPECT_TRUE(base::PathExists(
      real_tempdir_three.Append(kNetworkSubpath).Append(kCookieDatabaseName)));
  // Double check cookies are not in the old directory, meaning if they work
  // they must have been read from the new directory.
  EXPECT_FALSE(
      base::PathExists(real_tempdir_three.Append(kCookieDatabaseName)));

  base::HistogramTester histogram_tester;
  // Now create a new network context with migration set to false (default) but
  // pointing to the migrated directory. This verifies that even if no migration
  // is requested, the migrated data is still read correctly and that migration
  // is a one-way operation.
  auto file_paths = network::mojom::NetworkContextFilePaths::New();
  file_paths->data_directory = real_tempdir_three.Append(kNetworkSubpath);
  file_paths->unsandboxed_data_path = real_tempdir_three;
  file_paths->cookie_database_name = base::FilePath(kCookieDatabaseName);
  // If defaults are ever changed, this test will need to be updated.
  DCHECK_EQ(file_paths->trigger_migration, false);
  mojo::Remote<network::mojom::NetworkContext> network_context(
      CreateNetworkContextForPaths(
          std::move(file_paths),
          real_tempdir_three.Append(FILE_PATH_LITERAL("Cache"))));
  mojo::Remote<network::mojom::CookieManager> cookie_manager;
  network_context->GetCookieManager(
      cookie_manager.BindNewPipeAndPassReceiver());

  net::CookieList cookies = GetCookies(cookie_manager);
  histogram_tester.ExpectUniqueSample("NetworkService.GrantSandboxResult",
                                      /*sample=kMigrationAlreadySucceeded=*/10,
                                      /*expected_bucket_count=*/1);
  // Cookies work.
  ASSERT_EQ(1u, cookies.size());
  EXPECT_EQ(kCookieName, cookies[0].Name());
  EXPECT_EQ(kCookieValue, cookies[0].Value());
}

// This test verifies that a new un-used data path will be initialized correctly
// if `unsandboxed_data_path` is set. The Cookie file should be placed into the
// `data_directory` and not `unsandboxed_data_path`.
IN_PROC_BROWSER_TEST_F(MAYBE_NetworkServiceDataMigrationBrowserTest,
                       NewDataDirWithMigrationTest) {
  base::ScopedAllowBlockingForTesting allow_blocking;

  base::FilePath tempdir;
  EXPECT_TRUE(base::CreateTemporaryDirInDir(
      shell()->web_contents()->GetBrowserContext()->GetPath(),
      /*prefix=*/FILE_PATH_LITERAL(""), &tempdir));

  EXPECT_FALSE(base::PathExists(tempdir.Append(kCookieDatabaseName)));

  auto file_paths = network::mojom::NetworkContextFilePaths::New();
  file_paths->data_directory = tempdir.Append(FILE_PATH_LITERAL("Network"));
  file_paths->unsandboxed_data_path = tempdir;
  file_paths->cookie_database_name = base::FilePath(kCookieDatabaseName);
  file_paths->trigger_migration = true;
  base::HistogramTester histogram_tester;

  mojo::Remote<network::mojom::NetworkContext> network_context(
      CreateNetworkContextForPaths(std::move(file_paths),
                                   tempdir.Append(FILE_PATH_LITERAL("Cache"))));
  mojo::Remote<network::mojom::CookieManager> cookie_manager;
  network_context->GetCookieManager(
      cookie_manager.BindNewPipeAndPassReceiver());

  SetCookie(cookie_manager);
  FlushCookies(cookie_manager);

  // Verify that the cookie file exists in the `data_directory` and not the
  // `unsandboxed_data_path`.
  EXPECT_FALSE(base::PathExists(tempdir.Append(kCookieDatabaseName)));
  EXPECT_TRUE(base::PathExists(tempdir.Append(FILE_PATH_LITERAL("Network"))
                                   .Append(kCookieDatabaseName)));

  net::CookieList cookies = GetCookies(cookie_manager);
  histogram_tester.ExpectUniqueSample("NetworkService.GrantSandboxResult",
                                      /*sample=kSuccess=*/0,
                                      /*expected_bucket_count=*/1);
  // Cookie should be there.
  ASSERT_EQ(1u, cookies.size());
  EXPECT_EQ(kCookieName, cookies[0].Name());
  EXPECT_EQ(kCookieValue, cookies[0].Value());
}

// A test where a caller specifies both `data_directory` and
// `unsandboxed_data_path` but does not wish migration to occur. The data should
// be in `unsandboxed_data_path` in this case.
IN_PROC_BROWSER_TEST_F(MAYBE_NetworkServiceDataMigrationBrowserTest,
                       NewDataDirWithNoMigrationTest) {
  base::ScopedAllowBlockingForTesting allow_blocking;

  base::FilePath tempdir;
  EXPECT_TRUE(base::CreateTemporaryDirInDir(
      shell()->web_contents()->GetBrowserContext()->GetPath(),
      /*prefix=*/FILE_PATH_LITERAL(""), &tempdir));

  EXPECT_FALSE(base::PathExists(tempdir.Append(kCookieDatabaseName)));

  auto file_paths = network::mojom::NetworkContextFilePaths::New();
  file_paths->data_directory = tempdir.Append(FILE_PATH_LITERAL("Network"));
  file_paths->unsandboxed_data_path = tempdir;
  file_paths->cookie_database_name = base::FilePath(kCookieDatabaseName);
  file_paths->trigger_migration = false;
  base::HistogramTester histogram_tester;

  mojo::Remote<network::mojom::NetworkContext> network_context(
      CreateNetworkContextForPaths(std::move(file_paths),
                                   tempdir.Append(FILE_PATH_LITERAL("Cache"))));
  mojo::Remote<network::mojom::CookieManager> cookie_manager;
  network_context->GetCookieManager(
      cookie_manager.BindNewPipeAndPassReceiver());

  SetCookie(cookie_manager);
  FlushCookies(cookie_manager);

  // Verify that the cookie file still exists in the `unsandboxed_data_path`.
  EXPECT_TRUE(base::PathExists(tempdir.Append(kCookieDatabaseName)));
  // Verify that the cookie file has not been migrated to `data_directory`.
  EXPECT_FALSE(base::PathExists(tempdir.Append(FILE_PATH_LITERAL("Network"))
                                    .Append(kCookieDatabaseName)));
  // Verify no checkpoint file was written either.
  EXPECT_FALSE(base::PathExists(tempdir.Append(FILE_PATH_LITERAL("Network"))
                                    .Append(kCheckpointFileName)));

  net::CookieList cookies = GetCookies(cookie_manager);
  histogram_tester.ExpectUniqueSample("NetworkService.GrantSandboxResult",
                                      /*sample=kNoMigrationRequested=*/9,
                                      /*expected_bucket_count=*/1);

  // Cookie should be there.
  ASSERT_EQ(1u, cookies.size());
  EXPECT_EQ(kCookieName, cookies[0].Name());
  EXPECT_EQ(kCookieValue, cookies[0].Value());
}

// A test where a caller specifies `data_directory` but does not specify
// anything else, including `unsandboxed_data_path`. This verifies that existing
// behavior remains the same for call-sites that do not update anything.
IN_PROC_BROWSER_TEST_F(MAYBE_NetworkServiceDataMigrationBrowserTest,
                       LegacyDataDir) {
  base::ScopedAllowBlockingForTesting allow_blocking;

  base::FilePath tempdir;
  EXPECT_TRUE(base::CreateTemporaryDirInDir(
      shell()->web_contents()->GetBrowserContext()->GetPath(),
      /*prefix=*/FILE_PATH_LITERAL(""), &tempdir));

  EXPECT_FALSE(base::PathExists(tempdir.Append(kCookieDatabaseName)));

  auto file_paths = network::mojom::NetworkContextFilePaths::New();
  file_paths->data_directory = tempdir;
  file_paths->cookie_database_name = base::FilePath(kCookieDatabaseName);

  base::HistogramTester histogram_tester;
  mojo::Remote<network::mojom::NetworkContext> network_context(
      CreateNetworkContextForPaths(std::move(file_paths),
                                   tempdir.Append(FILE_PATH_LITERAL("Cache"))));
  mojo::Remote<network::mojom::CookieManager> cookie_manager;
  network_context->GetCookieManager(
      cookie_manager.BindNewPipeAndPassReceiver());

  SetCookie(cookie_manager);
  FlushCookies(cookie_manager);

  // Verify that the cookie file exists in the `unsandboxed_data_path`.
  EXPECT_TRUE(base::PathExists(tempdir.Append(kCookieDatabaseName)));

  net::CookieList cookies = GetCookies(cookie_manager);
  histogram_tester.ExpectUniqueSample(
      "NetworkService.GrantSandboxResult",
      /*sample=kDidNotAttemptToGrantSandboxAccess=*/7,
      /*expected_bucket_count=*/1);

  // Cookie should be there.
  ASSERT_EQ(1u, cookies.size());
  EXPECT_EQ(kCookieName, cookies[0].Name());
  EXPECT_EQ(kCookieValue, cookies[0].Value());
}

// This test is similar to the tests above that use two directories, but uses a
// third directory to verify that if a migration has previously occurred using
// the previous code without the checkpoint file, and then later takes place
// using the new code, then the data is still read from the correct directory
// despite there not being a checkpoint file prior to the migration.
IN_PROC_BROWSER_TEST_F(MAYBE_NetworkServiceDataMigrationBrowserTest,
                       MigratedPreviouslyAndMigrateAgain) {
  base::ScopedAllowBlockingForTesting allow_blocking;

  base::FilePath tempdir_one;
  EXPECT_TRUE(base::CreateTemporaryDirInDir(
      shell()->web_contents()->GetBrowserContext()->GetPath(),
      /*prefix=*/FILE_PATH_LITERAL("one"), &tempdir_one));
  base::FilePath tempdir_two;
  EXPECT_TRUE(base::CreateTemporaryDirInDir(
      shell()->web_contents()->GetBrowserContext()->GetPath(),
      /*prefix=*/FILE_PATH_LITERAL("two"), &tempdir_two));
  // Migrate within tempdir_two.
  MigrationTestInternal(tempdir_one, tempdir_two, FailureType::kNoFailures);
  // base::CopyDirectory copies the directory into a new directory if the target
  // directory already exists, so fix up the directory name here.
  base::FilePath real_tempdir_two = tempdir_two.Append(tempdir_one.BaseName());
  // Double check that the migration happened.
  EXPECT_TRUE(base::PathExists(
      real_tempdir_two.Append(kNetworkSubpath).Append(kCookieDatabaseName)));
  // Create a third testing directory, and copy the migrated data from
  // tempdir_two into it.
  base::FilePath tempdir_three;
  EXPECT_TRUE(base::CreateTemporaryDirInDir(
      shell()->web_contents()->GetBrowserContext()->GetPath(),
      /*prefix=*/FILE_PATH_LITERAL("three"), &tempdir_three));
  EXPECT_TRUE(base::CopyDirectory(real_tempdir_two, tempdir_three, true));
  // base::CopyDirectory copies the directory into a new directory if the target
  // directory already exists, so fix up the directory name here.
  base::FilePath real_tempdir_three =
      tempdir_three.Append(real_tempdir_two.BaseName());
  // Double check the directory was copied right.
  EXPECT_TRUE(base::PathExists(
      real_tempdir_three.Append(kNetworkSubpath).Append(kCookieDatabaseName)));
  // Double check cookies are not in the old directory, meaning if they work
  // they must have been read from the new directory.
  EXPECT_FALSE(
      base::PathExists(real_tempdir_three.Append(kCookieDatabaseName)));
  base::FilePath checkpoint_file =
      real_tempdir_three.Append(kNetworkSubpath).Append(kCheckpointFileName);
  // The directory should be fully migrated.
  EXPECT_TRUE(base::PathExists(checkpoint_file));
  // Delete the checkpoint file. This simulates that the directory was
  // previously migrated before the concept of a checkpoint file had been
  // introduced.
  EXPECT_TRUE(base::DeleteFile(checkpoint_file));
  // Test would be invalid if the delete failed.
  EXPECT_FALSE(base::PathExists(checkpoint_file));

  base::HistogramTester histogram_tester;
  auto file_paths = network::mojom::NetworkContextFilePaths::New();
  file_paths->data_directory = real_tempdir_three.Append(kNetworkSubpath);
  file_paths->unsandboxed_data_path = real_tempdir_three;
  file_paths->cookie_database_name = base::FilePath(kCookieDatabaseName);
  file_paths->trigger_migration = true;
  mojo::Remote<network::mojom::NetworkContext> network_context(
      CreateNetworkContextForPaths(
          std::move(file_paths),
          real_tempdir_three.Append(FILE_PATH_LITERAL("Cache"))));
  mojo::Remote<network::mojom::CookieManager> cookie_manager;
  network_context->GetCookieManager(
      cookie_manager.BindNewPipeAndPassReceiver());

  net::CookieList cookies = GetCookies(cookie_manager);
  // Success is reported here because although no files were copied from
  // `unsandboxed_data_path` to `data_directory`, the migration still succeeded
  // because a fresh Checkpoint file was placed down, and existing files were
  // preserved in the `data_directory`.
  histogram_tester.ExpectUniqueSample("NetworkService.GrantSandboxResult",
                                      /*sample=kSuccess=*/0,
                                      /*expected_bucket_count=*/1);

  // Cookies work.
  ASSERT_EQ(1u, cookies.size());
  EXPECT_EQ(kCookieName, cookies[0].Name());
  EXPECT_EQ(kCookieValue, cookies[0].Value());

  EXPECT_TRUE(base::PathExists(checkpoint_file));
}

// Disable instantiation of parametrized tests for disk access sandboxing on
// Android.
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_InProcess DISABLED_InProcess
#define MAYBE_OutOfProcess DISABLED_OutOfProcess
#else
#define MAYBE_InProcess InProcess
#define MAYBE_OutOfProcess OutOfProcess
#endif  // BUILDFLAG(IS_ANDROID)

INSTANTIATE_TEST_SUITE_P(
    MAYBE_InProcess,
    MAYBE_NetworkServiceDataMigrationBrowserTestWithFailures,
    ::testing::Combine(::testing::Values(true),
                       ::testing::ValuesIn(kFailureTypes)));
INSTANTIATE_TEST_SUITE_P(
    MAYBE_OutOfProcess,
    MAYBE_NetworkServiceDataMigrationBrowserTestWithFailures,
    ::testing::Combine(::testing::Values(false),
                       ::testing::ValuesIn(kFailureTypes)));

#endif  // !BUILDFLAG(IS_FUCHSIA)

class NetworkServiceInProcessBrowserTest : public ContentBrowserTest {
 public:
  NetworkServiceInProcessBrowserTest() {
    std::vector<base::test::FeatureRef> features;
    features.push_back(features::kNetworkServiceInProcess);
    scoped_feature_list_.InitWithFeatures(
        features, std::vector<base::test::FeatureRef>());
  }

  NetworkServiceInProcessBrowserTest(
      const NetworkServiceInProcessBrowserTest&) = delete;
  NetworkServiceInProcessBrowserTest& operator=(
      const NetworkServiceInProcessBrowserTest&) = delete;

  void SetUpOnMainThread() override {
    host_resolver()->AddRule("*", "127.0.0.1");
    EXPECT_TRUE(embedded_test_server()->Start());
  }

 private:
  base::test::ScopedFeatureList scoped_feature_list_;
};

// Verifies that in-process network service works.
IN_PROC_BROWSER_TEST_F(NetworkServiceInProcessBrowserTest, Basic) {
  GURL test_url = embedded_test_server()->GetURL("foo.com", "/echo");
  StoragePartitionImpl* partition =
      static_cast<StoragePartitionImpl*>(shell()
                                             ->web_contents()
                                             ->GetBrowserContext()
                                             ->GetDefaultStoragePartition());
  EXPECT_TRUE(NavigateToURL(shell(), test_url));
  ASSERT_EQ(net::OK,
            LoadBasicRequest(partition->GetNetworkContext(), test_url));
}

class NetworkServiceInvalidLogBrowserTest : public ContentBrowserTest {
 public:
  NetworkServiceInvalidLogBrowserTest() = default;

  NetworkServiceInvalidLogBrowserTest(
      const NetworkServiceInvalidLogBrowserTest&) = delete;
  NetworkServiceInvalidLogBrowserTest& operator=(
      const NetworkServiceInvalidLogBrowserTest&) = delete;

  void SetUpCommandLine(base::CommandLine* command_line) override {
    command_line->AppendSwitchASCII(network::switches::kLogNetLog, "/abc/def");
  }

  void SetUpOnMainThread() override {
    host_resolver()->AddRule("*", "127.0.0.1");
    EXPECT_TRUE(embedded_test_server()->Start());
  }
};

// Verifies that an invalid --log-net-log flag won't crash the browser.
IN_PROC_BROWSER_TEST_F(NetworkServiceInvalidLogBrowserTest, Basic) {
  GURL test_url = embedded_test_server()->GetURL("foo.com", "/echo");
  StoragePartitionImpl* partition =
      static_cast<StoragePartitionImpl*>(shell()
                                             ->web_contents()
                                             ->GetBrowserContext()
                                             ->GetDefaultStoragePartition());
  EXPECT_TRUE(NavigateToURL(shell(), test_url));
  ASSERT_EQ(net::OK,
            LoadBasicRequest(partition->GetNetworkContext(), test_url));
}

// Test fixture for using a NetworkService that has a non-default limit on the
// number of allowed open UDP sockets.
class NetworkServiceWithUDPSocketLimit : public NetworkServiceBrowserTest {
 public:
  NetworkServiceWithUDPSocketLimit() {
    base::FieldTrialParams params;
    params[net::features::kLimitOpenUDPSocketsMax.name] =
        base::NumberToString(kMaxUDPSockets);
    scoped_feature_list_.InitAndEnableFeatureWithParameters(
        net::features::kLimitOpenUDPSockets, params);
  }

 protected:
  static constexpr int kMaxUDPSockets = 4;

  // Creates and synchronously connects a UDPSocket using |network_context|.
  // Returns the network error for Connect().
  int ConnectUDPSocketSync(
      mojo::Remote<network::mojom::NetworkContext>* network_context,
      mojo::Remote<network::mojom::UDPSocket>* socket) {
    network_context->get()->CreateUDPSocket(
        socket->BindNewPipeAndPassReceiver(), mojo::NullRemote());

    // The address of this endpoint doesn't matter, since Connect() will not
    // actually send any datagrams, and is only being called to verify the
    // socket limit enforcement.
    net::IPEndPoint remote_addr(net::IPAddress(127, 0, 0, 1), 8080);

    network::mojom::UDPSocketOptionsPtr options =
        network::mojom::UDPSocketOptions::New();

    net::IPEndPoint local_addr;
    network::test::UDPSocketTestHelper helper(socket);
    return helper.ConnectSync(remote_addr, std::move(options), &local_addr);
  }

  // Creates a NetworkContext using default parameters.
  mojo::Remote<network::mojom::NetworkContext> CreateNetworkContext() {
    mojo::Remote<network::mojom::NetworkContext> network_context;
    network::mojom::NetworkContextParamsPtr context_params =
        network::mojom::NetworkContextParams::New();
    context_params->cert_verifier_params = GetCertVerifierParams(
        cert_verifier::mojom::CertVerifierCreationParams::New());
    CreateNetworkContextInNetworkService(
        network_context.BindNewPipeAndPassReceiver(),
        std::move(context_params));
    return network_context;
  }

 private:
  base::test::ScopedFeatureList scoped_feature_list_;
};

// Tests calling Connect() on |kMaxUDPSockets + 4| sockets. The first
// kMaxUDPSockets should succeed, whereas the last 4 should fail with
// ERR_INSUFFICIENT_RESOURCES due to having exceeding the global bound.
IN_PROC_BROWSER_TEST_F(NetworkServiceWithUDPSocketLimit,
                       UDPSocketBoundEnforced) {
  constexpr size_t kNumContexts = 2;

  mojo::Remote<network::mojom::NetworkContext> network_contexts[kNumContexts] =
      {CreateNetworkContext(), CreateNetworkContext()};

  mojo::Remote<network::mojom::UDPSocket> sockets[kMaxUDPSockets];

  // Try to connect the maximum number of UDP sockets (|kMaxUDPSockets|),
  // spread evenly between 2 NetworkContexts. These should succeed as the
  // global limit has not been reached yet. This assumes there are no
  // other consumers of UDP sockets in the browser yet.
  for (size_t i = 0; i < kMaxUDPSockets; ++i) {
    auto* network_context = &network_contexts[i % kNumContexts];
    EXPECT_EQ(net::OK, ConnectUDPSocketSync(network_context, &sockets[i]));
  }

  // Try to connect an additional 4 sockets, alternating between each of the
  // NetworkContexts. These should all fail with ERR_INSUFFICIENT_RESOURCES as
  // the limit has already been reached. Spreading across NetworkContext
  // is done to ensure the socket limit is global and not per
  // NetworkContext.
  for (size_t i = 0; i < 4; ++i) {
    auto* network_context = &network_contexts[i % kNumContexts];
    mojo::Remote<network::mojom::UDPSocket> socket;
    EXPECT_EQ(net::ERR_INSUFFICIENT_RESOURCES,
              ConnectUDPSocketSync(network_context, &socket));
  }
}

}  // namespace

}  // namespace content

redpajama_set_name: RedPajamaGithub


Belesse, Whom we don't know is part of the circle.
An obviously artificial island of unknown origins and purpose, exhibiting many strange traits. Its primary features are a pair of dormant volcanoes.
Striped Sand Beach - Abnormal beach of white and black sand.
Boring - A boring town.


The weekend is near, and that's always exciting. But when next week inevitably arrives, it won't be entirely depressing. For you see, next Tuesday, August 23rd, Deus Ex: Mankind Divided arrives. The game is the latest in the hit cyberpunk first-person action RPG series, and the follow-up to 2011's Deus Ex: Human Revolution.
With Mankind Divided's release so close now, a launch trailer has been released online. You can read more about the game and watch the new trailer below.
Developer Eidos Montreal and publisher Square Enix aren't waiting for E3 2016 next week to shower fans with Deus Ex: Mankind Divided goodies.
Not only have they released a new gameplay demo, which runs over 17 minutes long and is exciting enough on its own, but they've also released a trailer for a new game mode called "Breach," a brief reveal trailer for a mobile game inspired by Hitman GO and Lara Croft GO titled Deus Ex GO, and a video looking at real-life human augmentation for those who are missing a limb and how the world of Deus Ex is being used for inspiration in designing new artificial limbs.
You can see all of these below.
A new live-action trailer has been released for Deus Ex: Mankind Divided.
The trailer, titled "The Mechanical Apartheid," steps away from the main character of the game, Adam Jensen, and the story he's involved in that we've seen in previous trailers and gameplay videos. The trailer instead takes a closer look at the rise of augmentation technology, the division that arose between augmented humans and non-augmented humans when the former attacked the latter in Human Revolution, and how this affected people on a deeply personal level. It's only a few minutes long but acts as an excellent short film that sets up the world that Deus Ex is set in, especially for those who aren't familiar with the series but are interested in the new game.
You can check out the live-action trailer below.
One of the games I'm most excited for in 2016 is easily Deus Ex: Mankind Divided. I can't say I've been a fan since the very start of the series, unfortunately, but the release of Deus Ex: Human Revolution a few years back certainly recruited me into the fanbase.
What we've seen of the new game so far has been really exciting to see, but alas, some things we're excited about require patience. This is especially true about video games, which often require patience and then even more patience when the title gets delayed. This is the case with Mankind Divided, and I'm afraid this delay is a lengthy one.
A new trailer for Deus Ex: Mankind Divided titled "Adam Jensen 2.0" has been released by developer Eidos Montreal and publisher Square Enix.
The gameplay trailer focuses on some of technology that players will have at their disposal playing as the heavily augmented main character Adam Jensen, such as the Titan shield, a new gun-arm augmentation called the Tesla, the Nanoblade, and the PEPS.
You can watch the new trailer for Deus Ex: Mankind Divided below.
After the madness of E3 2015 settled down a bit last week, Square Enix decided to keep the fun going strong. During the convention they shared a gameplay trailer and tech demo for Deus Ex: Mankind Divided, but it was at the end of the week that they decided to unleash the excellent 25-minute-long E3 gameplay demo to give excited fans a significant peek at how impressive the game is looking.
The gameplay demo delivers a little taste of everything the game has to offer, from its look to the many stealth and combat options you'll have to the choices you'll make in strategy and dialogue. You can watch the full gameplay demo below.
Back in April we saw the excellent cinematic announcement trailer for the upcoming Deus Ex: Human Revolution sequel, titled Deus Ex: Mankind Divided.
As expected developer Eidos Montreal unveiled the first look at the gameplay of Mankind Divided, also in the form of a trailer, during publisher Square Enix's E3 2015 showcase presentation.
You can check out the E3 gameplay trailer below, and also an added bonus tech demo video that offers a look at the Dawn Engine that was used to create the game.
A couple of days back we got our first brief peek at the next game in the Deus Ex video game franchise, titled Deus Ex: Mankind Divided. Now today an official announcement trailer for the sequel from developer Eidos Montreal and publisher Square Enix has been released online.
Unlike yesterday, this is a full cinematic trailer and lays out what the game will be about. There's no actual gameplay to see yet, but it's still early. You can watch the Mankind Divided announcement trailer and learn more about the game below.
Developer Eidos Montreal and publisher Square Enix's 2011 reboot of the Deus Ex video game franchise, a prequel to the original games titled Deus Ex: Human Revolution, is a personal favorite of mine. Myself and other fans of the game have been waiting quite a while for the follow-up, while attempts have been made to turn the last game into a movie, and now the time has come.
After about four years, the next game in the franchise, titled Deus Ex: Mankind Divided, is in sight. It's also been unveiled as Game Informer's May cover reveal, and to celebrate the big reveal, a video has been released offering a first peek at the game.
You can learn more about the game and see the first look video below.
Predators writer Michael Finch has been hired by CBS Films for Deus Ex, an adaptation of the hit video game Deus Ex: Human Revolution.
The project was once being worked on by Sinister tag team Scott Derrickson and C. Robert Cargill, but Derrickson recently scored the Doctor Strange directing gig from Marvel, so he'll soon be quite occupied with that. Derrickson and Cargill are also working on the screenplay for a movie adaptation of The Outer Limits while screenwriter John Spaihts pens the script for Strange.


What Is There to Do in Copper Harbor, Michigan?
Copper Harbor sits at the top of Michigan's northern shore on the Keweenaw Peninsula. Most visitors venture from camp to visit the area's rich historical destinations, admire the constantly changing scenery or explore the dense wilderness that encompasses much of the landscape. A variety of camping options in Copper Harbor are suited for RVs or tents.
Fort Wilkins State Park features modern campground amenities. Sites include electrical service for RVs and campers, modern restroom and shower facilities and paved RV pads. A rustic cabin is available for overnight rental. Take advantage of historical tours of the 1844 military outpost, hike along the four-mile Fort Wilkins Foot Trail or walk to the lighthouse; the latter was one of the first lighthouses built on Lake Superior.
Although the State Park offers a historical appeal, a greater number of amenities are found at Lake Fanny Hooe Resort and Campground (fannyhooe.com). This is a private campground with laundry facilities, a camp store, and other additional services not available at Fort Wilkins. Fanny Hooe features full electrical service for RVs and campers, wireless Internet, propane refills and hookups, indoor restrooms, showers and a playground.
The temperature in Copper Harbor, Michigan in April tends to be very predictable, so you can generally count on the forecast and travel light.
The temperature in Copper Harbor, Michigan in April is somewhat unpredictable, so be on the safe side and prepare for a variety of conditions.
The temperature in Copper Harbor, Michigan in April is highly unpredictable, so use the forecast as a guide, but be ready for anything!
The Harbor Lights Inn (harborlightsinn.biz) features modern campsites in a convenient downtown location. The camp's atmosphere is family friendly and activity based. Harbor Lights features electrical, water, sewer and cable services for RVs and campers. It also is home to the Old Fashioned Candy Shoppe, where kids and adults alike sample traditional Michigan Fudge and other treats. Walk to downtown shopping and dining locations, or visit the harbor area just one block from the camp. Harbor Lights is open only during the summer months, and does not offer bathroom or shower facilities. For this reason, tent camping at Harbor Lights is not recommended.
The Copper Harbor area offers myriad recreational possibilities. The Keweenaw Peninsula is made up mostly of dense northern forests. Hikes in the area range from quick day-trips to overnight excursions leading across rivers and along the shore of Lake Superior. You might choose to rent a kayak from one of the outfitters in town. Paddle out to Manitou Island, three miles from the tip of the peninsula.
Jansen, Jim. "Camping in Copper Harbor, Michigan." Travel Tips - USA Today, https://traveltips.usatoday.com/camping-copper-harbor-michigan-56807.html. Accessed 26 April 2019.


One week to go until "the meltdown".
Libtarded mass-suicides anyone? Mass rioting and destruction of your own neighbourhoods anyone?
Or will we just get Together and have a massive 'scream at the sky' like adults?
Sounds like an Supideo complex.
Like I said to another poster, start a thread on republicans and I'll crap all over them as well.
THIS THREAD is about democrats and Pelosi specifically.
While I agree in theory about understanding the Constitution, it must be noted that not everyone embraced it when it was ratified, and not everyone embraces it now. Hell, many elected politicians from both sides--sworn to uphold the Constitution--openly advocate against it.
Understanding it will do nothing, unfortunately, especially considering the amount of laws and agencies that have been added that have bastardized our ability to run our nation in conjunction with the spirit of the Constitution.
If we ever want to reset the country, it will probably occur the way that it did the first time.
This site is a sad piece of poo compared to what it used to be.
I guess that was my point too, in a roundabout way: These partisan crappings-on are kind of pointless nowadays. Both sides are equally horrible. I feel that a lot could be solved if we stopped bickering over whose side is better, and came together to crap on the government as a whole. One giant group dump.
People would realize how similar we all actually are, and ultimately realize that we are all being taken advantage of by the entire government, not just one side.
That's when solutions will start popping up.
I'll never understand how Pelosi gets a single vote.


text:
Lake Anne ES Eco-School Team Presents at U.S. Green Building Council
Lake Anne Elementary's Eco-School team was invited to present at the second annual Student Innovation Showcase at the U.S. Green Building Council in Washington, D.C.
Students from Five Schools Compete in Junior Japan Bowl
Students from five schools competed in the third annual Mid-Atlantic Junior Japan Bowl, an academic competition modeled after the National Japan Bowl.
Students Win Category and Organizational Awards at International Science and Engineering Fair
Eleven students from Fairfax County Public Schools won awards at the 2019 International Science and Engineering Fair.
Chicks Take Center Stage in Woodlawn ES Classrooms
Woodlawn Elementary students in Quin Bergh's kindergarten class and Megan Ardovini's second grade class have been watching and studying eggs that recently hatched into adorable baby chicks.
Oak Hill ES Team Qualifies for World Championship
The fourth grade Odyssey of the Mind (OOTM) team from Oak Hill Elementary won first place in Division I (grades 3-5) in the Opposites Distract problem at the Virginia State Tournament.
Flint Hill Elementary Awarded Eco-Schools USA Lifetime Green Flag
Flint Hill Elementary School has been awarded the Lifetime Green Flag, Eco-Schools' highest honor, by the National Wildlife Federation's Eco-Schools USA program.
ArtsHerndon Recognizes Students for Outstanding Artwork Using Technology
Thirty Fairfax County Public Schools students from 14 high schools were recognized by ArtsHerndon for outstanding artworks created using technology in the 15th annual Technology and the Arts competition.
New Teacher, Mentor Making a Difference at Providence Elementary
A fourth grade student and Jacob Williams, a new physical education teacher, are the latest example of a successful mentor-mentee collaboration at Providence Elementary.
Student Poets Honored by Fairfax County Park Authority
Eight student poets were named winners of the Fairfax County Park Authority and Fairfax County Park Foundation's 2019 poetry contest.
South Lakes Food Pantry Branches Out with Healthy Eating Workshops
When South Lakes High School's PTSA established a Food Pantry in 2017, its goal was to help students avoid hunger by distributing nonperishable food items and toiletries to students in need. This year, thanks to a Delta Dream Grant from the Washington Nationals Dream Foundation, healthy eating workshops were provided to students by community organizations.

redpajama_set_name: RedPajamaCommonCrawl


This method helpful to multiply multiple values with a particular value. You can See in below image. The list 1 values are added by 4, value of cell B2. In this case, we will use symbol $ in the formula.
To use this method first put formula in cell then press F4 key. $ Sign will appear in the formula. See in below image in cell C2 $ sign appear after this press Enter key to get the result. Now drag the fill handle from cell C3 till cell C7. All values of list 1 will get divisible with 2.


Gain More Referrals! Visit Us Today!
◊ an opportunity to build real, genuine business relationships with likeminded professionals.
◊ No Competition – We are not fighting for attention or customers!
◊ No Meanness – Members are held accountable to remain professional, respectful, and ethical in their treatment of others.
◊ No Gossip – It not only reflects poorly on the Radical Referrals USA name, it reflects poorly on you and your company as well. Gossip may result in immediate dismissal.
◊ No Drama – Remember, we are Business First! Personal conflicts, either with fellow members or in your personal life, are left at the door.
◊ No Judgment – We all share a common goal, but we all have different ways of getting there. We support each other instead of criticizing or disparaging fellow members' businesses, products, or services.


text:
Springfield protestors brave the cold to show support for trans kids, opposition to SB 42
Susan Szuch Springfield News-Leader
Clarification: A previous version of this article stated broadly that S.B. 42 would allow districts to ban transgender girls from youth sports. Specifically, the bill as initially filed would have allowed districts to bar transgender girls from participating in sports on girls teams.
Despite the chilly temperature, about 50 people gathered in Park Central Square on Monday evening in support of transgender youths. The group chanted, cheered and listened to speakers for about an hour. The rally was organized by the Party for Socialism and Liberation-Springfield ahead of a public hearing in Jefferson City for Missouri Senate Bill 42.
The initial version of SB 42, proposed by Republican Sen. Rick Brattin of Harrisonville, contained measures that would allow school districts to ban transgender girls from competing on girls sports teams. That language was removed during Senate committee on Tuesday morning. Senate Bills 48 and 87, from Sen. Mike Moon of Ash Grove and Sen. Ben Brown of Washington, would cut off state funding to schools that allow transgender girls' participation on girls teams in youth sports.
More:Missouri Republicans renew attempts to restrict transgender sports, health care, education
Tonya Claiborne, the PSL-Springfield member who led the event, said the proposed bill and others like it will have a tangible, negative impact on people.
"This affects real peoples' lives. This will kill kids. ... You can't legislate trans away, you can't deny that it exists," Claiborne said.
Organizer: Bill doesn't 'protect children'
"Keeping children safe" has become a common turn of phrase for legislators and politicians, but Claiborne is skeptical of such clichés in Missouri's legislature.
"While claiming to protect children, this bill further subjects trans kids to further bullying, harassment and exclusion from essential learning activities and deprives them of a sense of belonging with their peers," Claiborne said.
It's not the only bill that imposes restrictions for the purported reason of making Missouri safer for children: There are at least three bills that would prohibit minors from receiving hormone therapy or puberty blockers.
"It doesn't matter to bigots that gender-affirming care is provided according to standard medical practice." Claiborne said. "That's evidence. That's science, folks."
Supporters and trans individuals themselves spoke at the rally, asserting that trans children deserve the same protections and rights as any other child.
Victoria Neal attended the rally with her daughter.
"I really oppose exclusionism on every level. I don't believe trans children are any different than other children, and they should not be excluded from anything," Neal said.
To Neal, a child being discriminated against for being trans is like a child being discriminated against for having brown hair — "It's just wrong."
'All marginalized people are increasingly under attack'
Throughout the evening, PSL members handed out hand-warmers and granola bars as speakers called for a united front against oppression.
"This is crucial that we stand against trans oppression and all kinds of oppression," Claiborne said. "... If we don't stand together, they will succeed in separating us."
Claiborne called for people to take action against the ruling class.
"For real change to happen, we must replace capitalism with socialism," she said.
More:Following Colorado LGBTQ nightclub shooting, Springfield gathers to remember trans lives
While organizers applauded local Democrats' actions, they felt the national party was "using (human) rights as a fundraising campaign" and expressed dismay at the fact that those rights were still in jeopardy.
"We do support the best efforts of those who work within the existing system to uphold our rights," Claiborne said. "But another year has come, and here we are, again."
As in the past summer's rallies, organizers reiterated the danger bills like SB 42 posed to the greater population.
"In recent years, the political establishment of this country has been making a concerted, dangerous effort to attack basic rights of marginalized people and rolling back the basic protections that billions of people have fought so hard for in this country. This bill is not likely to be the last," said organizer Autumn Reynolds.
Missouri State University student Andrew Harper was among the attendees, and emphasized that while people may not realize it, issues of trans rights impact everyone in the community.
"I think that this is a major issue that not many people are aware of or realize just how much it can affect the students here, and the kids here and the children here in Springfield," Harper said. "... People who are from Springfield and people around the world need to understand that this is not just an issue for the people who are directly impacted by this legislation, directly impacted by all of these horrible things that are happening — it's a problem for everyone, it's a problem for everyone to be involved (in) and a problem for everyone to stay involved to fix it."
Before the rally, PSL member Ari Patton shared a similar point.
The effort to protect trans kids' rights "benefits everyone, not just trans kids," Patton said.
Susan Szuch is the health and public policy reporter for the Springfield News-Leader. Follow her on Twitter @szuchsm. Story idea? Email her at sszuch@gannett.com.


text:
UFC 238 Preview: Is Henry Cejudo the UFC's next 'Champ Champ'?
Noah K. Murray-USA TODAY Sports. Pictured: Henry Cejudo (red) during UFC Fight Night at Barclays Center.
By James Carlucci
Henry "The Messenger" Cejudo (+105) looks to capture the UFC Bantamweight Championship and become the next two-division champion in the UFC.
White-hot "Magic" Marlon Moraes (-125) is poised to capture gold in the first title opportunity of his UFC career.
UFC Betting Odds: Henry Cejudo vs. Marlon Moraes
Henry "The Messenger" Cejudo (+105)
"Magic" Marlon Moraes (-125)
Date: Saturday, June 8
Fight Time: 12:00 a.m. ET
TV: Pay-per-view via ESPN+
At UFC 218, Henry Cejudo shocked the world. Entering as a +365 underdog, Cejudo won the UFC Flyweight Championship via split decision. During his post-fight interview Cejudo called out the winner of that night's main event — a bout for the UFC Bantamweight Championship.
Cejudo got the fight he wanted, but not in the way he hoped for. T.J. Dillashaw defended his title at UFC 218 and it was announced he'd be dropping down to flyweight to go after Cejudo and the Mexican-American's new title.
Cejudo squared off with Dillashaw at the inaugural UFC on ESPN+ event back in January. Once again, Cejudo was the underdog (+190) and ultimately the victor. "The Messenger" out-landed Dillashaw 18-1 and won via first-round knockout.
With concerns abound of how the weight cut affected Dillashaw, and more gold still on Cejudo's mind, a rematch was penciled in at 135 pounds. Those plans came to a screeching halt when Dillashaw was suspended for two years by USADA for testing positive for EPO.
Enter Marlon Moraes. "Magic" joined the UFC in June 2016 with an 18-4-1 record and riding a 13-fight winning streak. He stumbled out of the gate, losing a controversial split decision to Rafael dos Anjos in his promotional debut. Since then Moraes is 4-0 (including a win over dos Anjos in the rematch).
With Dillashaw out, there was no question that Moraes was the man for the job.
Now, at UFC 238, Henry Cejudo and Marlon Moraes will square off for the vacant UFC Bantamweight Championship.
Henry Cejudo's Path to Victory
Henry "The Messenger" Cejudo's (14-2) UFC career is a tale of two fighters. In his initial 4-2 run, Cejudo was still figuring out his striking and was able to keep opponents at bay with his Olympic-caliber wrestling. This was enough to get Cejudo a title shot in 2016 but not enough for him to survive the first round.
Beginning with the Joseph Benavidez bout later that year, Cejudo has been a fighter reborn.
No longer a reticent striker, the years of work in the gym finally began to pay off at an elite level for Cejudo. Favoring a more open, karate-style stance, Cejudo showcased powerful striking that made full use of his world-class athleticism.
Over his next few fights Cejudo would score the first stoppage of his UFC career and become more adept at blending his striking and wrestling together. He put it all together in his victory over Demetrious "Mighty Mouse" Johnson and blitzed through Dillashaw his next time out.
Despite his Olympic wrestling pedigree, Cejudo's best weapon in the UFC has been his striking. Among all active UFC flyweights, Cejudo is ranked:
No. 3 in significant strike defense (64.1%).
No. 4 in total strikes landed (615).
No. 4 in significant strike accuracy (42.4%).
No. 6 in knockdowns landed (3).
No. 6 in significant strikes landed (368).
No. 6 in significant strikes landed per minute (3.38).
No. 6 in strike differential (+0.65).
No. 6 in strikes absorbed per minute (2.73).
In his most recent fights, Cejudo achieved the most success on the feet when swarming his opponents. Against Johnson, Cejudo was able to back Johnson in the fence and blitz forward with punches. Though not everything landed, this is where Cejudo achieved his most success on the feet and undoubtedly scored points with the judges.
Against Dillashaw, Cejudo dropped the then-champion early and refused to let Dillashaw recover.
In this fight, Cejudo should look to hit stay patient and blitz Moraes when the opening arise. In both of Moraes's UFC fights that lasted more than a few minutes, the Brazilian was hurt and/or dropped by punches.
Cejudo should have a slight speed advantage in this fight and, if history is any indication, the move up to 135 pounds. will only help his power.
Wrestling should only be a secondary concern in Cejudo's gameplan. It's a useful tool to keep Moraes second-guessing on the feet and can be used to win rounds, but that's about it. The threat of Cejudo's wrestling may be a more effective tool for the former Olympian than wrestling itself.
Cejudo has never done much offensively from top position in the UFC. He can use his wrestling to control large portions of the fight, but Cejudo is unlikely to do much damage on the ground.
Marlon Moraes's Path to Victory
No. 1 ranked bantamweight "Magic" Morlan Moraes (22-5-1) has had two types of fights in the UFC: first-round finishes and split decisions.
Among all active UFC bantamweights (minimum 5 UFC fights), Marlon Moraes has the shortest average fight time at 6:59.
"Moraes" is a powerhouse with knockout power in his hands and feet. He's rocked and or/finished opponents with punches, knees, and kicks. Once he smells blood in the water, Moraes swarms his opponent, constantly hunting for the finish. He's capable of finishing with both ground & pound and submissions.
Moraes is a highly-skilled boxer and has powerful kicks that can debilitate his opponents as the fight goes on. Demetrious Johnson landed 39 leg kicks (of 51 attempted) in the second Cejudo fight. Moraes is a much more powerful kicker than Johnson; Cejudo will be in big trouble if he lets the Brazilian land the same way Johnson did.
In the UFC, we've seen little of Moraes's ground game. "Magic" has only landed 25% (1/4) of his takedowns and averages 0.43 takedowns per 15 minutes.
Defensively, Moraes has a 60% takedown defense rate and has surrendered zero passes and a single ground strike in five UFC fights. The Brazilian also has a dangerous guillotine that should make Cejudo think twice about shooting for takedowns.
Moraes should look to finish Cejudo from the opening bell. Moraes has been at his most effective when pursuing opponents early in the fight; an early finish is the Brazilian's most likely path to victory.
The X-Factor: Going the Distance
Both men have are capable of finishing the other at any time. There's not much technical analysis to be done on that front. What is worth examining is what happens if this fight does go past the first few minutes.