Skip to content

Commit

Permalink
Merge pull request #383 from dantol29/lmangall/web-270-implement-post…
Browse files Browse the repository at this point in the history
…-and-delete-for-cgi

Lmangall/web 270 implement post and delete for cgi
  • Loading branch information
552020 authored May 24, 2024
2 parents 35e9e05 + f108e33 commit bdbeb6f
Show file tree
Hide file tree
Showing 17 changed files with 462 additions and 108 deletions.
14 changes: 9 additions & 5 deletions conf/webserv_default.conf
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ server {
upload_path /upload/;
error_page 404 404.html;
cgi_ext .cgi;

location /admin {
return http://google.com;
index admin.html;
Expand All @@ -18,7 +17,6 @@ server {
autoindex off;
}
}

server {
listen 8080;
server_name www.example.com;
Expand All @@ -31,15 +29,13 @@ server {
upload_path upload/;
}
}

server {
listen 8081;
server_name www.php_site.com;
allow_methods GET POST DELETE;
autoindex off;
root var/;
}

server {
listen 8080;
autoindex on;
Expand All @@ -49,7 +45,6 @@ server {
allow_methods GET POST DELETE;
root var/;
}

server {
listen 8080;
server_name www.python_site.com;
Expand All @@ -59,6 +54,15 @@ server {
root var/;
}

server {
listen 8080;
server_name www.saladbook.xyz;
allow_methods GET POST DELETE;
autoindex on;
cgi_ext .cgi .py;
root var/;
}

server {
listen 8080;
server_name www.saladbook;
Expand Down
7 changes: 7 additions & 0 deletions database.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"Leo": "Fruity",
"Stefano": "Carrots",
"Daniil": "with_beets",
"Jane": "Caesar",
"Janeddsads": "Caesar"
}
70 changes: 46 additions & 24 deletions src/CGIHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ void CGIHandler::handleRequest(HTTPRequest &request, HTTPResponse &response)
Debug::log("CGIHandler::handleRequest", Debug::CGI);
MetaVariables env;
env.HTTPRequestToMetaVars(request, env);
if (!executeCGI(env, response))

if (!executeCGI(env, request.getBody(), response))
{
response.setStatusCode(500, "Internal Server Error");
// TODO: it should be hardcoded
Expand Down Expand Up @@ -69,6 +70,7 @@ std::vector<std::string> CGIHandler::createArgvForExecve(const MetaVariables &en
{
argv.push_back(scriptPath);
}

return argv;
}

Expand Down Expand Up @@ -102,26 +104,39 @@ void handleTimeout(int sig)
Debug::log("CGIHandler: Timeout", Debug::CGI);
}

bool CGIHandler::executeCGI(const MetaVariables &env, HTTPResponse &response)
bool CGIHandler::executeCGI(const MetaVariables &env, std::string body, HTTPResponse &response)
{
Debug::log("CGIHandler::executeCGI", Debug::CGI);
std::string cgiOutput;
std::vector<std::string> argv = createArgvForExecve(env);
std::vector<std::string> envp = env.getForExecve();

Debug::log("CGIHandler: executeCGI: body: " + body, Debug::NORMAL);

int pipeFD[2];
int bodyPipeFD[2];
if (pipe(pipeFD) == -1)
{
perror("pipe failed");
return false;
}

if (pipe(bodyPipeFD) == -1)
{
perror("body pipe failed");
close(pipeFD[0]);
close(pipeFD[1]);
return false;
}

pid_t pid = fork();
if (pid == -1)
{
perror("fork failed");
close(pipeFD[0]);
close(pipeFD[1]);
close(bodyPipeFD[0]);
close(bodyPipeFD[1]);
return false;
}
else if (pid == 0)
Expand All @@ -140,6 +155,10 @@ bool CGIHandler::executeCGI(const MetaVariables &env, HTTPResponse &response)
dup2(pipeFD[1], STDOUT_FILENO);
close(pipeFD[1]);

close(bodyPipeFD[1]);
dup2(bodyPipeFD[0], STDIN_FILENO);
close(bodyPipeFD[0]);

closeAllSocketFDs();

std::vector<char *> argvPointers = convertToCStringArray(argv);
Expand All @@ -150,42 +169,45 @@ bool CGIHandler::executeCGI(const MetaVariables &env, HTTPResponse &response)
Debug::log("CGIHandler: access failed", Debug::CGI);
return false;
_exit(EXIT_FAILURE);
// TODO: @leo I don't think we should exit here. We don't want to kill the whole server cause of a CGI
// error. No?
}

// execve(argvPointers[0], argvPointers.data(), envpPointers.data());
if (execve(argvPointers[0], argvPointers.data(), envpPointers.data()) == -1)
{
Debug::log("CGIHandler: execve failed", Debug::CGI);
return false;
// TODO: @leo We should check if execve failed and return an error response and not exti
_exit(EXIT_FAILURE);
}
}
// This is executed if the CGI is started successfully
response.setIsCGI(true);
response.setCGIpipeFD(pipeFD);
else
{
close(pipeFD[1]);
close(bodyPipeFD[0]);

write(bodyPipeFD[1], body.c_str(), body.size());
close(bodyPipeFD[1]);

Debug::log("PIPE SAVED: " + toString(*response.getCGIpipeFD()), Debug::CGI);
response.setIsCGI(true);
response.setCGIpipeFD(pipeFD);

close(pipeFD[1]);
EventData data = {1, pid, pipeFD[0], pipeFD[1]}; // Assuming 1 is the event type for CGI started
close(pipeFD[1]);
EventData data = {1, pid, pipeFD[0], pipeFD[1]}; // Assuming 1 is the event type for CGI started

_eventManager.emit(data); // Emit event indicating a CGI process has started
_eventManager.emit(data); // Emit event indicating a CGI process has started

_connection.addCGI(pid);
Debug::log("CGIHandler: CGI PID: " + toString(pid), Debug::CGI);
_connection.addCGI(pid);
// std::cout << GREEN << _connection.getCGIPid() << RESET << std::endl;

// clang-format off
// std::vector<std::pair<int, int> > pipes = _eventManager.getPipeFDs();
// for (std::vector<std::pair<int, int> >::const_iterator it = pipes.begin(); it != pipes.end(); ++it)
// {
// std::cout << GREEN << "CGIHandler: pipeFDs: " << (*it).first << RESET << std::endl;
// }
// clang-format on
Debug::log("CGIHandler: Waiting for CGI to finish", Debug::CGI);
return true;
// clang-format off
// std::vector<std::pair<int, int> > pipes = _eventManager.getPipeFDs();
// for (std::vector<std::pair<int, int> >::const_iterator it = pipes.begin(); it != pipes.end(); ++it)
// {
// std::cout << GREEN << "CGIHandler: pipeFDs: " << (*it).first << RESET << std::endl;
// }
// clang-format on
// std::cout << RED << "Exiting CGIHandler::executeCGI with true" << RESET << std::endl;
return true;
}
return false;
}

void CGIHandler::setFDsRef(std::vector<struct pollfd> *FDsRef)
Expand Down
2 changes: 1 addition & 1 deletion src/CGIHandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class CGIHandler : public AResponseHandler
CGIHandler &operator=(const CGIHandler &other);
virtual ~CGIHandler();
void handleRequest(HTTPRequest &request, HTTPResponse &response);
bool executeCGI(const MetaVariables &env, HTTPResponse &response);
bool executeCGI(const MetaVariables &env, std::string body, HTTPResponse &response);
std::vector<std::string> createArgvForExecve(const MetaVariables &env);
std::vector<char *> convertToCStringArray(const std::vector<std::string> &input);
// void CGIStringToResponse(const std::string &cgiOutput, HTTPResponse &response);
Expand Down
1 change: 1 addition & 0 deletions src/Debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ void Debug::log(const std::string &message, Debug::Level paramLevel)
}
if (debugLevel & paramLevel)
{
(void)paramLevel;
std::cout << message << std::endl;
}
}
16 changes: 15 additions & 1 deletion src/HTTPResponse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,15 @@ void HTTPResponse::setCGIpipeFD(int (&pipe)[2])

