304 lines
8.0 KiB
C++
304 lines
8.0 KiB
C++
// Copyright (c) 2020 The Chromium Embedded Framework 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 "tests/ceftests/test_server_manager.h"
|
|
|
|
#include "include/wrapper/cef_closure_task.h"
|
|
#include "include/wrapper/cef_helpers.h"
|
|
#include "tests/gtest/include/gtest/gtest.h"
|
|
|
|
namespace test_server {
|
|
|
|
namespace {
|
|
|
|
Manager* g_http_manager = nullptr;
|
|
Manager* g_https_manager = nullptr;
|
|
|
|
} // namespace
|
|
|
|
// May be created on any thread but will be destroyed on the UI thread.
|
|
class ObserverRegistration : public CefRegistration {
|
|
public:
|
|
ObserverRegistration(Observer* observer, bool https_server)
|
|
: observer_(observer), https_server_(https_server) {
|
|
EXPECT_TRUE(observer_);
|
|
}
|
|
|
|
~ObserverRegistration() override {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
|
|
if (auto manager = Manager::GetInstance(https_server_)) {
|
|
manager->RemoveObserver(
|
|
observer_,
|
|
base::BindOnce([](Observer* observer) { observer->OnUnregistered(); },
|
|
base::Unretained(observer_)));
|
|
}
|
|
}
|
|
|
|
void Initialize() {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
Manager::GetOrCreateInstance(https_server_)->AddObserver(observer_);
|
|
observer_->OnRegistered();
|
|
}
|
|
|
|
static void InitializeRegistration(
|
|
CefRefPtr<ObserverRegistration> registration,
|
|
Manager::DoneCallback callback) {
|
|
if (!CefCurrentlyOn(TID_UI)) {
|
|
CefPostTask(TID_UI, base::BindOnce(InitializeRegistration, registration,
|
|
std::move(callback)));
|
|
return;
|
|
}
|
|
|
|
registration->Initialize();
|
|
if (!callback.is_null()) {
|
|
std::move(callback).Run();
|
|
}
|
|
}
|
|
|
|
private:
|
|
Observer* const observer_;
|
|
const bool https_server_;
|
|
|
|
IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(ObserverRegistration);
|
|
DISALLOW_COPY_AND_ASSIGN(ObserverRegistration);
|
|
};
|
|
|
|
Manager::Manager(bool https_server) : https_server_(https_server) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
|
|
if (https_server) {
|
|
DCHECK(!g_https_manager);
|
|
g_https_manager = this;
|
|
} else {
|
|
DCHECK(!g_http_manager);
|
|
g_http_manager = this;
|
|
}
|
|
}
|
|
|
|
Manager::~Manager() {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
EXPECT_TRUE(observer_list_.empty());
|
|
EXPECT_TRUE(start_callback_list_.empty());
|
|
EXPECT_TRUE(stop_callback_.is_null());
|
|
|
|
if (https_server_) {
|
|
g_https_manager = nullptr;
|
|
} else {
|
|
g_http_manager = nullptr;
|
|
}
|
|
}
|
|
|
|
// static
|
|
Manager* Manager::GetInstance(bool https_server) {
|
|
return https_server ? g_https_manager : g_http_manager;
|
|
}
|
|
|
|
// static
|
|
Manager* Manager::GetOrCreateInstance(bool https_server) {
|
|
if (auto manager = GetInstance(https_server)) {
|
|
return manager;
|
|
}
|
|
|
|
new Manager(https_server);
|
|
auto manager = GetInstance(https_server);
|
|
DCHECK(manager);
|
|
return manager;
|
|
}
|
|
|
|
// static
|
|
void Manager::Start(StartDoneCallback callback, bool https_server) {
|
|
EXPECT_FALSE(callback.is_null());
|
|
if (!CefCurrentlyOn(TID_UI)) {
|
|
CefPostTask(TID_UI, base::BindOnce(Manager::Start, std::move(callback),
|
|
https_server));
|
|
return;
|
|
}
|
|
|
|
Manager::GetOrCreateInstance(https_server)->StartImpl(std::move(callback));
|
|
}
|
|
|
|
// static
|
|
void Manager::Stop(DoneCallback callback, bool https_server) {
|
|
EXPECT_FALSE(callback.is_null());
|
|
if (!CefCurrentlyOn(TID_UI)) {
|
|
CefPostTask(TID_UI, base::BindOnce(Manager::Stop, std::move(callback),
|
|
https_server));
|
|
return;
|
|
}
|
|
|
|
if (auto manager = Manager::GetInstance(https_server)) {
|
|
manager->StopImpl(std::move(callback));
|
|
} else {
|
|
std::move(callback).Run();
|
|
}
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefRegistration> Manager::AddObserver(Observer* observer,
|
|
DoneCallback callback,
|
|
bool https_server) {
|
|
EXPECT_TRUE(observer);
|
|
CefRefPtr<ObserverRegistration> registration =
|
|
new ObserverRegistration(observer, https_server);
|
|
ObserverRegistration::InitializeRegistration(registration,
|
|
std::move(callback));
|
|
return registration.get();
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefRegistration> Manager::AddObserverAndStart(
|
|
Observer* observer,
|
|
StartDoneCallback callback,
|
|
bool https_server) {
|
|
return AddObserver(
|
|
observer,
|
|
base::BindOnce(Manager::Start, std::move(callback), https_server),
|
|
https_server);
|
|
}
|
|
|
|
// static
|
|
std::string Manager::GetOrigin(bool https_server) {
|
|
if (auto manager = Manager::GetInstance(https_server)) {
|
|
return manager->origin_;
|
|
}
|
|
NOTREACHED();
|
|
return std::string();
|
|
}
|
|
|
|
void Manager::StartImpl(StartDoneCallback callback) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
EXPECT_FALSE(stopping_);
|
|
|
|
if (!origin_.empty()) {
|
|
// The server is already running.
|
|
std::move(callback).Run(origin_);
|
|
return;
|
|
}
|
|
|
|
// If tests run in parallel, and the server is starting, then there may be
|
|
// multiple pending callbacks.
|
|
start_callback_list_.push_back(std::move(callback));
|
|
|
|
// Only create the runner a single time.
|
|
if (!runner_) {
|
|
runner_ = Runner::Create(this, https_server_);
|
|
runner_->StartServer();
|
|
}
|
|
}
|
|
|
|
void Manager::StopImpl(DoneCallback callback) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
if (!runner_) {
|
|
// The server is not currently running.
|
|
std::move(callback).Run();
|
|
return;
|
|
}
|
|
|
|
// Stop will be called one time on test framework shutdown.
|
|
EXPECT_FALSE(stopping_);
|
|
stopping_ = true;
|
|
|
|
// Only 1 stop callback supported.
|
|
EXPECT_TRUE(stop_callback_.is_null());
|
|
stop_callback_ = std::move(callback);
|
|
|
|
runner_->ShutdownServer();
|
|
}
|
|
|
|
void Manager::AddObserver(Observer* observer) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
EXPECT_FALSE(stopping_);
|
|
observer_list_.push_back(observer);
|
|
}
|
|
|
|
void Manager::RemoveObserver(Observer* observer, DoneCallback callback) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
bool found = false;
|
|
ObserverList::iterator it = observer_list_.begin();
|
|
for (; it != observer_list_.end(); ++it) {
|
|
if (*it == observer) {
|
|
observer_list_.erase(it);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(found);
|
|
|
|
if (observer_list_.empty() && https_server_ && !stopping_) {
|
|
// Stop the HTTPS server when the last Observer is removed. We can't
|
|
// currently reuse the HTTPS server between tests due to
|
|
// https://crrev.com/dd2a57d753 causing cert registration issues.
|
|
StopImpl(std::move(callback));
|
|
} else {
|
|
std::move(callback).Run();
|
|
}
|
|
}
|
|
|
|
void Manager::OnServerCreated(const std::string& server_origin) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
|
|
EXPECT_TRUE(origin_.empty());
|
|
origin_ = server_origin;
|
|
|
|
for (auto& callback : start_callback_list_) {
|
|
std::move(callback).Run(origin_);
|
|
}
|
|
start_callback_list_.clear();
|
|
}
|
|
|
|
void Manager::OnServerDestroyed() {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
|
|
origin_.clear();
|
|
runner_.reset();
|
|
}
|
|
|
|
// All server-related objects have been torn down.
|
|
void Manager::OnServerHandlerDeleted() {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
|
|
EXPECT_FALSE(stop_callback_.is_null());
|
|
std::move(stop_callback_).Run();
|
|
|
|
delete this;
|
|
}
|
|
|
|
void Manager::OnTestServerRequest(CefRefPtr<CefRequest> request,
|
|
const ResponseCallback& response_callback) {
|
|
CEF_REQUIRE_UI_THREAD();
|
|
|
|
// TODO(chrome-runtime): Debug why favicon requests don't always have the
|
|
// correct resource type.
|
|
const std::string& url = request->GetURL();
|
|
if (request->GetResourceType() == RT_FAVICON ||
|
|
url.find("/favicon.ico") != std::string::npos) {
|
|
// We don't currently handle favicon requests.
|
|
response_callback.Run(Create404Response(), std::string());
|
|
return;
|
|
}
|
|
|
|
EXPECT_FALSE(observer_list_.empty()) << url;
|
|
|
|
// Use a copy in case |observer_list_| is modified during iteration.
|
|
ObserverList list = observer_list_;
|
|
|
|
bool handled = false;
|
|
|
|
ObserverList::const_iterator it = list.begin();
|
|
for (; it != list.end(); ++it) {
|
|
if ((*it)->OnTestServerRequest(request, response_callback)) {
|
|
handled = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!handled) {
|
|
LOG(WARNING) << "Unhandled request for: " << url;
|
|
response_callback.Run(Create404Response(), std::string());
|
|
}
|
|
}
|
|
|
|
} // namespace test_server
|