From bf36dd74d8181b9e6bd9b7c882c29eb6460f0843 Mon Sep 17 00:00:00 2001 From: whaffman Date: Tue, 21 Oct 2025 15:37:45 +0200 Subject: [PATCH] Cgi stderr --- webserv/client/Client.cpp | 5 ++++- webserv/client/Client.hpp | 2 +- webserv/handler/CgiHandler.cpp | 36 ++++++++++++++++++++++++++++++++-- webserv/handler/CgiHandler.hpp | 4 +++- webserv/handler/CgiProcess.cpp | 15 ++++++++++++-- webserv/handler/URI.cpp | 8 ++++++-- webserv/socket/ASocket.cpp | 2 +- 7 files changed, 62 insertions(+), 10 deletions(-) diff --git a/webserv/client/Client.cpp b/webserv/client/Client.cpp index 0ca3f51..7d2e7d9 100644 --- a/webserv/client/Client.cpp +++ b/webserv/client/Client.cpp @@ -107,13 +107,16 @@ void Client::request() } // -void Client::setCgiSockets(CgiSocket *cgiStdIn, CgiSocket *cgiStdOut) +void Client::setCgiSockets(CgiSocket *cgiStdIn, CgiSocket *cgiStdOut, CgiSocket *cgiStdErr) { server_.add(*cgiStdIn, EPOLLOUT, this); // write server_.add(*cgiStdOut, EPOLLIN, this); // read + server_.add(*cgiStdErr, EPOLLIN, this); // error + sockets_[cgiStdIn->getFd()] = cgiStdIn; sockets_[cgiStdOut->getFd()] = cgiStdOut; + sockets_[cgiStdErr->getFd()] = cgiStdErr; } void Client::removeCgiSocket(CgiSocket *cgiSocket) diff --git a/webserv/client/Client.hpp b/webserv/client/Client.hpp index 8323704..861546e 100644 --- a/webserv/client/Client.hpp +++ b/webserv/client/Client.hpp @@ -43,7 +43,7 @@ class Client [[nodiscard]] ASocket &getSocket(int fd = -1) const; // void setStatusCode(int code); - void setCgiSockets(CgiSocket *cgiStdIn, CgiSocket *cgiStdOut); + void setCgiSockets(CgiSocket *cgiStdIn, CgiSocket *cgiStdOut, CgiSocket *cgiStdErr); void removeCgiSocket(CgiSocket *cgiSocket); [[nodiscard]] HttpRequest &getHttpRequest() const noexcept; diff --git a/webserv/handler/CgiHandler.cpp b/webserv/handler/CgiHandler.cpp index 835cd5c..d091afe 100644 --- a/webserv/handler/CgiHandler.cpp +++ b/webserv/handler/CgiHandler.cpp @@ -84,15 +84,47 @@ void CgiHandler::read() } } -void CgiHandler::setCgiSockets(std::unique_ptr cgiStdIn, std::unique_ptr cgiStdOut) +void CgiHandler::error() +{ + Log::trace(LOCATION); + if (cgiStdErr_ == nullptr) + { + Log::error("CGI stderr socket is null"); + return; + } + char buffer[bufferSize_] = {}; // NOLINT(cppcoreguidelines-avoid-c-arrays) + ssize_t bytesRead + = cgiStdErr_->read(buffer, sizeof(buffer) - 1); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay) + if (bytesRead < 0) + { + Log::error("Failed to read from CGI stderr, fd: " + std::to_string(cgiStdErr_->getFd())); + } + else if (bytesRead == 0) + { + Log::info("CGI process closed stderr, fd: " + std::to_string(cgiStdErr_->getFd())); + request_.getClient().removeCgiSocket(cgiStdErr_.get()); + 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(bytesRead))); + } +} + +void CgiHandler::setCgiSockets(std::unique_ptr cgiStdIn, std::unique_ptr cgiStdOut, std::unique_ptr cgiStdErr) { cgiStdIn->setCallback([this]() { write(); }); cgiStdOut->setCallback([this]() { read(); }); + cgiStdErr->setCallback([this]() { error(); }); cgiStdOut_ = std::move(cgiStdOut); cgiStdIn_ = std::move(cgiStdIn); + cgiStdErr_ = std::move(cgiStdErr); - request_.getClient().setCgiSockets(cgiStdIn_.get(), cgiStdOut_.get()); // write + request_.getClient().setCgiSockets(cgiStdIn_.get(), cgiStdOut_.get(), cgiStdErr_.get()); // write // TODO add to handler } diff --git a/webserv/handler/CgiHandler.hpp b/webserv/handler/CgiHandler.hpp index 3c9c9b4..5d414e4 100644 --- a/webserv/handler/CgiHandler.hpp +++ b/webserv/handler/CgiHandler.hpp @@ -21,7 +21,7 @@ class CgiHandler : public AHandler void handle() override; void wait() noexcept; - void setCgiSockets(std::unique_ptr cgiStdIn, std::unique_ptr cgiStdOut); + void setCgiSockets(std::unique_ptr cgiStdIn, std::unique_ptr cgiStdOut, std::unique_ptr cgiStdErr); void setPid(int pid); private: @@ -31,6 +31,7 @@ class CgiHandler : public AHandler std::unique_ptr cgiProcess_; std::unique_ptr cgiStdIn_; std::unique_ptr cgiStdOut_; + std::unique_ptr cgiStdErr_; void parseCgiOutput(); void parseCgiHeaders(std::string &headers); void parseCgiBody(); @@ -41,4 +42,5 @@ class CgiHandler : public AHandler void write(); void read(); + void error(); }; \ No newline at end of file diff --git a/webserv/handler/CgiProcess.cpp b/webserv/handler/CgiProcess.cpp index 343b11f..ae1ecdb 100644 --- a/webserv/handler/CgiProcess.cpp +++ b/webserv/handler/CgiProcess.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -34,8 +35,9 @@ void CgiProcess::spawn() int pipeStdin[2]; int pipeStdout[2]; + int pipeStderr[2]; - if (pipe(pipeStdin) == -1 || pipe(pipeStdout) == -1) + if (pipe(pipeStdin) == -1 || pipe(pipeStdout) == -1 || pipe(pipeStderr) == -1) { throw std::runtime_error("Failed to create pipes"); } @@ -47,19 +49,25 @@ void CgiProcess::spawn() close(pipeStdin[1]); close(pipeStdout[0]); close(pipeStdout[1]); + close(pipeStderr[0]); + close(pipeStderr[1]); throw std::runtime_error("Failed to fork"); } if (_pid == 0) { dup2(pipeStdin[0], STDIN_FILENO); dup2(pipeStdout[1], STDOUT_FILENO); + dup2(pipeStderr[1], STDERR_FILENO); close(pipeStdin[0]); close(pipeStdin[1]); close(pipeStdout[0]); close(pipeStdout[1]); + close(pipeStderr[0]); + close(pipeStderr[1]); // Log::debug("Executing CGI: " + cgiPath); + std::cerr << "Executing CGI: " << cgiPath << std::endl; // Prepare arguments std::string fullPath = uri.getFullPath(); @@ -76,14 +84,17 @@ void CgiProcess::spawn() // Parent process auto cgiStdIn = std::make_unique(pipeStdin[1]); auto cgiStdOut = std::make_unique(pipeStdout[0]); + auto cgiStdErr = std::make_unique(pipeStderr[0]); + close(pipeStdin[0]); close(pipeStdout[1]); + close(pipeStderr[1]); Log::debug("CGI process forked with PID: " + std::to_string(_pid)); // request_.getClient().setCgiSockets(std::move(cgiStdIn), std::move(cgiStdOut)); // move the sockets to the // client - handler_.setCgiSockets(std::move(cgiStdIn), std::move(cgiStdOut)); + handler_.setCgiSockets(std::move(cgiStdIn), std::move(cgiStdOut), std::move(cgiStdErr)); handler_.setPid(_pid); } } diff --git a/webserv/handler/URI.cpp b/webserv/handler/URI.cpp index 2934741..434614c 100644 --- a/webserv/handler/URI.cpp +++ b/webserv/handler/URI.cpp @@ -103,6 +103,11 @@ void URI::parseFullpath() } else if (!baseName_.empty()) // not file or dir, but we have a baseName already { + if (pathInfo_.empty()) + { + pathInfo_ = "/"; + } + pathInfo_ = FileUtils::joinPath(pathInfo_, segment); } else // not file or dir, and no baseName yet @@ -124,8 +129,7 @@ void URI::parseFullpath() } } } - Log::debug("URI parseFullpath results", - {{"dir", dir_}, {"baseName", baseName_}, {"pathInfo", pathInfo_}}); + Log::debug("URI parseFullpath results", {{"dir", dir_}, {"baseName", baseName_}, {"pathInfo", pathInfo_}}); fullPath_ = FileUtils::joinPath(dir_, baseName_); } diff --git a/webserv/socket/ASocket.cpp b/webserv/socket/ASocket.cpp index 1507ce2..f465f60 100644 --- a/webserv/socket/ASocket.cpp +++ b/webserv/socket/ASocket.cpp @@ -23,7 +23,7 @@ ASocket::ASocket(int fd) : fd_(fd) ASocket::~ASocket() { - Log::trace(LOCATION); + Log::trace(LOCATION + "Closing socket fd: " + std::to_string(fd_)); if (fd_ != -1) { close(fd_);