feat: better status hanlding cgi and custom env

This commit is contained in:
Quinten 2025-10-30 15:15:06 +01:00
parent c2bdbeb307
commit 6d3941ddf2
8 changed files with 76 additions and 27 deletions

View File

@ -17,7 +17,7 @@ CgiExtValidationRule::CgiExtValidationRule(bool requiresValue)
bool isAllowedCGIExtension(const std::string &extension)
{
static const std::vector<std::string> allowedExtensions = {".php", ".py", ".bla", ".sh", ".cgi"};
static const std::vector<std::string> allowedExtensions = {".php", ".py", ".bla", ".cgi", ".sh"};
return std::ranges::any_of(allowedExtensions, [&extension](const auto &it) { return extension == it; });
}

View File

@ -1,14 +1,19 @@
#include <webserv/handler/CgiEnvironment.hpp>
#include "webserv/http/HttpRequest.hpp"
#include "webserv/log/Log.hpp"
#include <webserv/handler/CgiEnvironment.hpp>
#include <webserv/handler/URI.hpp> // for URI
#include <webserv/http/HttpHeaders.hpp> // for HttpHeaders
#include <algorithm>
#include <cctype>
#include <cstring> // for strcpy, size_t
#include <optional> // for optional
#include <utility> // for pair
CgiEnvironment::CgiEnvironment(const URI &uri, const HttpRequest &request)
{
Log::trace(LOCATION);
env_["GATEWAY_INTERFACE"] = "CGI/1.1";
env_["SERVER_PROTOCOL"] = "HTTP/1.1";
env_["REQUEST_METHOD"] = request.getMethod();
@ -38,7 +43,7 @@ CgiEnvironment::CgiEnvironment(const URI &uri, const HttpRequest &request)
env_["SERVER_NAME"] = host;
env_["SERVER_PORT"] = std::to_string(port);
env_["REMOTE_ADDR"] = request.getClient().getClientAddress(); // Placeholder, should be set to actual remote address
env_["REDIRECT_STATUS"] = "200"; // Required by PHP with force-cgi-redirect enabled
env_["REDIRECT_STATUS"] = "200"; // Required by PHP with force-cgi-redirect enabled
env_["SERVER_SOFTWARE"] = "Webserv/1.0";
env_["REQUEST_SCHEME"] = "HTTP";
env_["HTTP_VERSION"] = "1.1";
@ -49,6 +54,8 @@ CgiEnvironment::CgiEnvironment(const URI &uri, const HttpRequest &request)
env_["HTTP_ACCEPT"] = headers.get("Accept");
env_["HTTP_ACCEPT_LANGUAGE"] = headers.get("Accept-Language");
env_["HTTP_ACCEPT_ENCODING"] = headers.get("Accept-Encoding");
appendCustomHeaders(headers);
}
char **CgiEnvironment::toEnvp() const
@ -64,3 +71,20 @@ char **CgiEnvironment::toEnvp() const
envp[index] = nullptr; // Null-terminate the array
return envp;
}
void CgiEnvironment::appendCustomHeaders(const HttpHeaders &headers)
{
Log::trace(LOCATION);
for (const auto &header : headers.getAll())
{
if (!header.first.starts_with("x-"))
{
continue;
}
std::string key = "HTTP_" + header.first;
std::transform(key.begin(), key.end(), key.begin(), ::toupper);
std::replace(key.begin(), key.end(), '-', '_');
env_[key] = header.second;
Log::debug("Added custom header with key: " + key + " And value: " + header.second);
}
}

View File

@ -18,5 +18,6 @@ class CgiEnvironment
[[nodiscard]] char **toEnvp() const;
private:
void appendCustomHeaders(const HttpHeaders &headers);
std::map<std::string, std::string> env_;
};

View File

