refactor: simplify Client and HttpRequest constructors, add status code management

This commit is contained in:
whaffman 2025-09-29 16:09:40 +02:00
parent ae1b10c60b
commit 787432ff0c
12 changed files with 132 additions and 26 deletions

View File

@ -1,3 +1,4 @@
#include "webserv/config/ConfigManager.hpp"
#include <webserv/client/Client.hpp> #include <webserv/client/Client.hpp>
#include <webserv/http/HttpHeaders.hpp> // for HttpHeaders #include <webserv/http/HttpHeaders.hpp> // for HttpHeaders
#include <webserv/log/Log.hpp> // for Log, LOCATION #include <webserv/log/Log.hpp> // for Log, LOCATION
@ -13,9 +14,9 @@
class ServerConfig; class ServerConfig;
Client::Client(std::unique_ptr<Socket> socket, Server &server, const ServerConfig &server_config) Client::Client(std::unique_ptr<Socket> socket, Server &server)
: client_socket_(std::move(socket)), server_(std::ref(server)), server_config_(std::cref(server_config)), : client_socket_(std::move(socket)), server_(std::ref(server)),
httpRequest_(std::make_unique<HttpRequest>(&server_config, this)) httpRequest_(std::make_unique<HttpRequest>(this))
{ {
} }
@ -25,6 +26,16 @@ Client::~Client()
server_.removeFromEpoll(*client_socket_); server_.removeFromEpoll(*client_socket_);
}; };
int Client::getStatusCode() const
{
return statusCode_;
}
void Client::setStatusCode(int code)
{
statusCode_ = code;
}
void Client::request() void Client::request()
{ {
char buffer[bufferSize_] = {}; // NOLINT(cppcoreguidelines-avoid-c-arrays) char buffer[bufferSize_] = {}; // NOLINT(cppcoreguidelines-avoid-c-arrays)
@ -56,6 +67,13 @@ 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_ = ConfigManager::getInstance().getMatchingServerConfig(httpRequest_->getHeaders().get("Host"));
if (server_config_ == nullptr)
{
Log::warning("No matching server config found for Host: " + httpRequest_->getHeaders().get("Host"));
httpRequest_->setState(HttpRequest::State::ParseError);
}
// Example usage, replace with actual host and port extraction from request
server_.responseReady(client_socket_->getFd()); server_.responseReady(client_socket_->getFd());
} }
else else
@ -79,10 +97,16 @@ std::string Client::getResponse() const
else else
{ {
response += "200 OK\r\n"; response += "200 OK\r\n";
}
// further validation can be added here // further validation can be added here
response += "Content-Length: 18\r\n\r\n";
response += "Server port 8080\r\n"; auto serverName = server_config_->getDirectiveValue<std::string>("server_name");
auto port = server_config_->getDirectiveValue<int>("listen");
std::string body = "Server Name " + serverName + "\r\n";
body += "Server port " + std::to_string(port) + "\r\n";
response += "Content-Length: " + std::to_string(body.size()) + "\r\n\r\n";
response += body;
}
Log::debug("Sending response:\n" + response); Log::debug("Sending response:\n" + response);
return response; return response;

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <webserv/config/ServerConfig.hpp> // for ServerConfig #include <webserv/config/ServerConfig.hpp> // for ServerConfig
#include <webserv/http/HttpConstants.hpp> // for StatusCode, HTTP
#include <webserv/http/HttpRequest.hpp> // for HttpRequest #include <webserv/http/HttpRequest.hpp> // for HttpRequest
#include <webserv/server/Server.hpp> #include <webserv/server/Server.hpp>
#include <webserv/socket/Socket.hpp> #include <webserv/socket/Socket.hpp>
@ -16,7 +17,7 @@ class ServerConfig;
class Client class Client
{ {
public: public:
Client(std::unique_ptr<Socket> socket, Server &server, const ServerConfig &server_config); Client(std::unique_ptr<Socket> socket, Server &server);
Client(const Client &other) = delete; // Disable copy constructor Client(const Client &other) = delete; // Disable copy constructor
Client &operator=(const Client &other) = delete; // Disable copy assignment Client &operator=(const Client &other) = delete; // Disable copy assignment
@ -28,10 +29,14 @@ class Client
void request(); void request();
[[nodiscard]] std::string getResponse() const; [[nodiscard]] std::string getResponse() const;
[[nodiscard]] int getStatusCode() const;
void setStatusCode(int code);
private: private:
int statusCode_ = Http::StatusCode::OK;
constexpr static size_t bufferSize_ = 4096; constexpr static size_t bufferSize_ = 4096;
std::unique_ptr<HttpRequest> httpRequest_ = nullptr; std::unique_ptr<HttpRequest> httpRequest_ = nullptr;
std::unique_ptr<Socket> client_socket_; std::unique_ptr<Socket> client_socket_;
const Server &server_; Server &server_;
const ServerConfig &server_config_; mutable const ServerConfig *server_config_ = nullptr;
}; };

