From 72e3f962e44072b28ffb19721b11062ded6af2e5 Mon Sep 17 00:00:00 2001 From: Quinten Date: Wed, 1 Oct 2025 20:47:18 +0200 Subject: [PATCH] refactor(file handle): attempt to decouple a bit --- webserv/handler/FileHandler.cpp | 130 ++++++++++++++------------------ webserv/handler/FileHandler.hpp | 18 ++++- 2 files changed, 69 insertions(+), 79 deletions(-) diff --git a/webserv/handler/FileHandler.cpp b/webserv/handler/FileHandler.cpp index 437e435..16ebe86 100644 --- a/webserv/handler/FileHandler.cpp +++ b/webserv/handler/FileHandler.cpp @@ -1,4 +1,5 @@ #include "webserv/handler/ErrorHandler.hpp" +#include "webserv/http/HttpConstants.hpp" #include "webserv/http/HttpResponse.hpp" #include @@ -8,15 +9,12 @@ #include #include +#include #include // for errno #include // for strerror, strlen -#include #include -#include // for views #include #include -// for FILE, fopen, fclose, fread, SEEK_END, SEEK -#include // for stat, S_ISREG, S_ISDIR FileHandler::FileHandler(const LocationConfig *location, const URIParser &uriParser) : location_(location), uriParser_(uriParser) @@ -24,102 +22,84 @@ FileHandler::FileHandler(const LocationConfig *location, const URIParser &uriPar Log::trace(LOCATION); } -std::vector FileHandler::readBinaryFile(const std::string &filepath) +std::unique_ptr FileHandler::handleFile(const std::string &filepath) const { Log::trace(LOCATION); + auto response = std::make_unique(); - std::ifstream file(filepath, std::ios::binary | std::ios::ate); - if (!file.is_open()) + std::string extension = FileUtils::getExtension(filepath); + std::string mimeType = MIMETypes().getType(extension); + response->addHeader("Content-Type", mimeType); + + std::vector fileData = FileUtils::readBinaryFile(filepath); + Log::debug("Serving file: " + filepath + " with MIME type: " + mimeType); + if (fileData.empty()) { - Log::error("Failed to open file: " + filepath); - return {}; + return ErrorHandler::getErrorResponse(Http::StatusCode::NOT_FOUND, location_); } - - // Get file size - std::streamsize size = file.tellg(); - file.seekg(0, std::ios::beg); - - // Read entire file - std::vector buffer(size); - if (!file.read(buffer.data(), size)) - { - Log::error("Failed to read file: " + filepath); - return {}; - } - - return buffer; + // TODO: annoying: For reading files, vector is preferred, but for http data vector is preferred + response->setBody(std::vector{fileData.begin(), fileData.end()}); + response->setStatus(Http::StatusCode::OK); + return response; } -std::string FileHandler::readFileAsString(const std::string &filepath) +std::unique_ptr FileHandler::handleDirectory(const std::string &dirpath, ResourceType type) const { Log::trace(LOCATION); - std::ifstream file(filepath, std::ios::binary); - if (!file.is_open()) + if (type == DIRECTORY_INDEX) { - return ""; + auto possible_indexes = location_->get>("index").value(); + auto first_matching = std::ranges::find_if(possible_indexes, [&](const std::string &index) { + return FileUtils::isFile(FileUtils::joinPath(dirpath, index)); + }); + if (first_matching == possible_indexes.end()) + { + return ErrorHandler::getErrorResponse(Http::StatusCode::FORBIDDEN, location_); + } + return handleFile(FileUtils::joinPath(dirpath, *first_matching)); } - - return std::string(std::istreambuf_iterator(file), std::istreambuf_iterator()); + if (type == DIRECTORY_AUTOINDEX) + { + Log::debug("Requested path is a directory: " + dirpath); + return ErrorHandler::getErrorResponse(Http::StatusCode::FORBIDDEN, location_); + } + return ErrorHandler::getErrorResponse(Http::StatusCode::NOT_FOUND, location_); } std::unique_ptr FileHandler::getResponse() const { Log::trace(LOCATION); - auto response = std::make_unique(); - response->setStatus(200); std::string filepath = uriParser_.getFilePath(); + ResourceType resourceType = getResourceType(filepath); + + switch (resourceType) + { + case FILE: return handleFile(filepath); + case DIRECTORY_AUTOINDEX: + case DIRECTORY_INDEX: return handleDirectory(filepath, resourceType); + case NOT_FOUND: return ErrorHandler::getErrorResponse(Http::StatusCode::NOT_FOUND, location_); + } +} + +FileHandler::ResourceType FileHandler::getResourceType(const std::string &path) const +{ + Log::trace(LOCATION); + if (uriParser_.isFile()) { - std::string extension = uriParser_.getExtension(); - std::string mimeType = MIMETypes().getType(extension); - response->addHeader("Content-Type", mimeType); - - std::vector fileData = readBinaryFile(filepath); - Log::debug("Serving file: " + filepath + " with MIME type: " + mimeType); - if (fileData.empty()) - { - return ErrorHandler::getErrorResponse(404, location_); - } - response->setBody(std::string(fileData.begin(), fileData.end())); + return FILE; } - else if (uriParser_.isDirectory() && location_->get>("index").has_value()) + if (uriParser_.isDirectory()) { - auto possible_indexes = location_->get>("index").value(); - std::string indexPath; - for (auto &index : possible_indexes) + if (location_->get>("index").has_value()) { - indexPath = FileUtils::joinPath(filepath, index); - Log::debug("Checking for index file: " + indexPath); - if (FileUtils::isFile(indexPath)) - { - Log::debug("Found index file: " + indexPath); - break; - } - indexPath.clear(); + return DIRECTORY_INDEX; } - - std::vector fileData = readBinaryFile(indexPath); - Log::debug("Serving index file: " + indexPath); - if (fileData.empty()) + if (location_->get("autoindex").value_or(false)) { - return ErrorHandler::getErrorResponse(404); + return DIRECTORY_AUTOINDEX; } - - std::string extension = FileUtils::getExtension(indexPath); - std::string mimeType = MIMETypes().getType(extension); - response->addHeader("Content-Type", mimeType); - response->setBody(std::string(fileData.begin(), fileData.end())); } - - else if (uriParser_.isDirectory() && location_->get("autoindex").value_or(false)) - { - Log::debug("Requested path is a directory: " + filepath); - return ErrorHandler::getErrorResponse(403); - } - else - { - return ErrorHandler::getErrorResponse(404); - } - return response; + return NOT_FOUND; } \ No newline at end of file diff --git a/webserv/handler/FileHandler.hpp b/webserv/handler/FileHandler.hpp index f8aa1bb..ca59526 100644 --- a/webserv/handler/FileHandler.hpp +++ b/webserv/handler/FileHandler.hpp @@ -4,8 +4,9 @@ #include "webserv/handler/URIParser.hpp" #include "webserv/http/HttpResponse.hpp" -#include +#include #include +#include class FileHandler { @@ -13,11 +14,20 @@ class FileHandler FileHandler(const LocationConfig *location, const URIParser &uriParser); [[nodiscard]] std::unique_ptr getResponse() const; - static std::vector readBinaryFile(const std ::string &filepath); - static std::string readFileAsString(const std::string &filepath); private: - // std::unique_ptr response_; const LocationConfig *location_; const URIParser &uriParser_; + + enum ResourceType : uint8_t + { + FILE, + DIRECTORY_INDEX, + DIRECTORY_AUTOINDEX, + NOT_FOUND + }; + + [[nodiscard]] ResourceType getResourceType(const std::string &path) const; + [[nodiscard]] std::unique_ptr handleFile(const std::string &filepath) const; + [[nodiscard]] std::unique_ptr handleDirectory(const std::string &dirpath, ResourceType type) const; }; \ No newline at end of file