128 lines
4.7 KiB
C++
128 lines
4.7 KiB
C++
#include "webserv/utils/AutoIndex.hpp"
|
|
|
|
#include <webserv/config/AConfig.hpp> // for AConfig
|
|
#include <webserv/handler/ErrorHandler.hpp> // for ErrorHandler
|
|
#include <webserv/handler/FileHandler.hpp>
|
|
#include <webserv/handler/MIMETypes.hpp> // for MIMETypes
|
|
#include <webserv/handler/URI.hpp> // for URI
|
|
#include <webserv/http/HttpConstants.hpp> // for NOT_FOUND, FORBIDDEN, OK
|
|
#include <webserv/http/HttpResponse.hpp> // for HttpResponse
|
|
#include <webserv/log/Log.hpp> // for Log, LOCATION
|
|
#include <webserv/utils/FileUtils.hpp> // for joinPath, getExtension, isFile, readBinaryFile
|
|
|
|
#include <optional> // for optional
|
|
#include <ranges> // for __find_if_fn, find_if
|
|
#include <string> // for basic_string, allocator, operator+, string, char_traits
|
|
#include <vector> // for vector
|
|
|
|
FileHandler::FileHandler(const HttpRequest &request, HttpResponse &response)
|
|
: AHandler(request, response), uri_(request.getUri()), config_(uri_.getConfig())
|
|
{
|
|
Log::trace(LOCATION);
|
|
}
|
|
|
|
void FileHandler::handleTimeout()
|
|
{
|
|
Log::warning("File handler timeout occurred for path: " + uri_.getFullPath());
|
|
ErrorHandler::createErrorResponse(504, response_, config_);
|
|
}
|
|
|
|
void FileHandler::handleFile(const std::string &filepath) const
|
|
{
|
|
Log::trace(LOCATION);
|
|
Log::debug("Requested path is a file: " + filepath);
|
|
// auto response = std::make_unique<HttpResponse>();
|
|
|
|
std::string extension = FileUtils::getExtension(filepath);
|
|
std::string mimeType = MIMETypes().getType(extension);
|
|
response_.addHeader("Content-Type", mimeType);
|
|
|
|
std::vector<char> fileData = FileUtils::readBinaryFile(filepath);
|
|
Log::debug("Serving file: " + filepath + " with MIME type: " + mimeType);
|
|
// TODO empty file should not return 404 i guess
|
|
// if (fileData.empty())
|
|
// {
|
|
// ErrorHandler::createErrorResponse(Http::StatusCode::NOT_FOUND, response_, config_);
|
|
// return;
|
|
// }
|
|
// TODO: annoying: For reading files, vector<char> is preferred, but for http data vector<uint8_t> is preferred
|
|
response_.setBody(std::vector<uint8_t>{fileData.begin(), fileData.end()});
|
|
response_.setStatus(Http::StatusCode::OK);
|
|
// return response;
|
|
}
|
|
|
|
void FileHandler::handleDirectory(const std::string &dirpath, ResourceType type) const
|
|
{
|
|
Log::trace(LOCATION);
|
|
Log::debug("Requested path is a directory: " + dirpath);
|
|
if (type == DIRECTORY_INDEX)
|
|
{
|
|
auto possible_indexes = config_->get<std::vector<std::string>>("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())
|
|
{
|
|
ErrorHandler::createErrorResponse(Http::StatusCode::NOT_FOUND, response_, config_);
|
|
return;
|
|
}
|
|
handleFile(FileUtils::joinPath(dirpath, *first_matching));
|
|
return;
|
|
}
|
|
if (type == DIRECTORY_AUTOINDEX)
|
|
{
|
|
Log::debug("Requested path is a directory: " + dirpath);
|
|
response_.addHeader("Content-Type", "text/html");
|
|
response_.addHeader("Connection", "close");
|
|
response_.setBody(AutoIndex::generate(dirpath, uri_));
|
|
response_.setStatus(Http::StatusCode::OK);
|
|
return;
|
|
}
|
|
ErrorHandler::createErrorResponse(Http::StatusCode::NOT_FOUND, response_, config_);
|
|
}
|
|
|
|
void FileHandler::handle()
|
|
{
|
|
Log::trace(LOCATION);
|
|
if (!uri_.isValid())
|
|
{
|
|
ErrorHandler::createErrorResponse(Http::StatusCode::NOT_FOUND, response_, config_);
|
|
return;
|
|
}
|
|
std::string filepath = uri_.getFullPath();
|
|
Log::debug("Handling file request for path: " + filepath);
|
|
ResourceType resourceType = getResourceType(filepath);
|
|
|
|
switch (resourceType)
|
|
{
|
|
case FILE: handleFile(filepath); return;
|
|
case DIRECTORY_AUTOINDEX:
|
|
case DIRECTORY_INDEX: handleDirectory(filepath, resourceType); return;
|
|
case NOT_FOUND: ErrorHandler::createErrorResponse(Http::StatusCode::NOT_FOUND, response_, config_); return;
|
|
}
|
|
ErrorHandler::createErrorResponse(Http::StatusCode::NOT_FOUND, response_, config_);
|
|
}
|
|
|
|
FileHandler::ResourceType FileHandler::getResourceType(const std::string &path) const
|
|
{
|
|
static_cast<void>(path);
|
|
Log::trace(LOCATION);
|
|
Log::debug("Determining resource type for path: " + path);
|
|
|
|
if (uri_.isFile())
|
|
{
|
|
return FILE;
|
|
}
|
|
if (uri_.isDirectory())
|
|
{
|
|
// if (config_->get<std::vector<std::string>>("index").has_value())
|
|
// {
|
|
// return DIRECTORY_INDEX;
|
|
// }
|
|
if (config_->get<bool>("autoindex").value_or(false))
|
|
{
|
|
return DIRECTORY_AUTOINDEX;
|
|
}
|
|
}
|
|
return NOT_FOUND;
|
|
} |