diff --git a/webserv/handler/FileHandler.cpp b/webserv/handler/FileHandler.cpp index 60a38be..6b07daf 100644 --- a/webserv/handler/FileHandler.cpp +++ b/webserv/handler/FileHandler.cpp @@ -1,7 +1,8 @@ -#include +#include "webserv/utils/AutoIndex.hpp" #include // for AConfig #include // for ErrorHandler +#include #include // for MIMETypes #include // for URI #include // for NOT_FOUND, FORBIDDEN, OK @@ -53,7 +54,6 @@ void FileHandler::handleDirectory(const std::string &dirpath, ResourceType type) { Log::trace(LOCATION); Log::debug("Requested path is a directory: " + dirpath); - if (type == DIRECTORY_INDEX) { auto possible_indexes = config_->get>("index").value(); @@ -71,7 +71,10 @@ void FileHandler::handleDirectory(const std::string &dirpath, ResourceType type) if (type == DIRECTORY_AUTOINDEX) { Log::debug("Requested path is a directory: " + dirpath); - ErrorHandler::createErrorResponse(Http::StatusCode::FORBIDDEN, response_, config_); + // ErrorHandler::createErrorResponse(Http::StatusCode::FORBIDDEN, response_, config_); + // TODO: This doesn't trigger for some reason :p + response_.setBody(AutoIndex::generate(dirpath)); + response_.setStatus(Http::StatusCode::OK); return; } ErrorHandler::createErrorResponse(Http::StatusCode::NOT_FOUND, response_, config_); diff --git a/webserv/utils/AutoIndex.cpp b/webserv/utils/AutoIndex.cpp new file mode 100644 index 0000000..455b4ea --- /dev/null +++ b/webserv/utils/AutoIndex.cpp @@ -0,0 +1,83 @@ +#include +#include + +#include +#include +#include + +std::string AutoIndex::generate(const std::string &dir) +{ + std::ostringstream html; + + html << "\n" + << "\n" + << "Index of " << dir << "\n" + << "\n" + << "\n" + << "

Index of " << dir << "

\n" + << "\n" + << "\n"; + + // Add parent directory link if not root + if (dir != "/") + { + html << "\n"; + } + + auto entries = FileUtils::listDirectory(dir); + + for (const auto &entry : entries) + { + std::string href = entry.path().filename().string(); + if (entry.is_directory()) + { + href += "/"; + } + + html << "" << ""; //<< std::format("{:%Y-%m-%d %H:%M:%S}", entry.last_write_time()) << "" + html << "\n"; + } + + html << "
NameLast ModifiedSize
[Parent Directory]--
" << entry.path().filename().string(); + if (entry.is_directory()) + { + html << "/"; + } + html << "" << (entry.is_directory() ? "-" : formatFileSize(entry.file_size())) << "
\n" + << "

webserv

\n" + << "\n"; + + return html.str(); +} + +std::string AutoIndex::formatFileSize(uintmax_t size) +{ + static const std::vector units = {"B", "KB", "MB", "GB", "TB"}; + int unitIndex = 0; + auto displaySize = static_cast(size); + + while (displaySize >= 1024 && unitIndex < 4) + { + displaySize /= 1024; + ++unitIndex; + } + + std::ostringstream oss; + oss.precision(2); + oss << std::fixed << displaySize << " " << units.at(unitIndex); + return oss.str(); +} \ No newline at end of file diff --git a/webserv/utils/AutoIndex.hpp b/webserv/utils/AutoIndex.hpp new file mode 100644 index 0000000..f2ffd76 --- /dev/null +++ b/webserv/utils/AutoIndex.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +class AutoIndex +{ + public: + AutoIndex() = delete; + AutoIndex(const AutoIndex &) = delete; + AutoIndex &operator=(const AutoIndex &) = delete; + AutoIndex(AutoIndex &&) = delete; + AutoIndex &operator=(AutoIndex &&) = delete; + ~AutoIndex() = delete; + static std::string generate(const std::string &dir); + + private: + static std::string formatFileSize(uintmax_t size); +}; \ No newline at end of file diff --git a/webserv/utils/FileUtils.cpp b/webserv/utils/FileUtils.cpp index 0c55e1e..b9fc6db 100644 --- a/webserv/utils/FileUtils.cpp +++ b/webserv/utils/FileUtils.cpp @@ -1,11 +1,12 @@ +#include // for Log, LOCATION #include -#include // for Log, LOCATION - #include // for size_t +#include #include // for basic_ifstream, basic_ios, basic_istream, ios, ifstream, operator|, basic_istream::read, basic_istream::seekg, basic_istream::tellg, streamsize #include // for istreambuf_iterator, operator== #include // for basic_string, string, char_traits, operator+ +#include #include // for stat, S_ISDIR, S_ISREG @@ -13,7 +14,10 @@ namespace FileUtils { bool isDirectory(const std::string &path) { - struct stat pathStat{}; + struct stat pathStat + { + }; + if (stat(path.c_str(), &pathStat) != 0) { return false; // Could not access path @@ -23,7 +27,10 @@ bool isDirectory(const std::string &path) bool isFile(const std::string &path) { - struct stat pathStat{}; + struct stat pathStat + { + }; + if (stat(path.c_str(), &pathStat) != 0) { return false; // Could not access path @@ -33,7 +40,10 @@ bool isFile(const std::string &path) bool isValidPath(const std::string &path) { - struct stat pathStat{}; + struct stat pathStat + { + }; + return stat(path.c_str(), &pathStat) == 0; } @@ -115,4 +125,15 @@ std::string readFileAsString(const std::string &filepath) return {std::istreambuf_iterator(file), std::istreambuf_iterator()}; } +std::vector listDirectory(const std::string &dirpath) +{ + std::vector entries = {}; + + for (const auto &entry : std::filesystem::directory_iterator(dirpath)) + { + entries.emplace_back(entry); + } + return entries; +} + } // namespace FileUtils \ No newline at end of file diff --git a/webserv/utils/FileUtils.hpp b/webserv/utils/FileUtils.hpp index 338cb06..c9a8745 100644 --- a/webserv/utils/FileUtils.hpp +++ b/webserv/utils/FileUtils.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -14,4 +15,6 @@ std::string joinPath(const std::string &base, const std::string &addition); std::vector readBinaryFile(const std::string &filepath); std::string readFileAsString(const std::string &filepath); + +std::vector listDirectory(const std::string &dirpath); } // namespace FileUtils \ No newline at end of file