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

#include "net/url_request/url_request_http_job.h"

#include <stdint.h>

#include <cstddef>
#include <memory>
#include <sstream>
#include <utility>
#include <vector>

#include "base/byte_size.h"
#include "base/compiler_specific.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/unguessable_token.h"
#include "build/build_config.h"
#include "net/base/auth.h"
#include "net/base/features.h"
#include "net/base/isolation_info.h"
#include "net/base/load_flags.h"
#include "net/base/proxy_chain.h"
#include "net/base/proxy_server.h"
#include "net/base/proxy_string_util.h"
#include "net/base/request_priority.h"
#include "net/base/test_proxy_delegate.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/ct_policy_status.h"
#include "net/cookies/canonical_cookie_test_helpers.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_store_test_callbacks.h"
#include "net/cookies/cookie_store_test_helpers.h"
#include "net/cookies/test_cookie_access_delegate.h"
#include "net/filter/source_stream.h"
#include "net/filter/source_stream_type.h"
#include "net/http/http_transaction_factory.h"
#include "net/http/http_transaction_test_util.h"
#include "net/http/transport_security_state.h"
#include "net/log/net_log_event_type.h"
#include "net/log/test_net_log.h"
#include "net/log/test_net_log_util.h"
#include "net/net_buildflags.h"
#include "net/proxy_resolution/configured_proxy_resolution_service.h"
#include "net/socket/next_proto.h"
#include "net/socket/socket_test_util.h"
#include "net/test/cert_test_util.h"
#include "net/test/embedded_test_server/default_handlers.h"
#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "net/test/test_with_task_environment.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/device_bound_session_mode.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_builder.h"
#include "net/url_request/url_request_test_util.h"
#include "net/url_request/websocket_handshake_userdata_key.h"
#include "net/websockets/websocket_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/url_constants.h"

#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
#include "net/android/net_test_support_jni/AndroidNetworkLibraryTestUtil_jni.h"
#endif

#if BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS)
#include "net/device_bound_sessions/mock_session_service.h"
#include "net/device_bound_sessions/session_service.h"
#endif

using net::test::IsError;
using net::test::IsOk;

namespace net {

namespace {

using ::testing::_;
using ::testing::ElementsAre;
using ::testing::InSequence;
using ::testing::Pair;
using ::testing::Return;
using ::testing::UnorderedElementsAre;
using ::testing::Unused;

const std::string_view kSimpleGetMockWrite =
    "GET / HTTP/1.1\r\n"
    "Host: www.example.com\r\n"
    "Connection: keep-alive\r\n"
    "User-Agent: \r\n"
    "Accept-Encoding: gzip, deflate\r\n"
    "Accept-Language: en-us,fr\r\n\r\n";

const std::string_view kSimpleHeadMockWrite =
    "HEAD / HTTP/1.1\r\n"
    "Host: www.example.com\r\n"
    "Connection: keep-alive\r\n"
    "User-Agent: \r\n"
    "Accept-Encoding: gzip, deflate\r\n"
    "Accept-Language: en-us,fr\r\n\r\n";

const char kTrustAnchorRequestHistogram[] =
    "Net.Certificate.TrustAnchor.Request";
#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
const char kTrustAnchorRequestHistogram2[] =
    "Net.Certificate.TrustAnchor2.Request";
#endif

// Inherit from URLRequestHttpJob to expose the priority and some
// other hidden functions.
class TestURLRequestHttpJob : public URLRequestHttpJob {
 public:
  explicit TestURLRequestHttpJob(URLRequest* request)
      : URLRequestHttpJob(request,
                          request->context()->http_user_agent_settings()) {}

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

  ~TestURLRequestHttpJob() override = default;

  // URLRequestJob implementation:
  std::unique_ptr<SourceStream> SetUpSourceStream() override {
    if (use_null_source_stream_) {
      return nullptr;
    }
    return URLRequestHttpJob::SetUpSourceStream();
  }

  void set_use_null_source_stream(bool use_null_source_stream) {
    use_null_source_stream_ = use_null_source_stream;
  }

  using URLRequestHttpJob::Kill;
  using URLRequestHttpJob::priority;
  using URLRequestHttpJob::SetPriority;
  using URLRequestHttpJob::Start;

 private:
  bool use_null_source_stream_ = false;
};

class URLRequestHttpJobSetUpSourceTest : public TestWithTaskEnvironment {
 public:
  URLRequestHttpJobSetUpSourceTest() {
    auto context_builder = CreateTestURLRequestContextBuilder();
    context_builder->set_client_socket_factory_for_testing(&socket_factory_);
    context_ = context_builder->Build();
  }

 protected:
  MockClientSocketFactory socket_factory_;

  std::unique_ptr<URLRequestContext> context_;
  TestDelegate delegate_;
};

// Tests that if SetUpSourceStream() returns nullptr, the request fails.
TEST_F(URLRequestHttpJobSetUpSourceTest, SetUpSourceFails) {
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate_,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  auto job = std::make_unique<TestURLRequestHttpJob>(request.get());
  job->set_use_null_source_stream(true);
  TestScopedURLInterceptor interceptor(request->url(), std::move(job));
  request->Start();

  delegate_.RunUntilComplete();
  EXPECT_EQ(ERR_CONTENT_DECODING_INIT_FAILED, delegate_.request_status());
}

// Tests that if there is an unknown content-encoding type, the raw response
// body is passed through.
TEST_F(URLRequestHttpJobSetUpSourceTest, UnknownEncoding) {
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Encoding: foo, gzip\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate_,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  auto job = std::make_unique<TestURLRequestHttpJob>(request.get());
  TestScopedURLInterceptor interceptor(request->url(), std::move(job));
  request->Start();

  delegate_.RunUntilComplete();
  EXPECT_EQ(OK, delegate_.request_status());
  EXPECT_EQ("Test Content", delegate_.data_received());
}

// Tests that nested source streams of 10 layers shall be handled
TEST_F(URLRequestHttpJobSetUpSourceTest, NestedStreamsDepth10) {
  const unsigned char payload[] = {
      0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x93, 0xef,
      0xe6, 0x60, 0x00, 0x03, 0x66, 0xc6, 0xd9, 0x0c, 0x29, 0xff, 0xe5, 0xe1,
      0xdc, 0xc9, 0xef, 0x9f, 0x25, 0x30, 0x30, 0xa7, 0x1d, 0x0b, 0x6a, 0x5b,
      0xf7, 0xff, 0x53, 0xc1, 0xbb, 0x27, 0xdf, 0xcf, 0x0b, 0x49, 0xcc, 0x98,
      0x3f, 0xb7, 0xc6, 0x3e, 0xfe, 0xea, 0x81, 0x03, 0xf7, 0x7e, 0xa5, 0xdf,
      0xdd, 0x17, 0xda, 0xdb, 0x5b, 0xbd, 0x7f, 0xde, 0xfd, 0xd0, 0xdd, 0x51,
      0x5e, 0xbf, 0xaa, 0xe7, 0xbe, 0xfd, 0x77, 0x35, 0x35, 0xda, 0xf5, 0xd5,
      0xfb, 0x75, 0x7b, 0xf7, 0xff, 0xff, 0x5f, 0xf9, 0x7b, 0xfd, 0xfa, 0xdf,
      0xd3, 0xf3, 0xfb, 0xad, 0xb7, 0xfe, 0x3e, 0xfe, 0xef, 0x57, 0xf5, 0xfb,
      0x67, 0x6f, 0x2e, 0xc5, 0x14, 0xff, 0xee, 0x7f, 0xdf, 0xf4, 0xb8, 0xfe,
      0xe8, 0xcd, 0xa3, 0xef, 0xd7, 0x6c, 0xbf, 0x53, 0x1f, 0x9d, 0x7a, 0x71,
      0xde, 0x81, 0xe0, 0x69, 0xfe, 0x71, 0x6f, 0xf7, 0x4f, 0x3f, 0x5b, 0x3e,
      0xe9, 0xf9, 0x8b, 0xbb, 0x7b, 0xfe, 0x9b, 0xf6, 0x66, 0x9d, 0xe1, 0xd9,
      0x6d, 0xfe, 0xfa, 0x8d, 0x0f, 0xc3, 0xad, 0xa9, 0x1b, 0x3e, 0xf4, 0xd6,
      0x6b, 0x5e, 0x88, 0x62, 0xe0, 0x60, 0x78, 0xf3, 0xbf, 0x07, 0xe8, 0xa2,
      0xad, 0x1c, 0x92, 0xbf, 0x66, 0x03, 0x1d, 0x07, 0x00, 0x74, 0xd5, 0x75,
      0x8b, 0xb2, 0x00, 0x00, 0x00,
  };
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {
      MockRead(
          "HTTP/1.1 200 OK\r\n"
          "Content-Encoding: gzip, gzip, gzip, gzip, gzip, gzip, gzip, gzip, "
          "gzip, gzip\r\n"
          "Content-Length: 197\r\n\r\n"),
      MockRead(base::as_string_view(payload))};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate_,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  auto job = std::make_unique<TestURLRequestHttpJob>(request.get());
  TestScopedURLInterceptor interceptor(request->url(), std::move(job));
  request->Start();

  delegate_.RunUntilComplete();
  EXPECT_EQ(OK, delegate_.request_status());
  EXPECT_EQ("foobar", delegate_.data_received());
}

// Tests that nested source streams of 11 layers shall fail to initialize
TEST_F(URLRequestHttpJobSetUpSourceTest, NestedStreamsDepth11) {
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {
      MockRead(
          "HTTP/1.1 200 OK\r\n"
          "Content-Encoding: gzip, gzip, gzip, gzip, gzip, gzip, gzip, gzip, "
          "gzip, gzip, gzip\r\n\r\n"),
      MockRead("")};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate_,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  auto job = std::make_unique<TestURLRequestHttpJob>(request.get());
  TestScopedURLInterceptor interceptor(request->url(), std::move(job));
  request->Start();

  delegate_.RunUntilComplete();
  EXPECT_EQ(ERR_CONTENT_DECODING_INIT_FAILED, delegate_.request_status());
}

// TaskEnvironment is required to instantiate a
// net::ConfiguredProxyResolutionService, which registers itself as an IP
// Address Observer with the NetworkChangeNotifier.
using URLRequestHttpJobWithProxyTest = TestWithTaskEnvironment;

class URLRequestHttpJobWithProxy {
 public:
  explicit URLRequestHttpJobWithProxy(
      std::unique_ptr<ProxyResolutionService> proxy_resolution_service) {
    auto context_builder = CreateTestURLRequestContextBuilder();
    context_builder->set_client_socket_factory_for_testing(&socket_factory_);
    if (proxy_resolution_service) {
      context_builder->set_proxy_resolution_service(
          std::move(proxy_resolution_service));
    }
    context_ = context_builder->Build();
  }

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

  MockClientSocketFactory socket_factory_;
  std::unique_ptr<URLRequestContext> context_;
};

// Tests that when a proxy is not used, the proxy chain is set correctly on the
// URLRequest.
TEST_F(URLRequestHttpJobWithProxyTest, TestFailureWithoutProxy) {
  URLRequestHttpJobWithProxy http_job_with_proxy(nullptr);

  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_CONNECTION_RESET)};

  StaticSocketDataProvider socket_data(reads, writes);
  http_job_with_proxy.socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request =
      http_job_with_proxy.context_->CreateRequest(
          GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
          TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  request->Start();
  ASSERT_TRUE(request->is_pending());
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsError(ERR_CONNECTION_RESET));
  EXPECT_EQ(ProxyChain::Direct(), request->proxy_chain());
  EXPECT_EQ(0, request->received_response_content_length());
  EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
  EXPECT_EQ(CountReadByteSize(reads), request->GetTotalReceivedBytes());
}

// Tests that when one proxy chain is in use and the connection to a proxy
// server in the proxy chain fails, the proxy chain is still set correctly on
// the URLRequest.
TEST_F(URLRequestHttpJobWithProxyTest, TestSuccessfulWithOneProxy) {
  const std::string_view kSimpleProxyGetMockWrite =
      "GET http://www.example.com/ HTTP/1.1\r\n"
      "Host: www.example.com\r\n"
      "Proxy-Connection: keep-alive\r\n"
      "User-Agent: \r\n"
      "Accept-Encoding: gzip, deflate\r\n"
      "Accept-Language: en-us,fr\r\n\r\n";

  const ProxyChain proxy_chain =
      ProxyUriToProxyChain("http://origin.net:80", ProxyServer::SCHEME_HTTP);

  std::unique_ptr<ProxyResolutionService> proxy_resolution_service =
      ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
          ProxyServerToPacResultElement(proxy_chain.First()),
          TRAFFIC_ANNOTATION_FOR_TESTS);

  MockWrite writes[] = {MockWrite(kSimpleProxyGetMockWrite)};
  MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_CONNECTION_RESET)};

  StaticSocketDataProvider socket_data(reads, writes);

  URLRequestHttpJobWithProxy http_job_with_proxy(
      std::move(proxy_resolution_service));
  http_job_with_proxy.socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request =
      http_job_with_proxy.context_->CreateRequest(
          GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
          TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  request->Start();
  ASSERT_TRUE(request->is_pending());
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsError(ERR_CONNECTION_RESET));
  // When request fails due to proxy connection errors, the proxy chain should
  // still be set on the `request`.
  EXPECT_EQ(proxy_chain, request->proxy_chain());
  EXPECT_EQ(0, request->received_response_content_length());
  EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
  EXPECT_EQ(base::ByteSize(0), request->GetTotalReceivedBytes());
}

// Tests that when two proxy chains are in use and the connection to a proxy
// server in the first proxy chain fails, the proxy chain is set correctly on
// the URLRequest.
TEST_F(URLRequestHttpJobWithProxyTest,
       TestContentLengthSuccessfulRequestWithTwoProxies) {
  const ProxyChain proxy_chain =
      ProxyUriToProxyChain("http://origin.net:80", ProxyServer::SCHEME_HTTP);

  // Connection to `proxy_chain` would fail. Request should be fetched over
  // DIRECT.
  std::unique_ptr<ProxyResolutionService> proxy_resolution_service =
      ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
          ProxyServerToPacResultElement(proxy_chain.First()) + "; DIRECT",
          TRAFFIC_ANNOTATION_FOR_TESTS);

  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content"), MockRead(ASYNC, OK)};

  MockConnect mock_connect_1(SYNCHRONOUS, ERR_CONNECTION_RESET);
  StaticSocketDataProvider connect_data_1;
  connect_data_1.set_connect_data(mock_connect_1);

  StaticSocketDataProvider socket_data(reads, writes);

  URLRequestHttpJobWithProxy http_job_with_proxy(
      std::move(proxy_resolution_service));
  http_job_with_proxy.socket_factory_.AddSocketDataProvider(&connect_data_1);
  http_job_with_proxy.socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request =
      http_job_with_proxy.context_->CreateRequest(
          GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
          TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  request->Start();
  ASSERT_TRUE(request->is_pending());
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsOk());
  EXPECT_EQ(ProxyChain::Direct(), request->proxy_chain());
  EXPECT_EQ(12, request->received_response_content_length());
  EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
  EXPECT_EQ(CountReadByteSize(reads), request->GetTotalReceivedBytes());
}

