blob: 7a3246f4a1fbb85b2d40ebc00eff189e1955ed81 [file] [log] [blame]
// 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 "net/test/embedded_test_server/controllable_http_response.h"
#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_runner.h"
#include "net/base/tracing.h"
#include "net/test/embedded_test_server/http_response.h"
namespace net::test_server {
class ControllableHttpResponse::Interceptor : public HttpResponse {
public:
explicit Interceptor(
base::WeakPtr<ControllableHttpResponse> controller,
scoped_refptr<base::SingleThreadTaskRunner> controller_task_runner,
const HttpRequest& http_request)
: controller_(controller),
controller_task_runner_(controller_task_runner),
http_request_(std::make_unique<HttpRequest>(http_request)) {}
Interceptor(const Interceptor&) = delete;
Interceptor& operator=(const Interceptor&) = delete;
~Interceptor() override = default;
private:
void SendResponse(base::WeakPtr<HttpResponseDelegate> delegate) override {
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
base::SingleThreadTaskRunner::GetCurrentDefault();
CHECK(task_runner);
controller_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&ControllableHttpResponse::OnRequest,
controller_, std::move(task_runner), delegate,
std::move(http_request_)));
}
base::WeakPtr<ControllableHttpResponse> controller_;
scoped_refptr<base::SingleThreadTaskRunner> controller_task_runner_;
std::unique_ptr<HttpRequest> http_request_;
};
ControllableHttpResponse::ControllableHttpResponse(
EmbeddedTestServer* embedded_test_server,
const std::string& relative_url,
bool relative_url_is_prefix) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
embedded_test_server->RegisterRequestHandler(base::BindRepeating(
RequestHandler, weak_ptr_factory_.GetWeakPtr(),
base::SingleThreadTaskRunner::GetCurrentDefault(),
base::Owned(new bool(true)), relative_url, relative_url_is_prefix));
}
ControllableHttpResponse::~ControllableHttpResponse() = default;
void ControllableHttpResponse::WaitForRequest() {
TRACE_EVENT("test", "ControllableHttpResponse::WaitForRequest");
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK_EQ(State::WAITING_FOR_REQUEST, state_)
<< "WaitForRequest() called twice.";
loop_.Run();
CHECK(embedded_test_server_task_runner_);
state_ = State::READY_TO_SEND_DATA;
}
void ControllableHttpResponse::Send(
net::HttpStatusCode http_status,
const std::string& content_type,
const std::string& content,
const std::vector<std::string>& cookies,
const std::vector<std::string>& extra_headers) {
TRACE_EVENT("test", "ControllableHttpResponse::Send", "http_status",
http_status, "content_type", content_type, "content", content,
"cookies", cookies);
std::string content_data(base::StringPrintf(
"HTTP/1.1 %d %s\nContent-type: %s\n", static_cast<int>(http_status),
net::GetHttpReasonPhrase(http_status), content_type.c_str()));
for (auto& cookie : cookies)
content_data += "Set-Cookie: " + cookie + "\n";
for (auto& header : extra_headers)
content_data += header + "\n";
content_data += "\n";
content_data += content;
Send(content_data);
}
void ControllableHttpResponse::Send(const std::string& bytes) {
TRACE_EVENT("test", "ControllableHttpResponse::Send", "bytes", bytes);
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK_EQ(State::READY_TO_SEND_DATA, state_) << "Send() called without any "
"opened connection. Did you "
"call WaitForRequest()?";
base::RunLoop loop;
embedded_test_server_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&HttpResponseDelegate::SendContents, delegate_,
bytes, loop.QuitClosure()));
loop.Run();
}
void ControllableHttpResponse::Done() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK_EQ(State::READY_TO_SEND_DATA, state_) << "Done() called without any "
"opened connection. Did you "
"call WaitForRequest()?";
embedded_test_server_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&HttpResponseDelegate::FinishResponse, delegate_));
state_ = State::DONE;
}
bool ControllableHttpResponse::has_received_request() {
return loop_.AnyQuitCalled();
}
void ControllableHttpResponse::OnRequest(
scoped_refptr<base::SingleThreadTaskRunner>
embedded_test_server_task_runner,
base::WeakPtr<HttpResponseDelegate> delegate,
std::unique_ptr<HttpRequest> http_request) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(embedded_test_server_task_runner);
CHECK(!embedded_test_server_task_runner_)
<< "A ControllableHttpResponse can only handle one request at a time";
embedded_test_server_task_runner_ = embedded_test_server_task_runner;
delegate_ = delegate;
http_request_ = std::move(http_request);
loop_.Quit();
}
// Helper function used in the ControllableHttpResponse constructor.
// static
std::unique_ptr<HttpResponse> ControllableHttpResponse::RequestHandler(
base::WeakPtr<ControllableHttpResponse> controller,
scoped_refptr<base::SingleThreadTaskRunner> controller_task_runner,
bool* available,
const std::string& relative_url,
bool relative_url_is_prefix,
const HttpRequest& request) {
if (!*available)
return nullptr;
if (request.relative_url == relative_url ||
(relative_url_is_prefix &&
base::StartsWith(request.relative_url, relative_url,
base::CompareCase::SENSITIVE))) {
*available = false;
return std::make_unique<ControllableHttpResponse::Interceptor>(
controller, controller_task_runner, request);
}
return nullptr;
}
} // namespace net::test_server