View File

@ -1,3 +1,4 @@
#include "webserv/config/ServerConfig.hpp"
#include <webserv/config/ConfigManager.hpp> #include <webserv/config/ConfigManager.hpp>
#include <webserv/config/GlobalConfig.hpp> // for GlobalConfig #include <webserv/config/GlobalConfig.hpp> // for GlobalConfig
#include <webserv/config/utils.hpp> // for removeComments #include <webserv/config/utils.hpp> // for removeComments
@ -60,3 +61,38 @@ std::vector<ServerConfig *> ConfigManager::getServerConfigs() const
} }
return globalConfig_->getServerConfigs(); return globalConfig_->getServerConfigs();
} }
ServerConfig *ConfigManager::getMatchingServerConfig(const std::string &host_port) const
{
if (!initialized_)
{
throw std::runtime_error("ConfigManager is not initialized.");
}
// split host and port on the colon:
size_t colonPos = host_port.find(':');
std::string host = (colonPos != std::string::npos) ? host_port.substr(0, colonPos) : host_port;
int port = (colonPos != std::string::npos) ? std::stoi(host_port.substr(colonPos + 1)) : 0;
return getMatchingServerConfig(host, port);
}
ServerConfig *ConfigManager::getMatchingServerConfig(const std::string &host, int port) const
{
if (!initialized_)
{
throw std::runtime_error("ConfigManager is not initialized.");
}
std::vector<ServerConfig *> serverConfigs = globalConfig_->getServerConfigs();
for (ServerConfig *serverConfig : serverConfigs)
{
auto serverName = serverConfig->getDirectiveValue<std::string>("server_name", "");
auto listenPorts = serverConfig->getDirectiveValue<int>("listen", 80);
Log::debug("Checking server config: " + serverName + " on port " + std::to_string(listenPorts));
if ((serverName == host) && (listenPorts == port))
{
Log::info("Found matching server config for host: " + host + " and port: " + std::to_string(port));
return serverConfig;
}
}
Log::warning("No matching server config found for host: " + host + " and port: " + std::to_string(port));
return nullptr;
}

View File

@ -22,6 +22,9 @@ class ConfigManager
static ConfigManager &getInstance(); static ConfigManager &getInstance();
[[nodiscard]] std::vector<ServerConfig *> getServerConfigs() const; [[nodiscard]] std::vector<ServerConfig *> getServerConfigs() const;
[[nodiscard]] ServerConfig *getMatchingServerConfig(const std::string &host, int port) const;
[[nodiscard]] ServerConfig *getMatchingServerConfig(const std::string &host_port) const;
[[nodiscard]] GlobalConfig *getGlobalConfig() const;
private: private:
bool initialized_; bool initialized_;

View File

@ -38,7 +38,7 @@ class ADirective
} }
protected: protected:
std::string name_; std::string name_; //NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
}; };
// Non-member stream operator for ADirective // Non-member stream operator for ADirective

View File