class URLRequestHttpJobTest : public TestWithTaskEnvironment {
 protected:
  URLRequestHttpJobTest() {
    auto context_builder = CreateTestURLRequestContextBuilder();
    context_builder->SetHttpTransactionFactoryForTesting(
        std::make_unique<MockNetworkLayer>());
    context_builder->DisableHttpCache();
    context_builder->set_net_log(NetLog::Get());
    context_ = context_builder->Build();

    req_ = context_->CreateRequest(
        GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate_,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  }

  MockNetworkLayer& network_layer() {
    // This cast is safe because we set a MockNetworkLayer in the constructor.
    return *static_cast<MockNetworkLayer*>(
        context_->http_transaction_factory());
  }

  std::unique_ptr<URLRequest> CreateFirstPartyRequest(
      const URLRequestContext& context,
      const GURL& url,
      URLRequest::Delegate* delegate) {
    auto req = context.CreateRequest(url, DEFAULT_PRIORITY, delegate,
                                     TRAFFIC_ANNOTATION_FOR_TESTS,
                                     net::handles::kInvalidNetworkHandle);
    req->set_initiator(url::Origin::Create(url));
    req->set_site_for_cookies(SiteForCookies::FromUrl(url));
    return req;
  }

  std::unique_ptr<URLRequestContext> context_;
  TestDelegate delegate_;
  RecordingNetLogObserver net_log_observer_;
  std::unique_ptr<URLRequest> req_;
};

class URLRequestHttpJobWithMockSocketsTest : public TestWithTaskEnvironment {
 protected:
  URLRequestHttpJobWithMockSocketsTest() {
    auto context_builder = CreateTestURLRequestContextBuilder();
    context_builder->set_client_socket_factory_for_testing(&socket_factory_);
    context_ = context_builder->Build();
  }

  MockClientSocketFactory socket_factory_;
  std::unique_ptr<URLRequestContext> context_;
};

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestContentLengthSuccessfulRequest) {
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  request->Start();
  ASSERT_TRUE(request->is_pending());
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsOk());
  EXPECT_EQ(12, request->received_response_content_length());
  EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
  EXPECT_EQ(CountReadByteSize(reads), request->GetTotalReceivedBytes());
}

// Tests a successful HEAD request.
TEST_F(URLRequestHttpJobWithMockSocketsTest, TestSuccessfulHead) {
  MockWrite writes[] = {MockWrite(kSimpleHeadMockWrite)};
  MockRead reads[] = {
      MockRead("HTTP/1.1 200 OK\r\n"
               "Content-Length: 0\r\n\r\n")};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  request->set_method("HEAD");
  request->Start();
  ASSERT_TRUE(request->is_pending());
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsOk());
  EXPECT_EQ(0, request->received_response_content_length());
  EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
  EXPECT_EQ(CountReadByteSize(reads), request->GetTotalReceivedBytes());
}

// Similar to above test but tests that even if response body is there in the
// HEAD response stream, it should not be read due to HttpStreamParser's logic.
TEST_F(URLRequestHttpJobWithMockSocketsTest, TestSuccessfulHeadWithContent) {
  MockWrite writes[] = {MockWrite(kSimpleHeadMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  request->set_method("HEAD");
  request->Start();
  ASSERT_TRUE(request->is_pending());
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsOk());
  EXPECT_EQ(0, request->received_response_content_length());
  EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
  EXPECT_EQ(CountReadByteSize(reads) - base::ByteSize(12),
            request->GetTotalReceivedBytes());
}

TEST_F(URLRequestHttpJobWithMockSocketsTest, TestSuccessfulCachedHeadRequest) {
  const url::Origin kOrigin1 =
      url::Origin::Create(GURL("http://www.example.com"));
  const IsolationInfo kTestIsolationInfo =
      IsolationInfo::CreateForInternalRequest(kOrigin1);

  // Cache the response.
  {
    MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
    MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                                 "Content-Length: 12\r\n\r\n"),
                        MockRead("Test Content")};

    StaticSocketDataProvider socket_data(reads, writes);
    socket_factory_.AddSocketDataProvider(&socket_data);

    TestDelegate delegate;
    std::unique_ptr<URLRequest> request = context_->CreateRequest(
        GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

    request->set_isolation_info(kTestIsolationInfo);
    request->Start();
    ASSERT_TRUE(request->is_pending());
    delegate.RunUntilComplete();

    EXPECT_THAT(delegate.request_status(), IsOk());
    EXPECT_EQ(12, request->received_response_content_length());
    EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
    EXPECT_EQ(CountReadByteSize(reads), request->GetTotalReceivedBytes());
  }

  // Send a HEAD request for the cached response.
  {
    MockWrite writes[] = {MockWrite(kSimpleHeadMockWrite)};
    MockRead reads[] = {
        MockRead("HTTP/1.1 200 OK\r\n"
                 "Content-Length: 0\r\n\r\n")};

    StaticSocketDataProvider socket_data(reads, writes);
    socket_factory_.AddSocketDataProvider(&socket_data);

    TestDelegate delegate;
    std::unique_ptr<URLRequest> request = context_->CreateRequest(
        GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

    // Use the cached version.
    request->SetLoadFlags(LOAD_SKIP_CACHE_VALIDATION);
    request->set_method("HEAD");
    request->set_isolation_info(kTestIsolationInfo);
    request->Start();
    ASSERT_TRUE(request->is_pending());
    delegate.RunUntilComplete();

    EXPECT_THAT(delegate.request_status(), IsOk());
    EXPECT_EQ(0, request->received_response_content_length());
    EXPECT_EQ(base::ByteSize(0), request->GetTotalSentBytes());
    EXPECT_EQ(base::ByteSize(0), request->GetTotalReceivedBytes());
  }
}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestContentLengthSuccessfulHttp09Request) {
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("Test Content"),
                      MockRead(net::SYNCHRONOUS, net::OK)};

  StaticSocketDataProvider socket_data(reads, base::span<MockWrite>());
  socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  request->Start();
  ASSERT_TRUE(request->is_pending());
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsOk());
  EXPECT_EQ(12, request->received_response_content_length());
  EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
  EXPECT_EQ(CountReadByteSize(reads), request->GetTotalReceivedBytes());
}

TEST_F(URLRequestHttpJobWithMockSocketsTest, TestContentLengthFailedRequest) {
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 20\r\n\r\n"),
                      MockRead("Test Content"),
                      MockRead(net::SYNCHRONOUS, net::ERR_FAILED)};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  request->Start();
  ASSERT_TRUE(request->is_pending());
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsError(ERR_FAILED));
  EXPECT_EQ(12, request->received_response_content_length());
  EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
  EXPECT_EQ(CountReadByteSize(reads), request->GetTotalReceivedBytes());
}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestContentLengthCancelledRequest) {
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 20\r\n\r\n"),
                      MockRead("Test Content"),
                      MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING)};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  delegate.set_cancel_in_received_data(true);
  request->Start();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsError(ERR_ABORTED));
  EXPECT_EQ(12, request->received_response_content_length());
  EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
  EXPECT_EQ(CountReadByteSize(reads), request->GetTotalReceivedBytes());
}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestNetworkBytesRedirectedRequest) {
  MockWrite redirect_writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.redirect.com\r\n"
                "Connection: keep-alive\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: gzip, deflate\r\n"
                "Accept-Language: en-us,fr\r\n\r\n")};

  MockRead redirect_reads[] = {
      MockRead("HTTP/1.1 302 Found\r\n"
               "Location: http://www.example.com\r\n\r\n"),
  };
  StaticSocketDataProvider redirect_socket_data(redirect_reads,
                                                redirect_writes);
  socket_factory_.AddSocketDataProvider(&redirect_socket_data);

  MockWrite final_writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead final_reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                                     "Content-Length: 12\r\n\r\n"),
                            MockRead("Test Content")};
  StaticSocketDataProvider final_socket_data(final_reads, final_writes);
  socket_factory_.AddSocketDataProvider(&final_socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.redirect.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  request->Start();
  ASSERT_TRUE(request->is_pending());
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsOk());
  EXPECT_EQ(12, request->received_response_content_length());
  // Should not include the redirect.
  EXPECT_EQ(CountWriteByteSize(final_writes), request->GetTotalSentBytes());
  EXPECT_EQ(CountReadByteSize(final_reads), request->GetTotalReceivedBytes());
}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestNetworkBytesCancelledAfterHeaders) {
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n\r\n")};
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  delegate.set_cancel_in_response_started(true);
  request->Start();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsError(ERR_ABORTED));
  EXPECT_EQ(0, request->received_response_content_length());
  EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
  EXPECT_EQ(CountReadByteSize(reads), request->GetTotalReceivedBytes());
}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestNetworkBytesCancelledImmediately) {
  StaticSocketDataProvider socket_data;
  socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  request->Start();
  request->Cancel();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsError(ERR_ABORTED));
  EXPECT_EQ(0, request->received_response_content_length());
  EXPECT_EQ(base::ByteSize(0), request->GetTotalSentBytes());
  EXPECT_EQ(base::ByteSize(0), request->GetTotalReceivedBytes());
}

TEST_F(URLRequestHttpJobWithMockSocketsTest, TestHttpTimeToFirstByte) {
  base::HistogramTester histograms;
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  histograms.ExpectTotalCount("Net.HttpTimeToFirstByte", 0);

  request->Start();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsOk());
  histograms.ExpectTotalCount("Net.HttpTimeToFirstByte", 1);
}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpTimeToFirstByteForCancelledTask) {
  base::HistogramTester histograms;
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  request->Start();
  request->Cancel();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsError(ERR_ABORTED));
  histograms.ExpectTotalCount("Net.HttpTimeToFirstByte", 0);
}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpJobSuccessPriorityKeyedTotalTime) {
  base::HistogramTester histograms;

  for (int priority = 0; priority < net::NUM_PRIORITIES; ++priority) {
    for (int request_index = 0; request_index <= priority; ++request_index) {
      MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
      MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                                   "Content-Length: 12\r\n\r\n"),
                          MockRead("Test Content")};

      StaticSocketDataProvider socket_data(reads, writes);
      socket_factory_.AddSocketDataProvider(&socket_data);

      TestDelegate delegate;
      std::unique_ptr<URLRequest> request = context_->CreateRequest(
          GURL("http://www.example.com/"),
          static_cast<net::RequestPriority>(priority), &delegate,
          TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

      request->Start();
      delegate.RunUntilComplete();
      EXPECT_THAT(delegate.request_status(), IsOk());
    }
  }

  for (int priority = 0; priority < net::NUM_PRIORITIES; ++priority) {
    histograms.ExpectTotalCount("Net.HttpJob.TotalTimeSuccess.Priority" +
                                    base::NumberToString(priority),
                                priority + 1);
  }
}

#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpJobRecordsCrsTrustAnchorHistograms) {
  SSLSocketDataProvider ssl_socket_data(net::ASYNC, net::OK);
  ssl_socket_data.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");

  const int32_t kFakeCrsID = 8379;
  ssl_socket_data.ssl_info.crs_root_id = kFakeCrsID;

  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data);

  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  base::HistogramTester histograms;
  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("https://www.example.com/"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  request->Start();
  delegate.RunUntilComplete();
  EXPECT_THAT(delegate.request_status(), IsOk());

  histograms.ExpectUniqueSample(kTrustAnchorRequestHistogram2, kFakeCrsID, 1);
}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpJobDoesNotRecordCrsTrustAnchorHistogramsWhenNoNetworkLoad) {
  SSLSocketDataProvider ssl_socket_data(net::ASYNC, net::OK);
  ssl_socket_data.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
  // Simulate a request loaded from a non-network source, such as a disk
  // cache.
  ssl_socket_data.ssl_info.crs_root_id = std::nullopt;

  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data);

  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  base::HistogramTester histograms;
  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("https://www.example.com/"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  request->Start();
  delegate.RunUntilComplete();
  EXPECT_THAT(delegate.request_status(), IsOk());

  histograms.ExpectTotalCount(kTrustAnchorRequestHistogram2, 0);
}
#endif

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpJobRecordsTrustAnchorHistograms) {
  SSLSocketDataProvider ssl_socket_data(net::ASYNC, net::OK);
  ssl_socket_data.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
  // Simulate a certificate chain issued by "C=US, O=Google Trust Services LLC,
  // CN=GTS Root R4". This publicly-trusted root was chosen as it was included
  // in 2017 and is not anticipated to be removed from all supported platforms
  // for a few decades.
  // Note: The actual cert in |cert| does not matter for this testing.
  SHA256HashValue leaf_hash = {{0}};
  SHA256HashValue intermediate_hash = {{1}};
  SHA256HashValue root_hash = {
      {0x98, 0x47, 0xe5, 0x65, 0x3e, 0x5e, 0x9e, 0x84, 0x75, 0x16, 0xe5,
       0xcb, 0x81, 0x86, 0x06, 0xaa, 0x75, 0x44, 0xa1, 0x9b, 0xe6, 0x7f,
       0xd7, 0x36, 0x6d, 0x50, 0x69, 0x88, 0xe8, 0xd8, 0x43, 0x47}};
  ssl_socket_data.ssl_info.public_key_hashes.push_back(leaf_hash);
  ssl_socket_data.ssl_info.public_key_hashes.push_back(intermediate_hash);
  ssl_socket_data.ssl_info.public_key_hashes.push_back(root_hash);

  const base::HistogramBase::Sample32 kGTSRootR4HistogramID = 486;

  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data);

  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  base::HistogramTester histograms;
  histograms.ExpectTotalCount(kTrustAnchorRequestHistogram, 0);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("https://www.example.com/"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  request->Start();
  delegate.RunUntilComplete();
  EXPECT_THAT(delegate.request_status(), IsOk());

  histograms.ExpectTotalCount(kTrustAnchorRequestHistogram, 1);
  histograms.ExpectUniqueSample(kTrustAnchorRequestHistogram,
                                kGTSRootR4HistogramID, 1);
}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpJobDoesNotRecordTrustAnchorHistogramsWhenNoNetworkLoad) {
  SSLSocketDataProvider ssl_socket_data(net::ASYNC, net::OK);
  ssl_socket_data.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
  // Simulate a request loaded from a non-network source, such as a disk
  // cache.
  ssl_socket_data.ssl_info.public_key_hashes.clear();

  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data);

  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  base::HistogramTester histograms;
  histograms.ExpectTotalCount(kTrustAnchorRequestHistogram, 0);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("https://www.example.com/"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  request->Start();
  delegate.RunUntilComplete();
  EXPECT_THAT(delegate.request_status(), IsOk());

  histograms.ExpectTotalCount(kTrustAnchorRequestHistogram, 0);
}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpJobRecordsMostSpecificTrustAnchorHistograms) {
  SSLSocketDataProvider ssl_socket_data(net::ASYNC, net::OK);
  ssl_socket_data.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
  // Simulate a certificate chain issued by "C=US, O=Google Trust Services LLC,
  // CN=GTS Root R4". This publicly-trusted root was chosen as it was included
  // in 2017 and is not anticipated to be removed from all supported platforms
  // for a few decades.
  // Note: The actual cert in |cert| does not matter for this testing.
  SHA256HashValue leaf_hash = {{0}};
  SHA256HashValue intermediate_hash = {{1}};
  SHA256HashValue gts_root_r3_hash = {
      {0x41, 0x79, 0xed, 0xd9, 0x81, 0xef, 0x74, 0x74, 0x77, 0xb4, 0x96,
       0x26, 0x40, 0x8a, 0xf4, 0x3d, 0xaa, 0x2c, 0xa7, 0xab, 0x7f, 0x9e,
       0x08, 0x2c, 0x10, 0x60, 0xf8, 0x40, 0x96, 0x77, 0x43, 0x48}};
  SHA256HashValue gts_root_r4_hash = {
      {0x98, 0x47, 0xe5, 0x65, 0x3e, 0x5e, 0x9e, 0x84, 0x75, 0x16, 0xe5,
       0xcb, 0x81, 0x86, 0x06, 0xaa, 0x75, 0x44, 0xa1, 0x9b, 0xe6, 0x7f,
       0xd7, 0x36, 0x6d, 0x50, 0x69, 0x88, 0xe8, 0xd8, 0x43, 0x47}};
  ssl_socket_data.ssl_info.public_key_hashes.push_back(leaf_hash);
  ssl_socket_data.ssl_info.public_key_hashes.push_back(intermediate_hash);
  ssl_socket_data.ssl_info.public_key_hashes.push_back(gts_root_r3_hash);
  ssl_socket_data.ssl_info.public_key_hashes.push_back(gts_root_r4_hash);

  const base::HistogramBase::Sample32 kGTSRootR3HistogramID = 485;

  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data);

  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  base::HistogramTester histograms;
  histograms.ExpectTotalCount(kTrustAnchorRequestHistogram, 0);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("https://www.example.com/"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  request->Start();
  delegate.RunUntilComplete();
  EXPECT_THAT(delegate.request_status(), IsOk());

  histograms.ExpectTotalCount(kTrustAnchorRequestHistogram, 1);
  histograms.ExpectUniqueSample(kTrustAnchorRequestHistogram,
                                kGTSRootR3HistogramID, 1);
}