void HTTPResponse::CGIStringToResponse(const std::string &cgiOutput)
{
// std::cout << YELLOW << cgiOutput << RESET << std::endl;
std::size_t headerEndPos = cgiOutput.find("\r\n\r\n");
if (headerEndPos == std::string::npos)
{
headerEndPos = cgiOutput.find("\n\n");
}

std::string headersPart = cgiOutput.substr(0, headerEndPos);
// std::cout << "Headers: " << headersPart << std::endl;
std::string bodyPart = cgiOutput.substr(headerEndPos);

Debug::log("------------------CGIStringToResponse-------------------", Debug::CGI);
Expand All @@ -172,13 +174,25 @@ void HTTPResponse::CGIStringToResponse(const std::string &cgiOutput)
std::string headerName = headerLine.substr(0, separatorPos);
std::string headerValue = headerLine.substr(separatorPos + 2);
setHeader(headerName, headerValue);
// std::cout << "Header: " << headerName << ": " << headerValue << std::endl;
if (headerName == "Status")
{
std::size_t spacePos = headerValue.find(" ");
if (spacePos != std::string::npos)
{
std::string statusCodeStr = headerValue.substr(0, spacePos);
int statusCode = std::atoi(statusCodeStr.c_str());
setStatusCode(statusCode, "");
}
}
}
}

