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/client/Client.hpp>
#include <webserv/config/ConfigManager.hpp> // for ConfigManager
#include <webserv/config/ServerConfig.hpp> // for ServerConfig
@ -75,14 +76,14 @@ void Client::request()
{"body", httpRequest_->getBody()},
{"state", std::to_string(static_cast<uint8_t>(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<uint8_t> 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<HttpResponse>(
ErrorHandler::getErrorResponse(statusCode, const_cast<ServerConfig *>(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<HttpResponse>(
// ErrorHandler::getErrorResponse(statusCode, const_cast<ServerConfig *>(server_config_)));
// httpResponse_ = std::move(errorResponse);
// Log::debug("Error response set successfully");
// }

View File

@ -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);

View File

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

View File

@ -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;
};

View File

@ -1,7 +1,6 @@
#include <webserv/config/ServerConfig.hpp>
#include <webserv/config/AConfig.hpp> // for AConfig
#include <webserv/config/LocationConfig.hpp> // for LocationConfig
#include <webserv/config/ServerConfig.hpp>
#include <webserv/config/utils.hpp> // for findCorrespondingClosingBrace, trim
#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
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}});
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 <string>
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
#include "webserv/config/LocationConfig.hpp"
#include <webserv/http/HttpRequest.hpp>
#include <webserv/http/HttpResponse.hpp>
#include <string>
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;
};

View File

@ -20,7 +20,8 @@
#include <sys/types.h> // for ssize_t
#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);
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
#include "webserv/router/Router.hpp"
#include <webserv/client/Client.hpp>
#include <webserv/config/ConfigManager.hpp>
#include <webserv/config/ServerConfig.hpp> // for ServerConfig
#include <webserv/socket/Socket.hpp> // for Socket
#include <cstdint> // for uint32_t
#include <memory> // for unique_ptr
#include <set> // for set
#include <unordered_map> // for unordered_map
#include <vector> // for vector
#include <set> // 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<std::unique_ptr<Socket>> listeners_;
std::set<int> listener_fds_;
std::unordered_map<int, std::unique_ptr<Client>> clients_;