TEST_F(URLRequestHttpJobWithMockSocketsTest, EncodingAdvertisementOnRange) {
  MockWrite writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.example.com\r\n"
                "Connection: keep-alive\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: identity\r\n"
                "Accept-Language: en-us,fr\r\n"
                "Range: bytes=0-1023\r\n\r\n")};

  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Accept-Ranges: bytes\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  // Make the extra header to trigger the change in "Accepted-Encoding"
  HttpRequestHeaders headers;
  headers.SetHeader("Range", "bytes=0-1023");
  request->SetExtraRequestHeaders(headers);

  request->Start();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsOk());
  EXPECT_EQ(12, request->received_response_content_length());
  EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
  EXPECT_EQ(CountReadByteSize(reads), request->GetTotalReceivedBytes());
}

TEST_F(URLRequestHttpJobWithMockSocketsTest, RangeRequestOverrideEncoding) {
  MockWrite writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.example.com\r\n"
                "Connection: keep-alive\r\n"
                "Accept-Encoding: gzip, deflate\r\n"
                "User-Agent: \r\n"
                "Accept-Language: en-us,fr\r\n"
                "Range: bytes=0-1023\r\n\r\n")};

  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Accept-Ranges: bytes\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  // Explicitly set "Accept-Encoding" to make sure it's not overridden by
  // AddExtraHeaders
  HttpRequestHeaders headers;
  headers.SetHeader("Accept-Encoding", "gzip, deflate");
  headers.SetHeader("Range", "bytes=0-1023");
  request->SetExtraRequestHeaders(headers);

  request->Start();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsOk());
  EXPECT_EQ(12, request->received_response_content_length());
  EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
  EXPECT_EQ(CountReadByteSize(reads), request->GetTotalReceivedBytes());
}

TEST_F(URLRequestHttpJobTest, TestCancelWhileReadingCookies) {
  auto context_builder = CreateTestURLRequestContextBuilder();
  context_builder->SetCookieStore(std::make_unique<DelayedCookieMonster>());
  auto context = context_builder->Build();

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);

  request->Start();
  request->Cancel();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsError(ERR_ABORTED));
}

// Make sure that SetPriority actually sets the URLRequestHttpJob's
// priority, before start.  Other tests handle the after start case.
TEST_F(URLRequestHttpJobTest, SetPriorityBasic) {
  auto job = std::make_unique<TestURLRequestHttpJob>(req_.get());
  EXPECT_EQ(DEFAULT_PRIORITY, job->priority());

  job->SetPriority(LOWEST);
  EXPECT_EQ(LOWEST, job->priority());

  job->SetPriority(LOW);
  EXPECT_EQ(LOW, job->priority());
}

// Make sure that URLRequestHttpJob passes on its priority to its
// transaction on start.
TEST_F(URLRequestHttpJobTest, SetTransactionPriorityOnStart) {
  TestScopedURLInterceptor interceptor(
      req_->url(), std::make_unique<TestURLRequestHttpJob>(req_.get()));
  req_->SetPriority(LOW);

  EXPECT_FALSE(network_layer().last_transaction());

  req_->Start();

  ASSERT_TRUE(network_layer().last_transaction());
  EXPECT_EQ(LOW, network_layer().last_transaction()->priority());
}

// Make sure that URLRequestHttpJob passes on its priority updates to
// its transaction.
TEST_F(URLRequestHttpJobTest, SetTransactionPriority) {
  TestScopedURLInterceptor interceptor(
      req_->url(), std::make_unique<TestURLRequestHttpJob>(req_.get()));
  req_->SetPriority(LOW);
  req_->Start();
  ASSERT_TRUE(network_layer().last_transaction());
  EXPECT_EQ(LOW, network_layer().last_transaction()->priority());

  req_->SetPriority(HIGHEST);
  EXPECT_EQ(HIGHEST, network_layer().last_transaction()->priority());
}

TEST_F(URLRequestHttpJobTest, HSTSInternalRedirectTest) {
  // Setup HSTS state.
  context_->transport_security_state()->AddHSTS(
      "upgrade.test", base::Time::Now() + base::Seconds(10), true);
  // Setting `is_top_level_nav` true prevents the upgrade from being blocked by
  // kHstsTopLevelNavigationsOnly.
  ASSERT_TRUE(context_->transport_security_state()->ShouldUpgradeToSSL(
      "upgrade.test", /*is_top_level_nav=*/true));
  ASSERT_FALSE(context_->transport_security_state()->ShouldUpgradeToSSL(
      "no-upgrade.test", /*is_top_level_nav=*/true));

  struct TestCase {
    const char* url;
    bool upgrade_expected;
    const char* upgraded_url;
  } cases[] = {
      {"http://upgrade.test/", true, "https://upgrade.test/"},
      {"http://upgrade.test:123/", true, "https://upgrade.test:123/"},
      {"http://no-upgrade.test/", false, "http://no-upgrade.test/"},
      {"http://no-upgrade.test:123/", false, "http://no-upgrade.test:123/"},
#if BUILDFLAG(ENABLE_WEBSOCKETS)
      {"ws://upgrade.test/", true, "wss://upgrade.test/"},
      {"ws://upgrade.test:123/", true, "wss://upgrade.test:123/"},
      {"ws://no-upgrade.test/", false, "ws://no-upgrade.test/"},
      {"ws://no-upgrade.test:123/", false, "ws://no-upgrade.test:123/"},
#endif  // BUILDFLAG(ENABLE_WEBSOCKETS)
  };

  // This test has a few different test configurations, a combination of:
  // * kHstsTopLevelNavigationsOnly enabled/disabled.
  // * Request is considered a main frame navigation or not.
  for (bool top_level_only_enabled : {false, true}) {
    base::test::ScopedFeatureList scoped_feature_list;
    scoped_feature_list.InitWithFeatureState(
        features::kHstsTopLevelNavigationsOnly, top_level_only_enabled);

    for (bool is_main_frame_navigation : {false, true}) {
      for (const auto& test : cases) {
        std::stringstream scoped_trace_message;
        scoped_trace_message
            << "url: " << test.url << ", feature state: "
            << (top_level_only_enabled ? "enabled" : "disabled")
            << ", main frame navigation: "
            << (is_main_frame_navigation ? "yes" : "no");
        SCOPED_TRACE(scoped_trace_message.str());

        GURL url = GURL(test.url);
        url::Origin origin = url::Origin::Create(url);

        bool is_for_websockets = url.SchemeIsWSOrWSS();

        if (is_for_websockets && is_main_frame_navigation) {
          // Websockets are never main frame navigations, so skip this case.
          continue;
        }

        TestDelegate d;
        TestNetworkDelegate network_delegate;
        std::unique_ptr<URLRequest> r(context_->CreateRequest(
            url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS,
            net::handles::kInvalidNetworkHandle, is_for_websockets));

        // Only apply for main frame navigation based runs.
        if (is_main_frame_navigation) {
          r->set_isolation_info(IsolationInfo::Create(
              IsolationInfo::RequestType::kMainFrame, origin, origin,
              SiteForCookies::FromOrigin(origin)));
        }
        net_log_observer_.Clear();
        r->Start();
        d.RunUntilComplete();

        // An upgrade should be expected when
        // * The test case expects an upgrade AND
        // * The run isn't a non-main frame navigation with
        // `top_level_only_enabled`.
        const bool upgrade_expected =
            test.upgrade_expected &&
            !(!is_main_frame_navigation && top_level_only_enabled);

        if (upgrade_expected) {
          auto entries = net_log_observer_.GetEntriesWithType(
              net::NetLogEventType::URL_REQUEST_REDIRECT_JOB);
          int redirects = entries.size();
          for (const auto& entry : entries) {
            EXPECT_EQ("HSTS", GetStringValueFromParams(entry, "reason"));
          }
          EXPECT_EQ(1, redirects);
          EXPECT_EQ(1, d.received_redirect_count());
          EXPECT_EQ(2u, r->url_chain().size());

          EXPECT_EQ(GURL(test.upgraded_url), r->url());
        } else {
          EXPECT_EQ(0, d.received_redirect_count());
          EXPECT_EQ(1u, r->url_chain().size());

          EXPECT_EQ(GURL(test.url), r->url());
        }
      }
    }
  }
}

// Tests HSTS upgrades for MPArch frames (such as Fenced Frames). MPArch frames
// are similar to "normal" frames except that they set the IsolationInfo's
// nonce.
TEST_F(URLRequestHttpJobTest, HSTSInternalRedirectTestMPArchFrames) {
  // Setup HSTS state.
  context_->transport_security_state()->AddHSTS(
      "upgrade.test", base::Time::Now() + base::Seconds(10), true);
  // Setting `is_top_level_nav` true prevents the upgrade from being blocked by
  // kHstsTopLevelNavigationsOnly.
  ASSERT_TRUE(context_->transport_security_state()->ShouldUpgradeToSSL(
      "upgrade.test", /*is_top_level_nav=*/true));
  ASSERT_FALSE(context_->transport_security_state()->ShouldUpgradeToSSL(
      "no-upgrade.test", /*is_top_level_nav=*/true));

  struct TestCase {
    const char* url;
    // Upgrades for MPArch frames should only occur when
    // kHstsTopLevelNavigationsOnly is disabled.
    bool upgrade_expected;
    const char* upgraded_url;
  } cases[] = {
      {"http://upgrade.test/", true, "https://upgrade.test/"},
      {"http://upgrade.test:123/", true, "https://upgrade.test:123/"},
      {"http://no-upgrade.test/", false, "http://no-upgrade.test/"},
      {"http://no-upgrade.test:123/", false, "http://no-upgrade.test:123/"},
  };

  // This test has a few different test configurations, a combination of:
  // * kHstsTopLevelNavigationsOnly enabled/disabled.
  // * Request is considered a main frame navigation or not.
  for (bool top_level_only_enabled : {false, true}) {
    base::test::ScopedFeatureList scoped_feature_list;
    scoped_feature_list.InitWithFeatureState(
        features::kHstsTopLevelNavigationsOnly, top_level_only_enabled);

    // Even though MPArch frames are embedded within a "normal" frame their
    // navigations are still considered "main frame navigations".
    for (bool is_main_frame_navigation : {false, true}) {
      for (const auto& test : cases) {
        std::stringstream scoped_trace_message;
        scoped_trace_message
            << "url: " << test.url << ", feature state: "
            << (top_level_only_enabled ? "enabled" : "disabled")
            << ", main frame navigation: "
            << (is_main_frame_navigation ? "yes" : "no");
        SCOPED_TRACE(scoped_trace_message.str());

        GURL url = GURL(test.url);
        url::Origin origin = url::Origin::Create(url);

        TestDelegate d;
        TestNetworkDelegate network_delegate;
        std::unique_ptr<URLRequest> r(context_->CreateRequest(
            url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS,
            net::handles::kInvalidNetworkHandle, false));

        // Only apply for main frame navigation based runs.
        if (is_main_frame_navigation) {
          r->set_isolation_info(IsolationInfo::Create(
              IsolationInfo::RequestType::kMainFrame, origin, origin,
              SiteForCookies::FromOrigin(origin),
              /*nonce=*/base::UnguessableToken::Create()));
        } else {
          r->set_isolation_info(IsolationInfo::Create(
              IsolationInfo::RequestType::kOther, origin, origin,
              SiteForCookies::FromOrigin(origin),
              /*nonce=*/base::UnguessableToken::Create()));
        }
        net_log_observer_.Clear();
        r->Start();
        d.RunUntilComplete();

        // An upgrade should be expected when
        // * The test case expects an upgrade AND
        // * `top_level_only_enabled` is false.
        //
        // This is because since these frames' "main frame" navigations aren't
        // true top-level navgiations (or, outermost main frame navigations)
        // they should never be upgraded when the feature is enabled.
        const bool upgrade_expected =
            test.upgrade_expected && !top_level_only_enabled;

        if (upgrade_expected) {
          auto entries = net_log_observer_.GetEntriesWithType(
              net::NetLogEventType::URL_REQUEST_REDIRECT_JOB);
          int redirects = entries.size();
          for (const auto& entry : entries) {
            EXPECT_EQ("HSTS", GetStringValueFromParams(entry, "reason"));
          }
          EXPECT_EQ(1, redirects);
          EXPECT_EQ(1, d.received_redirect_count());
          EXPECT_EQ(2u, r->url_chain().size());

          EXPECT_EQ(GURL(test.upgraded_url), r->url());
        } else {
          EXPECT_EQ(0, d.received_redirect_count());
          EXPECT_EQ(1u, r->url_chain().size());

          EXPECT_EQ(GURL(test.url), r->url());
        }
      }
    }
  }
}

TEST_F(URLRequestHttpJobTest, ShouldBypassHSTS) {
  // Setup HSTS state.
  context_->transport_security_state()->AddHSTS(
      "upgrade.test", base::Time::Now() + base::Seconds(30), true);
  // Setting `is_top_level_nav` true prevents the upgrade from being blocked by
  // kHstsTopLevelNavigationsOnly.
  ASSERT_TRUE(context_->transport_security_state()->ShouldUpgradeToSSL(
      "upgrade.test", /*is_top_level_nav=*/true));

  struct TestCase {
    const char* url;
    bool bypass_hsts;
    const char* url_expected;
  } cases[] = {
      {"http://upgrade.test/example.crl", true,
       "http://upgrade.test/example.crl"},
      // This test ensures that the HSTS check and upgrade happens prior to
      // cache and socket pool checks
      {"http://upgrade.test/example.crl", false,
       "https://upgrade.test/example.crl"},
      {"http://upgrade.test", false, "https://upgrade.test"},
      {"http://upgrade.test:1080", false, "https://upgrade.test:1080"},
#if BUILDFLAG(ENABLE_WEBSOCKETS)
      {"ws://upgrade.test/example.crl", true, "ws://upgrade.test/example.crl"},
      {"ws://upgrade.test/example.crl", false,
       "wss://upgrade.test/example.crl"},
      {"ws://upgrade.test", false, "wss://upgrade.test"},
      {"ws://upgrade.test:1080", false, "wss://upgrade.test:1080"},
#endif  // BUILDFLAG(ENABLE_WEBSOCKETS)
  };

  for (bool top_level_only_enabled : {false, true}) {
    base::test::ScopedFeatureList scoped_feature_list;
    scoped_feature_list.InitWithFeatureState(
        features::kHstsTopLevelNavigationsOnly, top_level_only_enabled);

    for (const auto& test : cases) {
      std::stringstream scoped_trace_message;
      scoped_trace_message << "url: " << test.url << ", feature state: "
                           << (top_level_only_enabled ? "enabled" : "disabled");
      SCOPED_TRACE(scoped_trace_message.str());

      GURL url = GURL(test.url);
      url::Origin origin = url::Origin::Create(url);
      // This is needed to bypass logic that rejects using URLRequests directly
      // for WebSocket requests.
      bool is_for_websockets = url.SchemeIsWSOrWSS();

      if (is_for_websockets && top_level_only_enabled) {
        // Websocket upgrades can't happen when only top-level navigations are
        // upgraded, so skip these test cases
        continue;
      }

      TestDelegate d;
      TestNetworkDelegate network_delegate;
      std::unique_ptr<URLRequest> r(context_->CreateRequest(
          url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS,
          net::handles::kInvalidNetworkHandle, is_for_websockets));
      if (!is_for_websockets) {
        r->set_isolation_info(IsolationInfo::Create(
            IsolationInfo::RequestType::kMainFrame, origin, origin,
            SiteForCookies::FromOrigin(origin)));
      }
      if (test.bypass_hsts) {
        r->SetLoadFlags(net::LOAD_SHOULD_BYPASS_HSTS);
        r->set_disallow_credentials();
      }

      net_log_observer_.Clear();
      r->Start();
      d.RunUntilComplete();

      if (test.bypass_hsts) {
        EXPECT_EQ(0, d.received_redirect_count());
        EXPECT_EQ(1u, r->url_chain().size());
      } else {
        auto entries = net_log_observer_.GetEntriesWithType(
            net::NetLogEventType::URL_REQUEST_REDIRECT_JOB);
        int redirects = entries.size();
        for (const auto& entry : entries) {
          EXPECT_EQ("HSTS", GetStringValueFromParams(entry, "reason"));
        }
        EXPECT_EQ(1, redirects);
        EXPECT_EQ(1, d.received_redirect_count());
        EXPECT_EQ(2u, r->url_chain().size());
      }
      EXPECT_EQ(GURL(test.url_expected), r->url());
    }
  }
}

