upgrade core add header check and incrace upload speed

This commit is contained in:
UnknownObject
2026-08-05 17:35:27 +08:00
parent 45af94e535
commit 1f11a9d348
76 changed files with 2059 additions and 642 deletions
+82 -35
View File
@@ -13,8 +13,10 @@ public:
bool HTMLResponse = false;
std::string TempRoot;
IPTablePtr BlockedIPs = nullptr;
WebFileInfoVec FileInfo;
TempFileManager FileManager;
FileProcessorCallback Callback = nullptr;
std::jthread FileProcesser;
std::chrono::seconds FileTimeout = 300s, FileMaxProcTimeout = 600s;
};
FileReceiver::FileReceiver() : pimpl(std::make_unique<Impl>())
@@ -27,11 +29,11 @@ bool FileReceiver::CallFileProcesser()
{
if (pimpl->Callback == nullptr)
return false;
std::thread thFileProcesser(pimpl->Callback, pimpl->FileInfo, pimpl->TempRoot); //Use copy construst to avoid repeat data process.
if (!thFileProcesser.joinable())
pimpl->FileProcesser = std::jthread(pimpl->Callback, std::ref(pimpl->FileManager), pimpl->TempRoot);
if (!pimpl->FileProcesser.joinable())
return false;
thFileProcesser.detach();
pimpl->FileInfo.clear();
pimpl->FileProcesser.detach();
//pimpl->FileInfo.clear();
SCLOGF_TRACE("FileProcesser Function (Address: {}) Started.", pimpl->Callback);
return true;
}
@@ -39,19 +41,19 @@ bool FileReceiver::CallFileProcesser()
void FileReceiver::SetResponseMode(bool html)
{
pimpl->HTMLResponse = html;
SCLOG_DEBUG("FileReceiver init mode: %s", (html ? "html" : "json"));
SCLOGF_DEBUG("FileReceiver init mode: {}", (html ? "html" : "json"));
}
void FileReceiver::SetCORSEnable(bool enable)
{
pimpl->EnableCORS = enable;
SCLOG_DEBUG("FileReceiver CORS mode: %s", (enable ? "enabled" : "disabled"));
SCLOGF_DEBUG("FileReceiver CORS mode: {}", (enable ? "enabled" : "disabled"));
}
void FileReceiver::SetTempRoot(std::string temp_root)
{
pimpl->TempRoot = temp_root;
SCLOG_TRACE("FR-TempRoot: %s", pimpl->TempRoot.c_str());
SCLOGF_TRACE("FR-TempRoot: {}", pimpl->TempRoot);
return;
}
@@ -73,7 +75,7 @@ void FileReceiver::AppenedBlockedIP(DateTime::Span block_time, std::string ip)
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());
SCLOGF_INFO("IP: [{}] has been blocked untill {{{}}}", ip, std::string(expr_time));
return;
}
@@ -108,13 +110,24 @@ bool FileReceiver::WriteFile(const std::string& path, const std::string& bytes)
std::ofstream stream{ path, std::ios::binary };
if (stream.fail())
{
SCLOG_WARNING("Failed to write file [%s]: can't open stream", path.c_str());
SCLOGF_WARNING("Failed to write file [{}]: can't open stream", path);
return false;
}
stream.write(bytes.data(), bytes.size());
if (stream.fail())
SCLOG_WARNING("Failed to write file [%s]: can't write to stream", path.c_str());
return !stream.fail();
bool fail = stream.fail();
if (fail)
SCLOGF_WARNING("Failed to write file [{}]: can't write to stream", path);
else
SCLOGF_TRACE("Wrote {siz-b} to file [{}]", bytes.size(), path);
return !fail;
}
void FileReceiver::SetFileTimeout(std::chrono::seconds timeout, std::chrono::seconds max_proc_timeout) noexcept
{
if (timeout.count() > 0)
pimpl->FileTimeout = timeout;
if (max_proc_timeout.count() > 0)
pimpl->FileMaxProcTimeout = max_proc_timeout;
}
uns::PathTraversalDefenceLevel FileReceiver::PTDefence()
@@ -128,20 +141,36 @@ bool FileReceiver::IsPathSafe(const std::string& raw_path)
return false;
}
bool FileReceiver::IsHeaderValid(uns::RequestPtr request)
{
return true;
}
std::string FileReceiver::EncodeUploadResult()
{
Json::Value root;
Json::FastWriter writer;
root["AcceptedCount"] = pimpl->FileInfo.size();
root["AcceptedFiles"] = Json::Value(Json::arrayValue);
for (auto& ele : pimpl->FileInfo)
try
{
Json::Value sub;
sub["FileName"] = ele.GetStorageFileName();
sub["UploadTime"] = ele.GetUploadTime().GetTimeStamp();
root["AcceptedFiles"].append(sub);
Json::Value root;
Json::FastWriter writer;
// 1. 从管理器安全获取当前所有文件的快照
auto file_infos = pimpl->FileManager.GetAllFileInfos();
// 2. 组装 JSON 数据
root["AcceptedCount"] = static_cast<Json::Value::UInt64>(file_infos.size());
root["AcceptedFiles"] = Json::Value(Json::arrayValue);
for (const auto& ele : file_infos)
{
Json::Value sub;
sub["FileName"] = ele.GetStorageFileName();
sub["UploadTime"] = ele.GetUploadTime().GetTimeStamp();
root["AcceptedFiles"].append(sub);
}
return writer.write(root);
}
catch (...)
{
// 极致异常安全兜底:如果 Json 报错或内存写满,返回一个合法的空 JSON 字符串
return "{\"AcceptedCount\":0,\"AcceptedFiles\":[]}";
}
return writer.write(root);
}
std::string FileReceiver::EncodeUploadResultHTML()
@@ -162,16 +191,32 @@ std::string FileReceiver::EncodeUploadResultHTML()
</body>
</html>
)";
std::string tmp;
for (auto& ele : pimpl->FileInfo)
tmp += "[" + ele.GetStorageFileName() + "] - {" + ele.GetUploadTime().Format("%Y-%m-%d %H:%M:%S") + "}<br>";
size_t html_size = strlen(html) + tmp.size() + 10;
char* result = new char[html_size];
memset(result, 0, sizeof(result));
sprintf(result, html, pimpl->FileInfo.size(), tmp.c_str());
tmp = std::string(result);
delete[] result;
return tmp;
try
{
// 1. 获取文件快照
auto file_infos = pimpl->FileManager.GetAllFileInfos();
// 2. 拼接文件列表 HTML
std::string tmp;
for (const auto& ele : file_infos)
tmp += "[" + ele.GetStorageFileName() + "] - {" + ele.GetUploadTime().Format("%Y-%m-%d %H:%M:%S") + "}<br>";
// 3. 动态安全计算所需缓冲区大小(32字节用于容纳 %lld 的数字展开)
size_t html_size = strlen(html) + tmp.size() + 32;
// 利用 std::string 管理缓冲区内存(RAII 机制,无论发生什么都会自动释放,绝不泄漏)
std::string result_str(html_size, '\0');
// 使用安全的 snprintf 写入 string 内部缓冲区
int written = snprintf(result_str.data(), result_str.size(), html, static_cast<long long>(file_infos.size()), tmp.c_str());
if (written > 0)
{
result_str.resize(written); // 裁剪掉尾部多余的 \0
return result_str;
}
return "HTML generation failed";
}
catch (...)
{
// 异常安全兜底
return "<html><body><center><h1>Upload Result Error</h1></center></body></html>";
}
}
uns::ResponsePtr FileReceiver::Execute(uns::RequestPtr request)
@@ -181,7 +226,7 @@ uns::ResponsePtr FileReceiver::Execute(uns::RequestPtr request)
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);
SCLOG_DEBUG("Request recived, ip: [%s], method: %s", req_ip.c_str(), request->GetImpl()->webcc_req->method().c_str());
SCLOGF_DEBUG("Request recived, ip: [{}], method: {}", req_ip, request->GetImpl()->webcc_req->method());
// path test
std::string path = request->GetImpl()->webcc_req->url().path();
auto status = PathTraversal::AnalyzeUrlTraversal(path);
@@ -245,7 +290,9 @@ uns::ResponsePtr FileReceiver::Execute(uns::RequestPtr request)
SCLOGF_DEBUG("File recived: [{}], {} bytes", form->GetFileName(), form->GetDataSize());
WebFileInfo info(form->GetFileNameS(), form->GetDataSize());
WriteFile(info.MakePath(pimpl->TempRoot), form->GetData());
pimpl->FileInfo.push_back(info);
//pimpl->FileInfo.push_back(info);
if (!pimpl->FileManager.RegisterFile(info, pimpl->FileTimeout, pimpl->FileMaxProcTimeout))
SCLOGF_WARNING("FileManager.RegisterFile Error, File: {}, TempRoot: {}", form->GetFileName(), pimpl->TempRoot);
}
std::string resp_body = (pimpl->HTMLResponse ? EncodeUploadResultHTML() : EncodeUploadResult());
CallFileProcesser();