mirror of
https://github.com/BeamMP/BeamMP-Launcher.git
synced 2025-07-01 23:46:59 +00:00
Merge pull request #110 from WiserTixx/improve-http-proxy
HTTP proxy improvements, avatar endpoint
This commit is contained in:
commit
eae6d11476
@ -14,7 +14,7 @@ public:
|
||||
static std::string Post(const std::string& IP, const std::string& Fields);
|
||||
static std::string Get(const std::string& IP);
|
||||
static bool ProgressBar(size_t c, size_t t);
|
||||
|
||||
static void StartProxy();
|
||||
public:
|
||||
static bool isDownload;
|
||||
};
|
@ -14,8 +14,8 @@ void InitLauncher(int argc, char* argv[]);
|
||||
std::string GetEP(char* P = nullptr);
|
||||
std::string GetGamePath();
|
||||
std::string GetVer();
|
||||
std::string GetPatch();
|
||||
std::string GetEN();
|
||||
void StartProxy();
|
||||
void ConfigInit();
|
||||
extern bool Dev;
|
||||
|
||||
|
20
include/Utils.h
Normal file
20
include/Utils.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Utils {
|
||||
inline std::vector<std::string> Split(const std::string& String, const std::string& delimiter) {
|
||||
std::vector<std::string> Val;
|
||||
size_t pos;
|
||||
std::string token, s = String;
|
||||
while ((pos = s.find(delimiter)) != std::string::npos) {
|
||||
token = s.substr(0, pos);
|
||||
if (!token.empty())
|
||||
Val.push_back(token);
|
||||
s.erase(0, pos + delimiter.length());
|
||||
}
|
||||
if (!s.empty())
|
||||
Val.push_back(s);
|
||||
return Val;
|
||||
};
|
||||
};
|
@ -15,6 +15,9 @@
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <Startup.h>
|
||||
#include <Network/network.hpp>
|
||||
#include <Utils.h>
|
||||
|
||||
void WriteHttpDebug(const httplib::Client& client, const std::string& method, const std::string& target, const httplib::Result& result) try {
|
||||
const std::filesystem::path folder = ".https_debug";
|
||||
@ -171,3 +174,127 @@ bool HTTP::Download(const std::string& IP, const std::string& Path) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void set_headers(httplib::Response& res) {
|
||||
res.set_header("Access-Control-Allow-Origin", "*");
|
||||
res.set_header("Access-Control-Request-Method", "POST, OPTIONS, GET");
|
||||
res.set_header("Access-Control-Request-Headers", "X-API-Version");
|
||||
}
|
||||
|
||||
|
||||
void HTTP::StartProxy() {
|
||||
std::thread proxy([&]() {
|
||||
httplib::Server HTTPProxy;
|
||||
httplib::Headers headers = {
|
||||
{ "User-Agent", "BeamMP-Launcher/" + GetVer() + GetPatch() },
|
||||
{ "Accept", "*/*" }
|
||||
};
|
||||
httplib::Client backend("https://backend.beammp.com");
|
||||
httplib::Client forum("https://forum.beammp.com");
|
||||
|
||||
const std::string pattern = ".*";
|
||||
|
||||
auto handle_request = [&](const httplib::Request& req, httplib::Response& res) {
|
||||
set_headers(res);
|
||||
if (req.has_header("X-BMP-Authentication")) {
|
||||
headers.emplace("X-BMP-Authentication", PrivateKey);
|
||||
}
|
||||
if (req.has_header("X-API-Version")) {
|
||||
headers.emplace("X-API-Version", req.get_header_value("X-API-Version"));
|
||||
}
|
||||
|
||||
const std::vector<std::string> path = Utils::Split(req.path, "/");
|
||||
|
||||
httplib::Result cli_res;
|
||||
const std::string method = req.method;
|
||||
std::string host = "";
|
||||
|
||||
if (!path.empty())
|
||||
host = path[0];
|
||||
|
||||
if (host == "backend") {
|
||||
std::string remaining_path = req.path.substr(std::strlen("/backend"));
|
||||
|
||||
if (method == "GET")
|
||||
cli_res = backend.Get(remaining_path, headers);
|
||||
else if (method == "POST")
|
||||
cli_res = backend.Post(remaining_path, headers);
|
||||
|
||||
} else if (host == "avatar") {
|
||||
bool error = false;
|
||||
std::string username;
|
||||
std::string avatar_size = "100";
|
||||
|
||||
if (path.size() > 1) {
|
||||
username = path[1];
|
||||
} else {
|
||||
error = true;
|
||||
}
|
||||
|
||||
if (path.size() > 2) {
|
||||
try {
|
||||
if (std::stoi(path[2]) > 0)
|
||||
avatar_size = path[2];
|
||||
|
||||
} catch (std::exception&) {}
|
||||
}
|
||||
|
||||
httplib::Result summary_res;
|
||||
|
||||
if (!error) {
|
||||
summary_res = forum.Get("/u/" + username + ".json", headers);
|
||||
|
||||
if (!summary_res || summary_res->status != 200) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
try {
|
||||
nlohmann::json d = nlohmann::json::parse(summary_res->body, nullptr, false); // can fail with parse_error
|
||||
|
||||
auto user = d.at("user"); // can fail with out_of_range
|
||||
auto avatar_link_json = user.at("avatar_template"); // can fail with out_of_range
|
||||
|
||||
auto avatar_link = avatar_link_json.get<std::string>();
|
||||
size_t start_pos = avatar_link.find("{size}");
|
||||
if (start_pos != std::string::npos)
|
||||
avatar_link.replace(start_pos, std::strlen("{size}"), avatar_size);
|
||||
|
||||
cli_res = forum.Get(avatar_link, headers);
|
||||
|
||||
} catch (std::exception&) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (error) {
|
||||
cli_res = forum.Get("/user_avatar/forum.beammp.com/user/0/0.png", headers);
|
||||
}
|
||||
|
||||
} else {
|
||||
res.set_content("Host not found", "text/plain");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cli_res) {
|
||||
res.set_content(cli_res->body, cli_res->get_header_value("Content-Type"));
|
||||
} else {
|
||||
res.set_content(to_string(cli_res.error()), "text/plain");
|
||||
}
|
||||
};
|
||||
|
||||
HTTPProxy.Get(pattern, [&](const httplib::Request& req, httplib::Response& res) {
|
||||
handle_request(req, res);
|
||||
});
|
||||
|
||||
HTTPProxy.Post(pattern, [&](const httplib::Request& req, httplib::Response& res) {
|
||||
handle_request(req, res);
|
||||
});
|
||||
|
||||
ProxyPort = HTTPProxy.bind_to_any_port("0.0.0.0");
|
||||
debug("HTTP Proxy listening on port " + std::to_string(ProxyPort));
|
||||
HTTPProxy.listen_after_bind();
|
||||
});
|
||||
proxy.detach();
|
||||
}
|
||||
|
@ -28,26 +28,11 @@
|
||||
#include <fstream>
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <Utils.h>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
std::string ListOfMods;
|
||||
std::vector<std::string> Split(const std::string& String, const std::string& delimiter) {
|
||||
std::vector<std::string> Val;
|
||||
size_t pos;
|
||||
std::string token, s = String;
|
||||
while ((pos = s.find(delimiter)) != std::string::npos) {
|
||||
token = s.substr(0, pos);
|
||||
if (!token.empty())
|
||||
Val.push_back(token);
|
||||
s.erase(0, pos + delimiter.length());
|
||||
}
|
||||
if (!s.empty())
|
||||
Val.push_back(s);
|
||||
return Val;
|
||||
}
|
||||
|
||||
void CheckForDir() {
|
||||
if (!fs::exists("Resources")) {
|
||||
@ -247,7 +232,7 @@ void SyncResources(SOCKET Sock) {
|
||||
info("Checking Resources...");
|
||||
CheckForDir();
|
||||
|
||||
std::vector<std::string> list = Split(Ret, ";");
|
||||
std::vector<std::string> list = Utils::Split(Ret, ";");
|
||||
std::vector<std::string> FNames(list.begin(), list.begin() + (list.size() / 2));
|
||||
std::vector<std::string> FSizes(list.begin() + (list.size() / 2), list.end());
|
||||
list.clear();
|
||||
|
@ -357,59 +357,3 @@ void PreGame(const std::string& GamePath) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_headers(httplib::Response& res) {
|
||||
res.set_header("Access-Control-Allow-Origin", "*");
|
||||
res.set_header("Access-Control-Request-Method", "POST, OPTIONS, GET");
|
||||
res.set_header("Access-Control-Request-Headers", "X-API-Version");
|
||||
}
|
||||
|
||||
void StartProxy() {
|
||||
std::thread proxy([&]() {
|
||||
httplib::Server HTTPProxy;
|
||||
httplib::Headers headers = {
|
||||
{ "User-Agent", "BeamMP-Launcher/" + GetVer() + GetPatch() },
|
||||
{ "Accept", "*/*" }
|
||||
};
|
||||
std::string pattern = "/:any1";
|
||||
for (int i = 2; i <= 4; i++) {
|
||||
HTTPProxy.Get(pattern, [&](const httplib::Request& req, httplib::Response& res) {
|
||||
httplib::Client cli("https://backend.beammp.com");
|
||||
set_headers(res);
|
||||
if (req.has_header("X-BMP-Authentication")) {
|
||||
headers.emplace("X-BMP-Authentication", PrivateKey);
|
||||
}
|
||||
if (req.has_header("X-API-Version")) {
|
||||
headers.emplace("X-API-Version", req.get_header_value("X-API-Version"));
|
||||
}
|
||||
if (auto cli_res = cli.Get(req.path, headers); cli_res) {
|
||||
res.set_content(cli_res->body, cli_res->get_header_value("Content-Type"));
|
||||
} else {
|
||||
res.set_content(to_string(cli_res.error()), "text/plain");
|
||||
}
|
||||
});
|
||||
|
||||
HTTPProxy.Post(pattern, [&](const httplib::Request& req, httplib::Response& res) {
|
||||
httplib::Client cli("https://backend.beammp.com");
|
||||
set_headers(res);
|
||||
if (req.has_header("X-BMP-Authentication")) {
|
||||
headers.emplace("X-BMP-Authentication", PrivateKey);
|
||||
}
|
||||
if (req.has_header("X-API-Version")) {
|
||||
headers.emplace("X-API-Version", req.get_header_value("X-API-Version"));
|
||||
}
|
||||
if (auto cli_res = cli.Post(req.path, headers, req.body,
|
||||
req.get_header_value("Content-Type"));
|
||||
cli_res) {
|
||||
res.set_content(cli_res->body, cli_res->get_header_value("Content-Type"));
|
||||
} else {
|
||||
res.set_content(to_string(cli_res.error()), "text/plain");
|
||||
}
|
||||
});
|
||||
pattern += "/:any" + std::to_string(i);
|
||||
}
|
||||
ProxyPort = HTTPProxy.bind_to_any_port("0.0.0.0");
|
||||
HTTPProxy.listen_after_bind();
|
||||
});
|
||||
proxy.detach();
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ int main(int argc, char* argv[]) {
|
||||
fatal("Main 1 : " + std::string(e.what()));
|
||||
}
|
||||
|
||||
StartProxy();
|
||||
HTTP::StartProxy();
|
||||
PreGame(GetGameDir());
|
||||
InitGame(GetGameDir());
|
||||
CoreNetwork();
|
||||
|
Loading…
x
Reference in New Issue
Block a user