#if BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS)

class URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest
    : public TestWithTaskEnvironment {
 protected:
  URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest() {
    auto context_builder = CreateTestURLRequestContextBuilder();
    context_builder->set_client_socket_factory_for_testing(&socket_factory_);
    context_builder->set_device_bound_session_service(
        std::make_unique<
            testing::StrictMock<device_bound_sessions::SessionServiceMock>>());
    context_ = context_builder->Build();
    request_ = context_->CreateRequest(
        GURL("https://www.example.com"), DEFAULT_PRIORITY, &delegate_,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
    request_->set_device_bound_session_mode(
        net::DeviceBoundSessionMode::kAllowed);
  }

  device_bound_sessions::SessionServiceMock& GetMockService() {
    return *static_cast<device_bound_sessions::SessionServiceMock*>(
        context_->device_bound_session_service());
  }

  MockClientSocketFactory socket_factory_;
  std::unique_ptr<URLRequestContext> context_;
  TestDelegate delegate_;
  std::unique_ptr<URLRequest> request_;
};

TEST_F(URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest,
       ShouldRespondToDeviceBoundSessionHeader) {
  const MockWrite writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.example.com\r\n"
                "Connection: keep-alive\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: gzip, deflate\r\n"
                "Accept-Language: en-us,fr\r\n\r\n")};

  const MockRead reads[] = {
      MockRead("HTTP/1.1 200 OK\r\n"
               "Accept-Ranges: bytes\r\n"
               "Secure-Session-Registration: (ES256);path=\"new\";"
               "challenge=\"test\"\r\n"
               "Content-Length: 12\r\n\r\n"),
      MockRead("Test Content")};

  net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
  ssl_socket_data_provider.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  EXPECT_CALL(GetMockService(), ShouldDefer).WillOnce(Return(std::nullopt));
  request_->Start();
  EXPECT_CALL(GetMockService(), HandleResponseHeaders).Times(1);
  delegate_.RunUntilComplete();
  EXPECT_THAT(delegate_.request_status(), IsOk());
}

TEST_F(URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest,
       DeferRequestIfNeeded) {
  base::HistogramTester histogram_tester;
  const MockWrite writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.example.com\r\n"
                "Connection: keep-alive\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: gzip, deflate\r\n"
                "Accept-Language: en-us,fr\r\n\r\n")};

  const MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                                     "Accept-Ranges: bytes\r\n"
                                     "Content-Length: 12\r\n\r\n"),
                            MockRead("Test Content")};

  net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
  ssl_socket_data_provider.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  {
    device_bound_sessions::SessionKey expected_key{
        SchemefulSite(GURL("https://example.com")),
        device_bound_sessions::Session::Id("test")};

    InSequence s;
    EXPECT_CALL(GetMockService(), ShouldDefer)
        .WillOnce([](Unused, Unused, Unused) {
          return device_bound_sessions::SessionService::DeferralParams(
              device_bound_sessions::Session::Id("test"));
        });
    EXPECT_CALL(GetMockService(), DeferRequestForRefresh)
        .WillOnce([expected_key](device_bound_sessions::DbscRequest request,
                                 Unused,
                                 device_bound_sessions::SessionServiceMock::
                                     RefreshCompleteCallback callback) {
          request.set_device_bound_session_usage(
              expected_key,
              net::device_bound_sessions::SessionUsage::kDeferred);
          std::move(callback).Run(
              device_bound_sessions::RefreshResult::kUnreachable);
        });
    EXPECT_CALL(GetMockService(), ShouldDefer)
        .WillOnce([expected_key](device_bound_sessions::DbscRequest request,
                                 Unused, Unused) {
          EXPECT_THAT(request.device_bound_session_deferrals(),
                      ElementsAre(Pair(
                          expected_key,
                          device_bound_sessions::RefreshResult::kUnreachable)));
          return std::nullopt;
        });
    EXPECT_CALL(GetMockService(), HandleResponseHeaders).Times(1);
  }

  request_->Start();
  delegate_.RunUntilComplete();
  EXPECT_THAT(delegate_.request_status(), IsOk());
  histogram_tester.ExpectUniqueSample(
      "Net.DeviceBoundSessions.RequestDeferralCount",
      /*sample=*/1,
      /*expected_bucket_count=*/1);
  histogram_tester.ExpectUniqueSample(
      "Net.DeviceBoundSessions.RequestDeferralDecision3",
      /*sample=*/device_bound_sessions::SessionUsage::kDeferred,
      /*expected_bucket_count=*/1);
}

TEST_F(URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest,
       DontDeferRequestIfNotNeeded) {
  base::HistogramTester histogram_tester;
  const MockWrite writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.example.com\r\n"
                "Connection: keep-alive\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: gzip, deflate\r\n"
                "Accept-Language: en-us,fr\r\n\r\n")};

  const MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                                     "Accept-Ranges: bytes\r\n"
                                     "Content-Length: 12\r\n\r\n"),
                            MockRead("Test Content")};

  net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
  ssl_socket_data_provider.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  EXPECT_CALL(GetMockService(), ShouldDefer)
      .WillOnce([](Unused, Unused, Unused) { return std::nullopt; });
  EXPECT_CALL(GetMockService(), HandleResponseHeaders).Times(1);
  request_->Start();
  delegate_.RunUntilComplete();
  EXPECT_THAT(delegate_.request_status(), IsOk());

  histogram_tester.ExpectUniqueSample(
      "Net.DeviceBoundSessions.RequestDeferralCount",
      /*sample=*/0,
      /*expected_bucket_count=*/1);
  histogram_tester.ExpectUniqueSample(
      "Net.DeviceBoundSessions.RequestDeferralDecision3",
      /*sample=*/device_bound_sessions::SessionUsage::kNoSiteMatchNotInScope,
      /*expected_bucket_count=*/1);
}

TEST_F(URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest,
       DeferMultipleTimesIfNeeded) {
  const MockWrite writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.example.com\r\n"
                "Connection: keep-alive\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: gzip, deflate\r\n"
                "Accept-Language: en-us,fr\r\n\r\n")};

  const MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                                     "Accept-Ranges: bytes\r\n"
                                     "Content-Length: 12\r\n\r\n"),
                            MockRead("Test Content")};

  net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
  ssl_socket_data_provider.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  {
    SchemefulSite expected_site(GURL("https://example.com"));
    device_bound_sessions::SessionKey first_expected_key{
        expected_site, device_bound_sessions::Session::Id("test")};
    device_bound_sessions::SessionKey second_expected_key{
        expected_site, device_bound_sessions::Session::Id("test2")};

    InSequence s;
    EXPECT_CALL(GetMockService(), ShouldDefer)
        .WillOnce(Return(device_bound_sessions::SessionService::DeferralParams(
            device_bound_sessions::Session::Id("test"))));
    EXPECT_CALL(GetMockService(), DeferRequestForRefresh)
        .WillOnce(base::test::RunOnceCallback<2>(
            device_bound_sessions::RefreshResult::kUnreachable));
    EXPECT_CALL(GetMockService(), ShouldDefer)
        .WillOnce([first_expected_key](
                      device_bound_sessions::DbscRequest request, Unused,
                      Unused) {
          EXPECT_THAT(request.device_bound_session_deferrals(),
                      ElementsAre(Pair(
                          first_expected_key,
                          device_bound_sessions::RefreshResult::kUnreachable)));
          return device_bound_sessions::SessionService::DeferralParams(
              device_bound_sessions::Session::Id("test2"));
        });
    EXPECT_CALL(GetMockService(), DeferRequestForRefresh)
        .WillOnce(base::test::RunOnceCallback<2>(
            device_bound_sessions::RefreshResult::kUnreachable));
    EXPECT_CALL(GetMockService(), ShouldDefer)
        .WillOnce([first_expected_key, second_expected_key](
                      device_bound_sessions::DbscRequest request, Unused,
                      Unused) {
          EXPECT_THAT(
              request.device_bound_session_deferrals(),
              UnorderedElementsAre(
                  Pair(first_expected_key,
                       device_bound_sessions::RefreshResult::kUnreachable),
                  Pair(second_expected_key,
                       device_bound_sessions::RefreshResult::kUnreachable)));

          return std::nullopt;
        });
    EXPECT_CALL(GetMockService(), HandleResponseHeaders).Times(1);
  }

  request_->Start();
  delegate_.RunUntilComplete();
  EXPECT_THAT(delegate_.request_status(), IsOk());
}

TEST_F(URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest,
       MultipleSessionUsages) {
  base::HistogramTester histogram_tester;
  const MockWrite writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.example.com\r\n"
                "Connection: keep-alive\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: gzip, deflate\r\n"
                "Accept-Language: en-us,fr\r\n\r\n")};

  const MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                                     "Accept-Ranges: bytes\r\n"
                                     "Content-Length: 12\r\n\r\n"),
                            MockRead("Test Content")};

  net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
  ssl_socket_data_provider.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  {
    SchemefulSite expected_site(GURL("https://example.com"));
    device_bound_sessions::SessionKey first_key{
        expected_site, device_bound_sessions::Session::Id("test")};
    device_bound_sessions::SessionKey second_key{
        expected_site, device_bound_sessions::Session::Id("test2")};

    InSequence s;
    EXPECT_CALL(GetMockService(), ShouldDefer)
        .WillOnce(
            [first_key, second_key](device_bound_sessions::DbscRequest request,
                                    Unused, Unused) {
              request.set_device_bound_session_usage(
                  first_key, net::device_bound_sessions::SessionUsage::
                                 kInScopeRefreshNotYetNeeded);
              request.set_device_bound_session_usage(
                  second_key, net::device_bound_sessions::SessionUsage::
                                  kInScopeProactiveRefreshNotPossible);
              return std::nullopt;
            });
    EXPECT_CALL(GetMockService(), HandleResponseHeaders).Times(1);
  }

  request_->Start();
  delegate_.RunUntilComplete();
  EXPECT_THAT(delegate_.request_status(), IsOk());
  histogram_tester.ExpectUniqueSample(
      "Net.DeviceBoundSessions.RequestDeferralCount",
      /*sample=*/0,
      /*expected_bucket_count=*/1);
  histogram_tester.ExpectUniqueSample(
      "Net.DeviceBoundSessions.RequestDeferralDecision3",
      /*sample=*/
      device_bound_sessions::SessionUsage::kInScopeProactiveRefreshNotPossible,
      /*expected_bucket_count=*/1);
}

TEST_F(URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest,
       DeferSuccessfulRefresh) {
  const MockWrite writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.example.com\r\n"
                "Connection: keep-alive\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: gzip, deflate\r\n"
                "Accept-Language: en-us,fr\r\n\r\n")};

  const MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                                     "Accept-Ranges: bytes\r\n"
                                     "Content-Length: 12\r\n\r\n"),
                            MockRead("Test Content")};

  net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
  ssl_socket_data_provider.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  {
    device_bound_sessions::SessionKey expected_key{
        SchemefulSite(GURL("https://example.com")),
        device_bound_sessions::Session::Id("test")};

    InSequence s;
    EXPECT_CALL(GetMockService(), ShouldDefer)
        .WillOnce(Return(device_bound_sessions::SessionService::DeferralParams(
            device_bound_sessions::Session::Id("test"))));
    EXPECT_CALL(GetMockService(), DeferRequestForRefresh)
        .WillOnce([expected_key](device_bound_sessions::DbscRequest request,
                                 Unused,
                                 device_bound_sessions::SessionServiceMock::
                                     RefreshCompleteCallback callback) {
          request.set_device_bound_session_usage(
              expected_key,
              net::device_bound_sessions::SessionUsage::kDeferred);
          std::move(callback).Run(
              device_bound_sessions::RefreshResult::kUnreachable);
        });
    EXPECT_CALL(GetMockService(), ShouldDefer)
        .WillOnce([expected_key](device_bound_sessions::DbscRequest request,
                                 Unused, Unused) {
          EXPECT_THAT(request.device_bound_session_deferrals(),
                      ElementsAre(Pair(
                          expected_key,
                          device_bound_sessions::RefreshResult::kUnreachable)));
          return std::nullopt;
        });
    EXPECT_CALL(GetMockService(), HandleResponseHeaders).Times(1);
  }

  request_->Start();
  delegate_.RunUntilComplete();
  EXPECT_THAT(delegate_.request_status(), IsOk());
}

TEST_F(URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest,
       DeferSuccessfulRefreshForWebSockets) {
  const MockWrite writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.example.org\r\n"
                "Connection: Upgrade\r\n"
                "Pragma: no-cache\r\n"
                "Cache-Control: no-cache\r\n"
                "Upgrade: websocket\r\n"
                "Origin: http://origin.example.org\r\n"
                "Sec-WebSocket-Version: 13\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: gzip, deflate\r\n"
                "Accept-Language: en-us,fr\r\n"
                "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
                "Sec-WebSocket-Extensions: permessage-deflate; "
                "client_max_window_bits\r\n\r\n")};

  const MockRead reads[] = {
      MockRead("HTTP/1.1 101 Switching Protocols\r\n"
               "Upgrade: websocket\r\n"
               "Connection: Upgrade\r\n"
               "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"),
      MockRead(ASYNC, 0)};

  net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
  ssl_socket_data_provider.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  {
    device_bound_sessions::SessionKey expected_key{
        SchemefulSite(GURL("https://example.com")),
        device_bound_sessions::Session::Id("test")};

    InSequence s;
    EXPECT_CALL(GetMockService(), ShouldDefer)
        .WillOnce(Return(device_bound_sessions::SessionService::DeferralParams(
            device_bound_sessions::Session::Id("test"))));
    EXPECT_CALL(GetMockService(), DeferRequestForRefresh)
        .WillOnce([expected_key](device_bound_sessions::DbscRequest request,
                                 Unused,
                                 device_bound_sessions::SessionServiceMock::
                                     RefreshCompleteCallback callback) {
          request.set_device_bound_session_usage(
              expected_key,
              net::device_bound_sessions::SessionUsage::kDeferred);
          std::move(callback).Run(
              device_bound_sessions::RefreshResult::kUnreachable);
        });
    EXPECT_CALL(GetMockService(), ShouldDefer)
        .WillOnce([expected_key](device_bound_sessions::DbscRequest request,
                                 Unused, Unused) {
          EXPECT_THAT(request.device_bound_session_deferrals(),
                      ElementsAre(Pair(
                          expected_key,
                          device_bound_sessions::RefreshResult::kUnreachable)));
          return std::nullopt;
        });
    EXPECT_CALL(GetMockService(), HandleResponseHeaders).Times(1);
  }

  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("wss://www.example.com"), DEFAULT_PRIORITY, &delegate_,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle,
      /*is_for_websockets=*/true);
  request->set_device_bound_session_mode(net::DeviceBoundSessionMode::kAllowed);
  HttpRequestHeaders headers = WebSocketCommonTestHeaders();
  request->SetExtraRequestHeaders(headers);

  auto websocket_stream_create_helper =
      std::make_unique<TestWebSocketHandshakeStreamCreateHelper>();
  request->SetUserData(kWebSocketHandshakeUserDataKey,
                       std::move(websocket_stream_create_helper));

  request->Start();
  delegate_.RunUntilComplete();
  EXPECT_THAT(delegate_.request_status(), IsOk());
}

