#ifndef SERVICES_NETWORK_TEST_TEST_URL_LOADER_FACTORY_H_
#define SERVICES_NETWORK_TEST_TEST_URL_LOADER_FACTORY_H_
#include <map>
#include <string>
#include <string_view>
#include <vector>
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/http/http_status_code.h"
#include "services/network/public/cpp/resource_request.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"
namespace network {
class WeakWrapperSharedURLLoaderFactory;
class TestURLLoaderFactory : public mojom::URLLoaderFactory {
public:
class TestURLLoader final : public network::mojom::URLLoader {
public:
struct FollowRedirectParams {
FollowRedirectParams();
~FollowRedirectParams();
FollowRedirectParams(FollowRedirectParams&& other);
FollowRedirectParams& operator=(FollowRedirectParams&& other);
std::vector<std::string> removed_headers;
net::HttpRequestHeaders modified_headers;
net::HttpRequestHeaders modified_cors_exempt_headers;
std::optional<GURL> new_url;
};
explicit TestURLLoader(
mojo::PendingReceiver<network::mojom::URLLoader> url_loader_receiver);
~TestURLLoader() override;
TestURLLoader(const TestURLLoader&) = delete;
TestURLLoader& operator=(const TestURLLoader&) = delete;
void FollowRedirect(
const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers,
const net::HttpRequestHeaders& modified_cors_exempt_headers,
const std::optional<GURL>& new_url) override;
void SetPriority(net::RequestPriority priority,
int32_t intra_priority_value) override {}
const std::vector<FollowRedirectParams>& follow_redirect_params() const {
return follow_redirect_params_;
}
private:
std::vector<FollowRedirectParams> follow_redirect_params_;
mojo::Receiver<network::mojom::URLLoader> receiver_;
};
struct PendingRequest {
PendingRequest();
~PendingRequest();
PendingRequest(PendingRequest&& other);
PendingRequest& operator=(PendingRequest&& other);
std::unique_ptr<TestURLLoader> test_url_loader;
mojo::Remote<mojom::URLLoaderClient> client;
int32_t request_id;
uint32_t options;
ResourceRequest request;
net::MutableNetworkTrafficAnnotationTag traffic_annotation;
};
enum ResponseMatchFlags : uint32_t {
kMatchDefault = 0x0,
kUrlMatchPrefix = 0x1,
kMostRecentMatch = 0x2,
kWaitForRequest = 0x4,
};
enum ResponseProduceFlags : uint32_t {
kResponseDefault = 0,
kResponseOnlyRedirectsNoDestination = 0x1,
kSendHeadersOnNetworkError = 0x2,
};
explicit TestURLLoaderFactory(bool observe_loader_requests = false);
TestURLLoaderFactory(const TestURLLoaderFactory&) = delete;
TestURLLoaderFactory& operator=(const TestURLLoaderFactory&) = delete;
~TestURLLoaderFactory() override;
using Redirects =
std::vector<std::pair<net::RedirectInfo, mojom::URLResponseHeadPtr>>;
void AddResponse(const GURL& url,
mojom::URLResponseHeadPtr head,
std::string_view content,
const URLLoaderCompletionStatus& status,
Redirects redirects = Redirects(),
ResponseProduceFlags rp_flags = kResponseDefault);
void AddResponse(std::string_view url,
std::string_view content,
net::HttpStatusCode status = net::HTTP_OK);
void EraseResponse(const GURL& url) { responses_.erase(url); }
bool IsPending(std::string_view url,
const ResourceRequest** request_out = nullptr);
int NumPending();
void ClearResponses();
using Interceptor = base::RepeatingCallback<void(const ResourceRequest&)>;
void SetInterceptor(const Interceptor& interceptor);
std::vector<PendingRequest>* pending_requests() { return &pending_requests_; }
PendingRequest* GetPendingRequest(size_t index);
void WaitForRequest(const GURL& url,
ResponseMatchFlags flags = kMatchDefault);
bool SimulateResponseForPendingRequest(
const GURL& url,
const network::URLLoaderCompletionStatus& completion_status,
mojom::URLResponseHeadPtr response_head,
std::string_view content,
ResponseMatchFlags flags = kMatchDefault);
bool SimulateResponseForPendingRequest(
std::string_view url,
std::string_view content,
net::HttpStatusCode status = net::HTTP_OK,
ResponseMatchFlags flags = kMatchDefault);
void SimulateResponseWithoutRemovingFromPendingList(
PendingRequest* request,
mojom::URLResponseHeadPtr head,
std::string_view content,
const URLLoaderCompletionStatus& status);
void SimulateResponseWithoutRemovingFromPendingList(PendingRequest* request,
std::string_view content);
void CreateLoaderAndStart(mojo::PendingReceiver<mojom::URLLoader> receiver,
int32_t request_id,
uint32_t options,
const ResourceRequest& url_request,
mojo::PendingRemote<mojom::URLLoaderClient> client,
const net::MutableNetworkTrafficAnnotationTag&
traffic_annotation) override;
void Clone(mojo::PendingReceiver<mojom::URLLoaderFactory> receiver) override;
scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
GetSafeWeakWrapper();
size_t total_requests() const { return total_requests_; }
private:
bool CreateLoaderAndStartInternal(const GURL& url,
mojom::URLLoaderClient* client);
std::optional<network::TestURLLoaderFactory::PendingRequest>
FindPendingRequest(const GURL& url,
ResponseMatchFlags flags,
bool keep_request = false);
static void SimulateResponse(mojom::URLLoaderClient* client,
Redirects redirects,
mojom::URLResponseHeadPtr head,
std::string_view content,
URLLoaderCompletionStatus status,
ResponseProduceFlags response_flags);
struct Response {
Response();
~Response();
Response(Response&&);
Response& operator=(Response&&);
GURL url;
Redirects redirects;
mojom::URLResponseHeadPtr head;
std::string content;
URLLoaderCompletionStatus status;
ResponseProduceFlags flags;
};
std::map<GURL, Response> responses_;
std::vector<PendingRequest> pending_requests_;
base::OnceClosure on_new_pending_request_;
scoped_refptr<network::WeakWrapperSharedURLLoaderFactory> weak_wrapper_;
Interceptor interceptor_;
mojo::ReceiverSet<network::mojom::URLLoaderFactory> receivers_;
size_t total_requests_ = 0;
const bool observe_loader_requests_;
};
}
#endif