'Generic Commit'
All checks were successful
Build-Test-Publish / build (linux/amd64) (push) Successful in 1m21s
Build-Test-Publish / build (linux/arm64) (push) Successful in 2m20s
Build-Test-Publish / create-manifest (push) Successful in 17s

This commit is contained in:
Your Name
2025-06-15 16:32:29 +12:00
parent eedd39a533
commit a4d9e3ebb5
6 changed files with 56 additions and 26 deletions

View File

@@ -158,15 +158,5 @@ void HttpController::getAny(const drogon::HttpRequestPtr &req,
}
}
void HttpController::putNotFound(const drogon::HttpRequestPtr &req,
std::function<void(const drogon::HttpResponsePtr &)> &&callback,
const std::string &path) {
auto resp = drogon::HttpResponse::newHttpResponse();
resp->setStatusCode(drogon::k404NotFound);
nlohmann::json response = {{"result", "error"}, {"error", "Not found - put requests must be to /upload"}};
resp->setBody(response.dump());
resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
callback(resp);
}
} // namespace simple_object_storage

View File

@@ -21,7 +21,6 @@ public:
ADD_METHOD_TO(HttpController::getObject, "/object/{1}", {drogon::Get});
ADD_METHOD_TO(HttpController::getRoot, "/", {drogon::Get});
ADD_METHOD_TO(HttpController::getAny, "/{1}", {drogon::Get});
ADD_METHOD_TO(HttpController::putNotFound, "/{1}", {drogon::Put});
METHOD_LIST_END
void getIndex(const drogon::HttpRequestPtr &req,
@@ -68,10 +67,6 @@ public:
void getAny(const drogon::HttpRequestPtr &req,
std::function<void(const drogon::HttpResponsePtr &)> &&callback,
const std::string &path);
void putNotFound(const drogon::HttpRequestPtr &req,
std::function<void(const drogon::HttpResponsePtr &)> &&callback,
const std::string &path);
};
} // namespace simple_object_storage

View File

@@ -46,6 +46,25 @@ void PutHandler::handle_put_object(const drogon::HttpRequestPtr& req, std::funct
return;
}
// Check content length first
auto contentLengthHeader = req->getHeader("content-length");
if (!contentLengthHeader.empty()) {
try {
size_t contentLength = std::stoull(contentLengthHeader);
const size_t MAX_UPLOAD_SIZE = 2ULL * 1024 * 1024 * 1024; // 2GB
if (contentLength > MAX_UPLOAD_SIZE) {
resp->setStatusCode(drogon::k413RequestEntityTooLarge);
nlohmann::json response = {{"result", "error"}, {"error", "File too large"}};
resp->setBody(response.dump());
resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
callback(resp);
return;
}
} catch (const std::exception&) {
// Invalid content-length header, continue with parsing
}
}
// Parse the multipart form data
drogon::MultiPartParser fileParser;
if (fileParser.parse(req) != 0) {
@@ -169,21 +188,21 @@ void PutHandler::handle_put_object(const drogon::HttpRequestPtr& req, std::funct
return;
}
// Write file content to temporary file
auto fileContent = fileData->fileContent();
if (!temp_file.write(fileContent.data(), fileContent.size())) {
temp_file.close();
// Use Drogon's built-in file saving for large files
try {
fileData->saveAs(temp_path.string());
} catch (const std::exception& e) {
resp->setStatusCode(drogon::k500InternalServerError);
nlohmann::json response = {{"result", "error"}, {"error", "Failed to write to temporary file"}};
nlohmann::json response = {{"result", "error"}, {"error", "Failed to write to temporary file: " + std::string(e.what())}};
resp->setBody(response.dump());
resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
temp_file.close();
std::filesystem::remove(temp_path);
callback(resp);
return;
}
temp_file.close();
// Ensure the temporary file is removed even if errors occur
ScopeFileDeleter temp_file_deleter(temp_path);

View File

@@ -23,6 +23,7 @@
namespace simple_object_storage {
Server* Server::instance_ = nullptr;
std::mutex Server::instance_mutex_;
bool Server::init_db() {
@@ -145,6 +146,11 @@ bool Server::start() {
drogon::app().addListener(config_.host, config_.port);
drogon::app().setThreadNum(16);
// Set security limits (allowing for 1GB+ files for testing)
drogon::app().setClientMaxBodySize(2ULL * 1024 * 1024 * 1024); // 2GB max body size
drogon::app().setClientMaxMemoryBodySize(100 * 1024 * 1024); // 100MB max memory body (keep this lower)
drogon::app().enableGzip(true); // Enable compression
// Start the server
try {
drogon::app().run();
@@ -165,9 +171,11 @@ void Server::stop() {
}
void Server::setup_routes() {
// Configure global filters for CORS
// Configure CORS only for requests with Origin header
drogon::app().registerPostHandlingAdvice([this](const drogon::HttpRequestPtr &req, const drogon::HttpResponsePtr &resp) {
add_cors_headers(req, resp);
if (!req->getHeader("Origin").empty()) {
add_cors_headers(req, resp);
}
});
// Handle OPTIONS requests for CORS preflight
@@ -175,6 +183,7 @@ void Server::setup_routes() {
std::function<void(const drogon::HttpResponsePtr &)> &&callback) {
handle_cors_preflight(req, std::move(callback));
}, {}, "OPTIONS");
}
void Server::handle_cors_preflight(const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr &)>&& callback) {

View File

@@ -3,6 +3,7 @@
#include <string>
#include <vector>
#include <memory>
#include <mutex>
#include <nlohmann/json.hpp>
#include <drogon/drogon.h>
@@ -20,8 +21,14 @@ public:
Server(const ServerConfig& config);
~Server();
static Server* getInstance() { return instance_; }
static void setInstance(Server* server) { instance_ = server; }
static Server* getInstance() {
std::lock_guard<std::mutex> lock(instance_mutex_);
return instance_;
}
static void setInstance(Server* server) {
std::lock_guard<std::mutex> lock(instance_mutex_);
instance_ = server;
}
bool start();
void stop();
@@ -54,6 +61,7 @@ private:
std::unique_ptr<RateLimiter> auth_rate_limiter_;
static Server* instance_;
static std::mutex instance_mutex_;
};
} // namespace simple_object_storage

View File

@@ -414,5 +414,14 @@ if ! curl -s -H "Authorization: Bearer ${WRITE_TOKEN}" "${HOSTURL}/deleteobject?
die "failed to delete ${TODELHASH}"
fi
#------------------------------------------------------------------------------------------------
function test_1GB_file_upload() {
source test_1GB_file_upload.sh
}
title "Testing 1GB File upload"
test_1GB_file_upload
#------------------------------------------------------------------------------------------------
title "ALL TESTS PASSED"