TEST_F(URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest,
       ShouldNotRespondWithoutDeviceBoundSessionHeader) {
  const MockWrite writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.example.com\r\n"
                "Connection: keep-alive\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: gzip, deflate\r\n"
                "Accept-Language: en-us,fr\r\n\r\n")};

  const MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                                     "Accept-Ranges: bytes\r\n"
                                     "Content-Length: 12\r\n\r\n"),
                            MockRead("Test Content")};

  net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
  ssl_socket_data_provider.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  {
    InSequence s;
    EXPECT_CALL(GetMockService(), ShouldDefer).WillOnce(Return(std::nullopt));
    EXPECT_CALL(GetMockService(), RegisterBoundSession).Times(0);
    EXPECT_CALL(GetMockService(), HandleResponseHeaders)
        .WillOnce([](device_bound_sessions::DbscRequest& request,
                     HttpResponseHeaders* headers,
                     const FirstPartySetMetadata& first_party_set_metadata) {
          std::vector<device_bound_sessions::RegistrationFetcherParam> params =
              device_bound_sessions::RegistrationFetcherParam::CreateIfValid(
                  request.url(), headers,
                  /*restricted_sites=*/std::vector<SchemefulSite>());
          ASSERT_EQ(params.size(), 0u);
        });
  }
  request_->Start();
  delegate_.RunUntilComplete();
  EXPECT_THAT(delegate_.request_status(), IsOk());
}

TEST_F(URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest,
       ShouldProcessDeviceBoundSessionChallengeHeader) {
  const MockWrite writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.example.com\r\n"
                "Connection: keep-alive\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: gzip, deflate\r\n"
                "Accept-Language: en-us,fr\r\n\r\n")};

  const MockRead reads[] = {
      MockRead("HTTP/1.1 200 OK\r\n"
               "Accept-Ranges: bytes\r\n"
               "Secure-Session-Challenge: "
               "\"session_identifier\";challenge=\"test\"\r\n"
               "Content-Length: 12\r\n\r\n"),
      MockRead("Test Content")};

  net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
  ssl_socket_data_provider.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  {
    InSequence s;
    EXPECT_CALL(GetMockService(), ShouldDefer).WillOnce(Return(std::nullopt));
    EXPECT_CALL(GetMockService(), HandleResponseHeaders)
        .WillOnce([](device_bound_sessions::DbscRequest& request,
                     HttpResponseHeaders* headers,
                     const FirstPartySetMetadata& first_party_set_metadata) {
          std::vector<device_bound_sessions::SessionChallengeParam>
              challenge_params =
                  device_bound_sessions::SessionChallengeParam::CreateIfValid(
                      request.url(), headers);
          ASSERT_EQ(challenge_params.size(), 1u);
        });
  }
  request_->Start();
  delegate_.RunUntilComplete();
  EXPECT_THAT(delegate_.request_status(), IsOk());
}

// Verifies that Secure-Session-Registration headers are ignored when the
// response is served over a connection with certificate errors.
TEST_F(URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest,
       RegistrationHeaderIgnoredOnCertError) {
  const MockWrite writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.example.com\r\n"
                "Connection: keep-alive\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: gzip, deflate\r\n"
                "Accept-Language: en-us,fr\r\n\r\n")};

  const MockRead reads[] = {
      MockRead("HTTP/1.1 200 OK\r\n"
               "Accept-Ranges: bytes\r\n"
               "Secure-Session-Registration: (ES256);path=\"new\";"
               "challenge=\"test\"\r\n"
               "Content-Length: 12\r\n\r\n"),
      MockRead("Test Content")};

  net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
  ssl_socket_data_provider.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem");
  // Set cert status error.
  ssl_socket_data_provider.ssl_info.cert_status = CERT_STATUS_DATE_INVALID;
  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  EXPECT_CALL(GetMockService(), ShouldDefer)
      .WillRepeatedly(Return(std::nullopt));

  // Verify that ProcessDeviceBoundSessionsHeader() did NOT invoke the
  // SessionService because of the certificate error.
  EXPECT_CALL(GetMockService(), HandleResponseHeaders).Times(0);

  request_->Start();
  delegate_.RunUntilComplete();
  EXPECT_THAT(delegate_.request_status(), IsOk());

  // Verify that the connection was flagged with a certificate error.
  EXPECT_TRUE(IsCertStatusError(request_->ssl_info().cert_status));
}

#endif  // BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS)

namespace {
std::unique_ptr<test_server::HttpResponse> HandleRequest(
    const std::string_view& content,
    const test_server::HttpRequest& request) {
  auto response = std::make_unique<test_server::BasicHttpResponse>();
  response->set_content(content);
  return std::move(response);
}
}  // namespace

// This test checks that if an HTTP connection was made for a request that has
// the should_bypass_hsts flag set to true, subsequent calls to the exact same
// URL WITHOUT should_bypass_hsts=true will be upgraded to HTTPS early
// enough in the process such that the HTTP socket connection is not re-used,
// and the request does not have a hit in the cache.
TEST_F(URLRequestHttpJobTest, ShouldBypassHSTSResponseAndConnectionNotReused) {
  constexpr std::string_view kSecureContent = "Secure: Okay Content";
  constexpr std::string_view kInsecureContent = "Insecure: Bad Content";

  auto context_builder = CreateTestURLRequestContextBuilder();
  auto context = context_builder->Build();

  // The host of all EmbeddedTestServer URLs is 127.0.0.1.
  context->transport_security_state()->AddHSTS(
      "127.0.0.1", base::Time::Now() + base::Seconds(30), true);
  // Setting `is_top_level_nav` true prevents the upgrade from being blocked by
  // kHstsTopLevelNavigationsOnly.
  ASSERT_TRUE(context->transport_security_state()->ShouldUpgradeToSSL(
      "127.0.0.1", /*is_top_level_nav=*/true));

  GURL::Replacements replace_scheme;
  replace_scheme.SetSchemeStr("https");
  GURL insecure_url;
  GURL secure_url;

  int common_port = 0;

  // Create an HTTP request that is not upgraded to the should_bypass_hsts flag,
  // and ensure that the response is stored in the cache.
  {
    EmbeddedTestServer http_server(EmbeddedTestServer::TYPE_HTTP);
    http_server.AddDefaultHandlers(base::FilePath());
    http_server.RegisterRequestHandler(
        base::BindRepeating(&HandleRequest, kInsecureContent));
    ASSERT_TRUE(http_server.Start());
    common_port = http_server.port();

    insecure_url = http_server.base_url();
    ASSERT_TRUE(insecure_url.SchemeIs("http"));
    secure_url = insecure_url.ReplaceComponents(replace_scheme);
    ASSERT_TRUE(secure_url.SchemeIs("https"));

    net_log_observer_.Clear();
    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        insecure_url, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS,
        net::handles::kInvalidNetworkHandle));
    req->SetLoadFlags(net::LOAD_SHOULD_BYPASS_HSTS);
    req->set_disallow_credentials();
    req->Start();
    delegate.RunUntilComplete();
    EXPECT_EQ(kInsecureContent, delegate.data_received());
    // There should be 2 cache event entries, one for beginning the read and one
    // for finishing the read.
    EXPECT_EQ(2u, net_log_observer_
                      .GetEntriesWithType(
                          net::NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY)
                      .size());
    ASSERT_TRUE(http_server.ShutdownAndWaitUntilComplete());
  }
  // Test that a request with the same URL will be upgraded as long as
  // should_bypass_hsts flag is not set, and doesn't have an cache hit or
  // re-use an existing socket connection.
  {
    EmbeddedTestServer https_server(EmbeddedTestServer::TYPE_HTTPS);
    https_server.AddDefaultHandlers(base::FilePath());
    https_server.RegisterRequestHandler(
        base::BindRepeating(&HandleRequest, kSecureContent));
    ASSERT_TRUE(https_server.Start(common_port));

    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        insecure_url, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS,
        net::handles::kInvalidNetworkHandle));
    req->set_disallow_credentials();
    url::Origin insecure_origin = url::Origin::Create(insecure_url);
    req->set_isolation_info(IsolationInfo::Create(
        IsolationInfo::RequestType::kMainFrame, insecure_origin,
        insecure_origin, SiteForCookies::FromOrigin(insecure_origin)));
    req->Start();
    delegate.RunUntilRedirect();
    // Ensure that the new URL has an upgraded protocol. This ensures that when
    // the redirect request continues, the HTTP socket connection from before
    // will not be re-used, given that "protocol" is one of the fields used to
    // create a socket connection. Documentation here:
    // https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/life-of-a-url-request.md
    // under "Socket Pools" section.
    EXPECT_EQ(delegate.redirect_info().new_url, secure_url);
    EXPECT_TRUE(delegate.redirect_info().new_url.SchemeIs("https"));
    EXPECT_THAT(delegate.request_status(), net::ERR_IO_PENDING);

    req->FollowDeferredRedirect(std::nullopt /* removed_headers */,
                                std::nullopt /* modified_headers */);
    delegate.RunUntilComplete();
    EXPECT_EQ(kSecureContent, delegate.data_received());
    EXPECT_FALSE(req->was_cached());
    ASSERT_TRUE(https_server.ShutdownAndWaitUntilComplete());
  }
}

TEST_F(URLRequestHttpJobTest, HSTSInternalRedirectCallback) {
  EmbeddedTestServer https_test(EmbeddedTestServer::TYPE_HTTPS);
  https_test.AddDefaultHandlers(base::FilePath());
  ASSERT_TRUE(https_test.Start());

  auto context = CreateTestURLRequestContextBuilder()->Build();
  context->transport_security_state()->AddHSTS(
      "127.0.0.1", base::Time::Now() + base::Seconds(10), true);
  // Setting `is_top_level_nav` true prevents the upgrade from being blocked by
  // kHstsTopLevelNavigationsOnly.
  ASSERT_TRUE(context->transport_security_state()->ShouldUpgradeToSSL(
      "127.0.0.1", /*is_top_level_nav=*/true));

  GURL::Replacements replace_scheme;
  replace_scheme.SetSchemeStr("http");

  {
    GURL url(
        https_test.GetURL("/echoheader").ReplaceComponents(replace_scheme));
    url::Origin origin = url::Origin::Create(url);
    TestDelegate delegate;
    HttpRequestHeaders extra_headers;
    extra_headers.SetHeader("X-HSTS-Test", "1");

    std::unique_ptr<URLRequest> r(context->CreateRequest(
        url, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS,
        net::handles::kInvalidNetworkHandle));
    r->SetExtraRequestHeaders(extra_headers);
    bool seen_raw_request_headers = false;
    bool seen_raw_response_headers = false;
    r->SetRequestHeadersCallback(base::BindLambdaForTesting(
        [&seen_raw_request_headers](HttpRawRequestHeaders) {
          seen_raw_request_headers = true;
        }));
    r->SetResponseHeadersCallback(base::BindLambdaForTesting(
        [&seen_raw_response_headers](scoped_refptr<const HttpResponseHeaders>) {
          seen_raw_response_headers = true;
        }));
    r->set_isolation_info(
        IsolationInfo::Create(IsolationInfo::RequestType::kMainFrame, origin,
                              origin, SiteForCookies::FromOrigin(origin)));
    r->Start();
    delegate.RunUntilRedirect();

    EXPECT_FALSE(seen_raw_request_headers);
    EXPECT_FALSE(seen_raw_response_headers);

    r->FollowDeferredRedirect(std::nullopt /* removed_headers */,
                              std::nullopt /* modified_headers */);
    delegate.RunUntilComplete();
    EXPECT_TRUE(seen_raw_request_headers);
    EXPECT_TRUE(seen_raw_response_headers);
  }

  {
    GURL url(https_test.GetURL("/echoheader?foo=bar")
                 .ReplaceComponents(replace_scheme));
    url::Origin origin = url::Origin::Create(url);
    TestDelegate delegate;

    std::unique_ptr<URLRequest> r(context->CreateRequest(
        url, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS,
        net::handles::kInvalidNetworkHandle));
    r->SetRequestHeadersCallback(base::BindRepeating([](HttpRawRequestHeaders) {
      ADD_FAILURE() << "RequestHeadersCallback unexpectedly called.";
    }));
    r->SetResponseHeadersCallback(
        base::BindRepeating([](scoped_refptr<const HttpResponseHeaders>) {
          ADD_FAILURE() << "ResponseHeadersCallback unexpectedly called.";
        }));
    r->set_isolation_info(
        IsolationInfo::Create(IsolationInfo::RequestType::kMainFrame, origin,
                              origin, SiteForCookies::FromOrigin(origin)));
    r->Start();
    delegate.RunUntilRedirect();
  }

  {
    GURL url(
        https_test.GetURL("/echoheader#foo").ReplaceComponents(replace_scheme));
    url::Origin origin = url::Origin::Create(url);
    TestDelegate delegate;

    std::unique_ptr<URLRequest> r(context->CreateRequest(
        url, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS,
        net::handles::kInvalidNetworkHandle));
    r->SetRequestHeadersCallback(base::BindRepeating([](HttpRawRequestHeaders) {
      ADD_FAILURE() << "RequestHeadersCallback unexpectedly called.";
    }));
    r->SetResponseHeadersCallback(
        base::BindRepeating([](scoped_refptr<const HttpResponseHeaders>) {
          ADD_FAILURE() << "ResponseHeadersCallback unexpectedly called.";
        }));
    r->set_isolation_info(
        IsolationInfo::Create(IsolationInfo::RequestType::kMainFrame, origin,
                              origin, SiteForCookies::FromOrigin(origin)));
    r->Start();
    delegate.RunUntilRedirect();
  }
}

class URLRequestHttpJobWithBrotliSupportTest : public TestWithTaskEnvironment {
 protected:
  URLRequestHttpJobWithBrotliSupportTest() {
    HttpNetworkSessionParams params;
    auto context_builder = CreateTestURLRequestContextBuilder();
    context_builder->set_enable_brotli(true);
    context_builder->set_http_network_session_params(params);
    context_builder->set_client_socket_factory_for_testing(&socket_factory_);
    context_ = context_builder->Build();
  }

  MockClientSocketFactory socket_factory_;
  std::unique_ptr<URLRequestContext> context_;
};

TEST_F(URLRequestHttpJobWithBrotliSupportTest, NoBrotliAdvertisementOverHttp) {
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  request->Start();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsOk());
  EXPECT_EQ(12, request->received_response_content_length());
  EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
  EXPECT_EQ(CountReadByteSize(reads), request->GetTotalReceivedBytes());
}

TEST_F(URLRequestHttpJobWithBrotliSupportTest, BrotliAdvertisement) {
  net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
  ssl_socket_data_provider.next_proto = NextProto::kProtoHTTP11;
  ssl_socket_data_provider.ssl_info.cert =
      ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
  ASSERT_TRUE(ssl_socket_data_provider.ssl_info.cert);
  socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);

  MockWrite writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.example.com\r\n"
                "Connection: keep-alive\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: gzip, deflate, br\r\n"
                "Accept-Language: en-us,fr\r\n\r\n")};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};
  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("https://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  request->Start();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsOk());
  EXPECT_EQ(12, request->received_response_content_length());
  EXPECT_EQ(CountWriteByteSize(writes), request->GetTotalSentBytes());
  EXPECT_EQ(CountReadByteSize(reads), request->GetTotalReceivedBytes());
}

