feat: implement router request handling and error management

This commit is contained in:
Quinten 2025-09-30 20:03:05 +02:00
parent e1acf5b515
commit 927b9549c2
9 changed files with 138 additions and 38 deletions

View File

@ -1,4 +1,5 @@
#include "webserv/http/HttpConstants.hpp" #include "webserv/http/HttpConstants.hpp"
#include <webserv/client/Client.hpp> #include <webserv/client/Client.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
@ -75,14 +76,14 @@ void Client::request()
{"body", httpRequest_->getBody()}, {"body", httpRequest_->getBody()},
{"state", std::to_string(static_cast<uint8_t>(httpRequest_->getState()))}, {"state", std::to_string(static_cast<uint8_t>(httpRequest_->getState()))},
}); });
server_config_ = // server_config_ =
ConfigManager::getInstance().getMatchingServerConfig(httpRequest_->getHeaders().getHost().value_or("")); // ConfigManager::getInstance().getMatchingServerConfig(httpRequest_->getHeaders().getHost().value_or(""));
if (server_config_ == nullptr) // if (server_config_ == nullptr)
{ // {
Log::warning("No matching server config found for Host: " + // Log::warning("No matching server config found for Host: " +
httpRequest_->getHeaders().getHost().value_or("unknown host")); // httpRequest_->getHeaders().getHost().value_or("unknown host"));
setError(Http::StatusCode::BAD_REQUEST); // setError(Http::StatusCode::BAD_REQUEST);
} // }
// Example usage, replace with actual host and port extraction from request // Example usage, replace with actual host and port extraction from request
server_.responseReady(client_socket_->getFd()); server_.responseReady(client_socket_->getFd());
@ -107,23 +108,23 @@ bool Client::isResponseReady() const
std::vector<uint8_t> Client::getResponse() const std::vector<uint8_t> Client::getResponse() const
{ {
Log::trace(LOCATION); Log::trace(LOCATION);
Log::trace(LOCATION); // if (statusCode_ != Http::StatusCode::OK)
if (statusCode_ == Http::StatusCode::OK) // {
{ // return httpResponse_->toBytes();
httpResponse_->setStatus(200); // }
httpResponse_->addHeader("Content-Type", "text/plain");
httpResponse_->appendBody("Hello, World!\n"); const Router &router = server_.getRouter();
} auto response = router.handleRequest(*httpRequest_);
return httpResponse_->toBytes(); return response.toBytes();
} }
void Client::setError(int statusCode) // void Client::setError(int statusCode)
{ // {
Log::trace(LOCATION); // Log::trace(LOCATION);
statusCode_ = statusCode; // statusCode_ = statusCode;
Log::debug("Setting error response with status code: " + std::to_string(statusCode)); // Log::debug("Setting error response with status code: " + std::to_string(statusCode));
auto errorResponse = std::make_unique<HttpResponse>( // auto errorResponse = std::make_unique<HttpResponse>(
ErrorHandler::getErrorResponse(statusCode, const_cast<ServerConfig *>(server_config_))); // ErrorHandler::getErrorResponse(statusCode, const_cast<ServerConfig *>(server_config_)));
httpResponse_ = std::move(errorResponse); // httpResponse_ = std::move(errorResponse);
Log::debug("Error response set successfully"); // Log::debug("Error response set successfully");
} // }

View File

@ -39,7 +39,7 @@ class Client
[[nodiscard]] int getStatusCode() const; [[nodiscard]] int getStatusCode() const;
[[nodiscard]] Socket &getSocket() const { return *client_socket_; } [[nodiscard]] Socket &getSocket() const { return *client_socket_; }
void setError(int statusCode); // void setError(int statusCode);
void setStatusCode(int code); void setStatusCode(int code);

View File

@ -1,9 +1,9 @@
#include <webserv/config/LocationConfig.hpp>
#include <webserv/config/AConfig.hpp> // for AConfig #include <webserv/config/AConfig.hpp> // for AConfig
#include <webserv/config/LocationConfig.hpp>
#include <webserv/log/Log.hpp> // for Log, LOCATION #include <webserv/log/Log.hpp> // 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); parseBlock(block);
} }

View File

@ -8,7 +8,7 @@ class LocationConfig : public AConfig
{ {
public: public:
LocationConfig() = delete; 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(const LocationConfig &other) = delete;
LocationConfig &operator=(const LocationConfig &other) = delete; LocationConfig &operator=(const LocationConfig &other) = delete;
@ -17,6 +17,9 @@ class LocationConfig : public AConfig
~LocationConfig() override = default; ~LocationConfig() override = default;
[[nodiscard]] const std::string &getPath() const { return _path; }
private: private:
void parseBlock(const std::string &block) override; void parseBlock(const std::string &block) override;
std::string _path;
}; };

