feat(CgiHandler, TimerSocket): enhance error handling and add read/write methods
This commit is contained in:
parent
cd33bb1ce6
commit
656abd24e7
@ -140,7 +140,7 @@ void Client::poll() const
|
|||||||
auto *cgiHandler = dynamic_cast<CgiHandler *>(handler_.get());
|
auto *cgiHandler = dynamic_cast<CgiHandler *>(handler_.get());
|
||||||
if (cgiHandler != nullptr)
|
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
|
// CGI handler polling logic if needed
|
||||||
cgiHandler->wait();
|
cgiHandler->wait();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,9 +58,9 @@ class Client
|
|||||||
std::unique_ptr<HttpRequest> httpRequest_;
|
std::unique_ptr<HttpRequest> httpRequest_;
|
||||||
std::unique_ptr<HttpResponse> httpResponse_;
|
std::unique_ptr<HttpResponse> httpResponse_;
|
||||||
std::unique_ptr<Router> router_;
|
std::unique_ptr<Router> router_;
|
||||||
std::unique_ptr<AHandler> handler_ = nullptr;
|
|
||||||
std::unique_ptr<ClientSocket> clientSocket_;
|
std::unique_ptr<ClientSocket> clientSocket_;
|
||||||
std::unordered_map<int, ASocket *> sockets_;
|
std::unordered_map<int, ASocket *> sockets_;
|
||||||
|
std::unique_ptr<AHandler> handler_ = nullptr;
|
||||||
|
|
||||||
Server &server_;
|
Server &server_;
|
||||||
void writeToCgi();
|
void writeToCgi();
|
||||||
|
|||||||
@ -10,6 +10,10 @@
|
|||||||
|
|
||||||
AHandler::AHandler(const HttpRequest &request, HttpResponse &response) : request_(request), response_(response) {}
|
AHandler::AHandler(const HttpRequest &request, HttpResponse &response) : request_(request), response_(response) {}
|
||||||
|
|
||||||
|
AHandler::~AHandler()
|
||||||
|
{
|
||||||
|
cancelTimer();
|
||||||
|
}
|
||||||
void AHandler::startTimer()
|
void AHandler::startTimer()
|
||||||
{
|
{
|
||||||
timerSocket_ = std::make_unique<TimerSocket>(std::chrono::milliseconds(5000));
|
timerSocket_ = std::make_unique<TimerSocket>(std::chrono::milliseconds(5000));
|
||||||
|
|||||||
@ -10,7 +10,7 @@ class AHandler
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AHandler(const HttpRequest &request, HttpResponse &response);
|
AHandler(const HttpRequest &request, HttpResponse &response);
|
||||||
virtual ~AHandler() = default;
|
virtual ~AHandler();
|
||||||
|
|
||||||
AHandler(const AHandler &other) = delete;
|
AHandler(const AHandler &other) = delete;
|
||||||
AHandler &operator=(const AHandler &other) = delete;
|
AHandler &operator=(const AHandler &other) = delete;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include "webserv/handler/ErrorHandler.hpp"
|
#include "webserv/handler/ErrorHandler.hpp"
|
||||||
|
|
||||||
#include <webserv/client/Client.hpp> // for Client
|
#include <webserv/client/Client.hpp> // for Client
|
||||||
#include <webserv/handler/CgiHandler.hpp>
|
#include <webserv/handler/CgiHandler.hpp>
|
||||||
#include <webserv/handler/CgiProcess.hpp> // for CgiProcess
|
#include <webserv/handler/CgiProcess.hpp> // for CgiProcess
|
||||||
@ -8,6 +9,8 @@
|
|||||||
#include <webserv/socket/CgiSocket.hpp> // for CgiSocket
|
#include <webserv/socket/CgiSocket.hpp> // for CgiSocket
|
||||||
#include <webserv/utils/utils.hpp> // for stoul
|
#include <webserv/utils/utils.hpp> // for stoul
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
CgiHandler::CgiHandler(const HttpRequest &request, HttpResponse &response)
|
CgiHandler::CgiHandler(const HttpRequest &request, HttpResponse &response)
|
||||||
: AHandler(request, response), cgiProcess_(nullptr), cgiStdIn_(nullptr), cgiStdOut_(nullptr)
|
: 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()));
|
Log::info("CGI process closed stdout, fd: " + std::to_string(cgiStdOut_->getFd()));
|
||||||
request_.getClient().removeSocket(cgiStdOut_.get());
|
request_.getClient().removeSocket(cgiStdOut_.get());
|
||||||
request_.getClient().removeSocket(timerSocket_.get());
|
// request_.getClient().removeSocket(timerSocket_.get());
|
||||||
cgiStdOut_ = nullptr;
|
cgiStdOut_ = nullptr;
|
||||||
parseCgiOutput();
|
parseCgiOutput();
|
||||||
return;
|
return;
|
||||||
@ -107,19 +110,20 @@ void CgiHandler::error()
|
|||||||
{
|
{
|
||||||
Log::info("CGI process closed stderr, fd: " + std::to_string(cgiStdErr_->getFd()));
|
Log::info("CGI process closed stderr, fd: " + std::to_string(cgiStdErr_->getFd()));
|
||||||
request_.getClient().removeSocket(cgiStdErr_.get());
|
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;
|
cgiStdErr_ = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer[bytesRead] = '\0'; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
|
buffer[bytesRead] = '\0'; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
|
||||||
Log::error("CGI stderr output (fd: " + std::to_string(cgiStdErr_->getFd()) + "): "
|
Log::error("CGI stderr output (fd: " + std::to_string(cgiStdErr_->getFd())
|
||||||
+ std::string(buffer, static_cast<size_t>(bytesRead)));
|
+ "): " + 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(); });
|
cgiStdIn->setCallback([this]() { write(); });
|
||||||
cgiStdOut->setCallback([this]() { read(); });
|
cgiStdOut->setCallback([this]() { read(); });
|
||||||
@ -221,7 +225,14 @@ void CgiHandler::parseCgiHeaders(std::string &headers)
|
|||||||
void CgiHandler::handleTimeout()
|
void CgiHandler::handleTimeout()
|
||||||
{
|
{
|
||||||
Log::warning("CGI handler timeout occurred for PID: " + std::to_string(pid_));
|
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
|
// Terminate the CGI process if it's still running
|
||||||
if (cgiProcess_)
|
if (cgiProcess_)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -44,3 +44,25 @@ bool TimerSocket::isActive() const noexcept
|
|||||||
{
|
{
|
||||||
return active_;
|
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;
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "webserv/socket/ASocket.hpp"
|
#include "webserv/socket/ASocket.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
class TimerSocket : public ASocket
|
class TimerSocket : public ASocket
|
||||||
@ -11,7 +12,11 @@ class TimerSocket : public ASocket
|
|||||||
[[nodiscard]] ASocket::Type getType() const noexcept override;
|
[[nodiscard]] ASocket::Type getType() const noexcept override;
|
||||||
[[nodiscard]] bool isActive() const noexcept;
|
[[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();
|
void activate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool active_ = false;
|
bool active_ = false;
|
||||||
std::chrono::milliseconds timeout_;
|
std::chrono::milliseconds timeout_;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user