TEST_F(URLRequestHttpJobWithBrotliSupportTest, DefaultAcceptEncodingOverriden) {
  struct {
    base::flat_set<net::SourceStreamType> accepted_types;
    const std::string_view expected_request_headers;
  } kTestCases[] = {
      {{net::SourceStreamType::kDeflate},
       "GET / HTTP/1.1\r\n"
       "Host: www.example.com\r\n"
       "Connection: keep-alive\r\n"
       "User-Agent: \r\n"
       "Accept-Encoding: deflate\r\n"
       "Accept-Language: en-us,fr\r\n\r\n"},
      {{},
       "GET / HTTP/1.1\r\n"
       "Host: www.example.com\r\n"
       "Connection: keep-alive\r\n"
       "User-Agent: \r\n"
       "Accept-Language: en-us,fr\r\n\r\n"},
      {{net::SourceStreamType::kGzip},
       "GET / HTTP/1.1\r\n"
       "Host: www.example.com\r\n"
       "Connection: keep-alive\r\n"
       "User-Agent: \r\n"
       "Accept-Encoding: gzip\r\n"
       "Accept-Language: en-us,fr\r\n\r\n"},
      {{net::SourceStreamType::kGzip, net::SourceStreamType::kDeflate},
       "GET / HTTP/1.1\r\n"
       "Host: www.example.com\r\n"
       "Connection: keep-alive\r\n"
       "User-Agent: \r\n"
       "Accept-Encoding: gzip, deflate\r\n"
       "Accept-Language: en-us,fr\r\n\r\n"},
      {{net::SourceStreamType::kBrotli},
       "GET / HTTP/1.1\r\n"
       "Host: www.example.com\r\n"
       "Connection: keep-alive\r\n"
       "User-Agent: \r\n"
       "Accept-Encoding: br\r\n"
       "Accept-Language: en-us,fr\r\n\r\n"},
      {{net::SourceStreamType::kBrotli, net::SourceStreamType::kGzip,
        net::SourceStreamType::kDeflate},
       "GET / HTTP/1.1\r\n"
       "Host: www.example.com\r\n"
       "Connection: keep-alive\r\n"
       "User-Agent: \r\n"
       "Accept-Encoding: gzip, deflate, br\r\n"
       "Accept-Language: en-us,fr\r\n\r\n"}};

  for (auto test : kTestCases) {
    net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
    ssl_socket_data_provider.next_proto = NextProto::kProtoHTTP11;
    ssl_socket_data_provider.ssl_info.cert =
        ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
    ASSERT_TRUE(ssl_socket_data_provider.ssl_info.cert);
    socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);

    MockWrite writes[] = {MockWrite(test.expected_request_headers)};
    MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                                 "Content-Length: 12\r\n\r\n"),
                        MockRead("Test Content")};
    StaticSocketDataProvider socket_data(reads, writes);
    socket_factory_.AddSocketDataProvider(&socket_data);

    TestDelegate delegate;
    std::unique_ptr<URLRequest> request = context_->CreateRequest(
        GURL("https://www.example.com"), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
    request->set_accepted_stream_types(test.accepted_types);
    request->Start();
    delegate.RunUntilComplete();
    EXPECT_THAT(delegate.request_status(), IsOk());
    socket_factory_.ResetNextMockIndexes();
  }
}

#if BUILDFLAG(IS_ANDROID)
class URLRequestHttpJobWithCheckClearTextPermittedTest
    : public TestWithTaskEnvironment {
 protected:
  URLRequestHttpJobWithCheckClearTextPermittedTest() {
    auto context_builder = CreateTestURLRequestContextBuilder();
    context_builder->SetHttpTransactionFactoryForTesting(
        std::make_unique<MockNetworkLayer>());
    context_builder->set_check_cleartext_permitted(true);
    context_builder->set_client_socket_factory_for_testing(&socket_factory_);
    context_ = context_builder->Build();
  }

  MockClientSocketFactory socket_factory_;
  std::unique_ptr<URLRequestContext> context_;
};

TEST_F(URLRequestHttpJobWithCheckClearTextPermittedTest,
       AndroidCleartextPermittedTest) {
  static constexpr struct TestCase {
    const char* url;
    bool cleartext_permitted;
    bool should_block;
    int expected_per_host_call_count;
    int expected_default_call_count;
  } kTestCases[] = {
      {"http://unblocked.test/", true, false, 1, 0},
      {"https://unblocked.test/", true, false, 0, 0},
      {"http://blocked.test/", false, true, 1, 0},
      {"https://blocked.test/", false, false, 0, 0},
      // If determining the per-host cleartext policy causes an
      // IllegalArgumentException (because the hostname is invalid),
      // the default configuration should be applied, and the
      // exception should not cause a JNI error.
      {"http://./", false, true, 1, 1},
      {"http://./", true, false, 1, 1},
      // Even if the host name would be considered invalid, https
      // schemes should not trigger cleartext policy checks.
      {"https://./", false, false, 0, 0},
  };

  JNIEnv* env = base::android::AttachCurrentThread();
  for (const TestCase& test : kTestCases) {
    Java_AndroidNetworkLibraryTestUtil_setUpSecurityPolicyForTesting(
        env, test.cleartext_permitted);

    TestDelegate delegate;
    std::unique_ptr<URLRequest> request = context_->CreateRequest(
        GURL(test.url), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
    request->Start();
    delegate.RunUntilComplete();

    if (test.should_block) {
      EXPECT_THAT(delegate.request_status(),
                  IsError(ERR_CLEARTEXT_NOT_PERMITTED));
    } else {
      // Should fail since there's no test server running
      EXPECT_THAT(delegate.request_status(), IsError(ERR_FAILED));
    }
    EXPECT_EQ(
        Java_AndroidNetworkLibraryTestUtil_getPerHostCleartextCheckCount(env),
        test.expected_per_host_call_count);
    EXPECT_EQ(
        Java_AndroidNetworkLibraryTestUtil_getDefaultCleartextCheckCount(env),
        test.expected_default_call_count);
  }
}
#endif

#if BUILDFLAG(ENABLE_WEBSOCKETS)

class URLRequestHttpJobWebSocketTest : public TestWithTaskEnvironment {
 protected:
  URLRequestHttpJobWebSocketTest() {
    auto context_builder = CreateTestURLRequestContextBuilder();
    context_builder->set_client_socket_factory_for_testing(&socket_factory_);
    context_ = context_builder->Build();
    req_ = context_->CreateRequest(
        GURL("ws://www.example.org"), DEFAULT_PRIORITY, &delegate_,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle,
        /*is_for_websockets=*/true);
  }

  std::unique_ptr<URLRequestContext> context_;
  MockClientSocketFactory socket_factory_;
  TestDelegate delegate_;
  std::unique_ptr<URLRequest> req_;
};

TEST_F(URLRequestHttpJobWebSocketTest, RejectedWithoutCreateHelper) {
  req_->Start();
  delegate_.RunUntilComplete();
  EXPECT_THAT(delegate_.request_status(), IsError(ERR_DISALLOWED_URL_SCHEME));
}

TEST_F(URLRequestHttpJobWebSocketTest, CreateHelperPassedThrough) {
  HttpRequestHeaders headers;
  headers.SetHeader("Connection", "Upgrade");
  headers.SetHeader("Upgrade", "websocket");
  headers.SetHeader("Origin", "http://www.example.org");
  headers.SetHeader("Sec-WebSocket-Version", "13");
  req_->SetExtraRequestHeaders(headers);

  MockWrite writes[] = {
      MockWrite("GET / HTTP/1.1\r\n"
                "Host: www.example.org\r\n"
                "Connection: Upgrade\r\n"
                "Upgrade: websocket\r\n"
                "Origin: http://www.example.org\r\n"
                "Sec-WebSocket-Version: 13\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: gzip, deflate\r\n"
                "Accept-Language: en-us,fr\r\n"
                "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
                "Sec-WebSocket-Extensions: permessage-deflate; "
                "client_max_window_bits\r\n\r\n")};

  MockRead reads[] = {
      MockRead("HTTP/1.1 101 Switching Protocols\r\n"
               "Upgrade: websocket\r\n"
               "Connection: Upgrade\r\n"
               "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"),
      MockRead(ASYNC, 0)};

  StaticSocketDataProvider data(reads, writes);
  socket_factory_.AddSocketDataProvider(&data);

  auto websocket_stream_create_helper =
      std::make_unique<TestWebSocketHandshakeStreamCreateHelper>();

  req_->SetUserData(kWebSocketHandshakeUserDataKey,
                    std::move(websocket_stream_create_helper));
  req_->SetLoadFlags(LOAD_DISABLE_CACHE);
  req_->Start();
  delegate_.RunUntilComplete();
  EXPECT_THAT(delegate_.request_status(), IsOk());
  EXPECT_TRUE(delegate_.response_completed());

  EXPECT_TRUE(data.AllWriteDataConsumed());
  EXPECT_TRUE(data.AllReadDataConsumed());
}

#endif  // BUILDFLAG(ENABLE_WEBSOCKETS)

bool SetAllCookies(CookieMonster* cm, const CookieList& list) {
  DCHECK(cm);
  ResultSavingCookieCallback<CookieAccessResult> callback;
  cm->SetAllCookiesAsync(list, callback.MakeCallback());
  callback.WaitUntilDone();
  return callback.result().status.IsInclude();
}

bool CreateAndSetCookie(CookieStore* cs,
                        const GURL& url,
                        const std::string& cookie_line) {
  auto cookie = CanonicalCookie::CreateForTesting(
      url, cookie_line, base::Time::Now(), CookieSourceType::kOther);
  if (!cookie) {
    return false;
  }
  DCHECK(cs);
  ResultSavingCookieCallback<CookieAccessResult> callback;
  cs->SetCanonicalCookieAsync(
      std::move(cookie), url, CookieOptions::MakeAllInclusive(),
      callback.MakeCallback(), /*cookie_access_result=*/std::nullopt);
  callback.WaitUntilDone();
  return callback.result().status.IsInclude();
}

class SameSiteBypassNetworkDelegate : public TestNetworkDelegate {
 public:
  bool OnShouldForceIgnoreSiteForCookies(const URLRequest&) override {
    return true;
  }
};

void RunRequest(URLRequestContext* context, const GURL& url) {
  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context->CreateRequest(
      url, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS,
      net::handles::kInvalidNetworkHandle);

  // Make this a laxly same-site context to allow setting
  // SameSite=Lax-by-default cookies.
  request->set_site_for_cookies(SiteForCookies::FromUrl(url));
  request->Start();
  delegate.RunUntilComplete();
}

}  // namespace

TEST_F(URLRequestHttpJobTest, CookieSchemeRequestSchemeHistogram) {
  base::HistogramTester histograms;
  const std::string test_histogram = "Cookie.CookieSchemeRequestScheme";

  auto context_builder = CreateTestURLRequestContextBuilder();
  context_builder->SetCookieStore(std::make_unique<CookieMonster>(
      /*store=*/nullptr, /*net_log=*/nullptr));
  auto context = context_builder->Build();

  auto* cookie_store = static_cast<CookieMonster*>(context->cookie_store());

  // Secure set cookie marked as Unset source scheme.
  // Using port 7 because it fails the transaction without sending a request and
  // prevents a timeout due to the fake addresses. Because we only need the
  // headers to be generated (and thus the histogram filled) and not actually
  // sent this is acceptable.
  GURL nonsecure_url_for_unset1("http://unset1.example:7");
  GURL secure_url_for_unset1("https://unset1.example:7");

  // Normally the source scheme would be set by
  // CookieMonster::SetCanonicalCookie(), however we're using SetAllCookies() to
  // bypass the source scheme check in order to test the kUnset state which
  // would normally only happen during an existing cookie DB version upgrade.
  std::unique_ptr<CanonicalCookie> unset_cookie1 =
      CanonicalCookie::CreateForTesting(
          secure_url_for_unset1, "NoSourceSchemeHttps=val", base::Time::Now(),
          CookieSourceType::kOther);
  unset_cookie1->SetSourceScheme(net::CookieSourceScheme::kUnset);

  CookieList list1 = {*unset_cookie1};
  EXPECT_TRUE(SetAllCookies(cookie_store, list1));
  RunRequest(context.get(), nonsecure_url_for_unset1);
  histograms.ExpectBucketCount(
      test_histogram,
      URLRequestHttpJob::CookieRequestScheme::kUnsetCookieScheme, 1);
  RunRequest(context.get(), secure_url_for_unset1);
  histograms.ExpectBucketCount(
      test_histogram,
      URLRequestHttpJob::CookieRequestScheme::kUnsetCookieScheme, 2);

  // Nonsecure set cookie marked as unset source scheme.
  GURL nonsecure_url_for_unset2("http://unset2.example:7");
  GURL secure_url_for_unset2("https://unset2.example:7");

  std::unique_ptr<CanonicalCookie> unset_cookie2 =
      CanonicalCookie::CreateForTesting(
          nonsecure_url_for_unset2, "NoSourceSchemeHttp=val", base::Time::Now(),
          CookieSourceType::kOther);
  unset_cookie2->SetSourceScheme(net::CookieSourceScheme::kUnset);

  CookieList list2 = {*unset_cookie2};
  EXPECT_TRUE(SetAllCookies(cookie_store, list2));
  RunRequest(context.get(), nonsecure_url_for_unset2);
  histograms.ExpectBucketCount(
      test_histogram,
      URLRequestHttpJob::CookieRequestScheme::kUnsetCookieScheme, 3);
  RunRequest(context.get(), secure_url_for_unset2);
  histograms.ExpectBucketCount(
      test_histogram,
      URLRequestHttpJob::CookieRequestScheme::kUnsetCookieScheme, 4);

  // Secure set cookie with source scheme marked appropriately.
  GURL nonsecure_url_for_secure_set("http://secureset.example:7");
  GURL secure_url_for_secure_set("https://secureset.example:7");

  EXPECT_TRUE(CreateAndSetCookie(cookie_store, secure_url_for_secure_set,
                                 "SecureScheme=val"));
  RunRequest(context.get(), nonsecure_url_for_secure_set);
  histograms.ExpectBucketCount(
      test_histogram,
      URLRequestHttpJob::CookieRequestScheme::kSecureSetNonsecureRequest, 1);
  RunRequest(context.get(), secure_url_for_secure_set);
  histograms.ExpectBucketCount(
      test_histogram,
      URLRequestHttpJob::CookieRequestScheme::kSecureSetSecureRequest, 1);

  // Nonsecure set cookie with source scheme marked appropriately.
  GURL nonsecure_url_for_nonsecure_set("http://nonsecureset.example:7");
  GURL secure_url_for_nonsecure_set("https://nonsecureset.example:7");

  EXPECT_TRUE(CreateAndSetCookie(cookie_store, nonsecure_url_for_nonsecure_set,
                                 "NonSecureScheme=val"));
  RunRequest(context.get(), nonsecure_url_for_nonsecure_set);
  histograms.ExpectBucketCount(
      test_histogram,
      URLRequestHttpJob::CookieRequestScheme::kNonsecureSetNonsecureRequest, 1);
  RunRequest(context.get(), secure_url_for_nonsecure_set);
  histograms.ExpectBucketCount(
      test_histogram,
      URLRequestHttpJob::CookieRequestScheme::kNonsecureSetSecureRequest, 1);
}