View File

@ -1,7 +1,6 @@
#include <webserv/config/ServerConfig.hpp>
#include <webserv/config/AConfig.hpp> // for AConfig #include <webserv/config/AConfig.hpp> // for AConfig
#include <webserv/config/LocationConfig.hpp> // for LocationConfig #include <webserv/config/LocationConfig.hpp> // for LocationConfig
#include <webserv/config/ServerConfig.hpp>
#include <webserv/config/utils.hpp> // for findCorrespondingClosingBrace, trim #include <webserv/config/utils.hpp> // for findCorrespondingClosingBrace, trim
#include <webserv/log/Log.hpp> // for Log, LOCATION #include <webserv/log/Log.hpp> // for Log, LOCATION
@ -44,7 +43,7 @@ void ServerConfig::parseBlock(const std::string &block)
} }
// Optionally parse the server block here // Optionally parse the server block here
std::string locationBlock = block.substr(bracePos + 1, closeBrace - bracePos - 1); std::string locationBlock = block.substr(bracePos + 1, closeBrace - bracePos - 1);
locations_[locationPath] = std::make_unique<LocationConfig>(locationBlock, this); locations_[locationPath] = std::make_unique<LocationConfig>(locationBlock, locationPath, this);
Log::debug("Added location: " + locationPath, {{"block", locationBlock}}); Log::debug("Added location: " + locationPath, {{"block", locationBlock}});
pos = closeBrace + 1; pos = closeBrace + 1;
} }

View File

@ -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 <webserv/router/Router.hpp> #include <webserv/router/Router.hpp>
#include <string>
Router::Router() {} 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<std::string> 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;
}

View File

@ -1,10 +1,20 @@
#pragma once #pragma once
#include "webserv/config/LocationConfig.hpp"
#include <webserv/http/HttpRequest.hpp> #include <webserv/http/HttpRequest.hpp>
#include <webserv/http/HttpResponse.hpp> #include <webserv/http/HttpResponse.hpp>
#include <string>
class Router class Router
{ {
public: public:
Router(); 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;
}; };

View File

@ -20,7 +20,8 @@
#include <sys/types.h> // for ssize_t #include <sys/types.h> // for ssize_t
#include <unistd.h> // for close #include <unistd.h> // 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); Log::trace(LOCATION);
const auto &serverConfigs = configManager.getServerConfigs(); const auto &serverConfigs = configManager.getServerConfigs();
@ -230,3 +231,8 @@ void Server::eventLoop()
} }
} }
} }
const Router &Server::getRouter() const
{
return router_;
}

View File

@ -1,16 +1,17 @@
#pragma once #pragma once
#include "webserv/router/Router.hpp"
#include <webserv/client/Client.hpp> #include <webserv/client/Client.hpp>
#include <webserv/config/ConfigManager.hpp> #include <webserv/config/ConfigManager.hpp>
#include <webserv/config/ServerConfig.hpp> // for ServerConfig #include <webserv/config/ServerConfig.hpp> // for ServerConfig
#include <webserv/socket/Socket.hpp> // for Socket #include <webserv/socket/Socket.hpp> // for Socket
#include <cstdint> // for uint32_t #include <cstdint> // for uint32_t
#include <memory> // for unique_ptr #include <memory> // for unique_ptr
#include <set> // for set
#include <unordered_map> // for unordered_map #include <unordered_map> // for unordered_map
#include <vector> // for vector #include <vector> // for vector
#include <set> // for set
class Client; class Client;
class ConfigManager; class ConfigManager;
@ -41,13 +42,15 @@ class Server
void handleRequest(struct epoll_event *event) const; void handleRequest(struct epoll_event *event) const;
void responseReady(int client_fd) const; void responseReady(int client_fd) const;
void eventLoop(); void eventLoop();
Socket &getListener(int fd) const; Socket &getListener(int fd) const;
Client &getClient(int fd) const; Client &getClient(int fd) const;
const Router &getRouter() const;
private: private:
int epoll_fd_; int epoll_fd_;
const ConfigManager &configManager_; const ConfigManager &configManager_;
const Router router_;
std::vector<std::unique_ptr<Socket>> listeners_; std::vector<std::unique_ptr<Socket>> listeners_;
std::set<int> listener_fds_; std::set<int> listener_fds_;
std::unordered_map<int, std::unique_ptr<Client>> clients_; std::unordered_map<int, std::unique_ptr<Client>> clients_;