Working
This commit is contained in:
190
src/server.cpp
190
src/server.cpp
@@ -49,6 +49,32 @@ bool Server::init_db() {
|
||||
}
|
||||
}
|
||||
|
||||
bool Server::validate_write_request(const httplib::Request &req, httplib::Response &res, const std::vector<std::string> &required_params, std::map<std::string, std::string> ¶ms)
|
||||
{
|
||||
for (const auto& param : req.params) {
|
||||
params[param.first] = param.second;
|
||||
}
|
||||
|
||||
// Check for required parameters
|
||||
for (const auto& param : required_params) {
|
||||
if (!req.has_param(param)) {
|
||||
res.status = 400;
|
||||
res.set_content("Missing required query parameter: " + param, "text/plain");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check token is valid
|
||||
bool write_token_valid = std::find(config_.write_tokens.begin(), config_.write_tokens.end(), params["token"]) != config_.write_tokens.end();
|
||||
if (!write_token_valid) {
|
||||
res.status = 403;
|
||||
res.set_content("Invalid write token", "text/plain");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Server::Server(const ServerConfig& config)
|
||||
: config_(config), running_(false) {
|
||||
// Ensure object store directory exists
|
||||
@@ -121,7 +147,7 @@ void Server::setup_routes() {
|
||||
});
|
||||
|
||||
// Upload object
|
||||
server_.Put("/([^/]+)/(.*)", [this](const httplib::Request& req, httplib::Response& res) {
|
||||
server_.Put("/(.*)", [this](const httplib::Request& req, httplib::Response& res) {
|
||||
handle_put_object(req, res);
|
||||
});
|
||||
|
||||
@@ -129,6 +155,21 @@ void Server::setup_routes() {
|
||||
server_.Get("/meta/(.*)", [this](const httplib::Request& req, httplib::Response& res) {
|
||||
handle_get_metadata(req, res);
|
||||
});
|
||||
|
||||
// Delete a label/tag (object remains)
|
||||
server_.Get("/deletetag", [this](const httplib::Request& req, httplib::Response& res) {
|
||||
handle_delete_tag(req, res);
|
||||
});
|
||||
|
||||
// Delete an object (and all tags on that object)
|
||||
server_.Get("/deleteobject", [this](const httplib::Request& req, httplib::Response& res) {
|
||||
handle_delete_object(req, res);
|
||||
});
|
||||
|
||||
// Add a tag to an existing object
|
||||
server_.Get("/appendtag", [this](const httplib::Request& req, httplib::Response& res) {
|
||||
handle_append_tag(req, res);
|
||||
});
|
||||
}
|
||||
|
||||
void Server::handle_get_object(const httplib::Request& req, httplib::Response& res) {
|
||||
@@ -208,22 +249,29 @@ void Server::handle_get_directory(const httplib::Request& /*req*/, httplib::Resp
|
||||
}
|
||||
|
||||
void Server::handle_put_object(const httplib::Request& req, httplib::Response& res) {
|
||||
const auto& token = req.matches[1].str();
|
||||
const auto& label_tag = req.matches[2].str();
|
||||
|
||||
if (!validate_write_token(token)) {
|
||||
res.status = 403;
|
||||
res.set_content("Invalid write token", "text/plain");
|
||||
// Check all request parameters first before processing any data
|
||||
|
||||
std::map<std::string, std::string> params;
|
||||
if (!validate_write_request(req, res, {"token", "labeltag", "filename"}, params)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto [label, tag] = parse_label_tag(label_tag);
|
||||
// 1. Check we're in the /upload path
|
||||
if (req.path != "/upload") {
|
||||
res.status = 404;
|
||||
res.set_content("Not found - put requests must be to /upload", "text/plain");
|
||||
return;
|
||||
}
|
||||
|
||||
auto [label, tag] = parse_label_tag(params["labeltag"]);
|
||||
if (label.empty() || tag.empty()) {
|
||||
res.status = 400;
|
||||
res.set_content("Invalid label:tag format", "text/plain");
|
||||
return;
|
||||
}
|
||||
|
||||
// Now that all parameters are validated, process the upload
|
||||
|
||||
// Generate a random number for the temporary filename
|
||||
std::mt19937_64 rng(std::chrono::high_resolution_clock::now().time_since_epoch().count());
|
||||
std::uniform_int_distribution<uint64_t> dist;
|
||||
@@ -258,21 +306,18 @@ void Server::handle_put_object(const httplib::Request& req, httplib::Response& r
|
||||
|
||||
// Check for filename query parameter
|
||||
std::string filename = "";
|
||||
if (req.has_param("filename")) {
|
||||
filename = req.get_param_value("filename");
|
||||
metadata["original_filename"] = filename;
|
||||
}
|
||||
if (req.has_param("filename"))
|
||||
metadata["original_filename"] = params["filename"];
|
||||
|
||||
// Check if filename ends with ".tgz" using the utility function
|
||||
if (utils::ends_with(filename, ".tgz")) {
|
||||
if (utils::ends_with(params["filename"], ".tgz")) {
|
||||
metadata["tgz_content_hash"] = get_hash_from_tgz(temp_path.string());
|
||||
}
|
||||
|
||||
add_file_metadata(temp_path.string(), metadata);
|
||||
|
||||
// Move file to final location
|
||||
std::string hash_str = std::to_string(hash);
|
||||
std::filesystem::path final_path = config_.object_store_path / hash_str;
|
||||
std::filesystem::path final_path = config_.object_store_path / std::to_string(hash);
|
||||
if (!std::filesystem::exists(final_path)) {
|
||||
try {
|
||||
std::filesystem::rename(temp_path, final_path);
|
||||
@@ -287,8 +332,8 @@ void Server::handle_put_object(const httplib::Request& req, httplib::Response& r
|
||||
|
||||
// Update database index
|
||||
dbEntry entry;
|
||||
entry.label_tag = label_tag;
|
||||
entry.hash = hash_str;
|
||||
entry.label_tag = params["labeltag"];
|
||||
entry.hash = std::to_string(hash);
|
||||
entry.metadata = metadata; // Store the potentially updated metadata
|
||||
|
||||
if (!db_->update_or_insert(entry)) {
|
||||
@@ -299,7 +344,7 @@ void Server::handle_put_object(const httplib::Request& req, httplib::Response& r
|
||||
return;
|
||||
}
|
||||
|
||||
res.set_content(hash_str, "text/plain");
|
||||
res.set_content(std::to_string(hash), "text/plain");
|
||||
}
|
||||
|
||||
void Server::handle_get_metadata(const httplib::Request& req, httplib::Response& res) {
|
||||
@@ -321,10 +366,6 @@ void Server::handle_get_metadata(const httplib::Request& req, httplib::Response&
|
||||
}
|
||||
}
|
||||
|
||||
bool Server::validate_write_token(const std::string& token) const {
|
||||
return std::find(config_.write_tokens.begin(), config_.write_tokens.end(), token) != config_.write_tokens.end();
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> Server::parse_label_tag(const std::string& label_tag) const {
|
||||
size_t colon_pos = label_tag.find(':');
|
||||
if (colon_pos == std::string::npos || colon_pos == 0 || colon_pos == label_tag.length() - 1) {
|
||||
@@ -347,4 +388,109 @@ void Server::add_file_metadata(const std::string &file_path, nlohmann::json &met
|
||||
metadata["file_modification_time"] = std::chrono::system_clock::to_time_t(sctp);
|
||||
}
|
||||
|
||||
void Server::handle_delete_tag(const httplib::Request& req, httplib::Response& res) {
|
||||
std::map<std::string, std::string> params;
|
||||
if (!validate_write_request(req, res, {"token", "labeltag"}, params)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate label:tag format
|
||||
auto [label, tag] = parse_label_tag(params["labeltag"]);
|
||||
if (label.empty() || tag.empty()) {
|
||||
res.status = 400;
|
||||
res.set_content("Invalid label:tag format", "text/plain");
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete the label:tag from the database
|
||||
if (!db_->remove(params["labeltag"])) {
|
||||
res.status = 404;
|
||||
res.set_content("Label:tag not found or deletion failed", "text/plain");
|
||||
return;
|
||||
}
|
||||
|
||||
res.set_content("Label:tag deleted successfully", "text/plain");
|
||||
}
|
||||
|
||||
void Server::handle_delete_object(const httplib::Request& req, httplib::Response& res) {
|
||||
std::map<std::string, std::string> params;
|
||||
if (!validate_write_request(req, res, {"token", "hash"}, params)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate that the hash exists as a file
|
||||
std::filesystem::path file_path = config_.object_store_path / params["hash"];
|
||||
if (!std::filesystem::exists(file_path) || !std::filesystem::is_regular_file(file_path)) {
|
||||
res.status = 404;
|
||||
res.set_content("Object not found for hash: " + params["hash"], "text/plain");
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove all tags that reference this hash
|
||||
if (!db_->remove_by_hash(params["hash"])) {
|
||||
res.status = 500;
|
||||
res.set_content("Failed to remove some or all associated tags", "text/plain");
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the file
|
||||
try {
|
||||
std::filesystem::remove(file_path);
|
||||
} catch (const std::filesystem::filesystem_error& e) {
|
||||
std::cerr << "Error deleting object file: " << e.what() << std::endl;
|
||||
res.status = 500;
|
||||
res.set_content("Failed to delete object file: " + std::string(e.what()), "text/plain");
|
||||
return;
|
||||
}
|
||||
|
||||
res.set_content("Object and all associated tags deleted successfully", "text/plain");
|
||||
}
|
||||
|
||||
void Server::handle_append_tag(const httplib::Request& req, httplib::Response& res) {
|
||||
std::map<std::string, std::string> params;
|
||||
if (!validate_write_request(req, res, {"token", "labeltag", "hash"}, params)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate label:tag format
|
||||
auto [label, tag] = parse_label_tag(params["labeltag"]);
|
||||
if (label.empty() || tag.empty()) {
|
||||
res.status = 400;
|
||||
res.set_content("Invalid label:tag format", "text/plain");
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate that the hash exists as a file
|
||||
std::filesystem::path file_path = config_.object_store_path / params["hash"];
|
||||
if (!std::filesystem::exists(file_path) || !std::filesystem::is_regular_file(file_path)) {
|
||||
res.status = 404;
|
||||
res.set_content("Object not found for hash: " + params["hash"], "text/plain");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the label:tag already exists
|
||||
dbEntry existing_entry;
|
||||
if (db_->get(params["labeltag"], existing_entry)) {
|
||||
if (existing_entry.hash == params["hash"]) {
|
||||
// Label:tag already points to this hash, nothing to do
|
||||
res.set_content("Label:tag already points to this hash", "text/plain");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new entry with the label:tag pointing to the hash
|
||||
dbEntry entry;
|
||||
entry.label_tag = params["labeltag"];
|
||||
entry.hash = params["hash"];
|
||||
entry.metadata = nlohmann::json({}); // Empty metadata for appended tags
|
||||
|
||||
if (!db_->update_or_insert(entry)) {
|
||||
res.status = 500;
|
||||
res.set_content("Failed to append tag", "text/plain");
|
||||
return;
|
||||
}
|
||||
|
||||
res.set_content("Tag appended successfully", "text/plain");
|
||||
}
|
||||
|
||||
} // namespace simple_object_storage
|
Reference in New Issue
Block a user