feat: refactor HttpResponse and ErrorHandler for improved response handling and error management

This commit is contained in:
Quinten 2025-09-30 16:05:08 +02:00
parent be8c5a80b4
commit bd01a172c5
7 changed files with 66 additions and 75 deletions

View File

@ -16,7 +16,7 @@
Client::Client(std::unique_ptr<Socket> socket, Server &server)
: client_socket_(std::move(socket)), server_(std::ref(server)), httpRequest_(std::make_unique<HttpRequest>(this)),
httpResponse_(std::make_unique<HttpResponse>(this))
httpResponse_(std::make_unique<HttpResponse>())
{
Log::info("New client connected, fd: " + std::to_string(client_socket_->getFd()));
}
@ -93,26 +93,17 @@ void Client::request()
bool Client::isResponseReady() const
{
// todo: poll the httpResponse_ object
return httpResponse_->isComplete();
}
std::vector<uint8_t> Client::getResponse() const
{
Log::trace(LOCATION);
// if (httpRequest_->getState() == HttpRequest::State::ParseError)
// {
// return ErrorHandler::generateErrorPage(Http::StatusCode::BAD_REQUEST);
// }
// std::string response = "HTTP/1.1 ";
// response += "200 OK\r\n";
if (httpRequest_->getState() == HttpRequest::State::ParseError)
{
return ErrorHandler::getErrorResponse(Http::StatusCode::BAD_REQUEST).toBytes();
}
// 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::info("Prepared response for client fd: " + std::to_string(client_socket_->getFd()));
// Log::debug("Sending response:\n" + response);
httpResponse_->setStatus(200);
httpResponse_->addHeader("Content-Type", "text/plain");
httpResponse_->appendBody("Hello, World!\n");

View File

@ -13,7 +13,6 @@
#include <cstddef> // for size_t
#include <cstdint>
#include <memory> // for unique_ptr
#include <string> // for string
#include <vector>
class Server;

View File

@ -1,15 +1,16 @@
#pragma once
#include "webserv/http/HttpResponse.hpp"
#include <webserv/config/AConfig.hpp>
class ErrorHandler
{
public:
static std::string getErrorResponse(int statusCode, AConfig *config = nullptr);
static HttpResponse getErrorResponse(int statusCode, AConfig *config = nullptr);
private:
static std::string generateErrorPage(int statusCode, AConfig *config = nullptr);
static std::string generateErrorHeader(int statusCode, const std::string &body);
static std::string generateDefaultErrorPage(int statusCode);
static std::string_view getStatusMessage(int statusCode);
// static bool isValidStatusCode(int statusCode);
static std::string getErrorPageFile(const std::string &path);
};

View File

@ -1,3 +1,5 @@
#include "webserv/http/HttpResponse.hpp"
#include <webserv/config/AConfig.hpp> // for AConfig
#include <webserv/config/ConfigManager.hpp> // for ConfigManager
#include <webserv/config/GlobalConfig.hpp> // for GlobalConfig
@ -5,36 +7,32 @@
#include <webserv/http/HttpConstants.hpp> // for StatusCodeInfo, CRLF, DOUBLE_CRLF, INTERNAL_SERVER_ERROR, statusCodeInfos
#include <webserv/log/Log.hpp> // for Log
#include <array> // for array
#include <fstream> // for basic_ifstream, basic_filebuf, basic_ostream::operator<<, ifstream, stringstream
#include <sstream> // for basic_stringstream
#include <string> // for basic_string, operator+, allocator, char_traits, string, to_string
#include <string_view> // for string_view
std::string ErrorHandler::getErrorResponse(int statusCode, AConfig *config)
HttpResponse ErrorHandler::getErrorResponse(int statusCode, AConfig *config)
{
HttpResponse response;
std::string body = generateErrorPage(statusCode, config);
Log::debug("Generated error page : " + generateErrorHeader(statusCode, body) + body);
return generateErrorHeader(statusCode, body) + body;
}
std::string ErrorHandler::generateErrorHeader(int statusCode, const std::string &body)
{
std::string response = "HTTP/1.1 ";
response += std::to_string(statusCode) + " ";
response += std::string(getStatusMessage(statusCode)) + std::string(Http::Protocol::CRLF);
response += "Content-Type: text/html" + std::string(Http::Protocol::CRLF);
response +=
"Content-Length: " + std::to_string(body.size()) + std::string(Http::Protocol::DOUBLE_CRLF); // End of headers
response.appendBody(body);
response.setStatus(statusCode);
response.addHeader("Content-Type", "text/html");
response.addHeader("Connection", "close");
return response;
}
std::string ErrorHandler::generateErrorPage(int statusCode, AConfig *config)
{
if (config != nullptr)
Log::trace(LOCATION);
if (config == nullptr)
{
config = ConfigManager::getInstance().getGlobalConfig();
Log::debug("Using global config for error page generation");
}
if (config != nullptr)
{
Log::info("Checking for custom error page for status code: " + std::to_string(statusCode));
std::string customPage = config->getErrorPage(statusCode);
if (!customPage.empty())
@ -49,24 +47,11 @@ std::string ErrorHandler::generateErrorPage(int statusCode, AConfig *config)
std::string ErrorHandler::generateDefaultErrorPage(int statusCode)
{
Log::info("Generating default error page for status code: " + std::to_string(statusCode));
std::string_view statusMessage = getStatusMessage(statusCode);
std::string html = "<html><head><title>" + std::to_string(statusCode) + " " + std::string(statusMessage) +
"</title></head><body><h1>" + std::to_string(statusCode) + " " + std::string(statusMessage) +
std::string statusMessage = Http::getStatusCodeReason(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 generateErrorHeader(statusCode, html) + html;
}
std::string_view ErrorHandler::getStatusMessage(int statusCode)
{
for (const auto info : Http::statusCodeInfos)
{
if (info.code == statusCode)
{
return info.reason;
}
}
return "Unknown Status";
return html;
}
std::string ErrorHandler::getErrorPageFile(const std::string &path)

View File

@ -18,15 +18,6 @@
class HttpHeaders
{
public:
HttpHeaders() = default;
HttpHeaders(const HttpHeaders &other) = delete;
HttpHeaders(HttpHeaders &&other) noexcept = delete;
HttpHeaders &operator=(const HttpHeaders &other) = delete;
HttpHeaders &operator=(HttpHeaders &&other) noexcept = delete;
~HttpHeaders() = default;
const std::string &get(const std::string &name) const;
bool has(const std::string &name) const;

View File

@ -5,7 +5,7 @@
#include <string>
#include <vector>
HttpResponse::HttpResponse(Client *client) : client_(client), headers_(std::make_unique<HttpHeaders>()) {}
HttpResponse::HttpResponse() : headers_(std::make_unique<HttpHeaders>()) {}
void HttpResponse::addHeader(const std::string &key, const std::string &value)
{
@ -22,11 +22,33 @@ void HttpResponse::appendBody(const std::string &body)
body_.insert(body_.end(), body.begin(), body.end());
}
void HttpResponse::setBody(const std::vector<uint8_t> &data)
{
body_ = data;
setComplete();
}
void HttpResponse::setBody(const std::string &body)
{
body_.assign(body.begin(), body.end());
setComplete();
}
void HttpResponse::setStatus(int statusCode)
{
statusCode_ = statusCode;
}
void HttpResponse::setComplete()
{
complete_ = true;
}
bool HttpResponse::isComplete() const
{
return complete_;
}
const HttpHeaders &HttpResponse::getHeaders() const
{
return *headers_;

View File

@ -12,12 +12,12 @@ class Client;
class HttpResponse
{
public:
HttpResponse(Client *client);
HttpResponse();
HttpResponse(const HttpResponse &other) = delete; // Disable copy constructor
HttpResponse &operator=(const HttpResponse &other) = delete; // Disable copy assignment
HttpResponse(HttpResponse &&other) noexcept = delete; // Move constructor
HttpResponse &operator=(HttpResponse &&other) noexcept = delete; // Move assignment
HttpResponse(HttpResponse &&other) noexcept = default; // Move constructor
HttpResponse &operator=(HttpResponse &&other) noexcept = default; // Move assignment
~HttpResponse() = default;
@ -26,6 +26,9 @@ class HttpResponse
void appendBody(const std::vector<uint8_t> &data);
void appendBody(const std::string &body);
void setBody(const std::vector<uint8_t> &data);
void setBody(const std::string &body);
void setComplete();
void setStatus(int statusCode);
@ -40,7 +43,6 @@ class HttpResponse
[[nodiscard]] std::string getStatusLine() const;
[[nodiscard]] std::string getContentLength() const;
Client *client_;
std::vector<uint8_t> body_;
std::unique_ptr<HttpHeaders> headers_;
bool complete_ = false;