From d394d7b5a6128a48271f1684f8cdd799f5d53c3e Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 13 Jan 2021 22:39:45 +0100 Subject: [PATCH] use boost beast instead of curl --- CMakeLists.txt | 2 +- include/Curl/Http.h | 4 +- src/Init/Heartbeat.cpp | 10 ++- src/Network/Auth.cpp | 3 +- src/Network/Http.cpp | 149 +++++++++++++++++++++++++---------------- 5 files changed, 99 insertions(+), 69 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3452086..70ecc49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ endif () file(GLOB source_files "src/*.cpp" "include/*.h" "include/*/*.h" "include/*/*/*.h" "include/*.hpp" "include/*/*.hpp" "src/*/*.cpp") add_executable(BeamMP-Server ${source_files}) -target_include_directories(BeamMP-Server PUBLIC $) +target_include_directories(BeamMP-Server PUBLIC $ cpp-httplib) find_package(Lua REQUIRED) target_include_directories(BeamMP-Server PUBLIC ${LUA_INCLUDE_DIR}) diff --git a/include/Curl/Http.h b/include/Curl/Http.h index b11a88a..46744b7 100644 --- a/include/Curl/Http.h +++ b/include/Curl/Http.h @@ -7,5 +7,5 @@ /// #pragma once #include -std::string HttpRequest(const std::string& IP, int port); -std::string PostHTTP(const std::string& IP, const std::string& Fields, bool json); \ No newline at end of file +std::string HttpRequest(const std::string& host, int port, const std::string& target); +std::string PostHTTP(const std::string& host, int port, const std::string& target, const std::string& Fields, bool json); diff --git a/src/Init/Heartbeat.cpp b/src/Init/Heartbeat.cpp index 99cd88c..0adde69 100644 --- a/src/Init/Heartbeat.cpp +++ b/src/Init/Heartbeat.cpp @@ -36,8 +36,8 @@ std::string GenerateCall() { << "&desc=" << ServerDesc; return Ret.str(); } -std::string RunPromise(const std::string& IP, const std::string& R) { - std::packaged_task task([&] { return PostHTTP(IP, R, false); }); +std::string RunPromise(const std::string& host, const std::string& target, const std::string& R) { + std::packaged_task task([&] { return PostHTTP(host, 443, target, R, false); }); std::future f1 = task.get_future(); std::thread t(std::move(task)); t.detach(); @@ -56,14 +56,12 @@ std::string RunPromise(const std::string& IP, const std::string& R) { R = GenerateCall(); if (!CustomIP.empty()) R += "&ip=" + CustomIP; - std::string link = "https://beammp.com/heartbeatv2"; - T = RunPromise(link, R); + T = RunPromise("https://beammp.com", "/heartbeatv2", R); if (T.substr(0, 2) != "20") { //Backend system refused server startup! std::this_thread::sleep_for(std::chrono::seconds(10)); - std::string Backup = "https://backup1.beammp.com/heartbeatv2"; - T = RunPromise(Backup, R); + T = RunPromise("https://backup1.beammp.com", "/heartbeatv2", R); if (T.substr(0, 2) != "20") { warn("Backend system refused server! Server might not show in the public list"); } diff --git a/src/Network/Auth.cpp b/src/Network/Auth.cpp index e1f436c..bab6ac7 100644 --- a/src/Network/Auth.cpp +++ b/src/Network/Auth.cpp @@ -20,8 +20,7 @@ std::string GetClientInfo(const std::string& PK) { if (!PK.empty()) { - return PostHTTP("https://auth.beammp.com/pkToUser", R"({"key":")" + PK + "\"}", true); - ; + return PostHTTP("https://auth.beammp.com", 443, "/pkToUser", R"({"key":")" + PK + "\"}", true); } return ""; } diff --git a/src/Network/Http.cpp b/src/Network/Http.cpp index 748d66c..0296346 100644 --- a/src/Network/Http.cpp +++ b/src/Network/Http.cpp @@ -7,71 +7,104 @@ /// #include "CustomAssert.h" -#include #include -class CurlManager { -public: - CurlManager() { - curl = curl_easy_init(); - } - ~CurlManager() { - curl_easy_cleanup(curl); - } - inline CURL* Get() { - return curl; - } +#include +#include +#include +#include +#include +#include +#include +#include +#include -private: - CURL* curl; -}; +namespace beast = boost::beast; // from +namespace http = beast::http; // from +namespace net = boost::asio; // from +using tcp = net::ip::tcp; // from -static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) { - std::string((char*)userp).append((char*)contents, size * nmemb); - return size * nmemb; +// UNUSED?! +std::string HttpRequest(const std::string& host, int port, const std::string& target) { + try { + net::io_context io; + tcp::resolver resolver(io); + beast::tcp_stream stream(io); + auto const results = resolver.resolve(host, std::to_string(port)); + stream.connect(results); + + http::request req { http::verb::get, target, 11 /* http 1.1 */ }; + + req.set(http::field::host, host); + // tell the server what we are (boost beast) + req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); + + http::write(stream, req); + + // used for reading + beast::flat_buffer buffer; + http::response response; + + http::read(stream, buffer, response); + + std::string result(response.body()); + + beast::error_code ec; + stream.socket().shutdown(tcp::socket::shutdown_both, ec); + if (ec && ec != beast::errc::not_connected) { + throw beast::system_error { ec }; // goes down to `return "-1"` anyways + } + + return result; + + } catch (const std::exception& e) { + error(e.what()); + return "-1"; + } } -std::string HttpRequest(const std::string& IP, int port) { - CurlManager M; - std::string readBuffer; - CURL* curl = M.Get(); - CURLcode res; - Assert(curl); - if (curl) { - curl_easy_setopt(curl, CURLOPT_URL, IP.c_str()); - curl_easy_setopt(curl, CURLOPT_PORT, port); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); - res = curl_easy_perform(curl); - if (res != CURLE_OK) - return "-1"; - } - return readBuffer; -} +std::string PostHTTP(const std::string& host, int port, const std::string& target, const std::string& Fields, bool json) { + try { + net::io_context io; + tcp::resolver resolver(io); + beast::tcp_stream stream(io); + auto const results = resolver.resolve(host, std::to_string(port)); + stream.connect(results); -std::string PostHTTP(const std::string& IP, const std::string& Fields, bool json) { - auto header = curl_slist { (char*)"Content-Type: application/json", nullptr }; - static std::mutex Lock; - std::scoped_lock Guard(Lock); - CurlManager M; - CURL* curl = M.Get(); - CURLcode res; - char readBuffer[5000]; + http::request req { http::verb::post, target, 11 /* http 1.1 */ }; - Assert(curl); - if (curl) { - curl_easy_setopt(curl, CURLOPT_URL, IP.c_str()); - if (json) - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header); - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, Fields.size()); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, Fields.c_str()); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); - curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5); - res = curl_easy_perform(curl); - if (res != CURLE_OK) - return "-1"; + req.set(http::field::host, host); + if (json) { + req.set(http::field::content_type, "application/json"); + } + req.set(http::field::content_length, boost::lexical_cast(Fields.size())); + req.set(http::field::body, Fields.c_str()); + // tell the server what we are (boost beast) + req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); + req.prepare_payload(); + + stream.expires_after(std::chrono::seconds(5)); + + http::write(stream, req); + + // used for reading + beast::flat_buffer buffer; + http::response response; + + http::read(stream, buffer, response); + + std::string result(response.body()); + + beast::error_code ec; + stream.socket().shutdown(tcp::socket::shutdown_both, ec); + if (ec && ec != beast::errc::not_connected) { + throw beast::system_error { ec }; // goes down to `return "-1"` anyways + } + + return result; + + } catch (const std::exception& e) { + error(e.what()); + return "-1"; } - return readBuffer; }