chromium/net/url_request/url_request_http_job_unittest.cc

// 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 <utility>
#include <vector>

#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/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.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/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/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/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/session_service.h"
#include "net/device_bound_sessions/test_util.h"
#endif

IsError;
IsOk;

namespace net {

namespace {

_;
Return;
UnorderedElementsAre;

const char kSimpleGetMockWrite[] =;

const char kSimpleHeadMockWrite[] =;

const char kTrustAnchorRequestHistogram[] =;

// Inherit from URLRequestHttpJob to expose the priority and some
// other hidden functions.
class TestURLRequestHttpJob : public URLRequestHttpJob {};

class URLRequestHttpJobSetUpSourceTest : public TestWithTaskEnvironment {};

// Tests that if SetUpSourceStream() returns nullptr, the request fails.
TEST_F(URLRequestHttpJobSetUpSourceTest, SetUpSourceFails) {}

// Tests that if there is an unknown content-encoding type, the raw response
// body is passed through.
TEST_F(URLRequestHttpJobSetUpSourceTest, UnknownEncoding) {}

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

class URLRequestHttpJobWithProxy {};

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

// 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) {}

// 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) {}

// Test that for direct requests that are marked as being for IP Protection, the
// IP Protection-specific metrics get recorded as expected.
TEST_F(URLRequestHttpJobWithProxyTest, IpProtectionDirectProxyMetricsRecorded) {}

class URLRequestHttpJobTest : public TestWithTaskEnvironment {};

class URLRequestHttpJobWithMockSocketsTest : public TestWithTaskEnvironment {};

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestContentLengthSuccessfulRequest) {}

// Tests a successful HEAD request.
TEST_F(URLRequestHttpJobWithMockSocketsTest, TestSuccessfulHead) {}

// 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) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest, TestSuccessfulCachedHeadRequest) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestContentLengthSuccessfulHttp09Request) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest, TestContentLengthFailedRequest) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestContentLengthCancelledRequest) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestNetworkBytesRedirectedRequest) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestNetworkBytesCancelledAfterHeaders) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestNetworkBytesCancelledImmediately) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest, TestHttpTimeToFirstByte) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpTimeToFirstByteForCancelledTask) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpJobSuccessPriorityKeyedTotalTime) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpJobRecordsTrustAnchorHistograms) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpJobDoesNotRecordTrustAnchorHistogramsWhenNoNetworkLoad) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest,
       TestHttpJobRecordsMostSpecificTrustAnchorHistograms) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest, EncodingAdvertisementOnRange) {}

TEST_F(URLRequestHttpJobWithMockSocketsTest, RangeRequestOverrideEncoding) {}

TEST_F(URLRequestHttpJobTest, TestCancelWhileReadingCookies) {}

// Make sure that SetPriority actually sets the URLRequestHttpJob's
// priority, before start.  Other tests handle the after start case.
TEST_F(URLRequestHttpJobTest, SetPriorityBasic) {}

// Make sure that URLRequestHttpJob passes on its priority to its
// transaction on start.
TEST_F(URLRequestHttpJobTest, SetTransactionPriorityOnStart) {}

// Make sure that URLRequestHttpJob passes on its priority updates to
// its transaction.
TEST_F(URLRequestHttpJobTest, SetTransactionPriority) {}

TEST_F(URLRequestHttpJobTest, HSTSInternalRedirectTest) {}

TEST_F(URLRequestHttpJobTest, ShouldBypassHSTS) {}

#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("http://www.example.com"),
                                       DEFAULT_PRIORITY, &delegate_,
                                       TRAFFIC_ANNOTATION_FOR_TESTS);
  }

  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"
               "Sec-Session-Registration: (ES256);path=\"new\";"
               "challenge=\"test\"\r\n"
               "Content-Length: 12\r\n\r\n"),
      MockRead("Test Content")};

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

  request_->Start();
  EXPECT_CALL(GetMockService(), RegisterBoundSession).Times(1);
  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")};

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

  request_->Start();
  EXPECT_CALL(GetMockService(), RegisterBoundSession).Times(0);
  delegate_.RunUntilComplete();
  EXPECT_THAT(delegate_.request_status(), IsOk());
}

#endif  // BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS)

namespace {
std::unique_ptr<test_server::HttpResponse> HandleRequest(
    const std::string_view& content,
    const test_server::HttpRequest& request) {}
}  // 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) {}

TEST_F(URLRequestHttpJobTest, HSTSInternalRedirectCallback) {}

class URLRequestHttpJobWithBrotliSupportTest : public TestWithTaskEnvironment {};

TEST_F(URLRequestHttpJobWithBrotliSupportTest, NoBrotliAdvertisementOverHttp) {}

TEST_F(URLRequestHttpJobWithBrotliSupportTest, BrotliAdvertisement) {}

TEST_F(URLRequestHttpJobWithBrotliSupportTest, DefaultAcceptEncodingOverriden) {}

#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);
    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 {};

TEST_F(URLRequestHttpJobWebSocketTest, RejectedWithoutCreateHelper) {}

TEST_F(URLRequestHttpJobWebSocketTest, CreateHelperPassedThrough) {}

#endif  // BUILDFLAG(ENABLE_WEBSOCKETS)

bool SetAllCookies(CookieMonster* cm, const CookieList& list) {}

bool CreateAndSetCookie(CookieStore* cs,
                        const GURL& url,
                        const std::string& cookie_line) {}

void RunRequest(URLRequestContext* context, const GURL& url) {}

}  // namespace

TEST_F(URLRequestHttpJobTest, CookieSchemeRequestSchemeHistogram) {}

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

// Test that cookies are allowed to be selectively blocked by the network
// delegate.
TEST_F(URLRequestHttpJobTest, IndividuallyBlockedCookies) {}

namespace {

int content_count =;
std::unique_ptr<test_server::HttpResponse> IncreaseOnRequest(
    const test_server::HttpRequest& request) {}

void ResetContentCount() {}

}  // namespace

TEST_F(URLRequestHttpJobTest, GetFirstPartySetsCacheFilterMatchInfo) {}

TEST_F(URLRequestHttpJobTest, SetPartitionedCookie) {}

TEST_F(URLRequestHttpJobTest, PartitionedCookiePrivacyMode) {}

}  // namespace net