From 927b9549c29ffaa027f2ea563085251149acdb51 Mon Sep 17 00:00:00 2001 From: Quinten Date: Tue, 30 Sep 2025 20:03:05 +0200 Subject: [PATCH] feat: implement router request handling and error management --- webserv/client/Client.cpp | 53 ++++++++++----------- webserv/client/Client.hpp | 2 +- webserv/config/LocationConfig.cpp | 6 +-- webserv/config/LocationConfig.hpp | 5 +- webserv/config/ServerConfig.cpp | 5 +- webserv/router/Router.cpp | 78 +++++++++++++++++++++++++++++++ webserv/router/Router.hpp | 10 ++++ webserv/server/Server.cpp | 8 +++- webserv/server/Server.hpp | 9 ++-- 9 files changed, 138 insertions(+), 38 deletions(-) diff --git a/webserv/client/Client.cpp b/webserv/client/Client.cpp index 012b3ca..d56842d 100644 --- a/webserv/client/Client.cpp +++ b/webserv/client/Client.cpp @@ -1,4 +1,5 @@ #include "webserv/http/HttpConstants.hpp" + #include #include // for ConfigManager #include // for ServerConfig @@ -75,14 +76,14 @@ void Client::request() {"body", httpRequest_->getBody()}, {"state", std::to_string(static_cast(httpRequest_->getState()))}, }); - server_config_ = - ConfigManager::getInstance().getMatchingServerConfig(httpRequest_->getHeaders().getHost().value_or("")); - if (server_config_ == nullptr) - { - Log::warning("No matching server config found for Host: " + - httpRequest_->getHeaders().getHost().value_or("unknown host")); - setError(Http::StatusCode::BAD_REQUEST); - } + // server_config_ = + // ConfigManager::getInstance().getMatchingServerConfig(httpRequest_->getHeaders().getHost().value_or("")); + // if (server_config_ == nullptr) + // { + // Log::warning("No matching server config found for Host: " + + // httpRequest_->getHeaders().getHost().value_or("unknown host")); + // setError(Http::StatusCode::BAD_REQUEST); + // } // Example usage, replace with actual host and port extraction from request server_.responseReady(client_socket_->getFd()); @@ -107,23 +108,23 @@ bool Client::isResponseReady() const std::vector Client::getResponse() const { Log::trace(LOCATION); - Log::trace(LOCATION); - if (statusCode_ == Http::StatusCode::OK) - { - httpResponse_->setStatus(200); - httpResponse_->addHeader("Content-Type", "text/plain"); - httpResponse_->appendBody("Hello, World!\n"); - } - return httpResponse_->toBytes(); + // if (statusCode_ != Http::StatusCode::OK) + // { + // return httpResponse_->toBytes(); + // } + + const Router &router = server_.getRouter(); + auto response = router.handleRequest(*httpRequest_); + return response.toBytes(); } -void Client::setError(int statusCode) -{ - Log::trace(LOCATION); - statusCode_ = statusCode; - Log::debug("Setting error response with status code: " + std::to_string(statusCode)); - auto errorResponse = std::make_unique( - ErrorHandler::getErrorResponse(statusCode, const_cast(server_config_))); - httpResponse_ = std::move(errorResponse); - Log::debug("Error response set successfully"); -} +// void Client::setError(int statusCode) +// { +// Log::trace(LOCATION); +// statusCode_ = statusCode; +// Log::debug("Setting error response with status code: " + std::to_string(statusCode)); +// auto errorResponse = std::make_unique( +// ErrorHandler::getErrorResponse(statusCode, const_cast(server_config_))); +// httpResponse_ = std::move(errorResponse); +// Log::debug("Error response set successfully"); +// } diff --git a/webserv/client/Client.hpp b/webserv/client/Client.hpp index 0f7b03b..e068e76 100644 --- a/webserv/client/Client.hpp +++ b/webserv/client/Client.hpp @@ -39,7 +39,7 @@ class Client [[nodiscard]] int getStatusCode() const; [[nodiscard]] Socket &getSocket() const { return *client_socket_; } - void setError(int statusCode); + // void setError(int statusCode); void setStatusCode(int code); diff --git a/webserv/config/LocationConfig.cpp b/webserv/config/LocationConfig.cpp index 7bbbea9..8c8d945 100644 --- a/webserv/config/LocationConfig.cpp +++ b/webserv/config/LocationConfig.cpp @@ -1,9 +1,9 @@ -#include - #include // for AConfig +#include #include // for Log, LOCATION -LocationConfig::LocationConfig(const std::string &block, const AConfig *parent) : AConfig(parent) +LocationConfig::LocationConfig(const std::string &block, const std::string &path, const AConfig *parent) + : AConfig(parent), _path(path) { parseBlock(block); } diff --git a/webserv/config/LocationConfig.hpp b/webserv/config/LocationConfig.hpp index 66b9513..7fbcad6 100644 --- a/webserv/config/LocationConfig.hpp +++ b/webserv/config/LocationConfig.hpp @@ -8,7 +8,7 @@ class LocationConfig : public AConfig { public: LocationConfig() = delete; - LocationConfig(const std::string &Block, const AConfig *parent = nullptr); + LocationConfig(const std::string &Block, const std::string &path, const AConfig *parent = nullptr); LocationConfig(const LocationConfig &other) = delete; LocationConfig &operator=(const LocationConfig &other) = delete; @@ -17,6 +17,9 @@ class LocationConfig : public AConfig ~LocationConfig() override = default; + [[nodiscard]] const std::string &getPath() const { return _path; } + private: void parseBlock(const std::string &block) override; + std::string _path; }; \ No newline at end of file diff --git a/webserv/config/ServerConfig.cpp b/webserv/config/ServerConfig.cpp index f33bfb6..8eb9ad5 100644 --- a/webserv/config/ServerConfig.cpp +++ b/webserv/config/ServerConfig.cpp @@ -1,7 +1,6 @@ -#include - #include // for AConfig #include // for LocationConfig +#include #include // for findCorrespondingClosingBrace, trim #include // for Log, LOCATION @@ -44,7 +43,7 @@ void ServerConfig::parseBlock(const std::string &block) } // Optionally parse the server block here std::string locationBlock = block.substr(bracePos + 1, closeBrace - bracePos - 1); - locations_[locationPath] = std::make_unique(locationBlock, this); + locations_[locationPath] = std::make_unique(locationBlock, locationPath, this); Log::debug("Added location: " + locationPath, {{"block", locationBlock}}); pos = closeBrace + 1; } diff --git a/webserv/router/Router.cpp b/webserv/router/Router.cpp index 09e4afe..f8ab561 100644 --- a/webserv/router/Router.cpp +++ b/webserv/router/Router.cpp @@ -1,3 +1,81 @@ +#include "webserv/config/AConfig.hpp" +#include "webserv/config/ConfigManager.hpp" +#include "webserv/config/ServerConfig.hpp" +#include "webserv/handler/ErrorHandler.hpp" +#include "webserv/http/HttpResponse.hpp" +#include "webserv/log/Log.hpp" + #include +#include + Router::Router() {} + +HttpResponse Router::handleRequest(const HttpRequest &request) const +{ + Log::trace(LOCATION); + + ServerConfig *config = + ConfigManager::getInstance().getMatchingServerConfig(request.getHeaders().getHost().value_or("")); + HttpResponse response; + + if (config == nullptr) + { + Log::warning("No matching server config found"); + handleError(400, response); + return response; + } + + const std::string &target = request.getTarget(); + const std::string &method = request.getMethod(); + + const LocationConfig *location = getLocation(target, *config); + if (location == nullptr) + { + Log::warning("No matching location found for target: " + target); + handleError(404, response, config); + return response; + } + + response.setStatus(200); + response.addHeader("Content-Type", "text/plain"); + response.setBody("Hello, World! You requested " + target + " on " + request.getHeaders().getHost().value_or("") + + ". Current resource is " + location->getPath()); + response.setComplete(); + return response; +} + +void Router::handleError(int statusCode, HttpResponse &response, AConfig *config) const +{ + response = ErrorHandler::getErrorResponse(statusCode, config); + response.setComplete(); +} + +const LocationConfig *Router::getLocation(const std::string &path, const ServerConfig &serverConfig) const +{ + const LocationConfig *bestMatch = nullptr; + size_t maxSize = 0; + + std::vector locations = serverConfig.getLocationPaths(); + + for (const auto &locPath : locations) + { + if (!path.starts_with(locPath)) + { + continue; + } + if (locPath.length() > maxSize && + (path.length() == locPath.length() || locPath.back() == '/' || path[locPath.length()] == '/')) + { + maxSize = locPath.length(); + bestMatch = serverConfig.getLocation(locPath); + Log::debug("Found new best match: " + locPath); + } + } + + if (bestMatch == nullptr) + { + Log::warning("No location matched for path: " + path); + } + return bestMatch; +} \ No newline at end of file diff --git a/webserv/router/Router.hpp b/webserv/router/Router.hpp index 10e1177..eb9ea3c 100644 --- a/webserv/router/Router.hpp +++ b/webserv/router/Router.hpp @@ -1,10 +1,20 @@ #pragma once +#include "webserv/config/LocationConfig.hpp" + #include #include +#include + class Router { public: Router(); + + [[nodiscard]] HttpResponse handleRequest(const HttpRequest &request) const; + + private: + void handleError(int statusCode, HttpResponse &response, AConfig *config = nullptr) const; + [[nodiscard]] const LocationConfig *getLocation(const std::string &path, const ServerConfig &serverConfig) const; }; \ No newline at end of file diff --git a/webserv/server/Server.cpp b/webserv/server/Server.cpp index 6093871..47e1b55 100644 --- a/webserv/server/Server.cpp +++ b/webserv/server/Server.cpp @@ -20,7 +20,8 @@ #include // for ssize_t #include // for close -Server::Server(const ConfigManager &configManager) : epoll_fd_(epoll_create1(0)), configManager_(configManager) +Server::Server(const ConfigManager &configManager) + : epoll_fd_(epoll_create1(0)), configManager_(configManager), router_() { Log::trace(LOCATION); const auto &serverConfigs = configManager.getServerConfigs(); @@ -230,3 +231,8 @@ void Server::eventLoop() } } } + +const Router &Server::getRouter() const +{ + return router_; +} \ No newline at end of file diff --git a/webserv/server/Server.hpp b/webserv/server/Server.hpp index ca1af2d..b16ee89 100644 --- a/webserv/server/Server.hpp +++ b/webserv/server/Server.hpp @@ -1,16 +1,17 @@ #pragma once +#include "webserv/router/Router.hpp" + #include #include #include // for ServerConfig #include // for Socket #include // for uint32_t - #include // for unique_ptr +#include // for set #include // for unordered_map #include // for vector -#include // for set class Client; class ConfigManager; @@ -41,13 +42,15 @@ class Server void handleRequest(struct epoll_event *event) const; void responseReady(int client_fd) const; void eventLoop(); + Socket &getListener(int fd) const; Client &getClient(int fd) const; - + const Router &getRouter() const; private: int epoll_fd_; const ConfigManager &configManager_; + const Router router_; std::vector> listeners_; std::set listener_fds_; std::unordered_map> clients_;