HTTP proxy improvements

Adds the avatar endpoint and adds the possibility to easily add others
This commit is contained in:
Tixx 2024-08-22 10:28:53 +02:00
parent 7481ba4539
commit 4678701f42

View File

@ -364,6 +364,19 @@ void set_headers(httplib::Response& res) {
res.set_header("Access-Control-Request-Headers", "X-API-Version"); res.set_header("Access-Control-Request-Headers", "X-API-Version");
} }
std::vector<std::string> split_string(const std::string& s, const char delim) {
std::stringstream ss(s);
std::string item;
std::vector<std::string> elems;
while (std::getline(ss, item, delim)) {
if (!item.empty()) {
elems.push_back(item);
}
}
return elems;
}
void StartProxy() { void StartProxy() {
std::thread proxy([&]() { std::thread proxy([&]() {
httplib::Server HTTPProxy; httplib::Server HTTPProxy;
@ -371,44 +384,91 @@ void StartProxy() {
{ "User-Agent", "BeamMP-Launcher/" + GetVer() + GetPatch() }, { "User-Agent", "BeamMP-Launcher/" + GetVer() + GetPatch() },
{ "Accept", "*/*" } { "Accept", "*/*" }
}; };
std::string pattern = "/:any1"; httplib::Client backend("https://backend.beammp.com");
for (int i = 2; i <= 4; i++) { httplib::Client forum("https://forum.beammp.com");
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) { const std::string pattern = ".*";
httplib::Client cli("https://backend.beammp.com");
set_headers(res); auto handle_request = [&](const httplib::Request& req, httplib::Response& res) {
if (req.has_header("X-BMP-Authentication")) { set_headers(res);
headers.emplace("X-BMP-Authentication", PrivateKey); 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 = split_string(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") {
std::string username;
std::string avatar_size = "100";
if (1 < path.size())
username = path[1];
if (path.size() > 2) {
try {
if (std::stoi(path[2]) > 0)
avatar_size = path[2];
} catch (std::exception&) {}
} }
if (req.has_header("X-API-Version")) {
headers.emplace("X-API-Version", req.get_header_value("X-API-Version")); auto summary_res = forum.Get("/u/" + username + ".json", headers);
} nlohmann::json d = nlohmann::json::parse(summary_res->body, nullptr, false);
if (auto cli_res = cli.Post(req.path, headers, req.body,
req.get_header_value("Content-Type")); if (d.contains("user")) {
cli_res) { auto user = d.at("user");
res.set_content(cli_res->body, cli_res->get_header_value("Content-Type")); auto avatar_link_json = user.at("avatar_template");
} else {
res.set_content(to_string(cli_res.error()), "text/plain"); if (avatar_link_json.is_string()) {
} auto avatar_link = avatar_link_json.get<std::string>();
}); size_t start_pos = avatar_link.find("{size}");
pattern += "/:any" + std::to_string(i); if (start_pos != std::string::npos)
} avatar_link.replace(start_pos, std::strlen("{size}"), avatar_size);
cli_res = forum.Get(avatar_link, headers);
}
} else
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"); ProxyPort = HTTPProxy.bind_to_any_port("0.0.0.0");
debug("HTTP Proxy listening on port " + std::to_string(ProxyPort));
HTTPProxy.listen_after_bind(); HTTPProxy.listen_after_bind();
}); });
proxy.detach(); proxy.detach();