1#include "../includes/CGIManager.hpp"
2#include "../includes/Request.hpp"
3#include "../includes/AllowedMethods.hpp"
4#include "../includes/FatalExceptions.hpp"
14#ifndef MAX_ACTIVE_CGI_CHILDREN
15# define MAX_ACTIVE_CGI_CHILDREN 64;
23 for (
int fd = 3; fd < 1024; ++fd)
29 size_t slashPos = scriptPath.find_last_of(
'/');
30 if (slashPos == std::string::npos)
34 return scriptPath.substr(0, slashPos);
39 if (!scriptPath.empty() && scriptPath[0] ==
'/')
42 size_t slashPos = scriptPath.find_last_of(
'/');
43 if (slashPos == std::string::npos)
45 return scriptPath.substr(slashPos + 1);
50 if (scriptArgv.empty())
53 const std::string& scriptPath = scriptArgv.back();
55 if (chdir(scriptDir.c_str()) == -1)
59 if (scriptArgv.size() > 1)
60 std::strcpy(execveArgv[1], scriptExecArg.c_str());
62 std::strcpy(execveArgv[0], scriptExecArg.c_str());
74CGIManager::CGIManager(
const CGIManager& other): _pId(other._pId), _query(other._query), _scriptArgv(other._scriptArgv), _env(other._env), _execveEnvp(NULL), _execveArgv(NULL)
124 if (!interpreterOverride.empty())
125 interp = interpreterOverride;
136 throw ClientException(503,
"CGIManager::execute: max active CGI children reached");
153 if (dup2(inputFd, STDIN_FILENO) == -1)
157 if (dup2(
_outPipe[1], STDOUT_FILENO) == -1)
180 pid_t result = waitpid(
_pId, &status, WNOHANG);
198 _env[
"SCRIPT_FILENAME"] = scriptPath;
202 _env[
"GATEWAY_INTERFACE"] =
"CGI/1.1";
203 _env[
"REDIRECT_STATUS"] =
"200";
206 std::string ct = request.
getHeader(
"content-type");
208 _env[
"CONTENT_TYPE"] = ct;
210 std::string cl = request.
getHeader(
"content-length");
211 _env[
"CONTENT_LENGTH"] = (cl.empty()?
_env[
"CONTENT_LENGTH"] =
"0" :
_env[
"CONTENT_LENGTH"] = cl);
213 const std::map<std::string, std::string>& headers = request.
getHeaders();
214 for (std::map<std::string, std::string>::const_iterator it = headers.begin();
215 it != headers.end(); ++it)
217 std::string key = it->first;
218 for (
size_t i = 0; i < key.size(); ++i)
223 key[i] = std::toupper(key[i]);
225 _env[
"HTTP_" + key] = it->second;
242 for (std::map<std::string, std::string>::const_iterator it =
_env.begin();
243 it !=
_env.end(); ++it, ++idx)
245 std::string entry = it->first +
"=" + it->second;
296 std::set<pid_t> stillRunning;
300 pid_t result = waitpid(*it, &status, WNOHANG);
301 if (result == 0 || (result < 0 && errno == EINTR))
302 stillRunning.insert(*it);
328 time_t startTime = time(NULL);
329 const int GRACE_PERIOD = 5;
333 std::set<pid_t> remaining;
337 pid_t result = waitpid(*it, &status, WNOHANG);
339 remaining.insert(*it);
358 waitpid(*it, &status, 0);
#define MAX_ACTIVE_CGI_CHILDREN
static std::string methodToString(HTTPMethod method)
static void cleanupAllProcesses()
Cleans up all active CGI processes on server shutdown. Sends SIGTERM to all processes,...
static void _registerPid(pid_t pid)
static std::set< pid_t > _activePids
CGIManager & operator=(const CGIManager &other)
std::map< std::string, std::string > _env
void _buildEnvMap(const Request &request, const std::string &scriptPath)
void prepare(const Request &request, const std::string &scriptPath, const std::string &interpreterOverride="")
Prepares the environment and arguments for executing a CGI script.
std::vector< std::string > _scriptArgv
void execute(int inputFd)
Forks, redirs input file and outpipe, and executes the CGI script.
bool isDone()
Checks if the child process has finished executing (Non-blocking); waitpid with WNOHANG.
static bool _isSpawnLimitReached()
static void _unregisterPid(pid_t pid)
static void _reapFinishedActivePids()
Exception type for failures scoped to a single client request.
const std::string & getQuery() const
HTTPMethod getMethod() const
std::string getHeader(const std::string &key) const
Gets a specific header value.
const std::string & getURL() const
const std::map< std::string, std::string > & getHeaders() const
const std::string & getProtocol() const
std::string resolveScriptExecArg(const std::string &scriptPath)
std::string resolveScriptDirectory(const std::string &scriptPath)
void prepareChildExecutionContext(const std::vector< std::string > &scriptArgv, char **execveArgv)