feat: autoindex
This commit is contained in:
parent
b27b3fe2d2
commit
0534d07948
@ -1,7 +1,8 @@
|
|||||||
#include <webserv/handler/FileHandler.hpp>
|
#include "webserv/utils/AutoIndex.hpp"
|
||||||
|
|
||||||
#include <webserv/config/AConfig.hpp> // for AConfig
|
#include <webserv/config/AConfig.hpp> // for AConfig
|
||||||
#include <webserv/handler/ErrorHandler.hpp> // for ErrorHandler
|
#include <webserv/handler/ErrorHandler.hpp> // for ErrorHandler
|
||||||
|
#include <webserv/handler/FileHandler.hpp>
|
||||||
#include <webserv/handler/MIMETypes.hpp> // for MIMETypes
|
#include <webserv/handler/MIMETypes.hpp> // for MIMETypes
|
||||||
#include <webserv/handler/URI.hpp> // for URI
|
#include <webserv/handler/URI.hpp> // for URI
|
||||||
#include <webserv/http/HttpConstants.hpp> // for NOT_FOUND, FORBIDDEN, OK
|
#include <webserv/http/HttpConstants.hpp> // for NOT_FOUND, FORBIDDEN, OK
|
||||||
@ -53,7 +54,6 @@ void FileHandler::handleDirectory(const std::string &dirpath, ResourceType type)
|
|||||||
{
|
{
|
||||||
Log::trace(LOCATION);
|
Log::trace(LOCATION);
|
||||||
Log::debug("Requested path is a directory: " + dirpath);
|
Log::debug("Requested path is a directory: " + dirpath);
|
||||||
|
|
||||||
if (type == DIRECTORY_INDEX)
|
if (type == DIRECTORY_INDEX)
|
||||||
{
|
{
|
||||||
auto possible_indexes = config_->get<std::vector<std::string>>("index").value();
|
auto possible_indexes = config_->get<std::vector<std::string>>("index").value();
|
||||||
@ -71,7 +71,10 @@ void FileHandler::handleDirectory(const std::string &dirpath, ResourceType type)
|
|||||||
if (type == DIRECTORY_AUTOINDEX)
|
if (type == DIRECTORY_AUTOINDEX)
|
||||||
{
|
{
|
||||||
Log::debug("Requested path is a directory: " + dirpath);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
ErrorHandler::createErrorResponse(Http::StatusCode::NOT_FOUND, response_, config_);
|
ErrorHandler::createErrorResponse(Http::StatusCode::NOT_FOUND, response_, config_);
|
||||||
|
|||||||
83
webserv/utils/AutoIndex.cpp
Normal file
83
webserv/utils/AutoIndex.cpp
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#include <webserv/utils/AutoIndex.hpp>
|
||||||
|
#include <webserv/utils/FileUtils.hpp>
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
std::string AutoIndex::generate(const std::string &dir)
|
||||||
|
{
|
||||||
|
std::ostringstream html;
|
||||||
|
|
||||||
|
html << "<!DOCTYPE html>\n"
|
||||||
|
<< "<html><head>\n"
|
||||||
|
<< "<title>Index of " << dir << "</title>\n"
|
||||||
|
<< "<style>\n"
|
||||||
|
<< "body { font-family: Arial, sans-serif; margin: 40px; }\n"
|
||||||
|
<< "h1 { border-bottom: 1px solid #ccc; }\n"
|
||||||
|
<< "table { border-collapse: collapse; width: 100%; }\n"
|
||||||
|
<< "th, td { text-align: left; padding: 8px 12px; border-bottom: 1px solid #ddd; }\n"
|
||||||
|
<< "th { background-color: #f5f5f5; }\n"
|
||||||
|
<< "a { text-decoration: none; color: #0066cc; }\n"
|
||||||
|
<< "a:hover { text-decoration: underline; }\n"
|
||||||
|
<< ".dir { font-weight: bold; }\n"
|
||||||
|
<< "</style>\n"
|
||||||
|
<< "</head><body>\n"
|
||||||
|
<< "<h1>Index of " << dir << "</h1>\n"
|
||||||
|
<< "<table>\n"
|
||||||
|
<< "<tr><th>Name</th><th>Last Modified</th><th>Size</th></tr>\n";
|
||||||
|
|
||||||
|
// Add parent directory link if not root
|
||||||
|
if (dir != "/")
|
||||||
|
{
|
||||||
|
html << "<tr><td><a href=\"../\" class=\"dir\">[Parent Directory]</a></td><td>-</td><td>-</td></tr>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto entries = FileUtils::listDirectory(dir);
|
||||||
|
|
||||||
|
for (const auto &entry : entries)
|
||||||
|
{
|
||||||
|
std::string href = entry.path().filename().string();
|
||||||
|
if (entry.is_directory())
|
||||||
|
{
|
||||||
|
href += "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
html << "<tr><td><a href=\"" << href << "\"";
|
||||||
|
if (entry.is_directory())
|
||||||
|
{
|
||||||
|
html << " class=\"dir\"";
|
||||||
|
}
|
||||||
|
html << ">" << entry.path().filename().string();
|
||||||
|
if (entry.is_directory())
|
||||||
|
{
|
||||||
|
html << "/";
|
||||||
|
}
|
||||||
|
html << "</a></td>" << "<td></td>"; //<< std::format("{:%Y-%m-%d %H:%M:%S}", entry.last_write_time()) << "</td>"
|
||||||
|
html << "<td>" << (entry.is_directory() ? "-" : formatFileSize(entry.file_size())) << "</td></tr>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
html << "</table>\n"
|
||||||
|
<< "<hr><p><em>webserv</em></p>\n"
|
||||||
|
<< "</body></html>\n";
|
||||||
|
|
||||||
|
return html.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AutoIndex::formatFileSize(uintmax_t size)
|
||||||
|
{
|
||||||
|
static const std::vector<std::string> units = {"B", "KB", "MB", "GB", "TB"};
|
||||||
|
int unitIndex = 0;
|
||||||
|
auto displaySize = static_cast<double>(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();
|
||||||
|
}
|
||||||
19
webserv/utils/AutoIndex.hpp
Normal file
19
webserv/utils/AutoIndex.hpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
@ -1,11 +1,12 @@
|
|||||||
|
#include <webserv/log/Log.hpp> // for Log, LOCATION
|
||||||
#include <webserv/utils/FileUtils.hpp>
|
#include <webserv/utils/FileUtils.hpp>
|
||||||
|
|
||||||
#include <webserv/log/Log.hpp> // for Log, LOCATION
|
|
||||||
|
|
||||||
#include <cstring> // for size_t
|
#include <cstring> // for size_t
|
||||||
|
#include <filesystem>
|
||||||
#include <fstream> // for basic_ifstream, basic_ios, basic_istream, ios, ifstream, operator|, basic_istream::read, basic_istream::seekg, basic_istream::tellg, streamsize
|
#include <fstream> // for basic_ifstream, basic_ios, basic_istream, ios, ifstream, operator|, basic_istream::read, basic_istream::seekg, basic_istream::tellg, streamsize
|
||||||
#include <iterator> // for istreambuf_iterator, operator==
|
#include <iterator> // for istreambuf_iterator, operator==
|
||||||
#include <string> // for basic_string, string, char_traits, operator+
|
#include <string> // for basic_string, string, char_traits, operator+
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <sys/stat.h> // for stat, S_ISDIR, S_ISREG
|
#include <sys/stat.h> // for stat, S_ISDIR, S_ISREG
|
||||||
|
|
||||||
@ -13,7 +14,10 @@ namespace FileUtils
|
|||||||
{
|
{
|
||||||
bool isDirectory(const std::string &path)
|
bool isDirectory(const std::string &path)
|
||||||
{
|
{
|
||||||
struct stat pathStat{};
|
struct stat pathStat
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
if (stat(path.c_str(), &pathStat) != 0)
|
if (stat(path.c_str(), &pathStat) != 0)
|
||||||
{
|
{
|
||||||
return false; // Could not access path
|
return false; // Could not access path
|
||||||
@ -23,7 +27,10 @@ bool isDirectory(const std::string &path)
|
|||||||
|
|
||||||
bool isFile(const std::string &path)
|
bool isFile(const std::string &path)
|
||||||
{
|
{
|
||||||
struct stat pathStat{};
|
struct stat pathStat
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
if (stat(path.c_str(), &pathStat) != 0)
|
if (stat(path.c_str(), &pathStat) != 0)
|
||||||
{
|
{
|
||||||
return false; // Could not access path
|
return false; // Could not access path
|
||||||
@ -33,7 +40,10 @@ bool isFile(const std::string &path)
|
|||||||
|
|
||||||
bool isValidPath(const std::string &path)
|
bool isValidPath(const std::string &path)
|
||||||
{
|
{
|
||||||
struct stat pathStat{};
|
struct stat pathStat
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
return stat(path.c_str(), &pathStat) == 0;
|
return stat(path.c_str(), &pathStat) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,4 +125,15 @@ std::string readFileAsString(const std::string &filepath)
|
|||||||
return {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
|
return {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::filesystem::directory_entry> listDirectory(const std::string &dirpath)
|
||||||
|
{
|
||||||
|
std::vector<std::filesystem::directory_entry> entries = {};
|
||||||
|
|
||||||
|
for (const auto &entry : std::filesystem::directory_iterator(dirpath))
|
||||||
|
{
|
||||||
|
entries.emplace_back(entry);
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace FileUtils
|
} // namespace FileUtils
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -14,4 +15,6 @@ std::string joinPath(const std::string &base, const std::string &addition);
|
|||||||
|
|
||||||
std::vector<char> readBinaryFile(const std::string &filepath);
|
std::vector<char> readBinaryFile(const std::string &filepath);
|
||||||
std::string readFileAsString(const std::string &filepath);
|
std::string readFileAsString(const std::string &filepath);
|
||||||
|
|
||||||
|
std::vector<std::filesystem::directory_entry> listDirectory(const std::string &dirpath);
|
||||||
} // namespace FileUtils
|
} // namespace FileUtils
|
||||||
Loading…
Reference in New Issue
Block a user