chromium/services/network/public/cpp/simple_url_loader_unittest.cc

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

#include "services/network/public/cpp/simple_url_loader.h"

#include <stdint.h>

#include <list>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <vector>

#include "base/base_paths.h"
#include "base/check_op.h"
#include "base/containers/span.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/format_macros.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/notreached.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/sequence_checker.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/bind.h"
#include "base/test/power_monitor_test.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/test/test_timeouts.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "mojo/public/c/system/types.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/mock_network_change_notifier.h"
#include "net/base/network_change_notifier.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
#include "net/http/http_util.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/redirect_info.h"
#include "net/url_request/url_request.h"
#include "services/network/network_service.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
#include "services/network/public/mojom/data_pipe_getter.mojom.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "services/network/test/fake_test_cert_verifier_params_factory.h"
#include "services/network/test/test_network_context_client.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"

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

namespace network {
namespace {

ElementsAre;

// Server path that returns a response containing as many a's as are specified
// in the query part of the URL.
const char kResponseSizePath[] =;

// Server path that returns a gzip response with a non-gzipped body.
const char kInvalidGzipPath[] =;

// Server path that returns truncated response (Content-Length less than body
// size).
const char kTruncatedBodyPath[] =;
// The body of the truncated response (After truncation).
const char kTruncatedBody[] =;

// Server path returns a 5xx error once, then returns the request body.
const char kFailOnceThenEchoBody[] =;

// Used in string upload tests.
const char kShortUploadBody[] =;

// Standard value used on requests / responses.
const char kExpectedResponse[] =;

const int64_t kExpectedResponseSize =;

// Returns a string longer than
// SimpleURLLoader::kMaxUploadStringAsStringLength, to test the path where
// strings are streamed to the URLLoader.
std::string GetLongUploadBody(
    size_t size = SimpleURLLoader::kMaxUploadStringSizeToCopy) {}

// Class to make it easier to start a SimpleURLLoader, wait for it to complete,
// and check the result.
class SimpleLoaderTestHelper : public SimpleURLLoaderStreamConsumer {};

// Request handler for the embedded test server that returns a response body
// with the length indicated by the query string.
std::unique_ptr<net::test_server::HttpResponse> HandleResponseSize(
    const net::test_server::HttpRequest& request) {}

// Request handler for the embedded test server that returns a an invalid gzip
// response body. No body bytes will be read successfully.
std::unique_ptr<net::test_server::HttpResponse> HandleInvalidGzip(
    const net::test_server::HttpRequest& request) {}

// Request handler for the embedded test server that returns a response with a
// truncated body. Consumer should see an error after reading some data.
std::unique_ptr<net::test_server::HttpResponse> HandleTruncatedBody(
    const net::test_server::HttpRequest& request) {}

// Request handler for the embedded test server that returns a 5xx error once,
// and on future requests, has a response body matching the request body.
std::unique_ptr<net::test_server::HttpResponse> FailOnceThenEchoBody(
    bool* has_failed_request,
    const net::test_server::HttpRequest& request) {}

// Base class with shared setup logic.
class SimpleURLLoaderTestBase {};

enum class ReadAndDiscardBodyType {};

DownloadTypeAndOptions;

void PrintTo(const DownloadTypeAndOptions& value, std::ostream* os) {}

struct URLLoaderFactoryTestConfig {};

class SimpleURLLoaderTest
    : public SimpleURLLoaderTestBase,
      public testing::TestWithParam<DownloadTypeAndOptions> {};

TEST_P(SimpleURLLoaderTest, BasicRequest) {}

// Make sure the class works when the size of the encoded and decoded bodies are
// different.
TEST_P(SimpleURLLoaderTest, GzipBody) {}

// Make sure redirects are followed.
TEST_P(SimpleURLLoaderTest, Redirect) {}

// Redirect to a file:// URL.
TEST_P(SimpleURLLoaderTest, RedirectFile) {}

// Redirect to a data:// URL.
TEST_P(SimpleURLLoaderTest, RedirectData) {}

// Make sure OnRedirectCallback is invoked on a redirect.
TEST_P(SimpleURLLoaderTest, OnRedirectCallback) {}

// Make sure OnRedirectCallback is invoked on each redirect.
TEST_P(SimpleURLLoaderTest, OnRedirectCallbackTwoRedirects) {}

TEST_P(SimpleURLLoaderTest, DeleteInOnRedirectCallback) {}

TEST_P(SimpleURLLoaderTest, UploadShortStringWithRedirect) {}

TEST_P(SimpleURLLoaderTest, UploadLongStringWithRedirect) {}

TEST_P(SimpleURLLoaderTest,
       OnRedirectCallbackReturnsExistingToBeRemovedHeaders) {}

TEST_P(SimpleURLLoaderTest,
       OnRedirectCallbackReturnsNonExistingToBeRemovedHeaders) {}

TEST_P(SimpleURLLoaderTest, OnResponseStartedCallback) {}

TEST_P(SimpleURLLoaderTest, DeleteInOnResponseStartedCallback) {}

// Check the case where the SimpleURLLoader is deleted in the completion
// callback.
TEST_P(SimpleURLLoaderTest, DestroyLoaderInOnComplete) {}

// Check the case where a URLLoaderFactory with a closed Mojo pipe was passed
// in.
TEST_P(SimpleURLLoaderTest, DisconnectedURLLoader) {}

// Check that no body is returned with an HTTP error response.
TEST_P(SimpleURLLoaderTest, HttpErrorStatusCodeResponse) {}

// Check that the body is returned with an HTTP error response, when
// SetAllowHttpErrorResults(true) is called.
TEST_P(SimpleURLLoaderTest, HttpErrorStatusCodeResponseAllowed) {}

TEST_P(SimpleURLLoaderTest, EmptyResponseBody) {}

TEST_P(SimpleURLLoaderTest, BigResponseBody) {}

#define GTEST_SKIP_IF_STREAM()

TEST_P(SimpleURLLoaderTest, ResponseBodyWithSizeMatchingLimit) {}

TEST_P(SimpleURLLoaderTest, ResponseBodyWithSizeBelowLimit) {}

TEST_P(SimpleURLLoaderTest, ResponseBodyWithSizeAboveLimit) {}

// Same as above, but with setting allow_partial_results to true.
TEST_P(SimpleURLLoaderTest, ResponseBodyWithSizeAboveLimitPartialResponse) {}

// The next 4 tests duplicate the above 4, but with larger response sizes. This
// means the size limit will not be exceeded on the first read.
TEST_P(SimpleURLLoaderTest, BigResponseBodyWithSizeMatchingLimit) {}

TEST_P(SimpleURLLoaderTest, BigResponseBodyWithSizeBelowLimit) {}

TEST_P(SimpleURLLoaderTest, BigResponseBodyWithSizeAboveLimit) {}

TEST_P(SimpleURLLoaderTest, BigResponseBodyWithSizeAboveLimitPartialResponse) {}

TEST_P(SimpleURLLoaderTest, NetErrorBeforeHeaders) {}

TEST_P(SimpleURLLoaderTest, NetErrorBeforeHeadersWithPartialResults) {}

TEST_P(SimpleURLLoaderTest, NetErrorAfterHeaders) {}

TEST_P(SimpleURLLoaderTest, NetErrorAfterHeadersWithPartialResults) {}

TEST_P(SimpleURLLoaderTest, TruncatedBody) {}

TEST_P(SimpleURLLoaderTest, TruncatedBodyWithPartialResults) {}

// Test case where NetworkService is destroyed before headers are received (and
// before the request is even made, for that matter).
TEST_P(SimpleURLLoaderTest, DestroyServiceBeforeResponseStarts) {}

TEST_P(SimpleURLLoaderTest, UploadShortString) {}

TEST_P(SimpleURLLoaderTest, UploadLongString) {}

TEST_P(SimpleURLLoaderTest, UploadEmptyString) {}

TEST_P(SimpleURLLoaderTest, UploadShortStringWithRetry) {}

TEST_P(SimpleURLLoaderTest, UploadLongStringWithRetry) {}

TEST_P(SimpleURLLoaderTest, UploadFile) {}

TEST_P(SimpleURLLoaderTest, UploadFileRange) {}

TEST_P(SimpleURLLoaderTest, UploadFileWithPut) {}

TEST_P(SimpleURLLoaderTest, UploadFileWithRetry) {}

TEST_P(SimpleURLLoaderTest, UploadNonexistentFile) {}

// Test case where uploading a file is canceled before the URLLoader is started
// (But after the SimpleURLLoader is started).
TEST_P(SimpleURLLoaderTest, UploadFileCanceledBeforeLoaderStarted) {}

TEST_P(SimpleURLLoaderTest, UploadFileCanceledWithRetry) {}

enum class TestLoaderEvent {};

// URLLoader that the test fixture can control. This allows finer grained
// control over event order over when a pipe is closed, and in ordering of
// events where there are multiple pipes. It also allows sending events in
// unexpected order, to test handling of events from less trusted processes.
class MockURLLoader : public network::mojom::URLLoader {};

class MockURLLoaderFactory : public network::mojom::URLLoaderFactory {};

// Check that the request fails if OnComplete() is called before anything else.
TEST_P(SimpleURLLoaderTest, ResponseCompleteBeforeReceivedResponse) {}

// Check that the request fails if OnComplete() is called before the body pipe
// is received.
TEST_P(SimpleURLLoaderTest, ResponseCompleteAfterReceivedResponse) {}

TEST_P(SimpleURLLoaderTest, CloseClientPipeBeforeBodyStarts) {}

// This test tries closing the client pipe / completing the request in most
// possible valid orders relative to read events (Which always occur in the same
// order).
// TODO(crbug.com/40815508): Flakes on ios simulator.
#if BUILDFLAG(IS_IOS)
#define MAYBE_CloseClientPipeOrder
#else
#define MAYBE_CloseClientPipeOrder
#endif
TEST_P(SimpleURLLoaderTest, MAYBE_CloseClientPipeOrder) {}

// Make sure the close client pipe message doesn't cause any issues.
TEST_P(SimpleURLLoaderTest, ErrorAndCloseClientPipeBeforeBodyStarts) {}

// Make sure the close client pipe message doesn't cause any issues.
TEST_P(SimpleURLLoaderTest, SuccessAndCloseClientPipeBeforeBodyComplete) {}

// Make sure the close client pipe message doesn't cause any issues.
TEST_P(SimpleURLLoaderTest, SuccessAndCloseClientPipeAfterBodyComplete) {}

TEST_P(SimpleURLLoaderTest, DoubleReceivedResponse) {}

TEST_P(SimpleURLLoaderTest, RedirectAfterReceivedResponse) {}

TEST_P(SimpleURLLoaderTest, DoubleBodyBufferReceived) {}

TEST_P(SimpleURLLoaderTest, UnexpectedMessageAfterBodyStarts) {}

TEST_P(SimpleURLLoaderTest, UnexpectedMessageAfterBodyStarts2) {}

TEST_P(SimpleURLLoaderTest, UnexpectedMessageAfterBodyComplete) {}

TEST_P(SimpleURLLoaderTest, MoreDataThanExpected) {}

TEST_P(SimpleURLLoaderTest, DownloadProgressCallbackIncremental) {}

TEST_P(SimpleURLLoaderTest, RetryOn5xx) {}

TEST_P(SimpleURLLoaderTest, RetryOnNameNotResolved) {}

// Test that when retrying on 5xx is enabled, there's no retry on a 4xx error.
TEST_P(SimpleURLLoaderTest, NoRetryOn4xx) {}

// Checks that retrying after a redirect works. The original URL should be
// re-requested.
TEST_P(SimpleURLLoaderTest, RetryAfterRedirect) {}

TEST_P(SimpleURLLoaderTest, RetryOnNetworkChange) {}

// Check the case where the URLLoaderFactory has been disconnected before the
// request is retried.
TEST_P(SimpleURLLoaderTest, RetryWithUnboundFactory) {}

// Test the case where DataPipeGetter::Read is called twice in a row,
// with no intervening reads of the data on the pipe.
TEST_P(SimpleURLLoaderTest, UploadLongStringStartReadTwice) {}

// Test the case where DataPipeGetter::Read is called a second time, after only
// reading part of the response, with no intervening reads of the data on the
// pipe.
TEST_P(SimpleURLLoaderTest,
       UploadLongStringReadPartOfUploadBodyBeforeRestartBodyRead) {}

// Test for GetFinalURL.
TEST_P(SimpleURLLoaderTest, GetFinalURL) {}

// Test for GetFinalURL with a redirect.
TEST_P(SimpleURLLoaderTest, GetFinalURLAfterRedirect) {}

INSTANTIATE_TEST_SUITE_P();

class SimpleURLLoaderFileTest : public SimpleURLLoaderTestBase,
                                public testing::Test {};

// Make sure that an existing file will be completely overwritten.
TEST_F(SimpleURLLoaderFileTest, OverwriteFile) {}

// Make sure that file creation errors are handled correctly.
TEST_F(SimpleURLLoaderFileTest, FileCreateError) {}

// Make sure that destroying the loader destroys a partially downloaded file.
TEST_F(SimpleURLLoaderFileTest, DeleteLoaderDuringRequestDestroysFile) {}

// Used for testing stream-specific features.
class SimpleURLLoaderStreamTest : public SimpleURLLoaderTestBase,
                                  public testing::Test {};

TEST_F(SimpleURLLoaderStreamTest, OnDataReceivedCompletesAsync) {}

// Test case where class is destroyed during OnDataReceived. Main purpose is to
// make sure there's not a crash.
TEST_F(SimpleURLLoaderStreamTest, OnDataReceivedDestruction) {}

TEST_F(SimpleURLLoaderStreamTest, OnRetryCompletesAsync) {}

// Test case where class is destroyed during OnRetry. While setting the loader
// to retry and then destroying it on retry is perhaps a bit strange, seems best
// to be consistent in the provided API. Main purpose of this test is to make
// sure there's not a crash.
TEST_F(SimpleURLLoaderStreamTest, OnRetryDestruction) {}

// Don't inherit from SimpleURLLoaderTestBase so that we can initialize our
// |task_environment_| different namely with TimeSource::MOCK_TIME.
class SimpleURLLoaderMockTimeTest : public testing::Test {};

// The amount of time that's simulated passing is equal to the timeout value
// specified, so the request should fail.
TEST_F(SimpleURLLoaderMockTimeTest, TimeoutTriggered) {}

// Request fails with a timeout like in TimeoutTriggered, and the stream resume
// closure is called after the timeout. The loader is alive throughout.
TEST_F(SimpleURLLoaderMockTimeTest, StreamResumeAfterTimeout) {}

// Less time is simulated passing than the timeout value, so this request should
// succeed normally.
TEST_F(SimpleURLLoaderMockTimeTest, TimeoutNotTriggered) {}

// Simulate time passing, without setting the timeout. This should result in no
// timer being started, and request should succeed.
TEST_F(SimpleURLLoaderMockTimeTest, TimeNotSetAndTimeAdvanced) {}

// Simulate time passing before and after a redirect. The redirect should not
// reset the timeout timer, and the request should timeout.
TEST_F(SimpleURLLoaderMockTimeTest, TimeoutAfterRedirectTriggered) {}

// Simulate time passing after a failure. The retry restarts the timeout timer,
// so the second attempt gets a full two seconds and it is not exhausted.
TEST_F(SimpleURLLoaderMockTimeTest, TimeoutAfterRetryNotTriggered) {}

// Trigger a failure and retry, and then simulate enough time passing to trigger
// the timeout. The retry should have correctly started its timeout timer.
TEST_F(SimpleURLLoaderMockTimeTest, TimeoutAfterRetryTriggered) {}

TEST_P(SimpleURLLoaderTest, OnUploadProgressCallback) {}

TEST_P(SimpleURLLoaderTest, OnDownloadProgressCallback) {}

// Ensure that deleting the SimpleURLLoader in the upload progress
// callback is safe
TEST_P(SimpleURLLoaderTest, DeleteInOnUploadProgressCallback) {}

// Ensure that deleting the SimpleURLLoader in the upload progress
// callback is safe --- first invocation.
TEST_P(SimpleURLLoaderTest, DeleteInDownloadProgressCallback) {}

// Ensure that deleting the SimpleURLLoader in the upload progress
// callback is safe --- completion invocation.
TEST_P(SimpleURLLoaderTest, DeleteInDownloadProgressCallback2) {}

}  // namespace
}  // namespace network