From 56c40038100c84201e8cd822895441dd8fee073b Mon Sep 17 00:00:00 2001 From: Peter Repukat Date: Mon, 27 Feb 2023 19:47:34 +0100 Subject: [PATCH] Refactor: HttpServer endpoints --- GlosSITarget/AppLauncher.cpp | 46 ++++++++-- GlosSITarget/CommonHttpEndpoints.h | 25 ++++++ GlosSITarget/GlosSITarget.vcxproj | 1 + GlosSITarget/GlosSITarget.vcxproj.filters | 3 + GlosSITarget/HttpServer.cpp | 100 ++++++++++++---------- GlosSITarget/HttpServer.h | 22 ++++- GlosSITarget/SteamTarget.cpp | 6 +- 7 files changed, 145 insertions(+), 58 deletions(-) create mode 100644 GlosSITarget/CommonHttpEndpoints.h diff --git a/GlosSITarget/AppLauncher.cpp b/GlosSITarget/AppLauncher.cpp index fa9137a..971ff0c 100644 --- a/GlosSITarget/AppLauncher.cpp +++ b/GlosSITarget/AppLauncher.cpp @@ -28,10 +28,11 @@ limitations under the License. #pragma comment(lib, "Shell32.lib") #endif -#include "..\common\Settings.h" +#include "../common/Settings.h" #include +#include "HttpServer.h" #include "Overlay.h" #include "../common/UnhookUtil.h" #include "../common/util.h" @@ -47,6 +48,32 @@ AppLauncher::AppLauncher( spdlog::debug("App launch requested"); } #endif + + HttpServer::AddEndpoint({"/launched-pids", + HttpServer::Method::GET, + [this](const httplib::Request& req, httplib::Response& res) { + const nlohmann::json j = launchedPids(); + res.set_content(j.dump(), "text/json"); + }}); + + HttpServer::AddEndpoint({"/launched-pids", + HttpServer::Method::POST, + [this](const httplib::Request& req, httplib::Response& res) { + try { + const nlohmann::json postbody = nlohmann::json::parse(req.body); + addPids(postbody.get>()); + } + catch (std::exception& e) { + res.status = 401; + res.set_content(nlohmann::json{ + {"code", 401}, + {"name", "Bad Request"}, + {"message", e.what()}, + } + .dump(), + "text/json"); + } + }}); }; void AppLauncher::launchApp(const std::wstring& path, const std::wstring& args) @@ -255,7 +282,7 @@ void AppLauncher::getProcessHwnds() propStore->GetValue(PKEY_AppUserModel_ID, &prop); if (prop.bstrVal != nullptr && std::wstring(prop.bstrVal) == launched_uwp_path_) { process_hwnds_.push_back(curr_wnd); - } + } } } while (curr_wnd != nullptr); } @@ -298,11 +325,11 @@ void AppLauncher::launchWin32App(const std::wstring& path, const std::wstring& a // } std::wstring args_cpy( args.empty() - ? L"" + ? L"" : ((native_seps_path.find(L" ") != std::wstring::npos ? L"\"" + native_seps_path + L"\"" - : native_seps_path) + L" " + args) - ); + : native_seps_path) + + L" " + args)); DWORD pid; @@ -319,7 +346,8 @@ void AppLauncher::launchWin32App(const std::wstring& path, const std::wstring& a &process_info)) { pid = process_info.dwProcessId; - } else { + } + else { DWORD error_code = GetLastError(); if (error_code == ERROR_ELEVATION_REQUIRED) { @@ -342,11 +370,13 @@ void AppLauncher::launchWin32App(const std::wstring& path, const std::wstring& a spdlog::error(L"Couldn't get process id after starting program: \"{}\"; Error code {}", native_seps_path, GetLastError()); } CloseHandle(shExecInfo.hProcess); - } else { + } + else { spdlog::error(L"Couldn't start program with elevated permissions: \"{}\"; Error code {}", native_seps_path, GetLastError()); return; } - } else { + } + else { spdlog::error(L"Could't start program: \"{}\"; Error code: {}", native_seps_path, error_code); return; } diff --git a/GlosSITarget/CommonHttpEndpoints.h b/GlosSITarget/CommonHttpEndpoints.h new file mode 100644 index 0000000..bd1c2a4 --- /dev/null +++ b/GlosSITarget/CommonHttpEndpoints.h @@ -0,0 +1,25 @@ +#pragma once +#include "HttpServer.h" +#include "../common/Settings.h" +#include "../common/steam_util.h" + +namespace CHTE { + +inline void addEndpoints() +{ + HttpServer::AddEndpoint( + {"/settings", + HttpServer::Method::GET, + [](const httplib::Request& req, httplib::Response& res) { + res.set_content(Settings::toJson().dump(), "text/json"); + }}); + + HttpServer::AddEndpoint( + {"/steam_settings", + HttpServer::Method::GET, + [](const httplib::Request& req, httplib::Response& res) { + res.set_content(util::steam::getSteamConfig().dump(4), "text/json"); + }}); +}; + +} // namespace CHTE diff --git a/GlosSITarget/GlosSITarget.vcxproj b/GlosSITarget/GlosSITarget.vcxproj index 26b7db1..2d09a17 100644 --- a/GlosSITarget/GlosSITarget.vcxproj +++ b/GlosSITarget/GlosSITarget.vcxproj @@ -209,6 +209,7 @@ + diff --git a/GlosSITarget/GlosSITarget.vcxproj.filters b/GlosSITarget/GlosSITarget.vcxproj.filters index ddb734e..f5f4110 100644 --- a/GlosSITarget/GlosSITarget.vcxproj.filters +++ b/GlosSITarget/GlosSITarget.vcxproj.filters @@ -179,6 +179,9 @@ Header Files + + Header Files + diff --git a/GlosSITarget/HttpServer.cpp b/GlosSITarget/HttpServer.cpp index e71c594..768b36f 100644 --- a/GlosSITarget/HttpServer.cpp +++ b/GlosSITarget/HttpServer.cpp @@ -23,10 +23,15 @@ limitations under the License. #include "../common/Settings.h" #include "../common/steam_util.h" -HttpServer::HttpServer(AppLauncher& app_launcher, std::function close) : app_launcher_(app_launcher), close_(std::move(close)) +HttpServer::HttpServer(std::function close) : close_(std::move(close)) { } +void HttpServer::AddEndpoint(const Endpoint&& e) +{ + endpoints_.push_back(e); +} + void HttpServer::run() { auto setCorsHeader = [](httplib::Response& res) { @@ -38,65 +43,66 @@ void HttpServer::run() setCorsHeader(res); }); - server_.Get("/launched-pids", [this, &setCorsHeader](const httplib::Request& req, httplib::Response& res) { - const nlohmann::json j = app_launcher_.launchedPids(); - res.set_content(j.dump(), "text/json"); - setCorsHeader(res); - }); + for (const auto& e : endpoints_) { + const auto fn = ([this, &e]() -> httplib::Server& (httplib::Server::*)(const std::string&, httplib::Server::Handler) { + switch (e.method) { + case POST: + return &httplib::Server::Post; + case PUT: + return &httplib::Server::Put; + case PATCH: + return &httplib::Server::Patch; + default: + return &httplib::Server::Get; + } + })(); - server_.Post("/launched-pids", [this, &setCorsHeader](const httplib::Request& req, httplib::Response& res) { - setCorsHeader(res); - try { - const nlohmann::json postbody = nlohmann::json::parse(req.body); - app_launcher_.addPids(postbody.get>()); - } catch (std::exception& e) { - res.status = 401; - res.set_content(nlohmann::json{ - {"code", 401}, - {"name", "Bad Request"}, - {"message", e.what()}, - } - .dump(), - "text/json"); - return; - } - catch (...) { - res.status = 500; - res.set_content(nlohmann::json{ - {"code", 500}, - {"name", "Internal Server Error"}, - {"message", "Unknown Error"}, - } - .dump(), - "text/json"); - return; - } - const nlohmann::json j = app_launcher_.launchedPids(); - res.set_content(j.dump(), "text/json"); - }); + (server_.*fn)(e.path, [this, &e, &setCorsHeader](const httplib::Request& req, httplib::Response& res) { + setCorsHeader(res); + res.status = 0; + res.content_length_ = 0; + try { + e.handler(req, res); + } + catch (std::exception& err) { + spdlog::error("Exception in http handler: {}", err.what()); + res.status = res.status == 0 ? 500 : res.status; + if (res.content_length_ == 0) { + res.set_content(nlohmann::json{ + {"code", res.status}, + {"name", "HandlerError"}, + {"message", err.what()}, + } + .dump(), + "text/json"); + } + } + catch (...) { + res.status = 500; + res.set_content(nlohmann::json{ + {"code", res.status}, + {"name", "Internal Server Error"}, + {"message", "Unknown Error"}, + } + .dump(), + "text/json"); + return; + } + }); + } server_.Post("/quit", [this, &setCorsHeader](const httplib::Request& req, httplib::Response& res) { setCorsHeader(res); close_(); }); - server_.Get("/settings", [this, &setCorsHeader](const httplib::Request& req, httplib::Response& res) { - setCorsHeader(res); - res.set_content(Settings::toJson().dump(), "text/json"); - }); - - server_.Get("/steam_settings", [this, &setCorsHeader](const httplib::Request& req, httplib::Response& res) { - setCorsHeader(res); - res.set_content(util::steam::getSteamConfig().dump(4), "text/json"); - }); - server_thread_ = std::thread([this]() { if (!server_.listen("0.0.0.0", port_)) { spdlog::error("Couldn't start http-server"); return; } spdlog::debug("Started http-server on port {}", static_cast(port_)); -}); + }); } void HttpServer::stop() diff --git a/GlosSITarget/HttpServer.h b/GlosSITarget/HttpServer.h index 1660ffa..52fdd77 100644 --- a/GlosSITarget/HttpServer.h +++ b/GlosSITarget/HttpServer.h @@ -23,16 +23,34 @@ class AppLauncher; class HttpServer { public: - explicit HttpServer(AppLauncher& app_launcher, std::function close); + explicit HttpServer(std::function close); + + enum Method { + GET, + POST, + PUT, + PATCH, + }; + + struct Endpoint { + std::string path; + Method method; + std::function handler; + }; + + static void AddEndpoint(const Endpoint&& e); void run(); void stop(); + private: httplib::Server server_; std::thread server_thread_; uint16_t port_ = 8756; - AppLauncher& app_launcher_; std::function close_; + + static inline std::vector endpoints_; + }; \ No newline at end of file diff --git a/GlosSITarget/SteamTarget.cpp b/GlosSITarget/SteamTarget.cpp index 56253f0..98b042c 100644 --- a/GlosSITarget/SteamTarget.cpp +++ b/GlosSITarget/SteamTarget.cpp @@ -28,6 +28,8 @@ limitations under the License. #include +#include "CommonHttpEndpoints.h" + SteamTarget::SteamTarget() : window_( [this] { run_ = false; }, @@ -43,7 +45,7 @@ SteamTarget::SteamTarget() delayed_shutdown_ = true; delay_shutdown_clock_.restart(); }), - server_(launcher_, [this] { run_ = false; }) + server_([this] { run_ = false; }) { target_window_handle_ = window_.getSystemHandle(); } @@ -62,6 +64,8 @@ int SteamTarget::run() auto steam_tweaks = CEFInject::SteamTweaks(); steam_tweaks.setAutoInject(true); + CHTE::addEndpoints(); + server_.run();