Tubio/Tubio/HttpServer.cpp

225 lines
5.6 KiB
C++
Raw Normal View History

#include "HttpServer.h"
2020-09-24 01:16:44 +02:00
using namespace Logging;
2020-09-24 14:31:30 +02:00
using namespace Rest;
using namespace JasonPP;
2020-09-24 01:16:44 +02:00
HttpServer::HttpServer()
2020-09-24 01:16:44 +02:00
{
pMgr = new mg_mgr();
pNc = nullptr;
log = new Logger("HttpServer");
2020-09-24 01:16:44 +02:00
return;
}
HttpServer::~HttpServer()
2020-09-24 01:16:44 +02:00
{
delete pMgr;
delete log;
log = nullptr;
pMgr = nullptr;
return;
}
void HttpServer::PostInit()
2020-09-24 01:16:44 +02:00
{
isBootedSuccessfully = InitWebServer();
return;
}
bool HttpServer::InitWebServer()
2020-09-24 01:16:44 +02:00
{
mg_mgr_init(pMgr, NULL);
log->cout << "Starting http-server on port " << XGConfig::httpServer.port << "...";
2020-09-24 01:16:44 +02:00
log->Flush();
pNc = mg_bind(pMgr, XGConfig::httpServer.port.c_str(), this->EventHandler);
2020-09-24 01:16:44 +02:00
if (pNc == NULL)
{
log->cout << log->Err() << "Failed to boot the http-server! - Unable to bind listener! (port: " << XGConfig::httpServer.port << ")";
2020-09-24 01:16:44 +02:00
log->Flush();
return false;
}
mg_set_protocol_http_websocket(pNc);
frontend_serve_opts.document_root = XGConfig::httpServer.rootdir.c_str();
2020-09-24 15:35:07 +02:00
frontend_serve_opts.enable_directory_listing = "no";
2020-09-24 01:16:44 +02:00
log->cout << "Started http-server successfully!";
2020-09-24 01:16:44 +02:00
log->Flush();
isBootedSuccessfully = true;
return true;
}
void HttpServer::Update()
2020-09-24 01:16:44 +02:00
{
2020-09-27 13:06:04 +02:00
mg_mgr_poll(pMgr, XGConfig::httpServer.polling_rate);
2020-09-24 01:16:44 +02:00
return;
}
void HttpServer::ServeStringToConnection(struct mg_connection* c, std::string str, int httpStatusCode)
2020-09-24 01:16:44 +02:00
{
2020-09-24 14:31:30 +02:00
mg_send_head(c, httpStatusCode, str.length(), "content-type: application/json\nAccess-Control-Allow-Origin: *");
mg_printf(c, str.c_str());
2020-09-24 01:16:44 +02:00
return;
}
void HttpServer::EventHandler(mg_connection* pNc, int ev, void* p)
2020-09-24 01:16:44 +02:00
{
2020-09-24 14:31:30 +02:00
switch (ev)
2020-09-24 01:16:44 +02:00
{
case MG_EV_HTTP_REQUEST:
2020-09-24 14:31:30 +02:00
http_message* hpm = (http_message*)p;
2020-09-24 15:35:07 +02:00
std::string requestedUri = FixUnterminatedString(hpm->uri.p, hpm->uri.len);
std::string peer_addr;
{
char buf[32];
mg_sock_addr_to_str(&pNc->sa, buf, sizeof(buf), MG_SOCK_STRINGIFY_IP);
peer_addr = buf;
}
if ((XGConfig::general.onlyAllowLocalhost) && (peer_addr != "127.0.0.1"))
2020-09-24 14:31:30 +02:00
{
Json j;
j.CloneFrom(RestResponseTemplates::GetByCode(UNAUTHORIZED, "Only localhost allowed!"));
ServeStringToConnection(pNc, j.Render(), UNAUTHORIZED);
}
else
{
try
{
if (requestedUri == "/api")
{
ProcessAPIRequest(pNc, ev, p, peer_addr);
}
else if (requestedUri.substr(0, 9) == "/download")
{
ServeDownloadeableResource(pNc, ev, p, requestedUri);
}
else
{
// Just serve the files requested
mg_serve_http(pNc, (struct http_message*)p, frontend_serve_opts);
}
}
catch (std::exception& e)
{
Json j;
j.CloneFrom(RestResponseTemplates::GetByCode(INTERNAL_SERVER_ERROR, e.what()));
ServeStringToConnection(pNc, j.Render(), INTERNAL_SERVER_ERROR);
}
catch (...)
{
Json j;
j.CloneFrom(RestResponseTemplates::GetByCode(INTERNAL_SERVER_ERROR, "Das not good"));
ServeStringToConnection(pNc, j.Render(), INTERNAL_SERVER_ERROR);
}
2020-09-24 01:16:44 +02:00
break;
}
2020-09-24 01:16:44 +02:00
}
return;
}
void HttpServer::ProcessAPIRequest(mg_connection* pNc, int ev, void* p, std::string peerAddress)
2020-09-24 15:35:07 +02:00
{
// Get struct with http message informations
http_message* hpm = (http_message*)p;
// Get the transmitted message body
std::string requestBodyRaw = FixUnterminatedString(hpm->body.p, hpm->body.len);
// Check for the body being valid json
if (IsJsonValid(requestBodyRaw))
{
Json requestBody;
requestBody.Parse(requestBodyRaw);
2020-09-24 15:35:07 +02:00
JsonBlock responseBody;
HTTP_STATUS_CODE returnCode;
RestQueryHandler::ProcessQuery(peerAddress, requestBody, responseBody, returnCode);
2020-09-24 15:35:07 +02:00
Json response(responseBody);
ServeStringToConnection(pNc, response.Render(), returnCode);
}
else // return error message for invalid json
{
Json errorJson;
errorJson.CloneFrom(RestResponseTemplates::GetByCode(HTTP_STATUS_CODE::BAD_REQUEST, "Received json is fucked"));
2020-09-24 15:35:07 +02:00
ServeStringToConnection(pNc, errorJson.Render(), HTTP_STATUS_CODE::BAD_REQUEST);
}
return;
}
void HttpServer::ServeDownloadeableResource(mg_connection* pNc, int ev, void* p, std::string uri)
{
std::string fileId = uri.substr(10, uri.length() - 10);
if (Downloader::DownloadManager::DoesTubioIDExist(fileId))
{
Downloader::DownloadEntry& entry = Downloader::DownloadManager::GetDownloadEntryByTubioID(fileId);
if (entry.status == Downloader::DOWNLOAD_STATUS::FINISHED)
{
std::stringstream ss;
std::string downloadedFilename = entry.title + (entry.mode == Downloader::DOWNLOAD_MODE::AUDIO ? ".mp3" : ".mp4");
ss << "Access-Control-Allow-Origin: *\nContent-Disposition: attachment; filename=\"" << downloadedFilename << "\"\nPragma: public\nCache-Control: must-revalidate, post-check=0, pre-check=0";
mg_http_serve_file(pNc, (http_message*)p, entry.downloaded_filename.c_str(), mg_mk_str("application/octet-stream"), mg_mk_str(ss.str().c_str()));
}
else
{
Json j;
j.CloneFrom(RestResponseTemplates::GetByCode(BAD_REQUEST, "File download not ready!"));
ServeStringToConnection(pNc, j.Render(), BAD_REQUEST);
}
}
else
{
Json j;
j.CloneFrom(RestResponseTemplates::GetByCode(BAD_REQUEST, "Invalid tubio id!"));
ServeStringToConnection(pNc, j.Render(), BAD_REQUEST);
}
return;
}
void HttpServer::OnExit()
2020-09-24 01:16:44 +02:00
{
log->cout << "Shutting down http-server...";
2020-09-24 15:15:18 +02:00
log->Flush();
2020-09-24 01:16:44 +02:00
mg_mgr_free(pMgr);
return;
}
2020-09-24 14:31:30 +02:00
std::string HttpServer::FixUnterminatedString(const char* cstr, const std::size_t len)
2020-09-24 14:31:30 +02:00
{
std::stringstream ss;
for (std::size_t i = 0; i < len; i++)
{
ss << *(cstr + i);
}
return ss.str();
}
2020-09-24 15:35:07 +02:00
mg_serve_http_opts HttpServer::frontend_serve_opts;