setBody(bodyPart);
// At his point we are done with the CGI so setIsCGI(false)
// setIsCGI(true);
setStatusCode(200, "");
if (_statusCode == 0)
setStatusCode(200, "OK");
return;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Listen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Listen::Listen(const Listen &obj)
_options = obj._options;
_hasIpOrPort = obj._hasIpOrPort;

Debug::log("Listen copy constructor called", Debug::OCF);
// Debug::log("Listen copy constructor called", Debug::OCF);
}

Listen &Listen::operator=(const Listen &obj)
Expand Down
25 changes: 3 additions & 22 deletions src/MetaVariables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,26 +131,13 @@ void MetaVariables::subtractQueryFromPathInfo(std::string &pathInfo, const std::

void MetaVariables::HTTPRequestToMetaVars(const HTTPRequest &request, MetaVariables &env)
{
// TODO: several metavars have to be set from configfile

// This line will have the code put the interpreter path as argv[0] to execve
// env.setVar("X_INTERPRETER_PATH", "/home/lmangall/.brew/bin/python3"); // school computer...
env.setVar("X_INTERPRETER_PATH", X_INTERPRETER_PATH);

//________General variables
// Set the method used for the request (e.g., GET, POST)
env.setVar("REQUEST_METHOD", request.getMethod());
// Set the protocol version used in the request (e.g., HTTP/1.1)
env.setVar("PROTOCOL_VERSION", request.getProtocolVersion());

env.setVar("SERVER_PORT", request.getSingleHeader("listen").second);

//_______Server-related variables
env.setVar("SERVER_SOFTWARE", "Server_of_people_identifying_as_objects/1.0");
env.setVar("SERVER_NAME", request.getSingleHeader("host").second);
env.setVar("GATEWAY_INTERFACE", "CGI/1.1");

//_______Path-related variables
std::string queryString = formatQueryString(request.getQueryString());
env.setVar("QUERY_STRING", queryString);

Expand All @@ -164,22 +151,15 @@ void MetaVariables::HTTPRequestToMetaVars(const HTTPRequest &request, MetaVariab
std::string host = request.getSingleHeader("host").second;
std::string scriptName = pathComponents.first;
std::string pathInfo = pathComponents.second;

Debug::log("MetaVariables::HTTPRequestToMetaVars: root: " + root, Debug::NORMAL);
Debug::log("MetaVariables::HTTPRequestToMetaVars: host: " + host, Debug::NORMAL);
Debug::log("MetaVariables::HTTPRequestToMetaVars: scriptName: " + scriptName, Debug::NORMAL);
Debug::log("MetaVariables::HTTPRequestToMetaVars: pathInfo: " + pathInfo, Debug::NORMAL);

subtractQueryFromPathInfo(pathInfo, queryString);

env.setVar("PATH_INFO", pathInfo);
// std::string pathTranslated = translatePathToPhysical(scriptVirtualPath, pathInfo); // Implement this function
env.setVar("PATH_TRANSLATED", root + host + scriptName);
env.setVar("SCRIPT_NAME", scriptName);

// The query string from the URL sent by the client

//_______set the metadata from the headers of the request
std::pair<std::string, std::string> contentTypeHeader = request.getSingleHeader("Content-Type");
if (!contentTypeHeader.first.empty())
{
Expand All @@ -189,14 +169,15 @@ void MetaVariables::HTTPRequestToMetaVars(const HTTPRequest &request, MetaVariab
{
env.setVar("CONTENT_TYPE", "");
}
std::pair<std::string, std::string> contentLengthHeader = request.getSingleHeader("Content-Length");
std::pair<std::string, std::string> contentLengthHeader = request.getSingleHeader("content-length");
if (!contentLengthHeader.first.empty())
{
env.setVar("CONTENT_LENGTH", contentLengthHeader.second);
Debug::log("Content-Length header found.", Debug::NORMAL);
}
else
{
env.setVar("CONTENT_LENGTH", "0");
Debug::log("Content-Length header not found.", Debug::NORMAL);
}
}

Expand Down
9 changes: 4 additions & 5 deletions src/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ void Parser::parseHeaders(const char *request, HTTPRequest &req, HTTPResponse &r
if (!hasCRLF(request, i, 0))
return (res.setStatusCode(400, "No CRLF after headers"));
if (!hasMandatoryHeaders(req, res))
return ;
return;
_headersAreParsed = true;
saveCokies(req);
}
Expand Down Expand Up @@ -219,7 +219,7 @@ void Parser::parseFileUpload(const std::string &request, HTTPRequest &req, HTTPR

// ----------------UTILS----------------------------

bool Parser::hasMandatoryHeaders(HTTPRequest &req, HTTPResponse& res)
bool Parser::hasMandatoryHeaders(HTTPRequest &req, HTTPResponse &res)
{
_isChunked = false;
int isHost = 0;
Expand Down Expand Up @@ -619,9 +619,8 @@ bool Parser::isOrigForm(std::string &requestTarget, int &queryStart)

bool Parser::isValidContentType(std::string type)
{
if (type == "text/plain" || type == "text/html" || \
type.substr(0, 30) == "multipart/form-data; boundary=" \
|| type == "application/octet-stream")
if (type == "text/plain" || type == "text/html" || type.substr(0, 30) == "multipart/form-data; boundary=" ||
type == "application/octet-stream" || type == "application/x-www-form-urlencoded")
return (true);
return (false);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Router.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,13 @@ void Router::routeRequest(HTTPRequest &request, HTTPResponse &response)
request.setRoot(root);

adaptPathForFirefox(request);

Debug::log("Routing Request: path = " + request.getPath(), Debug::NORMAL);

PathValidation pathResult = pathIsValid(response, request);
Debug::log("Routing Request: pathResult = " + toString(pathResult), Debug::NORMAL);
Debug::log("Path requested: " + request.getPath(), Debug::NORMAL);
// check if method is allowed

if (!_directive._allowedMethods.empty())
{
for (size_t i = 0; i < _directive._allowedMethods.size(); i++)
Expand Down Expand Up @@ -110,6 +109,7 @@ void Router::routeRequest(HTTPRequest &request, HTTPResponse &response)
}
else
{
// std::cout << "Path is a static content, handling as static content" << std::endl;
StaticContentHandler staticContentHandler;
staticContentHandler.handleRequest(request, response);
}
Expand Down
Loading

0 comments on commit bdbeb6f

Please sign in to comment.