upload
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
#include "ServerProcessor.h"
|
||||
#include "ServerLogger.h"
|
||||
#include "PathTraversal.h"
|
||||
#include "HTTPObjectsBridge.h"
|
||||
#include "UNSResponseBuilder.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <typeinfo>
|
||||
#include <typeindex>
|
||||
#include <unordered_map>
|
||||
#ifdef __GNUG__
|
||||
#include <cxxabi.h>
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
// demangle(GNU)/回退(其他编译器)
|
||||
static std::string demangle_name(const char* name)
|
||||
{
|
||||
#ifdef __GNUG__
|
||||
int status = 0;
|
||||
char *dem = abi::__cxa_demangle(name, nullptr, nullptr, &status);
|
||||
std::string ret = (status == 0 && dem) ? dem : name;
|
||||
std::free(dem);
|
||||
return ret;
|
||||
#else
|
||||
return name;
|
||||
#endif
|
||||
}
|
||||
|
||||
// RTTI 名称缓存(线程安全)
|
||||
static const std::string& RTTISubClassName(const std::type_info &ti)
|
||||
{
|
||||
using key_t = std::type_index;
|
||||
static std::mutex m;
|
||||
static std::unordered_map<key_t, std::string> cache;
|
||||
key_t k(ti);
|
||||
|
||||
// 快速检查(持锁短时间)
|
||||
{
|
||||
std::lock_guard<std::mutex> g(m);
|
||||
auto it = cache.find(k);
|
||||
if (it != cache.end())
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// 若未缓存,先在无锁区做 demangle(可能较慢),然后再插入缓存
|
||||
std::string dem = demangle_name(ti.name());
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> g(m);
|
||||
auto [it, inserted] = cache.emplace(k, std::move(dem));
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
class ServerProcessor::Impl
|
||||
{
|
||||
public:
|
||||
bool IPCheck = false;
|
||||
IPTablePtr BlockedIPs = nullptr;
|
||||
std::map<std::string, bool> StreamInfo;
|
||||
};
|
||||
|
||||
ServerProcessor::ServerProcessor() : pimpl(std::make_unique<Impl>())
|
||||
{
|
||||
}
|
||||
|
||||
ServerProcessor::~ServerProcessor() = default;
|
||||
|
||||
void ServerProcessor::EnableIPCheck()
|
||||
{
|
||||
pimpl->IPCheck = true;
|
||||
return;
|
||||
}
|
||||
|
||||
void ServerProcessor::DisableIPCheck()
|
||||
{
|
||||
pimpl->IPCheck = false;
|
||||
return;
|
||||
}
|
||||
|
||||
void ServerProcessor::UpdateBlockedIPList(IPTablePtr ips)
|
||||
{
|
||||
pimpl->BlockedIPs = ips;
|
||||
return;
|
||||
}
|
||||
|
||||
void ServerProcessor::AppenedBlockedIP(DateTime::Span block_time, std::string ip)
|
||||
{
|
||||
DateTime expr_time = (DateTime::Now() += block_time);
|
||||
IPList li{ ip };
|
||||
pimpl->BlockedIPs->Appened(expr_time, li);
|
||||
pimpl->BlockedIPs->Update();
|
||||
SCLOG_INFO("IP: [%s] has been blocked untill {%s}", ip.c_str(), std::string(expr_time).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
uns::HTTPMethod ServerProcessor::GetMethod(uns::RequestPtr request)
|
||||
{
|
||||
std::string method = request->GetImpl()->webcc_req->method();
|
||||
if (method == "GET")
|
||||
return uns::HTTPMethod::H_GET;
|
||||
else if (method == "PUT")
|
||||
return uns::HTTPMethod::H_PUT;
|
||||
else if (method == "POST")
|
||||
return uns::HTTPMethod::H_POST;
|
||||
else if (method == "HEAD")
|
||||
return uns::HTTPMethod::H_HEAD;
|
||||
else if (method == "TRACE")
|
||||
return uns::HTTPMethod::H_TRACE;
|
||||
else if (method == "PATCH")
|
||||
return uns::HTTPMethod::H_PATCH;
|
||||
else if (method == "DELETE")
|
||||
return uns::HTTPMethod::H_DELETE;
|
||||
else if (method == "OPTIONS")
|
||||
return uns::HTTPMethod::H_OPTIONS;
|
||||
else if (method == "CONNECT")
|
||||
return uns::HTTPMethod::H_CONNECT;
|
||||
else
|
||||
return uns::HTTPMethod::H_UNKNOWN;
|
||||
}
|
||||
|
||||
void ServerProcessor::AddStreamSettings(std::string method, bool stream)
|
||||
{
|
||||
pimpl->StreamInfo.insert(std::pair<std::string, bool>(method, stream));
|
||||
return;
|
||||
}
|
||||
|
||||
uns::PathTraversalDefenceLevel ServerProcessor::PTDefence()
|
||||
{
|
||||
return uns::PathTraversalDefenceLevel::DenyAll;
|
||||
}
|
||||
|
||||
bool ServerProcessor::IsPathSafe(const std::string& raw_path)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uns::ResponsePtr ServerProcessor::Handle(uns::RequestPtr request)
|
||||
{
|
||||
std::string x_real_ip;
|
||||
if(request->GetImpl()->webcc_req->HasHeader("X-Real-IP"))
|
||||
x_real_ip = request->GetImpl()->webcc_req->GetHeader("X-Real-IP");
|
||||
std::string req_ip = (x_real_ip.empty() ? request->GetImpl()->webcc_req->address() : x_real_ip);
|
||||
SCLOGF_INFO("Request recived by {{{}}}, ip: [{}], method: {}, URL: {}", RTTISubClassName(typeid(*this)), req_ip, request->GetImpl()->webcc_req->method(), request->GetImpl()->webcc_req->url().path());
|
||||
if (pimpl->IPCheck && (pimpl->BlockedIPs != nullptr))
|
||||
{
|
||||
pimpl->BlockedIPs->Update();
|
||||
if (pimpl->BlockedIPs->IPExist(req_ip))
|
||||
return uns::ResponseBuilder().IPBlocked()();
|
||||
}
|
||||
// path test
|
||||
std::string path = request->GetImpl()->webcc_req->url().path();
|
||||
auto status = PathTraversal::AnalyzeUrlTraversal(path);
|
||||
if(status != PathTraversal::UrlSafetyStatus::Safe)
|
||||
SCLOGF_WARNING("PathTraversal Detected: {}, Level: {}", path, PathTraversal::ToString(status));
|
||||
switch(PTDefence())
|
||||
{
|
||||
case uns::PathTraversalDefenceLevel::DenyAll:
|
||||
if(status != PathTraversal::UrlSafetyStatus::Safe)
|
||||
return uns::ResponseBuilder().Forbidden()();
|
||||
break;
|
||||
case uns::PathTraversalDefenceLevel::AutoNormalize:
|
||||
{
|
||||
if(status == PathTraversal::UrlSafetyStatus::EvasiveTraversal)
|
||||
return uns::ResponseBuilder().Forbidden()();
|
||||
auto decoded_path = PathTraversal::UrlDecode(path);
|
||||
if(!IsPathSafe(decoded_path))
|
||||
return uns::ResponseBuilder().Forbidden()();
|
||||
auto url = request->GetImpl()->webcc_req->url();
|
||||
url.ForceSet_Path(PathTraversal::NormalizeUrlPath(decoded_path));
|
||||
request->GetImpl()->webcc_req->set_url(std::move(url));
|
||||
break;
|
||||
}
|
||||
case uns::PathTraversalDefenceLevel::AllowNormal:
|
||||
{
|
||||
if(status == PathTraversal::UrlSafetyStatus::EvasiveTraversal)
|
||||
return uns::ResponseBuilder().Forbidden()();
|
||||
auto decoded_path = PathTraversal::UrlDecode(path);
|
||||
if(!IsPathSafe(decoded_path))
|
||||
return uns::ResponseBuilder().Forbidden()();
|
||||
auto url = request->GetImpl()->webcc_req->url();
|
||||
url.ForceSet_Path(decoded_path);
|
||||
request->GetImpl()->webcc_req->set_url(std::move(url));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break; //Check Bypassed by [AllowAll]
|
||||
}
|
||||
uns::ResponsePtr ptr = Processor(request);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool ServerProcessor::Stream(const std::string& method)
|
||||
{
|
||||
if (pimpl->StreamInfo.find(method) != pimpl->StreamInfo.end())
|
||||
return pimpl->StreamInfo.at(method);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user