feat(CgiHandler, TimerSocket): enhance error handling and add read/write methods

This commit is contained in:
whaffman 2025-10-22 15:18:15 +02:00
parent cd33bb1ce6
commit 656abd24e7
7 changed files with 60 additions and 18 deletions

View File

@ -140,7 +140,7 @@ void Client::poll() const
auto *cgiHandler = dynamic_cast<CgiHandler *>(handler_.get());
if (cgiHandler != nullptr)
{
Log::debug("Polling CGI handler for client, fd: " + std::to_string(clientSocket_->getFd()));
// Log::debug("Polling CGI handler for client, fd: " + std::to_string(clientSocket_->getFd()));
// CGI handler polling logic if needed
cgiHandler->wait();
}

View File

@ -58,9 +58,9 @@ class Client
std::unique_ptr<HttpRequest> httpRequest_;
std::unique_ptr<HttpResponse> httpResponse_;
std::unique_ptr<Router> router_;
std::unique_ptr<AHandler> handler_ = nullptr;
std::unique_ptr<ClientSocket> clientSocket_;
std::unordered_map<int, ASocket *> sockets_;
std::unique_ptr<AHandler> handler_ = nullptr;
Server &server_;
void writeToCgi();

View File

@ -10,6 +10,10 @@
AHandler::AHandler(const HttpRequest &request, HttpResponse &response) : request_(request), response_(response) {}
AHandler::~AHandler()
{
cancelTimer();
}
void AHandler::startTimer()
{
timerSocket_ = std::make_unique<TimerSocket>(std::chrono::milliseconds(5000));

View File

@ -10,7 +10,7 @@ class AHandler
{
public:
AHandler(const HttpRequest &request, HttpResponse &response);
virtual ~AHandler() = default;
virtual ~AHandler();
AHandler(const AHandler &other) = delete;
AHandler &operator=(const AHandler &other) = delete;

View File

@ -1,4 +1,5 @@
#include "webserv/handler/ErrorHandler.hpp"
#include <webserv/client/Client.hpp> // for Client
#include <webserv/handler/CgiHandler.hpp>
#include <webserv/handler/CgiProcess.hpp> // for CgiProcess
@ -8,6 +9,8 @@
#include <webserv/socket/CgiSocket.hpp> // for CgiSocket
#include <webserv/utils/utils.hpp> // for stoul
#include <sys/types.h>
CgiHandler::CgiHandler(const HttpRequest &request, HttpResponse &response)
: AHandler(request, response), cgiProcess_(nullptr), cgiStdIn_(nullptr), cgiStdOut_(nullptr)
{
@ -74,7 +77,7 @@ void CgiHandler::read()
{
Log::info("CGI process closed stdout, fd: " + std::to_string(cgiStdOut_->getFd()));
request_.getClient().removeSocket(cgiStdOut_.get());
request_.getClient().removeSocket(timerSocket_.get());
// request_.getClient().removeSocket(timerSocket_.get());
cgiStdOut_ = nullptr;
parseCgiOutput();
return;
@ -107,19 +110,20 @@ void CgiHandler::error()
{
Log::info("CGI process closed stderr, fd: " + std::to_string(cgiStdErr_->getFd()));
request_.getClient().removeSocket(cgiStdErr_.get());
request_.getClient().removeSocket(timerSocket_.get()); // todo maybe this dangerous
// request_.getClient().removeSocket(timerSocket_.get()); // todo maybe this dangerous
cgiStdErr_ = nullptr;
return;
}
else
{
buffer[bytesRead] = '\0'; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
Log::error("CGI stderr output (fd: " + std::to_string(cgiStdErr_->getFd()) + "): "
+ std::string(buffer, static_cast<size_t>(bytesRead)));
Log::error("CGI stderr output (fd: " + std::to_string(cgiStdErr_->getFd())
+ "): " + std::string(buffer, static_cast<size_t>(bytesRead)));
}
}
void CgiHandler::setCgiSockets(std::unique_ptr<CgiSocket> cgiStdIn, std::unique_ptr<CgiSocket> cgiStdOut, std::unique_ptr<CgiSocket> cgiStdErr)
void CgiHandler::setCgiSockets(std::unique_ptr<CgiSocket> cgiStdIn, std::unique_ptr<CgiSocket> cgiStdOut,
std::unique_ptr<CgiSocket> cgiStdErr)
{
cgiStdIn->setCallback([this]() { write(); });
cgiStdOut->setCallback([this]() { read(); });
@ -221,7 +225,14 @@ void CgiHandler::parseCgiHeaders(std::string &headers)
void CgiHandler::handleTimeout()
{
Log::warning("CGI handler timeout occurred for PID: " + std::to_string(pid_));
char buffer[9] = {}; // NOLINT(cppcoreguidelines-avoid-c-arrays)
ssize_t bytesRead = timerSocket_->read(buffer, sizeof(buffer) - 1);
buffer[bytesRead] = '\0';
if (bytesRead <= 0)
{
// NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
return;
}
// Terminate the CGI process if it's still running
if (cgiProcess_)
{

View File

@ -44,3 +44,25 @@ bool TimerSocket::isActive() const noexcept
{
return active_;
}
ssize_t TimerSocket::read(void *buf, size_t len) const
{
Log::trace(LOCATION);
ssize_t bytesRead = ::read(getFd(), buf, len);
if (bytesRead == -1)
{
throw std::system_error(errno, std::generic_category(), "Socket: Read error");
}
return bytesRead;
}
ssize_t TimerSocket::write(const void *buf, size_t len) const
{
Log::trace(LOCATION);
ssize_t bytesSent = ::write(getFd(), buf, len);
if (bytesSent == -1)
{
throw std::system_error(errno, std::generic_category(), "Socket: Write error");
}
return bytesSent;
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "webserv/socket/ASocket.hpp"
#include <chrono>
class TimerSocket : public ASocket
@ -11,7 +12,11 @@ class TimerSocket : public ASocket
[[nodiscard]] ASocket::Type getType() const noexcept override;
[[nodiscard]] bool isActive() const noexcept;
ssize_t read(void *buf, size_t len) const override;
ssize_t write(const void *buf, size_t len) const override;
void activate();
private:
bool active_ = false;
std::chrono::milliseconds timeout_;