@ -29,7 +29,7 @@ class DirectiveFactory
constexpr static std::array<DirectiveInfo, 15> supportedDirectives = {{ constexpr static std::array<DirectiveInfo, 15> supportedDirectives = {{
{.name = "listen", .type = "IntDirective", .context = "SL"}, {.name = "listen", .type = "IntDirective", .context = "SL"},
{.name = "host", .type = "StringDirective", .context = "SL"}, {.name = "host", .type = "StringDirective", .context = "SL"},
{.name = "server_name", .type = "VectorDirective", .context = "SL"}, {.name = "server_name", .type = "StringDirective", .context = "SL"},
{.name = "root", .type = "StringDirective", .context = "SL"}, {.name = "root", .type = "StringDirective", .context = "SL"},
{.name = "index", .type = "VectorDirective", .context = "SL"}, {.name = "index", .type = "VectorDirective", .context = "SL"},
{.name = "error_page", .type = "IntStringDirective", .context = "SL"}, {.name = "error_page", .type = "IntStringDirective", .context = "SL"},

View File

@ -1 +1,11 @@
#pragma once #pragma once
// #include "webserv/config/AConfig.hpp"
// class ErrorHandler
// {
// public:
// static std::string generateErrorPage(int statusCode, AConfig *config = nullptr);
// static std::string getStatusMessage(int statusCode);
// static bool isValidStatusCode(int statusCode);
// };

View File

@ -0,0 +1,19 @@
#include <webserv/handler/ErrorHandler.hpp>
#include <webserv/http/HttpConstants.hpp> // for StatusCode
#include <webserv/config/AConfig.hpp>
#include <webserv/log/Log.hpp>
// std::string ErrorHandler::generateErrorPage(int statusCode, AConfig *config)
// {
// std::string statusMessage = getStatusMessage(statusCode);
// std::string html =
// "<html><head><title>" + std::to_string(statusCode) + " " + statusMessage +
// "</title></head><body><h1>" + std::to_string(statusCode) + " " + statusMessage +
// "</h1><hr><p>webserv</p></body></html>";
// return html;
// }

View File

@ -2,6 +2,8 @@
#include <webserv/http/HttpConstants.hpp> // for CRLF, DOUBLE_CRLF #include <webserv/http/HttpConstants.hpp> // for CRLF, DOUBLE_CRLF
#include <webserv/http/HttpRequest.hpp> #include <webserv/http/HttpRequest.hpp>
#include <webserv/log/Log.hpp> // for Log, LOCATION #include <webserv/log/Log.hpp> // for Log, LOCATION
#include <webserv/client/Client.hpp> // for Client
#include <map> // for map #include <map> // for map
#include <optional> // for optional #include <optional> // for optional
@ -11,8 +13,7 @@
class ServerConfig; class ServerConfig;
HttpRequest::HttpRequest(const ServerConfig *serverConfig, const Client *client) HttpRequest::HttpRequest(Client *client) : client_(client)
: serverConfig_(serverConfig), client_(client)
{ {
Log::trace(LOCATION); Log::trace(LOCATION);
} }
@ -28,6 +29,11 @@ HttpRequest::State HttpRequest::getState() const
return state_; return state_;
} }
void HttpRequest::setState(State state)
{
state_ = state;
}
const HttpHeaders &HttpRequest::getHeaders() const const HttpHeaders &HttpRequest::getHeaders() const
{ {
return headers_; return headers_;
@ -80,7 +86,10 @@ void HttpRequest::parseBuffer()
case State::Complete: case State::Complete:
Log::debug("HttpRequest::parseBuffer() request is complete"); Log::debug("HttpRequest::parseBuffer() request is complete");
return; // Request is complete return; // Request is complete
case State::ParseError: Log::warning("Parse error occurred, stopping further processing"); return; case State::ParseError:
Log::warning("Parse error occurred, stopping further processing");
client_->setStatusCode(Http::StatusCode::BAD_REQUEST);
return;
} }
} }
catch (...) catch (...)

View File

@ -23,7 +23,7 @@ class HttpRequest
ParseError ParseError
}; };
HttpRequest(const ServerConfig *serverConfig, const Client *client); HttpRequest(Client *client);
HttpRequest(const HttpRequest &other) = delete; HttpRequest(const HttpRequest &other) = delete;
HttpRequest(HttpRequest &&other) noexcept = delete; HttpRequest(HttpRequest &&other) noexcept = delete;
@ -32,6 +32,7 @@ class HttpRequest
~HttpRequest(); ~HttpRequest();
[[nodiscard]] State getState() const; [[nodiscard]] State getState() const;
void setState(State state);
[[nodiscard]] const HttpHeaders &getHeaders() const; [[nodiscard]] const HttpHeaders &getHeaders() const;
[[nodiscard]] const std::string &getBody() const; [[nodiscard]] const std::string &getBody() const;
@ -54,8 +55,7 @@ class HttpRequest
void parseContentLength(); void parseContentLength();
const ServerConfig *serverConfig_; Client *client_;
const Client *client_;
State state_ = State::RequestLine; State state_ = State::RequestLine;

View File

@ -23,12 +23,12 @@ int main(int argc, char **argv)
Log::info("ConfigManager initialized successfully."); Log::info("ConfigManager initialized successfully.");
auto serverConfigs = configManager.getServerConfigs(); // auto serverConfigs = configManager.getServerConfigs();
auto *firstServer = serverConfigs[0]; // auto *firstServer = serverConfigs[0];
const auto *location = firstServer->getLocation("/"); // const auto *location = firstServer->getLocation("/");
const auto *listenDirective = location->getDirective("listen"); // const auto *listenDirective = location->getDirective("listen");
int listenPort = listenDirective->getValueAs<int>(); // int listenPort = listenDirective->getValueAs<int>();
Log::warning("Listen port for '/' location: " + std::to_string(listenPort)); // Log::warning("Listen port for '/' location: " + std::to_string(listenPort));

View File

@ -113,7 +113,7 @@ void Server::handleConnection(struct epoll_event *event)
std::unique_ptr<Socket> clientSocket = listener.accept(); std::unique_ptr<Socket> clientSocket = listener.accept();
addToEpoll(*clientSocket, EPOLLIN); addToEpoll(*clientSocket, EPOLLIN);
clients_.insert( clients_.insert(
{clientSocket->getFd(), std::make_unique<Client>(std::move(clientSocket), *this, getConfig(listener))}); {clientSocket->getFd(), std::make_unique<Client>(std::move(clientSocket), *this)});
} }
Socket &Server::getListener(int fd) const Socket &Server::getListener(int fd) const