@ -1,6 +1,5 @@
#include <webserv/handler/CgiHandler.hpp>
#include <webserv/client/Client.hpp> // for Client
#include <webserv/handler/CgiHandler.hpp>
#include <webserv/handler/CgiProcess.hpp> // for CgiProcess
#include <webserv/handler/ErrorHandler.hpp> // for ErrorHandler
#include <webserv/http/HttpRequest.hpp> // for HttpRequest
@ -11,6 +10,8 @@
#include <webserv/utils/utils.hpp> // for trim
#include <algorithm>
#include <cstddef>
#include <cstdlib>
#include <functional> // for function
#include <utility> // for move
@ -268,7 +269,16 @@ void CgiHandler::parseCgiBody()
{
Log::trace(LOCATION);
// Append the body to the response
auto status = response_.getHeaders().get("Status");
if (cgiProcess_->getExitCode() > 0 && !status.empty())
{
response_.setStatus(500);
}
else if (!status.empty())
{
response_.setStatus(std::atoi(status.c_str()));
}
response_.appendBody(buffer_);
response_.setComplete();
buffer_.clear();

View File

@ -1,7 +1,6 @@
#include <webserv/handler/CgiProcess.hpp>
#include <webserv/handler/CgiEnvironment.hpp> // for CgiEnvironment
#include <webserv/handler/CgiHandler.hpp> // for CgiHandler
#include <webserv/handler/CgiProcess.hpp>
#include <webserv/handler/URI.hpp> // for URI
#include <webserv/http/HttpRequest.hpp> // for HttpRequest
#include <webserv/log/Log.hpp> // for Log
@ -19,7 +18,7 @@
#include <sys/wait.h> // for waitpid, WNOHANG
#include <unistd.h> // for close, dup2, pipe2, execve, fork, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO
CgiProcess::CgiProcess(const HttpRequest &request, CgiHandler &handler) : request_(request), handler_(handler), _pid(-1)
CgiProcess::CgiProcess(const HttpRequest &request, CgiHandler &handler) : request_(request), handler_(handler), pid_(-1), status_(-1)
{
if (!request_.getUri().isCgi())
{
@ -49,8 +48,8 @@ void CgiProcess::spawn()
}
// NOLINTEND
CgiEnvironment cgiEnv(uri, request_);
_pid = fork();
if (_pid < 0)
pid_ = fork();
if (pid_ < 0)
{
close(pipeStdin[0]);
close(pipeStdin[1]);
@ -60,7 +59,7 @@ void CgiProcess::spawn()
close(pipeStderr[1]);
throw std::runtime_error("Failed to fork");
}
if (_pid == 0)
if (pid_ == 0)
{
dup2(pipeStdin[0], STDIN_FILENO);
dup2(pipeStdout[1], STDOUT_FILENO);
@ -98,34 +97,34 @@ void CgiProcess::spawn()
close(pipeStdout[1]);
close(pipeStderr[1]);
Log::debug("CGI process forked with PID: " + std::to_string(_pid));
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), std::move(cgiStdErr));
handler_.setPid(_pid);
handler_.setPid(pid_);
}
}
void CgiProcess::kill() const noexcept
{
if (_pid > 0)
if (pid_ > 0)
{
::kill(_pid, SIGKILL);
Log::debug("Killed CGI process with PID: " + std::to_string(_pid));
::kill(pid_, SIGKILL);
Log::debug("Killed CGI process with PID: " + std::to_string(pid_));
}
}
void CgiProcess::wait() noexcept
{
if (_pid > 0)
if (pid_ > 0)
{
int status;
int waitResult = ::waitpid(_pid, &status, WNOHANG);
int waitResult = ::waitpid(pid_, &status, WNOHANG);
if (waitResult == -1)
{
Log::error("Error while waiting for CGI process with PID: " + std::to_string(_pid));
Log::error("Error while waiting for CGI process with PID: " + std::to_string(pid_));
return;
}
if (waitResult == 0)
@ -134,8 +133,13 @@ void CgiProcess::wait() noexcept
return;
}
Log::debug("CGI process with PID " + std::to_string(_pid) + " has terminated");
;
_pid = -1;
Log::debug("CGI process with PID " + std::to_string(pid_) + " has terminated with status " + std::to_string(status));
status_ = status;
pid_ = -1;
}
}
int CgiProcess::getExitCode() const noexcept
{
return status_;
}

View File

@ -20,11 +20,14 @@ class CgiProcess
void kill() const noexcept;
void wait() noexcept;
[[nodiscard]] int getExitCode() const noexcept;
private:
const HttpRequest &request_;
CgiHandler &handler_;
int _pid;
int pid_;
int status_;
// int _cgiFd;
void spawn();

View File

@ -1,12 +1,13 @@
#include <webserv/http/HttpHeaders.hpp> // for HttpHeaders
#include <webserv/http/HttpConstants.hpp> // for CRLF
#include <webserv/http/HttpHeaders.hpp> // for HttpHeaders
#include <webserv/log/Log.hpp>
#include <webserv/utils/utils.hpp> // for trim
#include <algorithm> // for __transform_fn, transform
#include <cctype> // for tolower
#include <utility> // for pair
#include <string>
#include <unordered_map>
#include <utility> // for pair
std::optional<size_t> HttpHeaders::getContentLength() const
{
@ -94,6 +95,11 @@ void HttpHeaders::parse(const std::string &rawHeaders) noexcept
}
}
const std::unordered_map<std::string, std::string> &HttpHeaders::getAll() const noexcept
{
return headers_;
}
std::string HttpHeaders::toString() const noexcept
{
std::string result;

View File

@ -29,6 +29,7 @@ class HttpHeaders
[[nodiscard]] std::optional<size_t> getContentLength() const;
[[nodiscard]] std::optional<std::string> getContentType() const noexcept;
[[nodiscard]] std::optional<std::string> getHost() const noexcept;
[[nodiscard]] const std::unordered_map<std::string, std::string> &getAll() const noexcept;
private:
std::unordered_map<std::string, std::string> headers_;