blob: aaa3c993fde80c4be1b0448681bd95b6551ab6d0 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/network/test/test_url_loader_factory.h"
#include "base/logging.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "net/http/http_status_code.h"
#include "net/http/http_util.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/resource_request_body.h"
namespace network {
namespace {
ResourceResponseHead CreateResourceResponseHead(
net::HttpStatusCode http_status) {
ResourceResponseHead head;
std::string headers(base::StringPrintf(
"HTTP/1.1 %d %s\nContent-type: text/html\n\n",
static_cast<int>(http_status), net::GetHttpReasonPhrase(http_status)));
head.headers = new net::HttpResponseHeaders(
net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()));
return head;
}
} // namespace
TestURLLoaderFactory::PendingRequest::PendingRequest() = default;
TestURLLoaderFactory::PendingRequest::~PendingRequest() = default;
TestURLLoaderFactory::PendingRequest::PendingRequest(PendingRequest&& other) =
default;
TestURLLoaderFactory::PendingRequest& TestURLLoaderFactory::PendingRequest::
operator=(PendingRequest&& other) = default;
TestURLLoaderFactory::Response::Response() = default;
TestURLLoaderFactory::Response::~Response() = default;
TestURLLoaderFactory::Response::Response(const Response&) = default;
TestURLLoaderFactory::TestURLLoaderFactory() {}
TestURLLoaderFactory::~TestURLLoaderFactory() {}
void TestURLLoaderFactory::AddResponse(const GURL& url,
const ResourceResponseHead& head,
const std::string& content,
const URLLoaderCompletionStatus& status,
const Redirects& redirects) {
Response response;
response.url = url;
response.redirects = redirects;
response.head = head;
response.content = content;
response.status = status;
responses_[url] = response;
for (auto it = pending_requests_.begin(); it != pending_requests_.end();) {
if (CreateLoaderAndStartInternal(it->url, it->client.get())) {
it = pending_requests_.erase(it);
} else {
++it;
}
}
}
void TestURLLoaderFactory::AddResponse(const std::string& url,
const std::string& content,
net::HttpStatusCode http_status) {
ResourceResponseHead head = CreateResourceResponseHead(http_status);
head.mime_type = "text/html";
URLLoaderCompletionStatus status;
status.decoded_body_length = content.size();
AddResponse(GURL(url), head, content, status);
}
bool TestURLLoaderFactory::IsPending(const std::string& url,
int* load_flags_out) {
base::RunLoop().RunUntilIdle();
for (const auto& candidate : pending_requests_) {
if (candidate.url == url) {
if (load_flags_out)
*load_flags_out = candidate.load_flags;
return !candidate.client.encountered_error();
}
}
return false;
}
int TestURLLoaderFactory::NumPending() {
int pending = 0;
base::RunLoop().RunUntilIdle();
for (const auto& candidate : pending_requests_) {
if (!candidate.client.encountered_error())
++pending;
}
return pending;
}
void TestURLLoaderFactory::ClearResponses() {
responses_.clear();
}
void TestURLLoaderFactory::SetInterceptor(const Interceptor& interceptor) {
interceptor_ = interceptor;
}
void TestURLLoaderFactory::CreateLoaderAndStart(
mojom::URLLoaderRequest request,
int32_t routing_id,
int32_t request_id,
uint32_t options,
const ResourceRequest& url_request,
mojom::URLLoaderClientPtr client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
if (interceptor_)
interceptor_.Run(url_request);
if (CreateLoaderAndStartInternal(url_request.url, client.get()))
return;
PendingRequest pending_request;
pending_request.url = url_request.url;
pending_request.load_flags = url_request.load_flags;
pending_request.client = std::move(client);
pending_request.request_body = std::move(url_request.request_body);
pending_requests_.push_back(std::move(pending_request));
}
void TestURLLoaderFactory::Clone(mojom::URLLoaderFactoryRequest request) {
bindings_.AddBinding(this, std::move(request));
}
bool TestURLLoaderFactory::CreateLoaderAndStartInternal(
const GURL& url,
mojom::URLLoaderClient* client) {
auto it = responses_.find(url);
if (it == responses_.end())
return false;
SimulateResponseImpl(client, it->second.redirects, it->second.head,
it->second.content, it->second.status);
return true;
}
// static
void TestURLLoaderFactory::SimulateResponse(
TestURLLoaderFactory::PendingRequest request,
std::string content,
int net_error) {
network::URLLoaderCompletionStatus status(net::OK);
ResourceResponseHead head = CreateResourceResponseHead(net::HTTP_OK);
status.decoded_body_length = content.size();
SimulateResponseImpl(request.client.get(), TestURLLoaderFactory::Redirects(),
head, content, status);
base::RunLoop().RunUntilIdle();
}
// static
void TestURLLoaderFactory::SimulateResponseImpl(
mojom::URLLoaderClient* client,
TestURLLoaderFactory::Redirects redirects,
ResourceResponseHead head,
std::string content,
URLLoaderCompletionStatus status) {
for (const auto& redirect : redirects)
client->OnReceiveRedirect(redirect.first, redirect.second);
if (status.error_code == net::OK) {
client->OnReceiveResponse(head);
mojo::DataPipe data_pipe(content.size());
uint32_t bytes_written = content.size();
CHECK_EQ(MOJO_RESULT_OK, data_pipe.producer_handle->WriteData(
content.data(), &bytes_written,
MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
client->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle));
}
client->OnComplete(status);
}
} // namespace network