blob: 88e388b05cf7bca8e6d7e787b9ef3aa3dcac78df [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_HTTP_HTTP_TRANSACTION_TEST_UTIL_H_
#define NET_HTTP_HTTP_TRANSACTION_TEST_UTIL_H_
#include "base/memory/raw_ptr.h"
#include "net/http/http_transaction.h"
#include <stdint.h>
#include <set>
#include <string>
#include <vector>
#include "base/compiler_specific.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "net/base/completion_once_callback.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_error_details.h"
#include "net/base/net_errors.h"
#include "net/base/request_priority.h"
#include "net/base/test_completion_callback.h"
#include "net/base/transport_info.h"
#include "net/cert/x509_certificate.h"
#include "net/disk_cache/disk_cache.h"
#include "net/http/http_cache.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/log/net_log_source.h"
#include "net/socket/connection_attempts.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace net {
class IOBuffer;
class SSLPrivateKey;
class NetLogWithSource;
struct HttpRequestInfo;
//-----------------------------------------------------------------------------
// mock transaction data
// these flags may be combined to form the test_mode field
enum {
TEST_MODE_NORMAL = 0,
TEST_MODE_SYNC_NET_START = 1 << 0,
TEST_MODE_SYNC_NET_READ = 1 << 1,
TEST_MODE_SYNC_CACHE_START = 1 << 2,
TEST_MODE_SYNC_CACHE_READ = 1 << 3,
TEST_MODE_SYNC_CACHE_WRITE = 1 << 4,
TEST_MODE_SYNC_ALL = (TEST_MODE_SYNC_NET_START | TEST_MODE_SYNC_NET_READ |
TEST_MODE_SYNC_CACHE_START | TEST_MODE_SYNC_CACHE_READ |
TEST_MODE_SYNC_CACHE_WRITE),
TEST_MODE_SLOW_READ = 1 << 5
};
using MockTransactionReadHandler = int (*)(int64_t content_length,
int64_t offset,
IOBuffer* buf,
int buf_len);
using MockTransactionHandler = void (*)(const HttpRequestInfo* request,
std::string* response_status,
std::string* response_headers,
std::string* response_data);
// Default TransportInfo suitable for most MockTransactions.
// Describes a direct connection to (127.0.0.1, 80).
TransportInfo DefaultTransportInfo();
struct MockTransaction {
const char* url;
const char* method;
// If |request_time| is unspecified, the current time will be used.
base::Time request_time;
const char* request_headers;
int load_flags;
// Connection info passed to ConnectedCallback(), if any.
TransportInfo transport_info = DefaultTransportInfo();
const char* status;
const char* response_headers;
// If |response_time| is unspecified, the current time will be used.
base::Time response_time;
const char* data;
// Any aliases for the requested URL, as read from DNS records. Includes all
// known aliases, e.g. from A, AAAA, or HTTPS, not just from the address used
// for the connection, in no particular order.
std::set<std::string> dns_aliases;
absl::optional<int64_t> fps_cache_filter;
absl::optional<int64_t> browser_run_id;
int test_mode;
MockTransactionHandler handler;
MockTransactionReadHandler read_handler;
scoped_refptr<X509Certificate> cert;
CertStatus cert_status;
int ssl_connection_status;
// Value returned by MockNetworkTransaction::Start (potentially
// asynchronously if |!(test_mode & TEST_MODE_SYNC_NET_START)|.)
Error start_return_code;
// Value returned by MockNetworkTransaction::Read (potentially
// asynchronously if |!(test_mode & TEST_MODE_SYNC_NET_START)|.)
Error read_return_code;
};
extern const MockTransaction kSimpleGET_Transaction;
extern const MockTransaction kSimplePOST_Transaction;
extern const MockTransaction kTypicalGET_Transaction;
extern const MockTransaction kETagGET_Transaction;
extern const MockTransaction kRangeGET_Transaction;
// returns the mock transaction for the given URL
const MockTransaction* FindMockTransaction(const GURL& url);
// Add/Remove a mock transaction that can be accessed via FindMockTransaction.
// There can be only one MockTransaction associated with a given URL.
void AddMockTransaction(const MockTransaction* trans);
void RemoveMockTransaction(const MockTransaction* trans);
struct ScopedMockTransaction : MockTransaction {
ScopedMockTransaction() {
AddMockTransaction(this);
}
explicit ScopedMockTransaction(const MockTransaction& t)
: MockTransaction(t) {
AddMockTransaction(this);
}
~ScopedMockTransaction() {
RemoveMockTransaction(this);
}
};
//-----------------------------------------------------------------------------
// mock http request
class MockHttpRequest : public HttpRequestInfo {
public:
explicit MockHttpRequest(const MockTransaction& t);
std::string CacheKey();
};
//-----------------------------------------------------------------------------
// use this class to test completely consuming a transaction
class TestTransactionConsumer {
public:
TestTransactionConsumer(RequestPriority priority,
HttpTransactionFactory* factory);
virtual ~TestTransactionConsumer();
void Start(const HttpRequestInfo* request, const NetLogWithSource& net_log);
bool is_done() const { return state_ == State::kDone; }
int error() const { return error_; }
const HttpResponseInfo* response_info() const {
return trans_->GetResponseInfo();
}
const HttpTransaction* transaction() const { return trans_.get(); }
const std::string& content() const { return content_; }
private:
enum class State { kIdle, kStarting, kReading, kDone };
void DidStart(int result);
void DidRead(int result);
void DidFinish(int result);
void Read();
void OnIOComplete(int result);
State state_ = State::kIdle;
std::unique_ptr<HttpTransaction> trans_;
std::string content_;
scoped_refptr<IOBuffer> read_buf_;
int error_ = OK;
static int quit_counter_;
};
//-----------------------------------------------------------------------------
// mock network layer
class MockNetworkLayer;
// This transaction class inspects the available set of mock transactions to
// find data for the request URL. It supports IO operations that complete
// synchronously or asynchronously to help exercise different code paths in the
// HttpCache implementation.
class MockNetworkTransaction
: public HttpTransaction,
public base::SupportsWeakPtr<MockNetworkTransaction> {
typedef WebSocketHandshakeStreamBase::CreateHelper CreateHelper;
public:
MockNetworkTransaction(RequestPriority priority, MockNetworkLayer* factory);
~MockNetworkTransaction() override;
int Start(const HttpRequestInfo* request,
CompletionOnceCallback callback,
const NetLogWithSource& net_log) override;
int RestartIgnoringLastError(CompletionOnceCallback callback) override;
int RestartWithCertificate(scoped_refptr<X509Certificate> client_cert,
scoped_refptr<SSLPrivateKey> client_private_key,
CompletionOnceCallback callback) override;
int RestartWithAuth(const AuthCredentials& credentials,
CompletionOnceCallback callback) override;
bool IsReadyToRestartForAuth() override;
int Read(IOBuffer* buf,
int buf_len,
CompletionOnceCallback callback) override;
void PopulateNetErrorDetails(NetErrorDetails* details) const override;
void StopCaching() override;
int64_t GetTotalReceivedBytes() const override;
int64_t GetTotalSentBytes() const override;
void DoneReading() override;
const HttpResponseInfo* GetResponseInfo() const override;
LoadState GetLoadState() const override;
void SetQuicServerInfo(QuicServerInfo* quic_server_info) override;
bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
bool GetRemoteEndpoint(IPEndPoint* endpoint) const override;
void SetPriority(RequestPriority priority) override;
void SetWebSocketHandshakeStreamCreateHelper(
CreateHelper* create_helper) override;
void SetBeforeNetworkStartCallback(
BeforeNetworkStartCallback callback) override;
void SetConnectedCallback(const ConnectedCallback& callback) override;
void SetRequestHeadersCallback(RequestHeadersCallback callback) override {}
void SetResponseHeadersCallback(ResponseHeadersCallback) override {}
void SetEarlyResponseHeadersCallback(ResponseHeadersCallback) override {}
int ResumeNetworkStart() override;
ConnectionAttempts GetConnectionAttempts() const override;
void CloseConnectionOnDestruction() override;
CreateHelper* websocket_handshake_stream_create_helper() {
return websocket_handshake_stream_create_helper_;
}
RequestPriority priority() const { return priority_; }
const HttpRequestInfo* request() const { return request_; }
// Bogus value that will be returned by GetTotalReceivedBytes() if the
// MockNetworkTransaction was started.
static const int64_t kTotalReceivedBytes;
// Bogus value that will be returned by GetTotalSentBytes() if the
// MockNetworkTransaction was started.
static const int64_t kTotalSentBytes;
private:
int StartInternal(const HttpRequestInfo* request,
CompletionOnceCallback callback,
const NetLogWithSource& net_log);
void CallbackLater(CompletionOnceCallback callback, int result);
void RunCallback(CompletionOnceCallback callback, int result);
raw_ptr<const HttpRequestInfo> request_ = nullptr;
HttpResponseInfo response_;
std::string data_;
int64_t data_cursor_ = 0;
int64_t content_length_ = 0;
int test_mode_;
RequestPriority priority_;
MockTransactionReadHandler read_handler_ = nullptr;
raw_ptr<CreateHelper> websocket_handshake_stream_create_helper_ = nullptr;
BeforeNetworkStartCallback before_network_start_callback_;
ConnectedCallback connected_callback_;
base::WeakPtr<MockNetworkLayer> transaction_factory_;
int64_t received_bytes_ = 0;
int64_t sent_bytes_ = 0;
// NetLog ID of the fake / non-existent underlying socket used by the
// connection. Requires Start() be passed a NetLogWithSource with a real
// NetLog to
// be initialized.
unsigned int socket_log_id_ = NetLogSource::kInvalidId;
bool done_reading_called_ = false;
bool reading_ = false;
CompletionOnceCallback resume_start_callback_; // used for pause and restart.
base::WeakPtrFactory<MockNetworkTransaction> weak_factory_{this};
};
class MockNetworkLayer : public HttpTransactionFactory,
public base::SupportsWeakPtr<MockNetworkLayer> {
public:
MockNetworkLayer();
~MockNetworkLayer() override;
int transaction_count() const { return transaction_count_; }
bool done_reading_called() const { return done_reading_called_; }
bool stop_caching_called() const { return stop_caching_called_; }
void TransactionDoneReading();
void TransactionStopCaching();
// Resets the transaction count. Can be called after test setup in order to
// make test expectations independent of how test setup is performed.
void ResetTransactionCount();
// Returns the last priority passed to CreateTransaction, or
// DEFAULT_PRIORITY if it hasn't been called yet.
RequestPriority last_create_transaction_priority() const {
return last_create_transaction_priority_;
}
// Returns the last transaction created by
// CreateTransaction. Returns a NULL WeakPtr if one has not been
// created yet, or the last transaction has been destroyed, or
// ClearLastTransaction() has been called and a new transaction
// hasn't been created yet.
base::WeakPtr<MockNetworkTransaction> last_transaction() {
return last_transaction_;
}
// Makes last_transaction() return NULL until the next transaction
// is created.
void ClearLastTransaction() {
last_transaction_.reset();
}
// HttpTransactionFactory:
int CreateTransaction(RequestPriority priority,
std::unique_ptr<HttpTransaction>* trans) override;
HttpCache* GetCache() override;
HttpNetworkSession* GetSession() override;
// The caller must guarantee that |clock| will outlive this object.
void SetClock(base::Clock* clock);
base::Clock* clock() const { return clock_; }
// The current time (will use clock_ if it is non NULL).
base::Time Now();
private:
int transaction_count_ = 0;
bool done_reading_called_ = false;
bool stop_caching_called_ = false;
RequestPriority last_create_transaction_priority_ = DEFAULT_PRIORITY;
// By default clock_ is NULL but it can be set to a custom clock by test
// frameworks using SetClock.
raw_ptr<base::Clock> clock_ = nullptr;
base::WeakPtr<MockNetworkTransaction> last_transaction_;
};
//-----------------------------------------------------------------------------
// helpers
// read the transaction completely
int ReadTransaction(HttpTransaction* trans, std::string* result);
//-----------------------------------------------------------------------------
// connected callback handler
// Used for injecting ConnectedCallback instances in HttpTransaction.
class ConnectedHandler {
public:
ConnectedHandler();
~ConnectedHandler();
// Instances of this class are copyable and efficiently movable.
// WARNING: Do not move an instance to which a callback is bound.
ConnectedHandler(const ConnectedHandler&);
ConnectedHandler& operator=(const ConnectedHandler&);
ConnectedHandler(ConnectedHandler&&);
ConnectedHandler& operator=(ConnectedHandler&&);
// Returns a callback bound to this->OnConnected().
// The returned callback must not outlive this instance.
HttpTransaction::ConnectedCallback Callback() {
return base::BindRepeating(&ConnectedHandler::OnConnected,
base::Unretained(this));
}
// Compatible with HttpTransaction::ConnectedCallback.
// Returns the last value passed to set_result(), if any, OK otherwise.
int OnConnected(const TransportInfo& info, CompletionOnceCallback callback);
// Returns the list of arguments with which OnConnected() was called.
// The arguments are listed in the same order as the calls were received.
const std::vector<TransportInfo>& transports() const { return transports_; }
// Sets the value to be returned by subsequent calls to OnConnected().
void set_result(int result) { result_ = result; }
// If true, runs the callback supplied to OnConnected asynchronously with
// `result_`. Otherwise, the callback is skipped and `result_` is returned
// directly.
void set_run_callback(bool run_callback) { run_callback_ = run_callback; }
private:
std::vector<TransportInfo> transports_;
int result_ = OK;
bool run_callback_ = false;
};
} // namespace net
#endif // NET_HTTP_HTTP_TRANSACTION_TEST_UTIL_H_