refactor: uri parser now does parsing
This commit is contained in:
parent
6b9ce1dda4
commit
c3e5117fcb
@ -52,7 +52,7 @@ std::unique_ptr<ADirective> DirectiveFactory::create(std::string_view type, cons
|
|||||||
{
|
{
|
||||||
throw std::invalid_argument("No factory found for directive type: " + std::string(type));
|
throw std::invalid_argument("No factory found for directive type: " + std::string(type));
|
||||||
}
|
}
|
||||||
return it->second(name, utils::trimSemi(utils::trim(arg)));
|
return it->second(name, utils::trim(arg, " \t\n\r;"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map<std::string_view, DirectiveFactory::CreatorFunc> &DirectiveFactory::getFactories()
|
const std::unordered_map<std::string_view, DirectiveFactory::CreatorFunc> &DirectiveFactory::getFactories()
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include <webserv/config/LocationConfig.hpp> // for LocationConfig
|
#include "webserv/config/AConfig.hpp"
|
||||||
#include <webserv/handler/ErrorHandler.hpp> // for ErrorHandler
|
|
||||||
|
#include <webserv/handler/ErrorHandler.hpp> // for ErrorHandler
|
||||||
#include <webserv/handler/FileHandler.hpp>
|
#include <webserv/handler/FileHandler.hpp>
|
||||||
#include <webserv/handler/MIMETypes.hpp> // for MIMETypes
|
#include <webserv/handler/MIMETypes.hpp> // for MIMETypes
|
||||||
#include <webserv/handler/URIParser.hpp> // for URIParser
|
#include <webserv/handler/URIParser.hpp> // for URIParser
|
||||||
@ -8,16 +9,12 @@
|
|||||||
#include <webserv/log/Log.hpp> // for Log, LOCATION
|
#include <webserv/log/Log.hpp> // for Log, LOCATION
|
||||||
#include <webserv/utils/FileUtils.hpp> // for joinPath, getExtension, isFile, readBinaryFile
|
#include <webserv/utils/FileUtils.hpp> // for joinPath, getExtension, isFile, readBinaryFile
|
||||||
|
|
||||||
#include <functional> // for identity
|
#include <memory> // for unique_ptr, allocator, make_unique
|
||||||
#include <memory> // for unique_ptr, allocator, make_unique
|
#include <ranges>
|
||||||
#include <optional> // for optional
|
#include <string> // for basic_string, string, operator+, char_traits
|
||||||
#include <ranges> // for __find_if_fn, find_if
|
#include <vector> // for vector
|
||||||
#include <string> // for basic_string, string, operator+, char_traits
|
|
||||||
#include <utility> // for move
|
|
||||||
#include <vector> // for vector
|
|
||||||
|
|
||||||
FileHandler::FileHandler(const LocationConfig *location, const URIParser &uriParser)
|
FileHandler::FileHandler(const AConfig *config, const URIParser &uriParser) : config_(config), uriParser_(uriParser)
|
||||||
: location_(location), uriParser_(uriParser)
|
|
||||||
{
|
{
|
||||||
Log::trace(LOCATION);
|
Log::trace(LOCATION);
|
||||||
}
|
}
|
||||||
@ -35,7 +32,7 @@ std::unique_ptr<HttpResponse> FileHandler::handleFile(const std::string &filepat
|
|||||||
Log::debug("Serving file: " + filepath + " with MIME type: " + mimeType);
|
Log::debug("Serving file: " + filepath + " with MIME type: " + mimeType);
|
||||||
if (fileData.empty())
|
if (fileData.empty())
|
||||||
{
|
{
|
||||||
return ErrorHandler::getErrorResponse(Http::StatusCode::NOT_FOUND, location_);
|
return ErrorHandler::getErrorResponse(Http::StatusCode::NOT_FOUND, config_);
|
||||||
}
|
}
|
||||||
// TODO: annoying: For reading files, vector<char> is preferred, but for http data vector<uint8_t> is preferred
|
// 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->setBody(std::vector<uint8_t>{fileData.begin(), fileData.end()});
|
||||||
@ -49,28 +46,28 @@ std::unique_ptr<HttpResponse> FileHandler::handleDirectory(const std::string &di
|
|||||||
|
|
||||||
if (type == DIRECTORY_INDEX)
|
if (type == DIRECTORY_INDEX)
|
||||||
{
|
{
|
||||||
auto possible_indexes = location_->get<std::vector<std::string>>("index").value();
|
auto possible_indexes = config_->get<std::vector<std::string>>("index").value();
|
||||||
auto first_matching = std::ranges::find_if(possible_indexes, [&](const std::string &index) {
|
auto first_matching = std::ranges::find_if(possible_indexes, [&](const std::string &index) {
|
||||||
return FileUtils::isFile(FileUtils::joinPath(dirpath, index));
|
return FileUtils::isFile(FileUtils::joinPath(dirpath, index));
|
||||||
});
|
});
|
||||||
if (first_matching == possible_indexes.end())
|
if (first_matching == possible_indexes.end())
|
||||||
{
|
{
|
||||||
return ErrorHandler::getErrorResponse(Http::StatusCode::FORBIDDEN, location_);
|
return ErrorHandler::getErrorResponse(Http::StatusCode::FORBIDDEN, config_);
|
||||||
}
|
}
|
||||||
return handleFile(FileUtils::joinPath(dirpath, *first_matching));
|
return handleFile(FileUtils::joinPath(dirpath, *first_matching));
|
||||||
}
|
}
|
||||||
if (type == DIRECTORY_AUTOINDEX)
|
if (type == DIRECTORY_AUTOINDEX)
|
||||||
{
|
{
|
||||||
Log::debug("Requested path is a directory: " + dirpath);
|
Log::debug("Requested path is a directory: " + dirpath);
|
||||||
return ErrorHandler::getErrorResponse(Http::StatusCode::FORBIDDEN, location_);
|
return ErrorHandler::getErrorResponse(Http::StatusCode::FORBIDDEN, config_);
|
||||||
}
|
}
|
||||||
return ErrorHandler::getErrorResponse(Http::StatusCode::NOT_FOUND, location_);
|
return ErrorHandler::getErrorResponse(Http::StatusCode::NOT_FOUND, config_);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<HttpResponse> FileHandler::getResponse() const
|
std::unique_ptr<HttpResponse> FileHandler::getResponse() const
|
||||||
{
|
{
|
||||||
Log::trace(LOCATION);
|
Log::trace(LOCATION);
|
||||||
std::string filepath = uriParser_.getFilePath();
|
std::string filepath = uriParser_.getFullPath();
|
||||||
ResourceType resourceType = getResourceType(filepath);
|
ResourceType resourceType = getResourceType(filepath);
|
||||||
|
|
||||||
switch (resourceType)
|
switch (resourceType)
|
||||||
@ -78,9 +75,9 @@ std::unique_ptr<HttpResponse> FileHandler::getResponse() const
|
|||||||
case FILE: return handleFile(filepath);
|
case FILE: return handleFile(filepath);
|
||||||
case DIRECTORY_AUTOINDEX:
|
case DIRECTORY_AUTOINDEX:
|
||||||
case DIRECTORY_INDEX: return handleDirectory(filepath, resourceType);
|
case DIRECTORY_INDEX: return handleDirectory(filepath, resourceType);
|
||||||
case NOT_FOUND: return ErrorHandler::getErrorResponse(Http::StatusCode::NOT_FOUND, location_);
|
case NOT_FOUND: return ErrorHandler::getErrorResponse(Http::StatusCode::NOT_FOUND, config_);
|
||||||
}
|
}
|
||||||
return ErrorHandler::getErrorResponse(Http::StatusCode::NOT_FOUND, location_);
|
return ErrorHandler::getErrorResponse(Http::StatusCode::NOT_FOUND, config_);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileHandler::ResourceType FileHandler::getResourceType(const std::string &path) const
|
FileHandler::ResourceType FileHandler::getResourceType(const std::string &path) const
|
||||||
@ -94,11 +91,11 @@ FileHandler::ResourceType FileHandler::getResourceType(const std::string &path)
|
|||||||
}
|
}
|
||||||
if (uriParser_.isDirectory())
|
if (uriParser_.isDirectory())
|
||||||
{
|
{
|
||||||
if (location_->get<std::vector<std::string>>("index").has_value())
|
if (config_->get<std::vector<std::string>>("index").has_value())
|
||||||
{
|
{
|
||||||
return DIRECTORY_INDEX;
|
return DIRECTORY_INDEX;
|
||||||
}
|
}
|
||||||
if (location_->get<bool>("autoindex").value_or(false))
|
if (config_->get<bool>("autoindex").value_or(false))
|
||||||
{
|
{
|
||||||
return DIRECTORY_AUTOINDEX;
|
return DIRECTORY_AUTOINDEX;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "webserv/config/AConfig.hpp"
|
||||||
|
|
||||||
#include <webserv/config/LocationConfig.hpp>
|
#include <webserv/config/LocationConfig.hpp>
|
||||||
#include <webserv/handler/URIParser.hpp>
|
#include <webserv/handler/URIParser.hpp>
|
||||||
#include <webserv/http/HttpResponse.hpp> // for HttpResponse
|
#include <webserv/http/HttpResponse.hpp> // for HttpResponse
|
||||||
@ -8,18 +10,18 @@
|
|||||||
#include <memory> // for unique_ptr
|
#include <memory> // for unique_ptr
|
||||||
#include <string> // for string
|
#include <string> // for string
|
||||||
|
|
||||||
class LocationConfig;
|
class AConfig;
|
||||||
class URIParser;
|
class URIParser;
|
||||||
|
|
||||||
class FileHandler
|
class FileHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FileHandler(const LocationConfig *location, const URIParser &uriParser);
|
FileHandler(const AConfig *config, const URIParser &uriParser);
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<HttpResponse> getResponse() const;
|
[[nodiscard]] std::unique_ptr<HttpResponse> getResponse() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const LocationConfig *location_;
|
const AConfig *config_;
|
||||||
const URIParser &uriParser_;
|
const URIParser &uriParser_;
|
||||||
|
|
||||||
enum ResourceType : uint8_t
|
enum ResourceType : uint8_t
|
||||||
|
|||||||
@ -1,96 +1,155 @@
|
|||||||
#include <webserv/handler/URIParser.hpp>
|
#include "webserv/config/AConfig.hpp"
|
||||||
|
#include "webserv/utils/FileUtils.hpp"
|
||||||
|
#include "webserv/utils/utils.hpp"
|
||||||
|
|
||||||
#include <webserv/config/LocationConfig.hpp> // for LocationConfig
|
#include <webserv/config/LocationConfig.hpp> // for LocationConfig
|
||||||
#include <webserv/config/ServerConfig.hpp> // for ServerConfig
|
#include <webserv/config/ServerConfig.hpp> // for ServerConfig
|
||||||
|
#include <webserv/handler/URIParser.hpp>
|
||||||
|
|
||||||
#include <optional> // for optional
|
#include <optional> // for optional
|
||||||
|
|
||||||
#include <stddef.h> // for size_t
|
#include <stddef.h> // for size_t
|
||||||
#include <sys/stat.h> // for stat, S_ISDIR, S_ISREG
|
#include <sys/stat.h> // for stat, S_ISDIR, S_ISREG
|
||||||
|
|
||||||
URIParser::URIParser(const std::string &uri, const ServerConfig &serverConfig) : _locationConfig(nullptr)
|
URIParser::URIParser(const std::string &uri, const ServerConfig &serverConfig)
|
||||||
|
: uriTrimmed_(utils::trim(uri, "/")), config_(matchConfig(uriTrimmed_, serverConfig))
|
||||||
|
{
|
||||||
|
parseUri(uri);
|
||||||
|
parseFullpath();
|
||||||
|
}
|
||||||
|
|
||||||
|
const AConfig *URIParser::matchConfig(const std::string &uri, const ServerConfig &serverConfig)
|
||||||
{
|
{
|
||||||
const auto &locations = serverConfig.getLocationPaths();
|
const auto &locations = serverConfig.getLocationPaths();
|
||||||
size_t maxMatchLength = 0;
|
const AConfig *bestMatch = &serverConfig;
|
||||||
|
|
||||||
|
size_t maxMatchLength = 0;
|
||||||
for (const auto &locationPath : locations)
|
for (const auto &locationPath : locations)
|
||||||
{
|
{
|
||||||
if (uri.starts_with((locationPath == "/") ? locationPath : locationPath + "/"))
|
if (uri.empty() && locationPath == "/")
|
||||||
{ // TODO HMHMMz why does it need to end on a /?
|
{
|
||||||
|
return serverConfig.getLocation(locationPath);
|
||||||
|
}
|
||||||
|
if (uri.starts_with(utils::trim(locationPath, "/")))
|
||||||
|
{
|
||||||
if (locationPath.length() > maxMatchLength)
|
if (locationPath.length() > maxMatchLength)
|
||||||
{
|
{
|
||||||
maxMatchLength = locationPath.length();
|
maxMatchLength = locationPath.length();
|
||||||
_locationConfig = serverConfig.getLocation(locationPath);
|
bestMatch = serverConfig.getLocation(locationPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return bestMatch;
|
||||||
|
}
|
||||||
|
|
||||||
root_ = _locationConfig != nullptr ? _locationConfig->get<std::string>("root").value_or("") : "";
|
void URIParser::parseUri(const std::string &uri)
|
||||||
if (!root_.empty() && root_.back() == '/')
|
{
|
||||||
|
if (config_->getType() == "server")
|
||||||
{
|
{
|
||||||
root_.pop_back(); // Remove trailing slash to avoid double slashes in path
|
fullPath_ = FileUtils::joinPath(config_->get<std::string>("root").value_or(""), uriTrimmed_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto const *locConfig = dynamic_cast<LocationConfig const *>(config_);
|
||||||
|
std::string locTrimmed = utils::trim(locConfig->getPath(), "/");
|
||||||
|
std::string uriSub = uri.substr(locTrimmed.length());
|
||||||
|
fullPath_ = FileUtils::joinPath(locConfig->get<std::string>("root").value_or(""), uriSub);
|
||||||
}
|
}
|
||||||
|
|
||||||
relativePath_ = uri.substr(maxMatchLength);
|
size_t fragmentPos = fullPath_.find_first_of('#');
|
||||||
if (relativePath_.empty() || relativePath_[0] != '/')
|
if (fragmentPos != std::string::npos)
|
||||||
{
|
{
|
||||||
relativePath_ = "/" + relativePath_;
|
fragment_ = fullPath_.substr(fragmentPos + 1);
|
||||||
|
fullPath_ = fullPath_.substr(0, fragmentPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t queryPos = fullPath_.find_first_of('?');
|
||||||
|
if (queryPos != std::string::npos)
|
||||||
|
{
|
||||||
|
query_ = fullPath_.substr(queryPos + 1);
|
||||||
|
fullPath_ = fullPath_.substr(0, queryPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string URIParser::getFilePath() const
|
void URIParser::parseFullpath()
|
||||||
{
|
{
|
||||||
return root_ + relativePath_;
|
auto uriSegments = utils::split(fullPath_, '/');
|
||||||
}
|
|
||||||
|
|
||||||
std::string URIParser::getFilename() const
|
for (const auto &segment : uriSegments)
|
||||||
{
|
|
||||||
size_t lastSlash = relativePath_.find_last_of('/');
|
|
||||||
if (lastSlash == std::string::npos)
|
|
||||||
{
|
{
|
||||||
return relativePath_; // No slashes, return the whole path
|
std::string curDir = FileUtils::joinPath(dir_, segment);
|
||||||
|
if (segment.empty())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FileUtils::isFile(curDir) && baseName_.empty())
|
||||||
|
{
|
||||||
|
baseName_ = segment;
|
||||||
|
}
|
||||||
|
else if (FileUtils::isDirectory(curDir))
|
||||||
|
{
|
||||||
|
dir_ = FileUtils::joinPath(dir_, segment);
|
||||||
|
}
|
||||||
|
else if (!baseName_.empty()) // not file or dir, but we have a baseName already
|
||||||
|
{
|
||||||
|
pathInfo_ = FileUtils::joinPath(pathInfo_, baseName_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return relativePath_.substr(lastSlash + 1);
|
fullPath_ = FileUtils::joinPath(dir_, baseName_);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string URIParser::getExtension() const
|
const AConfig *URIParser::getConfig() const
|
||||||
{
|
{
|
||||||
std::string filename = getFilename();
|
return config_;
|
||||||
size_t lastDot = filename.find_last_of('.');
|
|
||||||
if (lastDot == std::string::npos || lastDot == 0 || lastDot == filename.length() - 1)
|
|
||||||
{
|
|
||||||
return ""; // No extension found or dot is at start/end
|
|
||||||
}
|
|
||||||
return filename.substr(lastDot + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
LocationConfig const *URIParser::getLocation() const
|
|
||||||
{
|
|
||||||
return _locationConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool URIParser::isFile() const
|
bool URIParser::isFile() const
|
||||||
{
|
{
|
||||||
struct stat pathStat{};
|
return !baseName_.empty();
|
||||||
if (stat(getFilePath().c_str(), &pathStat) != 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return S_ISREG(pathStat.st_mode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool URIParser::isDirectory() const
|
bool URIParser::isDirectory() const
|
||||||
{
|
{
|
||||||
struct stat pathStat{};
|
return baseName_.empty();
|
||||||
if (stat(getFilePath().c_str(), &pathStat) != 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return S_ISDIR(pathStat.st_mode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool URIParser::isValid() const
|
bool URIParser::isValid() const
|
||||||
{
|
{
|
||||||
struct stat pathStat{};
|
return FileUtils::isValidPath(fullPath_);
|
||||||
return stat(getFilePath().c_str(), &pathStat) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string &URIParser::getBaseName() const
|
||||||
|
{
|
||||||
|
return baseName_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string URIParser::getExtension() const
|
||||||
|
{
|
||||||
|
return FileUtils::getExtension(baseName_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &URIParser::getFullPath() const
|
||||||
|
{
|
||||||
|
return fullPath_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &URIParser::getDir() const
|
||||||
|
{
|
||||||
|
return dir_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &URIParser::getPathInfo() const
|
||||||
|
{
|
||||||
|
return pathInfo_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &URIParser::getQuery() const
|
||||||
|
{
|
||||||
|
return query_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &URIParser::getFragment() const
|
||||||
|
{
|
||||||
|
return fragment_;
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "webserv/config/AConfig.hpp"
|
||||||
|
|
||||||
#include <webserv/config/LocationConfig.hpp>
|
#include <webserv/config/LocationConfig.hpp>
|
||||||
#include <webserv/config/ServerConfig.hpp>
|
#include <webserv/config/ServerConfig.hpp>
|
||||||
#include <webserv/server/Server.hpp>
|
#include <webserv/server/Server.hpp>
|
||||||
@ -14,19 +16,31 @@ class URIParser
|
|||||||
public:
|
public:
|
||||||
URIParser(const std::string &uri, const ServerConfig &serverConfig);
|
URIParser(const std::string &uri, const ServerConfig &serverConfig);
|
||||||
|
|
||||||
[[nodiscard]] std::string getFilePath() const;
|
|
||||||
[[nodiscard]] std::string getFilename() const;
|
|
||||||
[[nodiscard]] std::string getExtension() const;
|
|
||||||
|
|
||||||
[[nodiscard]] const LocationConfig *getLocation() const;
|
|
||||||
|
|
||||||
[[nodiscard]] bool isFile() const;
|
[[nodiscard]] bool isFile() const;
|
||||||
|
|
||||||
[[nodiscard]] bool isDirectory() const;
|
[[nodiscard]] bool isDirectory() const;
|
||||||
[[nodiscard]] bool isValid() const;
|
[[nodiscard]] bool isValid() const;
|
||||||
|
|
||||||
|
[[nodiscard]] std::string getExtension() const;
|
||||||
|
[[nodiscard]] const AConfig *getConfig() const;
|
||||||
|
[[nodiscard]] const std::string &getBaseName() const;
|
||||||
|
[[nodiscard]] const std::string &getFullPath() const;
|
||||||
|
[[nodiscard]] const std::string &getDir() const;
|
||||||
|
[[nodiscard]] const std::string &getPathInfo() const;
|
||||||
|
[[nodiscard]] const std::string &getQuery() const;
|
||||||
|
[[nodiscard]] const std::string &getFragment() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const LocationConfig *_locationConfig;
|
void parseUri(const std::string &uri);
|
||||||
std::string relativePath_;
|
void parseFullpath();
|
||||||
std::string root_;
|
|
||||||
|
std::string uriTrimmed_;
|
||||||
|
const AConfig *config_;
|
||||||
|
std::string fullPath_; // dir_ + baseName_ + pathInfo_
|
||||||
|
std::string baseName_;
|
||||||
|
std::string dir_;
|
||||||
|
std::string pathInfo_;
|
||||||
|
std::string query_;
|
||||||
|
std::string fragment_;
|
||||||
|
|
||||||
|
static const AConfig *matchConfig(const std::string &uri, const ServerConfig &serverConfig);
|
||||||
};
|
};
|
||||||
@ -1,14 +1,14 @@
|
|||||||
#include <webserv/router/Router.hpp>
|
#include "webserv/config/AConfig.hpp"
|
||||||
|
|
||||||
#include <webserv/config/directive/ADirective.hpp>
|
|
||||||
|
|
||||||
#include <webserv/config/ConfigManager.hpp> // for ConfigManager
|
#include <webserv/config/ConfigManager.hpp> // for ConfigManager
|
||||||
#include <webserv/config/ServerConfig.hpp> // for ServerConfig
|
#include <webserv/config/ServerConfig.hpp> // for ServerConfig
|
||||||
|
#include <webserv/config/directive/ADirective.hpp>
|
||||||
#include <webserv/handler/ErrorHandler.hpp> // for ErrorHandler
|
#include <webserv/handler/ErrorHandler.hpp> // for ErrorHandler
|
||||||
#include <webserv/handler/FileHandler.hpp> // for FileHandler
|
#include <webserv/handler/FileHandler.hpp> // for FileHandler
|
||||||
#include <webserv/handler/URIParser.hpp> // for URIParser
|
#include <webserv/handler/URIParser.hpp> // for URIParser
|
||||||
#include <webserv/http/HttpHeaders.hpp> // for HttpHeaders
|
#include <webserv/http/HttpHeaders.hpp> // for HttpHeaders
|
||||||
#include <webserv/log/Log.hpp> // for LOCATION, Log
|
#include <webserv/log/Log.hpp> // for LOCATION, Log
|
||||||
|
#include <webserv/router/Router.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory> // for unique_ptr
|
#include <memory> // for unique_ptr
|
||||||
@ -18,11 +18,9 @@
|
|||||||
|
|
||||||
class LocationConfig;
|
class LocationConfig;
|
||||||
|
|
||||||
Router::Router() {}
|
bool Router::isMethodSupported(const std::string &method, const AConfig &config)
|
||||||
|
|
||||||
bool Router::isMethodSupported(const std::string &method, const LocationConfig &location)
|
|
||||||
{
|
{
|
||||||
const ADirective *allowedMethods = location.getDirective("allowed_methods");
|
const ADirective *allowedMethods = config.getDirective("allowed_methods");
|
||||||
if (allowedMethods == nullptr || !allowedMethods->getValue().try_get<std::vector<std::string>>().has_value())
|
if (allowedMethods == nullptr || !allowedMethods->getValue().try_get<std::vector<std::string>>().has_value())
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@ -35,28 +33,24 @@ std::unique_ptr<HttpResponse> Router::handleRequest(const HttpRequest &request)
|
|||||||
{
|
{
|
||||||
Log::trace(LOCATION);
|
Log::trace(LOCATION);
|
||||||
|
|
||||||
ServerConfig *config =
|
ServerConfig *serverConfig =
|
||||||
ConfigManager::getInstance().getMatchingServerConfig(request.getHeaders().getHost().value_or(""));
|
ConfigManager::getInstance().getMatchingServerConfig(request.getHeaders().getHost().value_or(""));
|
||||||
|
|
||||||
if (config == nullptr)
|
if (serverConfig == nullptr)
|
||||||
{
|
{
|
||||||
return ErrorHandler::getErrorResponse(400);
|
return ErrorHandler::getErrorResponse(400);
|
||||||
}
|
}
|
||||||
URIParser uriParser{request.getTarget(), *config};
|
URIParser uriParser{request.getTarget(), *serverConfig};
|
||||||
|
|
||||||
const std::string &target = request.getTarget();
|
const std::string &target = request.getTarget();
|
||||||
static_cast<void>(target); // Suppress unused variable warning
|
static_cast<void>(target); // Suppress unused variable warning
|
||||||
const std::string &method = request.getMethod();
|
const std::string &method = request.getMethod();
|
||||||
|
|
||||||
const LocationConfig *location = uriParser.getLocation();
|
const AConfig *config = uriParser.getConfig();
|
||||||
if (location == nullptr)
|
if (!isMethodSupported(method, *config))
|
||||||
{
|
|
||||||
return ErrorHandler::getErrorResponse(404, config);
|
|
||||||
}
|
|
||||||
if (!isMethodSupported(method, *location))
|
|
||||||
{
|
{
|
||||||
return ErrorHandler::getErrorResponse(405, config);
|
return ErrorHandler::getErrorResponse(405, config);
|
||||||
}
|
}
|
||||||
FileHandler fileHandler(location, uriParser);
|
FileHandler fileHandler(config, uriParser);
|
||||||
return fileHandler.getResponse();
|
return fileHandler.getResponse();
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "webserv/config/AConfig.hpp"
|
||||||
#include <webserv/config/LocationConfig.hpp>
|
#include <webserv/config/LocationConfig.hpp>
|
||||||
#include <webserv/http/HttpRequest.hpp> // for HttpRequest
|
#include <webserv/http/HttpRequest.hpp> // for HttpRequest
|
||||||
#include <webserv/http/HttpResponse.hpp> // for HttpResponse
|
#include <webserv/http/HttpResponse.hpp> // for HttpResponse
|
||||||
@ -13,11 +14,8 @@ class ServerConfig;
|
|||||||
class Router
|
class Router
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Router();
|
|
||||||
|
|
||||||
[[nodiscard]] static std::unique_ptr<HttpResponse> handleRequest(const HttpRequest &request);
|
[[nodiscard]] static std::unique_ptr<HttpResponse> handleRequest(const HttpRequest &request);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] const LocationConfig *getLocation(const std::string &path, const ServerConfig &serverConfig) const;
|
[[nodiscard]] static bool isMethodSupported(const std::string &method, const AConfig &config);
|
||||||
[[nodiscard]] static bool isMethodSupported(const std::string &method, const LocationConfig &location);
|
|
||||||
};
|
};
|
||||||
@ -1,6 +1,5 @@
|
|||||||
#include <webserv/utils/FileUtils.hpp>
|
|
||||||
|
|
||||||
#include <webserv/log/Log.hpp> // for Log, LOCATION
|
#include <webserv/log/Log.hpp> // for Log, LOCATION
|
||||||
|
#include <webserv/utils/FileUtils.hpp>
|
||||||
|
|
||||||
#include <cstring> // for size_t
|
#include <cstring> // for size_t
|
||||||
#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
|
||||||
@ -31,6 +30,12 @@ bool isFile(const std::string &path)
|
|||||||
return S_ISREG(pathStat.st_mode);
|
return S_ISREG(pathStat.st_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isValidPath(const std::string &path)
|
||||||
|
{
|
||||||
|
struct stat pathStat{};
|
||||||
|
return stat(path.c_str(), &pathStat) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
std::string getExtension(const std::string &filename)
|
std::string getExtension(const std::string &filename)
|
||||||
{
|
{
|
||||||
size_t dotPos = filename.find_last_of('.');
|
size_t dotPos = filename.find_last_of('.');
|
||||||
|
|||||||
@ -7,6 +7,7 @@ namespace FileUtils
|
|||||||
{
|
{
|
||||||
bool isDirectory(const std::string &path);
|
bool isDirectory(const std::string &path);
|
||||||
bool isFile(const std::string &path);
|
bool isFile(const std::string &path);
|
||||||
|
bool isValidPath(const std::string &path);
|
||||||
|
|
||||||
std::string getExtension(const std::string &filename);
|
std::string getExtension(const std::string &filename);
|
||||||
std::string joinPath(const std::string &base, const std::string &addition);
|
std::string joinPath(const std::string &base, const std::string &addition);
|
||||||
|
|||||||
@ -23,10 +23,10 @@ size_t stoul(const std::string &str, int base)
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string trim(const std::string &str)
|
std::string trim(const std::string &str, const std::string &charset)
|
||||||
{
|
{
|
||||||
size_t first = str.find_first_not_of(" \t\n\r");
|
size_t first = str.find_first_not_of(charset);
|
||||||
size_t last = str.find_last_not_of(" \t\n\r");
|
size_t last = str.find_last_not_of(charset);
|
||||||
if (first == std::string::npos || last == std::string::npos)
|
if (first == std::string::npos || last == std::string::npos)
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
@ -82,7 +82,7 @@ void removeEmptyLines(std::string &str)
|
|||||||
{
|
{
|
||||||
if (!utils::trim(line).empty())
|
if (!utils::trim(line).empty())
|
||||||
{
|
{
|
||||||
result += utils::trimSemi(utils::trim(line)) + '\n';
|
result += utils::trim(line, " \t\n\r;") + '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
str = result;
|
str = result;
|
||||||
|
|||||||
@ -7,8 +7,8 @@
|
|||||||
namespace utils
|
namespace utils
|
||||||
{
|
{
|
||||||
size_t stoul(const std::string &str, int base = 10);
|
size_t stoul(const std::string &str, int base = 10);
|
||||||
std::string trimSemi(const std::string &str);
|
// std::string trimSemi(const std::string &str);
|
||||||
std::string trim(const std::string &str);
|
std::string trim(const std::string &str, const std::string &charset = " \t\n\r");
|
||||||
size_t findCorrespondingClosingBrace(const std::string &str, size_t openPos);
|
size_t findCorrespondingClosingBrace(const std::string &str, size_t openPos);
|
||||||
void removeEmptyLines(std::string &str);
|
void removeEmptyLines(std::string &str);
|
||||||
void removeComments(std::string &str);
|
void removeComments(std::string &str);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user