[Deps] Update Mongoose (#540)
This commit is contained in:
parent
c946e26467
commit
41e7d1c37f
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -17,7 +17,7 @@
|
||||
[submodule "deps/mongoose"]
|
||||
path = deps/mongoose
|
||||
url = https://github.com/cesanta/mongoose.git
|
||||
branch = dev
|
||||
branch = master
|
||||
[submodule "deps/protobuf"]
|
||||
path = deps/protobuf
|
||||
url = https://github.com/google/protobuf.git
|
||||
|
2
deps/mongoose
vendored
2
deps/mongoose
vendored
@ -1 +1 @@
|
||||
Subproject commit cb602f178ccea7f0c790cf5510f7a29c017db954
|
||||
Subproject commit c25234df83f612270c5ef81b1ca8e9151515925a
|
@ -1,9 +1,12 @@
|
||||
#include <STDInclude.hpp>
|
||||
#include "GSC/Script.hpp"
|
||||
|
||||
#include <mongoose.h>
|
||||
|
||||
namespace Components
|
||||
{
|
||||
mg_mgr Download::Mgr;
|
||||
static mg_mgr Mgr;
|
||||
|
||||
Download::ClientDownload Download::CLDownload;
|
||||
|
||||
std::thread Download::ServerThread;
|
||||
@ -111,41 +114,6 @@ namespace Components
|
||||
return true;
|
||||
}
|
||||
|
||||
void Download::DownloadHandler(mg_connection *nc, int ev, void* ev_data)
|
||||
{
|
||||
http_message* hm = reinterpret_cast<http_message*>(ev_data);
|
||||
Download::FileDownload* fDownload = reinterpret_cast<Download::FileDownload*>(nc->mgr->user_data);
|
||||
|
||||
if (ev == MG_EV_CONNECT)
|
||||
{
|
||||
if (hm->message.p)
|
||||
{
|
||||
fDownload->downloading = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ev == MG_EV_CLOSE)
|
||||
{
|
||||
fDownload->downloading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev == MG_EV_RECV)
|
||||
{
|
||||
size_t bytes = static_cast<size_t>(*reinterpret_cast<int*>(ev_data));
|
||||
Download::DownloadProgress(fDownload, bytes);
|
||||
}
|
||||
|
||||
if (ev == MG_EV_HTTP_REPLY)
|
||||
{
|
||||
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
fDownload->buffer = std::string(hm->body.p, hm->body.len);
|
||||
fDownload->downloading = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool Download::DownloadFile(ClientDownload* download, unsigned int index)
|
||||
{
|
||||
if (!download || download->files.size() <= index) return false;
|
||||
@ -227,21 +195,7 @@ namespace Components
|
||||
|
||||
Utils::String::Replace(url, " ", "%20");
|
||||
|
||||
// Just a speedtest ;)
|
||||
//download->totalBytes = 1048576000;
|
||||
//url = "http://speed.hetzner.de/1GB.bin";
|
||||
|
||||
download->valid = true;
|
||||
/*ZeroMemory(&download->mgr, sizeof download->mgr);
|
||||
mg_mgr_init(&download->mgr, &fDownload);
|
||||
mg_connect_http(&download->mgr, Download::DownloadHandler, url.data(), nullptr, nullptr);
|
||||
|
||||
while (fDownload.downloading && !fDownload.download->terminateThread)
|
||||
{
|
||||
mg_mgr_poll(&download->mgr, 100);
|
||||
}
|
||||
|
||||
mg_mgr_free(&download->mgr);*/
|
||||
|
||||
fDownload.downloading = true;
|
||||
|
||||
@ -386,33 +340,8 @@ namespace Components
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Server
|
||||
|
||||
bool Download::IsClient(mg_connection *nc)
|
||||
{
|
||||
return (Download::GetClient(nc) != nullptr);
|
||||
}
|
||||
|
||||
Game::client_t* Download::GetClient(mg_connection *nc)
|
||||
{
|
||||
Network::Address address(nc->sa.sa);
|
||||
|
||||
for (int i = 0; i < *Game::svs_clientCount; ++i)
|
||||
{
|
||||
Game::client_t* client = &Game::svs_clients[i];
|
||||
|
||||
if (client->header.state >= Game::CS_CONNECTED)
|
||||
{
|
||||
if (address.getIP().full == Network::Address(client->header.netchan.remoteAddress).getIP().full)
|
||||
{
|
||||
return client;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Download::DownloadProgress(FileDownload* fDownload, size_t bytes)
|
||||
|
||||
void Download::DownloadProgress(FileDownload* fDownload, std::size_t bytes)
|
||||
{
|
||||
fDownload->receivedBytes += bytes;
|
||||
fDownload->download->downBytes += bytes;
|
||||
@ -475,287 +404,21 @@ namespace Components
|
||||
}
|
||||
}
|
||||
|
||||
bool Download::VerifyPassword(mg_connection *nc, http_message* message)
|
||||
static std::string InfoHandler()
|
||||
{
|
||||
std::string g_password = Dvar::Var("g_password").get<std::string>();
|
||||
if (g_password.empty()) return true;
|
||||
|
||||
// sha256 hashes are 64 chars long but we're gonna be safe here
|
||||
char buffer[128] = { 0 };
|
||||
int passLen = mg_get_http_var(&message->query_string, "password", buffer, sizeof buffer);
|
||||
|
||||
if (passLen <= 0 || std::string(buffer, passLen) != Utils::Cryptography::SHA256::Compute(g_password, true))
|
||||
{
|
||||
mg_printf(nc, ("HTTP/1.1 403 Forbidden\r\n"s +
|
||||
"Content-Type: text/html\r\n"s +
|
||||
"Connection: close\r\n"s +
|
||||
"\r\n"s +
|
||||
((passLen == 0) ? "Password Required"s : "Invalid Password"s)).c_str());
|
||||
|
||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Download::Forbid(mg_connection *nc)
|
||||
{
|
||||
mg_printf(nc, "HTTP/1.1 403 Forbidden\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n"
|
||||
"403 - Forbidden");
|
||||
|
||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||
}
|
||||
|
||||
void Download::ServerlistHandler(mg_connection* nc, int ev, void* /*ev_data*/)
|
||||
{
|
||||
// Only handle http requests
|
||||
if (ev != MG_EV_HTTP_REQUEST) return;
|
||||
|
||||
std::vector<nlohmann::json> servers;
|
||||
|
||||
// Build server list
|
||||
for (auto& node : Node::GetNodes())
|
||||
{
|
||||
if (node.isValid())
|
||||
{
|
||||
servers.push_back(nlohmann::json{ node.to_json()});
|
||||
}
|
||||
}
|
||||
|
||||
mg_printf(nc,
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/json\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Access-Control-Allow-Origin: *\r\n"
|
||||
"\r\n"
|
||||
"%s", nlohmann::json(servers).dump().data());
|
||||
|
||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||
}
|
||||
|
||||
void Download::MapHandler(mg_connection *nc, int ev, void* ev_data)
|
||||
{
|
||||
// Only handle http requests
|
||||
if (ev != MG_EV_HTTP_REQUEST) return;
|
||||
|
||||
if (!Download::VerifyPassword(nc, reinterpret_cast<http_message*>(ev_data))) return;
|
||||
|
||||
static std::string mapnamePre;
|
||||
static nlohmann::json jsonList;
|
||||
|
||||
std::string mapname = (Party::IsInUserMapLobby() ? Dvar::Var("ui_mapname").get<std::string>() : Maps::GetUserMap()->getName());
|
||||
if (!Maps::GetUserMap()->isValid() && !Party::IsInUserMapLobby())
|
||||
{
|
||||
mapnamePre.clear();
|
||||
jsonList = std::vector<nlohmann::json>();
|
||||
}
|
||||
else if (!mapname.empty() && mapname != mapnamePre)
|
||||
{
|
||||
std::vector<nlohmann::json> fileList;
|
||||
|
||||
mapnamePre = mapname;
|
||||
|
||||
std::string path = Dvar::Var("fs_basepath").get<std::string>() + "\\usermaps\\" + mapname;
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(Maps::UserMapFiles); ++i)
|
||||
{
|
||||
std::string filename = path + "\\" + mapname + Maps::UserMapFiles[i];
|
||||
if (Utils::IO::FileExists(filename))
|
||||
{
|
||||
std::map<std::string, nlohmann::json> file;
|
||||
std::string fileBuffer = Utils::IO::ReadFile(filename);
|
||||
|
||||
file["name"] = mapname + Maps::UserMapFiles[i];
|
||||
file["size"] = static_cast<int>(fileBuffer.size());
|
||||
file["hash"] = Utils::Cryptography::SHA256::Compute(fileBuffer, true);
|
||||
|
||||
fileList.push_back(file);
|
||||
}
|
||||
}
|
||||
|
||||
jsonList = fileList;
|
||||
}
|
||||
|
||||
mg_printf(nc,
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/json\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n"
|
||||
"%s", jsonList.dump().data());
|
||||
|
||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||
}
|
||||
|
||||
void Download::ListHandler(mg_connection* nc, int ev, void* ev_data)
|
||||
{
|
||||
// Only handle http requests
|
||||
if (ev != MG_EV_HTTP_REQUEST) return;
|
||||
|
||||
if (!Download::VerifyPassword(nc, reinterpret_cast<http_message*>(ev_data))) return;
|
||||
|
||||
// if (!Download::IsClient(nc))
|
||||
// {
|
||||
// Download::Forbid(nc);
|
||||
// }
|
||||
// else
|
||||
{
|
||||
static std::string fsGamePre;
|
||||
static nlohmann::json jsonList;
|
||||
|
||||
const std::string fsGame = (*Game::fs_gameDirVar)->current.string;
|
||||
|
||||
if (!fsGame.empty() && fsGame != fsGamePre)
|
||||
{
|
||||
std::vector<nlohmann::json> fileList;
|
||||
|
||||
fsGamePre = fsGame;
|
||||
|
||||
std::string path = Dvar::Var("fs_basepath").get<std::string>() + "\\" + fsGame;
|
||||
auto list = FileSystem::GetSysFileList(path, "iwd", false);
|
||||
|
||||
list.push_back("mod.ff");
|
||||
|
||||
for (auto i = list.begin(); i != list.end(); ++i)
|
||||
{
|
||||
std::string filename = path + "\\" + *i;
|
||||
if (strstr(i->data(), "_svr_") == nullptr && Utils::IO::FileExists(filename))
|
||||
{
|
||||
std::map<std::string, nlohmann::json> file;
|
||||
std::string fileBuffer = Utils::IO::ReadFile(filename);
|
||||
|
||||
file["name"] = *i;
|
||||
file["size"] = static_cast<int>(fileBuffer.size());
|
||||
file["hash"] = Utils::Cryptography::SHA256::Compute(fileBuffer, true);
|
||||
|
||||
fileList.push_back(file);
|
||||
}
|
||||
}
|
||||
|
||||
jsonList = fileList;
|
||||
}
|
||||
|
||||
mg_printf(nc,
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/json\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n"
|
||||
"%s", jsonList.dump().data());
|
||||
|
||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||
}
|
||||
}
|
||||
|
||||
void Download::FileHandler(mg_connection *nc, int ev, void *ev_data)
|
||||
{
|
||||
// Only handle http requests
|
||||
if (ev != MG_EV_HTTP_REQUEST) return;
|
||||
|
||||
http_message* message = reinterpret_cast<http_message*>(ev_data);
|
||||
|
||||
//if (!Download::VerifyPassword(nc, message)) return;
|
||||
|
||||
// if (!Download::IsClient(nc))
|
||||
// {
|
||||
// Download::Forbid(nc);
|
||||
// }
|
||||
// else
|
||||
{
|
||||
std::string url(message->uri.p, message->uri.len);
|
||||
Utils::String::Replace(url, "\\", "/");
|
||||
|
||||
if (url.size() >= 6)
|
||||
{
|
||||
url = url.substr(6);
|
||||
}
|
||||
|
||||
Utils::String::Replace(url, "%20", " ");
|
||||
|
||||
bool isMap = false;
|
||||
if (Utils::String::StartsWith(url, "map/"))
|
||||
{
|
||||
isMap = true;
|
||||
url = url.substr(4);
|
||||
|
||||
std::string mapname = (Party::IsInUserMapLobby() ? Dvar::Var("ui_mapname").get<std::string>() : Maps::GetUserMap()->getName());
|
||||
|
||||
bool isValidFile = false;
|
||||
for (int i = 0; i < ARRAYSIZE(Maps::UserMapFiles); ++i)
|
||||
{
|
||||
if (url == (mapname + Maps::UserMapFiles[i]))
|
||||
{
|
||||
isValidFile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!Maps::GetUserMap()->isValid() && !Party::IsInUserMapLobby()) || !isValidFile)
|
||||
{
|
||||
Download::Forbid(nc);
|
||||
return;
|
||||
}
|
||||
|
||||
url = Utils::String::VA("usermaps\\%s\\%s", mapname.data(), url.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (url.find_first_of("/") != std::string::npos || (!Utils::String::EndsWith(url, ".iwd") && url != "mod.ff") || strstr(url.data(), "_svr_") != nullptr)
|
||||
{
|
||||
Download::Forbid(nc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string file;
|
||||
const std::string fsGame = (*Game::fs_gameDirVar)->current.string;
|
||||
std::string path = Dvar::Var("fs_basepath").get<std::string>() + "\\" + (isMap ? "" : fsGame + "\\") + url;
|
||||
|
||||
if ((!isMap && fsGame.empty()) || !Utils::IO::ReadFile(path, &file))
|
||||
{
|
||||
mg_printf(nc,
|
||||
"HTTP/1.1 404 Not Found\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n"
|
||||
"404 - Not Found %s", path.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
mg_printf(nc,
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/octet-stream\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n", file.size());
|
||||
|
||||
mg_send(nc, file.data(), static_cast<int>(file.size()));
|
||||
}
|
||||
|
||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||
}
|
||||
}
|
||||
|
||||
void Download::InfoHandler(mg_connection* nc, int ev, void* /*ev_data*/)
|
||||
{
|
||||
// Only handle http requests
|
||||
if (ev != MG_EV_HTTP_REQUEST) return;
|
||||
|
||||
const auto status = ServerInfo::GetInfo();
|
||||
const auto host = ServerInfo::GetHostInfo();
|
||||
|
||||
std::map<std::string, nlohmann::json> info;
|
||||
std::unordered_map<std::string, nlohmann::json> info;
|
||||
info["status"] = status.to_json();
|
||||
info["host"] = host.to_json();
|
||||
|
||||
std::vector<nlohmann::json> players;
|
||||
|
||||
// Build player list
|
||||
for (int i = 0; i < atoi(status.get("sv_maxclients").data()); ++i) // Maybe choose 18 here?
|
||||
for (auto i = 0; i < Game::MAX_CLIENTS; ++i)
|
||||
{
|
||||
std::map<std::string, nlohmann::json> playerInfo;
|
||||
std::unordered_map<std::string, nlohmann::json> playerInfo;
|
||||
playerInfo["score"] = 0;
|
||||
playerInfo["ping"] = 0;
|
||||
playerInfo["name"] = "";
|
||||
@ -771,133 +434,254 @@ namespace Components
|
||||
else
|
||||
{
|
||||
// Score and ping are irrelevant
|
||||
const char* namePtr = Game::PartyHost_GetMemberName(Game::g_lobbyData, i);
|
||||
if (!namePtr || !namePtr[0]) continue;
|
||||
const auto* name = Game::PartyHost_GetMemberName(Game::g_lobbyData, i);
|
||||
if (!name || *name == '\0') continue;
|
||||
|
||||
playerInfo["name"] = namePtr;
|
||||
playerInfo["name"] = name;
|
||||
}
|
||||
|
||||
players.emplace_back(playerInfo);
|
||||
}
|
||||
|
||||
info["players"] = players;
|
||||
|
||||
mg_printf(nc,
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/json\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Access-Control-Allow-Origin: *\r\n"
|
||||
"\r\n"
|
||||
"%s", nlohmann::json(info).dump().data());
|
||||
|
||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||
return {nlohmann::json(info).dump()};
|
||||
}
|
||||
|
||||
void Download::EventHandler(mg_connection *nc, int ev, void *ev_data)
|
||||
static std::string ListHandler()
|
||||
{
|
||||
// Only handle http requests
|
||||
if (ev != MG_EV_HTTP_REQUEST) return;
|
||||
static nlohmann::json jsonList;
|
||||
static auto handled = false;
|
||||
|
||||
http_message* message = reinterpret_cast<http_message*>(ev_data);
|
||||
const std::string fs_gameDirVar = (*Game::fs_gameDirVar)->current.string;
|
||||
|
||||
// if (message->uri.p, message->uri.len == "/"s)
|
||||
// {
|
||||
// mg_printf(nc,
|
||||
// "HTTP/1.1 200 OK\r\n"
|
||||
// "Content-Type: text/html\r\n"
|
||||
// "Connection: close\r\n"
|
||||
// "\r\n"
|
||||
// "Hi fella!<br>You are%s connected to this server!", (Download::IsClient(nc) ? " " : " not"));
|
||||
//
|
||||
// Game::client_t* client = Download::GetClient(nc);
|
||||
//
|
||||
// if (client)
|
||||
// {
|
||||
// mg_printf(nc, "<br>Hello %s!", client->name);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
if (!fs_gameDirVar.empty() && !handled)
|
||||
{
|
||||
//std::string path = (Dvar::Var("fs_basepath").get<std::string>() + "\\" BASEGAME "\\html");
|
||||
//mg_serve_http_opts opts = { 0 };
|
||||
//opts.document_root = path.data();
|
||||
//mg_serve_http(nc, message, opts);
|
||||
handled = true;
|
||||
|
||||
FileSystem::File file;
|
||||
std::string url = "html" + std::string(message->uri.p, message->uri.len);
|
||||
std::vector<nlohmann::json> fileList;
|
||||
|
||||
if (Utils::String::EndsWith(url, "/"))
|
||||
const auto path = Dvar::Var("fs_basepath").get<std::string>() + "\\" + fs_gameDirVar;
|
||||
auto list = FileSystem::GetSysFileList(path, "iwd", false);
|
||||
list.emplace_back("mod.ff");
|
||||
|
||||
for (const auto& file : list)
|
||||
{
|
||||
url.append("index.html");
|
||||
file = FileSystem::File(url);
|
||||
}
|
||||
else
|
||||
{
|
||||
file = FileSystem::File(url);
|
||||
|
||||
if (!file.exists())
|
||||
std::string filename = path + "\\" + file;
|
||||
if (file.find("_svr_") == std::string::npos)
|
||||
{
|
||||
url.append("/index.html");
|
||||
file = FileSystem::File(url);
|
||||
std::unordered_map<std::string, nlohmann::json> jsonFileList;
|
||||
std::string fileBuffer = Utils::IO::ReadFile(filename);
|
||||
if (fileBuffer.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
jsonFileList["name"] = file;
|
||||
jsonFileList["size"] = fileBuffer.size();
|
||||
jsonFileList["hash"] = Utils::Cryptography::SHA256::Compute(fileBuffer, true);
|
||||
|
||||
fileList.emplace_back(jsonFileList);
|
||||
}
|
||||
}
|
||||
|
||||
std::string mimeType = Utils::GetMimeType(url);
|
||||
jsonList = fileList;
|
||||
}
|
||||
|
||||
if (file.exists())
|
||||
return {jsonList.dump()};
|
||||
}
|
||||
|
||||
static std::string MapHandler()
|
||||
{
|
||||
static std::string mapNamePre;
|
||||
static nlohmann::json jsonList;
|
||||
|
||||
const auto mapName = (Party::IsInUserMapLobby() ? Dvar::Var("ui_mapname").get<std::string>() : Maps::GetUserMap()->getName());
|
||||
if (!Maps::GetUserMap()->isValid() && !Party::IsInUserMapLobby())
|
||||
{
|
||||
mapNamePre.clear();
|
||||
jsonList = {};
|
||||
}
|
||||
else if (!mapName.empty() && mapName != mapNamePre)
|
||||
{
|
||||
std::vector<nlohmann::json> fileList;
|
||||
|
||||
mapNamePre = mapName;
|
||||
|
||||
const auto path = Dvar::Var("fs_basepath").get<std::string>() + "\\usermaps\\" + mapName;
|
||||
|
||||
for (auto i = 0; i < ARRAYSIZE(Maps::UserMapFiles); ++i)
|
||||
{
|
||||
std::string buffer = file.getBuffer();
|
||||
const auto filename = path + "\\" + mapName + Maps::UserMapFiles[i];
|
||||
|
||||
std::map<std::string, nlohmann::json> file;
|
||||
std::string fileBuffer = Utils::IO::ReadFile(filename);
|
||||
if (fileBuffer.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mg_printf(nc,
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: %s\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n", mimeType.data(), buffer.size());
|
||||
file["name"] = mapName + Maps::UserMapFiles[i];
|
||||
file["size"] = fileBuffer.size();
|
||||
file["hash"] = Utils::Cryptography::SHA256::Compute(fileBuffer, true);
|
||||
|
||||
mg_send(nc, buffer.data(), static_cast<int>(buffer.size()));
|
||||
fileList.emplace_back(file);
|
||||
}
|
||||
else
|
||||
|
||||
jsonList = fileList;
|
||||
}
|
||||
|
||||
return {jsonList.dump()};
|
||||
}
|
||||
|
||||
static void FileHandler(mg_connection* c, const mg_http_message* hm)
|
||||
{
|
||||
std::string url(hm->uri.ptr, hm->uri.len);
|
||||
|
||||
Utils::String::Replace(url, "\\", "/");
|
||||
|
||||
// Strip /file
|
||||
url = url.substr(6);
|
||||
Utils::String::Replace(url, "%20", " ");
|
||||
|
||||
auto isMap = false;
|
||||
if (url.starts_with("map/"))
|
||||
{
|
||||
isMap = true;
|
||||
url = url.substr(4);
|
||||
|
||||
auto mapName = (Party::IsInUserMapLobby() ? Dvar::Var("ui_mapname").get<std::string>() : Maps::GetUserMap()->getName());
|
||||
auto isValidFile = false;
|
||||
for (auto i = 0; i < ARRAYSIZE(Maps::UserMapFiles); ++i)
|
||||
{
|
||||
mg_printf(nc,
|
||||
"HTTP/1.1 404 Not Found\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n"
|
||||
"404 - Not Found");
|
||||
if (url == (mapName + Maps::UserMapFiles[i]))
|
||||
{
|
||||
isValidFile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!Maps::GetUserMap()->isValid() && !Party::IsInUserMapLobby()) || !isValidFile)
|
||||
{
|
||||
mg_http_reply(c, 403, "Content-Type: text/html\r\n", "%s", "403 - Forbidden");
|
||||
return;
|
||||
}
|
||||
|
||||
url = std::format("usermaps\\{}\\{}", mapName, url);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((!url.ends_with(".iwd") && url != "mod.ff") || url.find("_svr_") != std::string::npos)
|
||||
{
|
||||
mg_http_reply(c, 403, "Content-Type: text/html\r\n", "%s", "403 - Forbidden");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||
std::string file;
|
||||
const auto fsGame = Dvar::Var("fs_game").get<std::string>();
|
||||
const auto path = Dvar::Var("fs_basepath").get<std::string>() + "\\" + (isMap ? "" : fsGame + "\\") + url;
|
||||
|
||||
if ((!isMap && fsGame.empty()) || !Utils::IO::ReadFile(path, &file))
|
||||
{
|
||||
mg_http_reply(c, 404, "Content-Type: text/html\r\n", "404 - Not Found %s", path.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
mg_printf(c, "%s", "HTTP/1.1 200 OK\r\n");
|
||||
mg_printf(c, "%s", "Content-Type: application/octet-stream\r\n");
|
||||
mg_printf(c, "Content-Length: %d\r\n", static_cast<int>(file.size()));
|
||||
mg_printf(c, "%s", "Connection: close\r\n");
|
||||
mg_printf(c, "%s", "\r\n");
|
||||
mg_send(c, file.data(), static_cast<int>(file.size()));
|
||||
}
|
||||
}
|
||||
|
||||
static void HTMLHandler(mg_connection* c, mg_http_message* hm)
|
||||
{
|
||||
auto url = "html" + std::string(hm->uri.ptr, hm->uri.len);
|
||||
FileSystem::File file;
|
||||
|
||||
if (url.ends_with("/"))
|
||||
{
|
||||
url.append("index.html");
|
||||
file = FileSystem::File(url);
|
||||
}
|
||||
else
|
||||
{
|
||||
file = FileSystem::File(url);
|
||||
if (!file.exists())
|
||||
{
|
||||
url.append("/index.html");
|
||||
file = FileSystem::File(url);
|
||||
}
|
||||
}
|
||||
|
||||
const auto mimeType = Utils::GetMimeType(url);
|
||||
|
||||
if (file.exists())
|
||||
{
|
||||
mg_printf(c, "%s", "HTTP/1.1 200 OK\r\n");
|
||||
mg_printf(c, "Content-Type: %s\r\n", mimeType.data());
|
||||
mg_printf(c, "Content-Length: %d\r\n", static_cast<int>(file.getBuffer().size()));
|
||||
mg_printf(c, "%s", "Connection: close\r\n");
|
||||
mg_printf(c, "%s", "\r\n");
|
||||
mg_send(c, file.getBuffer().data(), static_cast<int>(file.getBuffer().size()));
|
||||
}
|
||||
else
|
||||
{
|
||||
mg_http_reply(c, 404, "Content-Type: text/html\r\n", "404 - Not Found");
|
||||
}
|
||||
}
|
||||
|
||||
static void EventHandler(mg_connection* c, int ev, void* ev_data, [[maybe_unused]] void* fn_data)
|
||||
{
|
||||
if (ev != MG_EV_HTTP_MSG)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto* hm = static_cast<mg_http_message*>(ev_data);
|
||||
std::string url(hm->uri.ptr, hm->uri.len);
|
||||
|
||||
if (url.starts_with("/info"))
|
||||
{
|
||||
const auto reply = InfoHandler();
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s", reply.data());
|
||||
}
|
||||
else if (url.starts_with("/list"))
|
||||
{
|
||||
const auto reply = ListHandler();
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s", reply.data());
|
||||
}
|
||||
else if (url.starts_with("/map"))
|
||||
{
|
||||
const auto reply = MapHandler();
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s", reply.data());
|
||||
}
|
||||
else if (url.starts_with("/file"))
|
||||
{
|
||||
FileHandler(c, hm);
|
||||
}
|
||||
else
|
||||
{
|
||||
HTMLHandler(c, hm);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
Download::Download()
|
||||
{
|
||||
if (Dedicated::IsEnabled() /*|| Dvar::Var("mod_force_download_server").get<bool>()*/)
|
||||
if (Dedicated::IsEnabled())
|
||||
{
|
||||
ZeroMemory(&Download::Mgr, sizeof Download::Mgr);
|
||||
mg_mgr_init(&Download::Mgr, nullptr);
|
||||
mg_mgr_init(&Mgr);
|
||||
|
||||
Network::OnStart([]()
|
||||
Network::OnStart([]
|
||||
{
|
||||
mg_connection* nc = mg_bind(&Download::Mgr, Utils::String::VA("%hu", Network::GetPort()), Download::EventHandler);
|
||||
|
||||
if (nc)
|
||||
const auto* nc = mg_http_listen(&Mgr, Utils::String::VA(":%hu", Network::GetPort()), &EventHandler, &Mgr);
|
||||
if (!nc)
|
||||
{
|
||||
// Handle special requests
|
||||
mg_register_http_endpoint(nc, "/info", Download::InfoHandler);
|
||||
mg_register_http_endpoint(nc, "/list", Download::ListHandler);
|
||||
mg_register_http_endpoint(nc, "/map", Download::MapHandler);
|
||||
mg_register_http_endpoint(nc, "/file/", Download::FileHandler);
|
||||
mg_register_http_endpoint(nc, "/serverlist", Download::ServerlistHandler);
|
||||
|
||||
mg_set_protocol_http_websocket(nc);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::Print("Failed to bind TCP socket, moddownload won't work!\n");
|
||||
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Failed to bind TCP socket, mod download won't work!\n");
|
||||
}
|
||||
});
|
||||
|
||||
@ -907,7 +691,7 @@ namespace Components
|
||||
{
|
||||
while (!Download::Terminate)
|
||||
{
|
||||
mg_mgr_poll(&Download::Mgr, 100);
|
||||
mg_mgr_poll(&Mgr, 100);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -928,13 +712,8 @@ namespace Components
|
||||
|
||||
Scheduler::Once([]
|
||||
{
|
||||
Dvar::Register<bool>("sv_wwwDownload", false, Game::DVAR_ARCHIVE, "Set to true to enable downloading maps/mods from an external server.");
|
||||
Dvar::Register<const char*>("sv_wwwBaseUrl", "", Game::DVAR_ARCHIVE, "Set to the base url for the external map download.");
|
||||
|
||||
// Force users to enable this because we don't want to accidentally turn everyone's pc into a http server into all their files again
|
||||
// not saying we are but ya know... accidents happen
|
||||
// by having it saved we force the user to enable it in config_mp because it only checks the dvar on startup to see if we should init download or not
|
||||
Dvar::Register<bool>("mod_force_download_server", false, Game::DVAR_ARCHIVE, "Set to true to force the client to run the download server for mods (for mods in private matches).");
|
||||
Dvar::Register<bool>("sv_wwwDownload", false, Game::DVAR_NONE, "Set to true to enable downloading maps/mods from an external server.");
|
||||
Dvar::Register<const char*>("sv_wwwBaseUrl", "", Game::DVAR_NONE, "Set to the base url for the external map download.");
|
||||
}, Scheduler::Pipeline::MAIN);
|
||||
|
||||
Script::AddFunction("HttpGet", Script::ShowDeprecationWarning);
|
||||
@ -945,7 +724,7 @@ namespace Components
|
||||
{
|
||||
if (Download::ServerRunning)
|
||||
{
|
||||
mg_mgr_free(&Download::Mgr);
|
||||
mg_mgr_free(&Mgr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
#include <mongoose.h>
|
||||
|
||||
namespace Components
|
||||
{
|
||||
@ -26,24 +25,23 @@ namespace Components
|
||||
bool terminateThread;
|
||||
bool isMap;
|
||||
bool isPrivate;
|
||||
//mg_mgr mgr;
|
||||
Network::Address target;
|
||||
std::string hashedPassword;
|
||||
std::string mod;
|
||||
std::thread thread;
|
||||
|
||||
size_t totalBytes;
|
||||
size_t downBytes;
|
||||
std::size_t totalBytes;
|
||||
std::size_t downBytes;
|
||||
|
||||
int lastTimeStamp;
|
||||
size_t timeStampBytes;
|
||||
std::size_t timeStampBytes;
|
||||
|
||||
class File
|
||||
{
|
||||
public:
|
||||
std::string name;
|
||||
std::string hash;
|
||||
size_t size;
|
||||
std::size_t size;
|
||||
};
|
||||
|
||||
std::vector<File> files;
|
||||
@ -64,7 +62,6 @@ namespace Components
|
||||
if (this->valid)
|
||||
{
|
||||
this->valid = false;
|
||||
//mg_mgr_free(&(this->mgr));
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -79,30 +76,15 @@ namespace Components
|
||||
bool downloading;
|
||||
unsigned int index;
|
||||
std::string buffer;
|
||||
size_t receivedBytes;
|
||||
std::size_t receivedBytes;
|
||||
};
|
||||
|
||||
static mg_mgr Mgr;
|
||||
static ClientDownload CLDownload;
|
||||
static std::thread ServerThread;
|
||||
static bool Terminate;
|
||||
static bool ServerRunning;
|
||||
|
||||
static void DownloadProgress(FileDownload* fDownload, size_t bytes);
|
||||
|
||||
static bool VerifyPassword(mg_connection *nc, http_message* message);
|
||||
|
||||
static void EventHandler(mg_connection *nc, int ev, void *ev_data);
|
||||
static void ListHandler(mg_connection *nc, int ev, void *ev_data);
|
||||
static void MapHandler(mg_connection *nc, int ev, void *ev_data);
|
||||
static void ServerlistHandler(mg_connection *nc, int ev, void *ev_data);
|
||||
static void FileHandler(mg_connection *nc, int ev, void *ev_data);
|
||||
static void InfoHandler(mg_connection *nc, int ev, void *ev_data);
|
||||
static void DownloadHandler(mg_connection *nc, int ev, void *ev_data);
|
||||
|
||||
static bool IsClient(mg_connection *nc);
|
||||
static Game::client_t* GetClient(mg_connection *nc);
|
||||
static void Forbid(mg_connection *nc);
|
||||
static void DownloadProgress(FileDownload* fDownload, std::size_t bytes);
|
||||
|
||||
static void ModDownloader(ClientDownload* download);
|
||||
static bool ParseModList(ClientDownload* download, const std::string& list);
|
||||
|
@ -18,6 +18,14 @@ namespace Components
|
||||
std::vector<int> Script::ScriptMainHandles;
|
||||
std::vector<int> Script::ScriptInitHandles;
|
||||
|
||||
void Script::ShowDeprecationWarning()
|
||||
{
|
||||
Toast::Show("cardicon_gumby", "WARNING!", "You are using deprecated HttpGet/HttpCancel GSC function.", 2048);
|
||||
Logger::Print(Game::CON_CHANNEL_SCRIPT, "*** DEPRECATION WARNING ***\n");
|
||||
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Attempted to execute deprecated built-in HttpGet/HttpCancel! These functions have been deemed unsafe and are scheduled for removal. Please update your mod!\n");
|
||||
Logger::Print(Game::CON_CHANNEL_SCRIPT, "***************************\n");
|
||||
}
|
||||
|
||||
void Script::FunctionError()
|
||||
{
|
||||
const auto* funcName = Game::SL_ConvertToString(Script::FunctionName);
|
||||
@ -530,14 +538,6 @@ namespace Components
|
||||
return &Game::svs_clients[ent->s.number];
|
||||
}
|
||||
|
||||
void Script::ShowDeprecationWarning()
|
||||
{
|
||||
Toast::Show("cardicon_gumby", "WARNING!", "You are using deprecated HttpGet/HttpCancel GSC function.", 2048);
|
||||
Logger::Print(Game::CON_CHANNEL_SCRIPT, "*** DEPRECATION WARNING ***\n");
|
||||
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Attempted to execute deprecated built-in HttpGet/HttpCancel! These functions have been deemed unsafe and are scheduled for removal. Please update your mod!\n");
|
||||
Logger::Print(Game::CON_CHANNEL_SCRIPT, "***************************\n");
|
||||
}
|
||||
|
||||
void Script::AddFunctions()
|
||||
{
|
||||
Script::AddFunction("ReplaceFunc", [] // gsc: ReplaceFunc(<function>, <function>)
|
||||
|
@ -50,11 +50,6 @@ namespace Components
|
||||
this->lastRequest.reset();
|
||||
}
|
||||
|
||||
nlohmann::json Node::Entry::to_json() const
|
||||
{
|
||||
return this->address.getString();
|
||||
}
|
||||
|
||||
void Node::LoadNodeRemotePreset()
|
||||
{
|
||||
std::string nodes = Utils::Cache::GetFile("/iw4/nodes.txt");
|
||||
|
@ -31,7 +31,6 @@ namespace Components
|
||||
void sendRequest();
|
||||
|
||||
void reset();
|
||||
nlohmann::json to_json() const;
|
||||
};
|
||||
|
||||
Node();
|
||||
|
@ -118,7 +118,6 @@ namespace Components
|
||||
{
|
||||
Utils::InfoString info;
|
||||
|
||||
// TODO: Possibly add all Dvar starting with _
|
||||
info.set("admin", Dvar::Var("_Admin").get<const char*>());
|
||||
info.set("website", Dvar::Var("_Website").get<const char*>());
|
||||
info.set("email", Dvar::Var("_Email").get<const char*>());
|
||||
|
Loading…
Reference in New Issue
Block a user