// Test that cookies are annotated with the appropriate exclusion reason when
// privacy mode is enabled.
TEST_F(URLRequestHttpJobTest, PrivacyMode_ExclusionReason) {
  HttpTestServer test_server;
  ASSERT_TRUE(test_server.Start());

  auto context_builder = CreateTestURLRequestContextBuilder();
  context_builder->SetCookieStore(std::make_unique<CookieMonster>(
      /*store=*/nullptr, /*net_log=*/nullptr));
  auto& network_delegate = *context_builder->set_network_delegate(
      std::make_unique<FilteringTestNetworkDelegate>());
  auto context = context_builder->Build();

  // Set cookies.
  {
    TestDelegate d;
    GURL test_url = test_server.GetURL(
        "/set-cookie?one=1&"
        "two=2&"
        "three=3");
    std::unique_ptr<URLRequest> req =
        CreateFirstPartyRequest(*context, test_url, &d);
    req->Start();
    d.RunUntilComplete();
  }

  // Get cookies.
  network_delegate.ResetAnnotateCookiesCalledCount();
  ASSERT_EQ(0, network_delegate.annotate_cookies_called_count());
  // We want to fetch cookies from the cookie store, so we use the
  // NetworkDelegate to override the privacy mode (rather than setting it via
  // `allow_credentials`, since that skips querying the cookie store).
  network_delegate.set_force_privacy_mode(true);
  TestDelegate d;
  std::unique_ptr<URLRequest> req = CreateFirstPartyRequest(
      *context, test_server.GetURL("/echoheader?Cookie"), &d);
  req->Start();
  d.RunUntilComplete();

  EXPECT_EQ("None", d.data_received());
  EXPECT_THAT(
      req->maybe_sent_cookies(),
      UnorderedElementsAre(
          MatchesCookieWithAccessResult(
              MatchesCookieWithNameSourceType("one", CookieSourceType::kHTTP),
              MatchesCookieAccessResult(
                  HasExactlyExclusionReasonsForTesting(
                      {CookieInclusionStatus::ExclusionReason::
                           EXCLUDE_USER_PREFERENCES}),
                  _, _, _)),
          MatchesCookieWithAccessResult(
              MatchesCookieWithNameSourceType("two", CookieSourceType::kHTTP),
              MatchesCookieAccessResult(
                  HasExactlyExclusionReasonsForTesting(
                      {CookieInclusionStatus::ExclusionReason::
                           EXCLUDE_USER_PREFERENCES}),
                  _, _, _)),
          MatchesCookieWithAccessResult(
              MatchesCookieWithNameSourceType("three", CookieSourceType::kHTTP),
              MatchesCookieAccessResult(
                  HasExactlyExclusionReasonsForTesting(
                      {CookieInclusionStatus::ExclusionReason::
                           EXCLUDE_USER_PREFERENCES}),
                  _, _, _))));

  EXPECT_EQ(0, network_delegate.annotate_cookies_called_count());
}

// Test that cookies are allowed to be selectively blocked by the network
// delegate.
TEST_F(URLRequestHttpJobTest, IndividuallyBlockedCookies) {
  HttpTestServer test_server;
  ASSERT_TRUE(test_server.Start());

  auto network_delegate = std::make_unique<FilteringTestNetworkDelegate>();
  network_delegate->set_block_get_cookies_by_name(true);
  network_delegate->SetCookieFilter("blocked_");
  auto context_builder = CreateTestURLRequestContextBuilder();
  context_builder->SetCookieStore(std::make_unique<CookieMonster>(
      /*store=*/nullptr, /*net_log=*/nullptr));
  context_builder->set_network_delegate(std::move(network_delegate));
  auto context = context_builder->Build();

  // Set cookies.
  {
    TestDelegate d;
    GURL test_url = test_server.GetURL(
        "/set-cookie?blocked_one=1;SameSite=Lax;Secure&"
        "blocked_two=1;SameSite=Lax;Secure&"
        "allowed=1;SameSite=Lax;Secure");
    std::unique_ptr<URLRequest> req =
        CreateFirstPartyRequest(*context, test_url, &d);
    req->Start();
    d.RunUntilComplete();
  }

  // Get cookies.
  TestDelegate d;
  std::unique_ptr<URLRequest> req = CreateFirstPartyRequest(
      *context, test_server.GetURL("/echoheader?Cookie"), &d);
  req->Start();
  d.RunUntilComplete();

  EXPECT_EQ("allowed=1", d.data_received());
  EXPECT_THAT(req->maybe_sent_cookies(),
              UnorderedElementsAre(
                  MatchesCookieWithAccessResult(
                      MatchesCookieWithNameSourceType("blocked_one",
                                                      CookieSourceType::kHTTP),
                      MatchesCookieAccessResult(
                          HasExactlyExclusionReasonsForTesting(
                              {CookieInclusionStatus::ExclusionReason::
                                   EXCLUDE_USER_PREFERENCES}),
                          _, _, _)),
                  MatchesCookieWithAccessResult(
                      MatchesCookieWithNameSourceType("blocked_two",
                                                      CookieSourceType::kHTTP),
                      MatchesCookieAccessResult(
                          HasExactlyExclusionReasonsForTesting(
                              {CookieInclusionStatus::ExclusionReason::
                                   EXCLUDE_USER_PREFERENCES}),
                          _, _, _)),
                  MatchesCookieWithAccessResult(
                      MatchesCookieWithNameSourceType("allowed",
                                                      CookieSourceType::kHTTP),
                      MatchesCookieAccessResult(IsInclude(), _, _, _))));
}

namespace {

int content_count = 0;
std::unique_ptr<test_server::HttpResponse> IncreaseOnRequest(
    const test_server::HttpRequest& request) {
  auto http_response = std::make_unique<test_server::BasicHttpResponse>();
  http_response->set_content(base::NumberToString(content_count));
  content_count++;
  return std::move(http_response);
}

void ResetContentCount() {
  content_count = 0;
}

}  // namespace

TEST_F(URLRequestHttpJobTest, GetFirstPartySetsCacheFilterMatchInfo) {
  EmbeddedTestServer https_test(EmbeddedTestServer::TYPE_HTTPS);
  https_test.AddDefaultHandlers(base::FilePath());
  https_test.RegisterRequestHandler(base::BindRepeating(&IncreaseOnRequest));
  ASSERT_TRUE(https_test.Start());

  auto context_builder = CreateTestURLRequestContextBuilder();
  auto cookie_access_delegate = std::make_unique<TestCookieAccessDelegate>();
  TestCookieAccessDelegate* raw_cookie_access_delegate =
      cookie_access_delegate.get();
  auto cm = std::make_unique<CookieMonster>(nullptr, nullptr);
  cm->SetCookieAccessDelegate(std::move(cookie_access_delegate));
  context_builder->SetCookieStore(std::move(cm));
  auto context = context_builder->Build();

  const GURL kTestUrl = https_test.GetURL("/");
  const IsolationInfo kTestIsolationInfo =
      IsolationInfo::CreateForInternalRequest(url::Origin::Create(kTestUrl));
  {
    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        kTestUrl, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS,
        net::handles::kInvalidNetworkHandle));
    req->set_isolation_info(kTestIsolationInfo);
    req->set_disallow_credentials();
    req->Start();
    delegate.RunUntilComplete();
    EXPECT_EQ("0", delegate.data_received());
  }
  {  // Test using the cached response.
    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        kTestUrl, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS,
        net::handles::kInvalidNetworkHandle));
    req->SetLoadFlags(LOAD_SKIP_CACHE_VALIDATION);
    req->set_disallow_credentials();
    req->set_isolation_info(kTestIsolationInfo);
    req->Start();
    delegate.RunUntilComplete();
    EXPECT_EQ("0", delegate.data_received());
  }

  // Set cache filter and test cache is bypassed because the request site has a
  // matched entry in the filter and its response cache was stored before being
  // marked to clear.
  const int64_t kClearAtRunId = 3;
  const int64_t kBrowserRunId = 3;
  FirstPartySetsCacheFilter cache_filter(
      {{SchemefulSite(kTestUrl), kClearAtRunId}}, kBrowserRunId);
  raw_cookie_access_delegate->set_first_party_sets_cache_filter(
      std::move(cache_filter));
  {
    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        kTestUrl, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS,
        net::handles::kInvalidNetworkHandle));
    req->SetLoadFlags(LOAD_SKIP_CACHE_VALIDATION);
    req->set_disallow_credentials();
    req->set_isolation_info(kTestIsolationInfo);
    req->Start();
    delegate.RunUntilComplete();
    EXPECT_EQ("1", delegate.data_received());
  }

  ResetContentCount();
}

TEST_F(URLRequestHttpJobTest, SetPartitionedCookie) {
  EmbeddedTestServer https_test(EmbeddedTestServer::TYPE_HTTPS);
  https_test.AddDefaultHandlers(base::FilePath());
  ASSERT_TRUE(https_test.Start());

  auto context_builder = CreateTestURLRequestContextBuilder();
  context_builder->SetCookieStore(std::make_unique<CookieMonster>(
      /*store=*/nullptr, /*net_log=*/nullptr));
  auto context = context_builder->Build();

  const url::Origin kTopFrameOrigin =
      url::Origin::Create(GURL("https://www.toplevelsite.com"));
  const IsolationInfo kTestIsolationInfo =
      IsolationInfo::CreateForInternalRequest(kTopFrameOrigin);

  {
    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        https_test.GetURL(
            "/set-cookie?__Host-foo=bar;SameSite=None;Secure;Path=/"
            ";Partitioned;"),
        DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS,
        net::handles::kInvalidNetworkHandle));

    req->set_isolation_info(kTestIsolationInfo);
    req->Start();
    ASSERT_TRUE(req->is_pending());
    delegate.RunUntilComplete();
  }

  {  // Test request from the same top-level site.
    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        https_test.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle));
    req->set_isolation_info(kTestIsolationInfo);
    req->Start();
    delegate.RunUntilComplete();
    EXPECT_EQ("__Host-foo=bar", delegate.data_received());
  }

  {  // Test request from a different top-level site.
    const url::Origin kOtherTopFrameOrigin =
        url::Origin::Create(GURL("https://www.anothertoplevelsite.com"));
    const IsolationInfo kOtherTestIsolationInfo =
        IsolationInfo::CreateForInternalRequest(kOtherTopFrameOrigin);

    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        https_test.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle));
    req->set_isolation_info(kOtherTestIsolationInfo);
    req->Start();
    delegate.RunUntilComplete();
    EXPECT_EQ("None", delegate.data_received());
  }

  {  // Test request from same top-level eTLD+1 but different scheme. Note that
     // although the top-level site is insecure, the endpoint setting/receiving
     // the cookie is always secure.
    const url::Origin kHttpTopFrameOrigin =
        url::Origin::Create(GURL("http://www.toplevelsite.com"));
    const IsolationInfo kHttpTestIsolationInfo =
        IsolationInfo::CreateForInternalRequest(kHttpTopFrameOrigin);

    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        https_test.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle));
    req->set_isolation_info(kHttpTestIsolationInfo);
    req->Start();
    delegate.RunUntilComplete();
    EXPECT_EQ("None", delegate.data_received());
  }
}

TEST_F(URLRequestHttpJobTest, PartitionedCookiePrivacyMode) {
  EmbeddedTestServer https_test(EmbeddedTestServer::TYPE_HTTPS);
  https_test.AddDefaultHandlers(base::FilePath());
  ASSERT_TRUE(https_test.Start());

  auto context_builder = CreateTestURLRequestContextBuilder();
  context_builder->SetCookieStore(
      std::make_unique<CookieMonster>(/*store=*/nullptr, /*net_log=*/nullptr));
  auto& network_delegate = *context_builder->set_network_delegate(
      std::make_unique<FilteringTestNetworkDelegate>());
  auto context = context_builder->Build();

  const url::Origin kTopFrameOrigin =
      url::Origin::Create(GURL("https://www.toplevelsite.com"));
  const IsolationInfo kTestIsolationInfo =
      IsolationInfo::CreateForInternalRequest(kTopFrameOrigin);

  {
    // Set an unpartitioned and partitioned cookie.
    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        https_test.GetURL(
            "/set-cookie?__Host-partitioned=0;SameSite=None;Secure;Path=/"
            ";Partitioned;&__Host-unpartitioned=1;SameSite=None;Secure;Path=/"),
        DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS,
        net::handles::kInvalidNetworkHandle));
    req->set_isolation_info(kTestIsolationInfo);
    req->Start();
    ASSERT_TRUE(req->is_pending());
    delegate.RunUntilComplete();
  }

  {  // Get both cookies when privacy mode is disabled.
    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        https_test.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle));
    req->set_isolation_info(kTestIsolationInfo);
    req->Start();
    delegate.RunUntilComplete();
    EXPECT_EQ("__Host-partitioned=0; __Host-unpartitioned=1",
              delegate.data_received());
  }

  {  // Get cookies with privacy mode enabled and partitioned state allowed.
    network_delegate.set_force_privacy_mode(true);
    network_delegate.set_partitioned_state_allowed(true);
    network_delegate.SetCookieFilter("unpartitioned");
    network_delegate.set_block_get_cookies_by_name(true);
    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        https_test.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle));
    req->set_isolation_info(kTestIsolationInfo);
    req->Start();
    delegate.RunUntilComplete();
    EXPECT_EQ("__Host-partitioned=0", delegate.data_received());
    CookieInclusionStatus::ExclusionReasonBitset want_exclusion_reasons;

    EXPECT_THAT(
        req->maybe_sent_cookies(),
        UnorderedElementsAre(
            MatchesCookieWithAccessResult(
                MatchesCookieWithNameSourceType("__Host-partitioned",
                                                CookieSourceType::kHTTP),
                MatchesCookieAccessResult(HasExactlyExclusionReasonsForTesting(
                                              want_exclusion_reasons),
                                          _, _, _)),
            MatchesCookieWithAccessResult(
                MatchesCookieWithNameSourceType("__Host-unpartitioned",
                                                CookieSourceType::kHTTP),
                MatchesCookieAccessResult(
                    HasExactlyExclusionReasonsForTesting(
                        {CookieInclusionStatus::ExclusionReason::
                             EXCLUDE_USER_PREFERENCES}),
                    _, _, _))));
  }

  {  // Get cookies with privacy mode enabled and partitioned state is not
     // allowed.
    network_delegate.set_force_privacy_mode(true);
    network_delegate.set_partitioned_state_allowed(false);
    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        https_test.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle));
    req->set_isolation_info(kTestIsolationInfo);
    req->Start();
    delegate.RunUntilComplete();
    EXPECT_EQ("None", delegate.data_received());
    EXPECT_THAT(req->maybe_sent_cookies(),
                UnorderedElementsAre(
                    MatchesCookieWithAccessResult(
                        MatchesCookieWithNameSourceType(
                            "__Host-partitioned", CookieSourceType::kHTTP),
                        MatchesCookieAccessResult(
                            HasExactlyExclusionReasonsForTesting(
                                {CookieInclusionStatus::ExclusionReason::
                                     EXCLUDE_USER_PREFERENCES}),
                            _, _, _)),
                    MatchesCookieWithAccessResult(
                        MatchesCookieWithNameSourceType(
                            "__Host-unpartitioned", CookieSourceType::kHTTP),
                        MatchesCookieAccessResult(
                            HasExactlyExclusionReasonsForTesting(
                                {CookieInclusionStatus::ExclusionReason::
                                     EXCLUDE_USER_PREFERENCES}),
                            _, _, _))));
  }
}

TEST_F(URLRequestHttpJobTest, IgnoreUnsafeMethodForSameSiteLax) {
  EmbeddedTestServer https_test(EmbeddedTestServer::TYPE_HTTPS);
  https_test.AddDefaultHandlers(base::FilePath());
  ASSERT_TRUE(https_test.Start());

  auto context_builder = CreateTestURLRequestContextBuilder();
  context_builder->SetCookieStore(
      std::make_unique<CookieMonster>(/*store=*/nullptr, /*net_log=*/nullptr));
  auto context = context_builder->Build();

  const url::Origin kTestOrigin = url::Origin::Create(https_test.GetURL("/"));
  // kMainFrame so we get lax cookies.
  const IsolationInfo kTestIsolationInfo = IsolationInfo::Create(
      IsolationInfo::RequestType::kMainFrame, kTestOrigin, kTestOrigin,
      SiteForCookies::FromOrigin(kTestOrigin));

  // We will use this as the initiator so that the request is cross-site.
  const url::Origin kCrossSiteOrigin =
      url::Origin::Create(GURL("https://www.toplevelsite.com"));

  {
    // Set a SameSite=Lax cookie.
    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        https_test.GetURL("/set-cookie?name=value;SameSite=Lax;Secure;Path=/"),
        DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS,
        net::handles::kInvalidNetworkHandle));
    req->set_isolation_info(kTestIsolationInfo);
    req->set_site_for_cookies(kTestIsolationInfo.site_for_cookies());
    req->set_initiator(kCrossSiteOrigin);
    req->Start();
    ASSERT_TRUE(req->is_pending());
    delegate.RunUntilComplete();
  }

  {
    // Make sure that the cookie gets sent even for a post request when
    // ignore_unsafe_method_for_same_site_lax is true.
    TestDelegate delegate;
    std::unique_ptr<URLRequest> req(context->CreateRequest(
        https_test.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle));
    req->set_isolation_info(kTestIsolationInfo);
    req->set_site_for_cookies(kTestIsolationInfo.site_for_cookies());
    req->set_initiator(kCrossSiteOrigin);
    req->set_ignore_unsafe_method_for_same_site_lax(true);
    req->set_method("POST");
    req->Start();
    delegate.RunUntilComplete();
    EXPECT_EQ("name=value", delegate.data_received());
  }
}

TEST_F(URLRequestHttpJobTest, ForceIgnoreSiteForCookiesFromNetworkDelegate) {
  EmbeddedTestServer https_test(EmbeddedTestServer::TYPE_HTTPS);
  https_test.AddDefaultHandlers(base::FilePath());
  ASSERT_TRUE(https_test.Start());

  auto context_builder = CreateTestURLRequestContextBuilder();
  context_builder->SetCookieStore(
      std::make_unique<CookieMonster>(/*store=*/nullptr, /*net_log=*/nullptr));
  context_builder->set_network_delegate(
      std::make_unique<SameSiteBypassNetworkDelegate>());
  auto context = context_builder->Build();

  const url::Origin kCrossSiteOrigin =
      url::Origin::Create(GURL("https://www.toplevelsite.com"));
  auto create_cross_site_request = [&](const GURL& url,
                                       TestDelegate& delegate) {
    std::unique_ptr<URLRequest> req = context->CreateRequest(
        url, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS,
        net::handles::kInvalidNetworkHandle);
    req->set_site_for_cookies(SiteForCookies::FromOrigin(kCrossSiteOrigin));
    req->set_initiator(kCrossSiteOrigin);
    return req;
  };

  {
    TestDelegate delegate;
    std::unique_ptr<URLRequest> req = create_cross_site_request(
        https_test.GetURL(
            "/set-cookie?strict=value;SameSite=Strict;Secure;Path=/"),
        delegate);
    req->Start();
    delegate.RunUntilComplete();
    EXPECT_THAT(delegate.request_status(), IsOk());
  }

  {
    TestDelegate delegate;
    std::unique_ptr<URLRequest> req = create_cross_site_request(
        https_test.GetURL("/echoheader?Cookie"), delegate);
    req->Start();
    delegate.RunUntilComplete();

    EXPECT_THAT(delegate.request_status(), IsOk());
    EXPECT_EQ("strict=value", delegate.data_received());
  }
}

TEST_F(URLRequestHttpJobTest,
       PlatformLocalNetworkAccessPermissionGranted_Sync) {
  MockConnect mock_connect(SYNCHRONOUS, ERR_LOCAL_NETWORK_PERMISSION_MISSING);
  StaticSocketDataProvider socket_data;
  socket_data.set_connect_data(mock_connect);

  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 7\r\n\r\n"),
                      MockRead("Success")};
  StaticSocketDataProvider success_data(reads, base::span<MockWrite>());

  MockClientSocketFactory socket_factory;
  socket_factory.AddSocketDataProvider(&socket_data);
  socket_factory.AddSocketDataProvider(&success_data);

  auto context_builder = CreateTestURLRequestContextBuilder();
  context_builder->set_client_socket_factory_for_testing(&socket_factory);
  context_builder->DisableHttpCache();
  auto context = context_builder->Build();

  TestDelegate delegate;
  delegate.set_platform_network_access_behavior(
      TestDelegate::PlatformNetworkAccessBehavior::kGrant);

  std::unique_ptr<URLRequest> req(context->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle));
  req->Start();

  // The request should not have completed yet because
  // SetPlatformLocalNetworkAccessGranted() posts a task to call
  // OnStartCompleted() when the restart completes synchronously.
  EXPECT_FALSE(delegate.response_completed());

  delegate.RunUntilComplete();

  EXPECT_EQ("Success", delegate.data_received());
  EXPECT_EQ(OK, delegate.request_status());
}

TEST_F(URLRequestHttpJobTest, PlatformLocalNetworkAccessPermissionDenied_Sync) {
  MockConnect mock_connect(SYNCHRONOUS, ERR_LOCAL_NETWORK_PERMISSION_MISSING);
  StaticSocketDataProvider socket_data;
  socket_data.set_connect_data(mock_connect);

  MockClientSocketFactory socket_factory;
  socket_factory.AddSocketDataProvider(&socket_data);

  auto context_builder = CreateTestURLRequestContextBuilder();
  context_builder->set_client_socket_factory_for_testing(&socket_factory);
  context_builder->DisableHttpCache();
  auto context = context_builder->Build();

  TestDelegate delegate;
  delegate.set_platform_network_access_behavior(
      TestDelegate::PlatformNetworkAccessBehavior::kDeny);

  std::unique_ptr<URLRequest> req(context->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle));
  req->Start();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(),
              IsError(ERR_LOCAL_NETWORK_PERMISSION_MISSING));
}

TEST_F(URLRequestHttpJobTest,
       PlatformLocalNetworkAccessPermissionGranted_Async) {
  MockConnect mock_connect(ASYNC, ERR_LOCAL_NETWORK_PERMISSION_MISSING);
  StaticSocketDataProvider socket_data;
  socket_data.set_connect_data(mock_connect);

  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 7\r\n\r\n"),
                      MockRead("Success")};
  StaticSocketDataProvider success_data(reads, base::span<MockWrite>());

  MockClientSocketFactory socket_factory;
  socket_factory.AddSocketDataProvider(&socket_data);
  socket_factory.AddSocketDataProvider(&success_data);

  auto context_builder = CreateTestURLRequestContextBuilder();
  context_builder->set_client_socket_factory_for_testing(&socket_factory);
  context_builder->DisableHttpCache();
  auto context = context_builder->Build();

  TestDelegate delegate;
  delegate.set_platform_network_access_behavior(
      TestDelegate::PlatformNetworkAccessBehavior::kGrant);
  delegate.set_async_platform_local_network_access_decision(true);

  std::unique_ptr<URLRequest> req(context->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle));
  req->Start();
  delegate.RunUntilComplete();

  EXPECT_EQ("Success", delegate.data_received());
  EXPECT_EQ(OK, delegate.request_status());
}

TEST_F(URLRequestHttpJobTest,
       PlatformLocalNetworkAccessPermissionDenied_Async) {
  MockConnect mock_connect(ASYNC, ERR_LOCAL_NETWORK_PERMISSION_MISSING);
  StaticSocketDataProvider socket_data;
  socket_data.set_connect_data(mock_connect);

  MockClientSocketFactory socket_factory;
  socket_factory.AddSocketDataProvider(&socket_data);

  auto context_builder = CreateTestURLRequestContextBuilder();
  context_builder->set_client_socket_factory_for_testing(&socket_factory);
  context_builder->DisableHttpCache();
  auto context = context_builder->Build();

  TestDelegate delegate;
  delegate.set_platform_network_access_behavior(
      TestDelegate::PlatformNetworkAccessBehavior::kDeny);
  delegate.set_async_platform_local_network_access_decision(true);

  std::unique_ptr<URLRequest> req(context->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle));
  req->Start();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(),
              IsError(ERR_LOCAL_NETWORK_PERMISSION_MISSING));
}

TEST_F(URLRequestHttpJobTest, PlatformLocalNetworkAccessDefault_Sync) {
  MockConnect mock_connect(SYNCHRONOUS, ERR_LOCAL_NETWORK_PERMISSION_MISSING);
  StaticSocketDataProvider socket_data;
  socket_data.set_connect_data(mock_connect);

  MockClientSocketFactory socket_factory;
  socket_factory.AddSocketDataProvider(&socket_data);

  auto context_builder = CreateTestURLRequestContextBuilder();
  context_builder->set_client_socket_factory_for_testing(&socket_factory);
  context_builder->DisableHttpCache();
  auto context = context_builder->Build();

  TestDelegate delegate;
  // TestDelegate::OnPlatformLocalNetworkAccessPermissionRequired will call the
  // default implementation when behavior is kDefault.
  delegate.set_platform_network_access_behavior(
      TestDelegate::PlatformNetworkAccessBehavior::kDefault);

  std::unique_ptr<URLRequest> req(context->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle));
  req->Start();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(),
              IsError(ERR_LOCAL_NETWORK_PERMISSION_MISSING));
}

TEST_F(URLRequestHttpJobTest, PlatformLocalNetworkAccessDefault_Async) {
  MockConnect mock_connect(ASYNC, ERR_LOCAL_NETWORK_PERMISSION_MISSING);
  StaticSocketDataProvider socket_data;
  socket_data.set_connect_data(mock_connect);

  MockClientSocketFactory socket_factory;
  socket_factory.AddSocketDataProvider(&socket_data);

  auto context_builder = CreateTestURLRequestContextBuilder();
  context_builder->set_client_socket_factory_for_testing(&socket_factory);
  context_builder->DisableHttpCache();
  auto context = context_builder->Build();

  TestDelegate delegate;
  delegate.set_platform_network_access_behavior(
      TestDelegate::PlatformNetworkAccessBehavior::kDefault);
  delegate.set_async_platform_local_network_access_decision(true);

  std::unique_ptr<URLRequest> req(context->CreateRequest(
      GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle));
  req->Start();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(),
              IsError(ERR_LOCAL_NETWORK_PERMISSION_MISSING));
}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpTimeToFirstByteServerPadding) {
  base::HistogramTester histograms;
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);
  SSLSocketDataProvider ssl_data(ASYNC, OK);
  ssl_data.ssl_info.server_padding_received = true;
  socket_factory_.AddSSLSocketDataProvider(&ssl_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("https://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  histograms.ExpectTotalCount("Net.HttpTimeToFirstByte.ServerPadding", 0);
  histograms.ExpectTotalCount(
      "Net.HttpTimeToFirstByte.ServerPaddingFirstConnectionOnly", 0);

  request->Start();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsOk());
  histograms.ExpectTotalCount("Net.HttpTimeToFirstByte.ServerPadding", 1);
  histograms.ExpectTotalCount(
      "Net.HttpTimeToFirstByte.ServerPaddingFirstConnectionOnly", 1);
}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpTimeToFirstByteServerPaddingNotSent) {
  base::HistogramTester histograms;
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);
  SSLSocketDataProvider ssl_data(ASYNC, OK);
  socket_factory_.AddSSLSocketDataProvider(&ssl_data);

  TestDelegate delegate;
  std::unique_ptr<URLRequest> request = context_->CreateRequest(
      GURL("https://www.example.com"), DEFAULT_PRIORITY, &delegate,
      TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
  histograms.ExpectTotalCount("Net.HttpTimeToFirstByte.ServerPadding", 0);
  histograms.ExpectTotalCount(
      "Net.HttpTimeToFirstByte.ServerPaddingFirstConnectionOnly", 0);

  request->Start();
  delegate.RunUntilComplete();

  EXPECT_THAT(delegate.request_status(), IsOk());
  histograms.ExpectTotalCount("Net.HttpTimeToFirstByte.ServerPadding", 0);
  histograms.ExpectTotalCount(
      "Net.HttpTimeToFirstByte.ServerPaddingFirstConnectionOnly", 0);
}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpTimeToFirstByteServerPaddingReusedConnection) {
  base::HistogramTester histograms;
  MockWrite writes[] = {
      MockWrite(kSimpleGetMockWrite),
      MockWrite("GET /two HTTP/1.1\r\n"
                "Host: www.example.com\r\n"
                "Connection: keep-alive\r\n"
                "User-Agent: \r\n"
                "Accept-Encoding: gzip, deflate\r\n"
                "Accept-Language: en-us,fr\r\n\r\n"),
  };
  MockRead reads[] = {
      MockRead("HTTP/1.1 200 OK\r\n"
               "Content-Length: 12\r\n\r\n"),
      MockRead("Test Content"),
      MockRead("HTTP/1.1 200 OK\r\n"
               "Content-Length: 12\r\n\r\n"),
      MockRead("Test Content"),
  };

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);
  SSLSocketDataProvider ssl_data(ASYNC, OK);
  ssl_data.ssl_info.server_padding_received = true;
  socket_factory_.AddSSLSocketDataProvider(&ssl_data);

  // First request: new connection.
  {
    TestDelegate delegate;
    std::unique_ptr<URLRequest> request = context_->CreateRequest(
        GURL("https://www.example.com/"), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
    request->Start();
    delegate.RunUntilComplete();
    EXPECT_THAT(delegate.request_status(), IsOk());
  }

  histograms.ExpectTotalCount("Net.HttpTimeToFirstByte.ServerPadding", 1);
  histograms.ExpectTotalCount(
      "Net.HttpTimeToFirstByte.ServerPaddingFirstConnectionOnly", 1);

  // Second request: reuses connection.
  {
    TestDelegate delegate;
    std::unique_ptr<URLRequest> request = context_->CreateRequest(
        GURL("https://www.example.com/two"), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
    request->Start();
    delegate.RunUntilComplete();
    EXPECT_THAT(delegate.request_status(), IsOk());
  }

  histograms.ExpectTotalCount("Net.HttpTimeToFirstByte.ServerPadding", 2);
  histograms.ExpectTotalCount(
      "Net.HttpTimeToFirstByte.ServerPaddingFirstConnectionOnly", 1);
}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpTimeToFirstByteServerPaddingCachedResponse) {
  base::HistogramTester histograms;
  MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
  MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
                               "Cache-Control: max-age=3600\r\n"
                               "Content-Length: 12\r\n\r\n"),
                      MockRead("Test Content")};

  StaticSocketDataProvider socket_data(reads, writes);
  socket_factory_.AddSocketDataProvider(&socket_data);
  SSLSocketDataProvider ssl_data(ASYNC, OK);
  ssl_data.ssl_info.server_padding_received = true;
  socket_factory_.AddSSLSocketDataProvider(&ssl_data);

  // First request: network response, cached.
  {
    TestDelegate delegate;
    std::unique_ptr<URLRequest> request = context_->CreateRequest(
        GURL("https://www.example.com"), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
    request->Start();
    delegate.RunUntilComplete();
    EXPECT_THAT(delegate.request_status(), IsOk());
    EXPECT_FALSE(request->was_cached());
  }

  histograms.ExpectTotalCount("Net.HttpTimeToFirstByte.ServerPadding", 1);
  histograms.ExpectTotalCount(
      "Net.HttpTimeToFirstByte.ServerPaddingFirstConnectionOnly", 1);

  // Second request: served from cache.
  {
    TestDelegate delegate;
    std::unique_ptr<URLRequest> request = context_->CreateRequest(
        GURL("https://www.example.com"), DEFAULT_PRIORITY, &delegate,
        TRAFFIC_ANNOTATION_FOR_TESTS, net::handles::kInvalidNetworkHandle);
    request->Start();
    delegate.RunUntilComplete();
    EXPECT_THAT(delegate.request_status(), IsOk());
    EXPECT_TRUE(request->was_cached());
  }

  histograms.ExpectTotalCount("Net.HttpTimeToFirstByte.ServerPadding", 1);
  histograms.ExpectTotalCount(
      "Net.HttpTimeToFirstByte.ServerPaddingFirstConnectionOnly", 1);
}

}  // namespace net

#if BUILDFLAG(IS_ANDROID)
DEFINE_JNI(AndroidNetworkLibraryTestUtil)
#endif
