mirror of
https://github.com/3lswear/webserv.git
synced 2025-10-28 21:07:59 +03:00
add: CgiHandle class
This commit is contained in:
2
Makefile
2
Makefile
@@ -15,7 +15,7 @@ CPPFLAGS += -MD -MP
|
||||
SRC = $(wildcard ./src/*.cpp)
|
||||
SRC += $(wildcard ./src/*/*.cpp)
|
||||
|
||||
INCLUDES = ./includes/ -I src/Autoindex -I src/config -I src/Client -I src/Server
|
||||
INCLUDES = ./includes/ -I src/Autoindex -I src/config -I src/Client -I src/Server -I src/CGI
|
||||
|
||||
OBJ = $(SRC:.cpp=.o)
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <wait.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
192
src/CGI/CgiHandle.cpp
Normal file
192
src/CGI/CgiHandle.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
#include "CgiHandle.hpp"
|
||||
|
||||
CgiHandle::CgiHandle(Request &request, Response &response):
|
||||
_request(request), _response(response)
|
||||
{
|
||||
initEnvVariables();
|
||||
}
|
||||
|
||||
std::string toString(unsigned long var)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << var;
|
||||
|
||||
return (ss.str());
|
||||
}
|
||||
|
||||
std::string getEnvFormat(std:: string tmp)
|
||||
{
|
||||
std::string str = tmp;
|
||||
std::replace(str.begin(), str.end(), '-', '_');
|
||||
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
|
||||
return (str);
|
||||
}
|
||||
|
||||
char **CgiHandle::mapToCharPtr(void)
|
||||
{
|
||||
char **tmp = new char *[_variable.size() + 1];
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
|
||||
int i = 0;
|
||||
std::string value;
|
||||
for (it = _variable.begin(); it != _variable.end(); it++)
|
||||
{
|
||||
if (it->second.empty())
|
||||
continue;
|
||||
value = it->first + "=" + it->second;
|
||||
tmp[i] = new char[value.size() + 1];
|
||||
strcpy(tmp[i], value.data());
|
||||
i++;
|
||||
}
|
||||
tmp[i] = NULL;
|
||||
|
||||
return (tmp);
|
||||
}
|
||||
|
||||
void CgiHandle::freeEnvVariables()
|
||||
{
|
||||
for (size_t i = 0; env[i]; i++)
|
||||
{
|
||||
delete[] env[i];
|
||||
}
|
||||
delete[] env;
|
||||
|
||||
}
|
||||
|
||||
void CgiHandle::printSSmap(std::map<std::string, std::string> &m)
|
||||
{
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
|
||||
DBOUT << RED << "print MAP" << ENDL;
|
||||
it = m.begin();
|
||||
for (; it != m.end(); it++)
|
||||
{
|
||||
DBOUT << BLUE << it->first << PINK << it->second << ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void printenv(char **env)
|
||||
{
|
||||
for(size_t i = 0; env[i]; i++)
|
||||
{
|
||||
DBOUT << RED << env[i] << ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
std::string CgiHandle::executeCgi()
|
||||
{
|
||||
char *argv[2];
|
||||
pid_t pid;
|
||||
int sI;
|
||||
int sO;
|
||||
int byte_read = 1;
|
||||
std::string body;
|
||||
|
||||
argv[0] = const_cast<char *>(_response.getCgiPass().data());
|
||||
argv[1] = NULL;
|
||||
try
|
||||
{
|
||||
env = mapToCharPtr();
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
std::cerr << RED << e.what() << RESET << '\n';
|
||||
}
|
||||
printenv(env);
|
||||
sI = dup(STDIN_FILENO);
|
||||
sO = dup(STDOUT_FILENO);
|
||||
|
||||
FILE *fIn = tmpfile();
|
||||
FILE *fOt = tmpfile();
|
||||
long fdin = fileno(fIn);
|
||||
long fdOut = fileno(fOt);
|
||||
DBOUT << BLUE << "in CGI exe" << ENDL;
|
||||
// DBOUT << "BODY[\n" << _request.getBody() << "\n]" << ENDL;
|
||||
write(fdin, _request.getBody().data(), _request.getBody().size());
|
||||
lseek(fdin, 0, SEEK_SET);
|
||||
pid = fork();
|
||||
if (pid == -1)
|
||||
{
|
||||
std::cerr << RED << "Pid = -1. Fork error." << ENDL;
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
dup2(fdin, STDIN_FILENO);
|
||||
dup2(fdOut, STDOUT_FILENO);
|
||||
execve(_response.getCgiPass().c_str(), argv, env);
|
||||
std::cerr << RED << "Execve error." << RESET << ENDL;
|
||||
write(STDOUT_FILENO, "Status: 500\r\n\r\n", 15);
|
||||
}
|
||||
else
|
||||
{
|
||||
char buffer[BUFFSIZE + 1] = {0};
|
||||
|
||||
waitpid(-1, NULL, 0);
|
||||
lseek(fdOut, 0, SEEK_SET);
|
||||
|
||||
while (byte_read)
|
||||
{
|
||||
bzero(buffer, BUFFSIZE);
|
||||
byte_read = read(fdOut, buffer, BUFFSIZE);
|
||||
body.append(buffer, byte_read);
|
||||
}
|
||||
}
|
||||
dup2(sI, STDIN_FILENO);
|
||||
dup2(sO, STDOUT_FILENO);
|
||||
fclose(fIn);
|
||||
fclose(fOt);
|
||||
close(fdin);
|
||||
close(fdOut);
|
||||
close(sI);
|
||||
close(sO);
|
||||
freeEnvVariables();
|
||||
return (body);
|
||||
}
|
||||
|
||||
void CgiHandle::initEnvVariables()
|
||||
{
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
std::map<std::string, std::string> tmp1 = _request.getClientFields();
|
||||
_scriptName = _response.getFullURI().substr(_response.getFullURI().rfind("/"));
|
||||
it = tmp1.find("content_type");
|
||||
if (it != tmp1.end())
|
||||
_variable["AUTH TYPE"] = it->second;
|
||||
else
|
||||
_variable["AUTH TYPE"] = "";
|
||||
_variable["CONTENT_LENGTH"] = toString(_request.getContentLength());
|
||||
it = _request.getClientFields().find("content-type");
|
||||
_variable["CONTENT_TYPE"] = "";
|
||||
_variable["GATEWAY_INTERFACE"] = std::string("CGI/1.1");
|
||||
|
||||
_variable["SCRIPT_NAME"] = _response.getFullURI();
|
||||
_variable["SCRIPT_FILENAME"] = _response.getFullURI();
|
||||
|
||||
_variable["PATH_TRANSLATED"] = _response.getFullURI();
|
||||
_variable["REQUEST_URI"] = _request.getURI();
|
||||
_variable["PATH_INFO"] = _request.getURI();
|
||||
|
||||
_variable["QUERY_STRING"] = _request.getQuery();
|
||||
_variable["REMOTE_ADDR"] = _response.getListen().ip;
|
||||
_variable["REMOTE_HOST"] = _response.getListen().ip;
|
||||
_variable["REMOTE_IDENT"] = "";
|
||||
_variable["REMOTE_USER"] = "";
|
||||
_variable["REQUEST_METHOD"] = _request.getMethod();
|
||||
_variable["SERVER_NAME"] = _request.getHost();
|
||||
_variable["SERVER_PORT"] = toString(_response.getListen().port);
|
||||
_variable["SERVER_PROTOCOL"] = "HTTP/1.1";
|
||||
_variable["REDIRECT_STATUS"] = "200";
|
||||
_variable["SERVER_SOFTVARE"] = "poheck/1.0.0";
|
||||
|
||||
it = tmp1.begin();
|
||||
std::string tmp;
|
||||
for (; it != tmp1.end(); it++)
|
||||
{
|
||||
tmp = getEnvFormat(it->first);
|
||||
_variable["HTTP_" + tmp] = it->second;
|
||||
}
|
||||
printSSmap(_variable);
|
||||
}
|
||||
|
||||
CgiHandle::~CgiHandle()
|
||||
{
|
||||
}
|
||||
30
src/CGI/CgiHandle.hpp
Normal file
30
src/CGI/CgiHandle.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef CGIHANDLE_HPP
|
||||
#define CGIHANDLE_HPP
|
||||
|
||||
#include "webserv.hpp"
|
||||
#include "Request.hpp"
|
||||
#include "ServerConfig.hpp"
|
||||
#include "Response.hpp"
|
||||
|
||||
class Response;
|
||||
|
||||
class CgiHandle
|
||||
{
|
||||
private:
|
||||
Request &_request;
|
||||
Response &_response;
|
||||
std::map<std::string, std::string> _variable;
|
||||
std::string _scriptName;
|
||||
char **env;
|
||||
public:
|
||||
void printSSmap(std::map<std::string, std::string> &);
|
||||
CgiHandle(Request &request, Response &response);
|
||||
void initEnvVariables();
|
||||
void freeEnvVariables();
|
||||
char **mapToCharPtr();
|
||||
std::string executeCgi();
|
||||
~CgiHandle();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -49,7 +49,7 @@ void Response::setHeaderBlocks(void)
|
||||
}
|
||||
void Response::setContentType(void)
|
||||
{
|
||||
if (_code == 204)
|
||||
if (_code == 204 || !_contentType.empty())
|
||||
return ;
|
||||
else if (_request.badCode(_code))
|
||||
_contentType = "text/html";
|
||||
@@ -98,6 +98,11 @@ serverListen Response::getListen()
|
||||
return (_listen);
|
||||
}
|
||||
|
||||
std::string Response::getCgiPass(void)
|
||||
{
|
||||
return (_location->cgi_pass);
|
||||
}
|
||||
|
||||
//-------------------------------------------------File---------------------------------------
|
||||
|
||||
void Response::OpenResponseFile(const char *path)
|
||||
@@ -259,8 +264,8 @@ bool Response::allowedMethod(std::string &method)
|
||||
DBOUT << BLUE << *it << ENDL;
|
||||
it++;
|
||||
}
|
||||
DBOUT << "location " << _location->location << ENDL;
|
||||
_code = 405;
|
||||
if (_location->cgi_pass.empty())
|
||||
_code = 405;
|
||||
return (false);
|
||||
|
||||
}
|
||||
@@ -314,11 +319,17 @@ void Response::generate2(serverListen &l)
|
||||
_hostPort.port = _config->getPort();
|
||||
_fullURI = getFullURI();
|
||||
_method = _request.getMethod();
|
||||
_maxBodySize = (_location->clientBodySize > 0) ? _location->clientBodySize : _config->getClientBodySize();
|
||||
_code = (_request.getContentLength() > _maxBodySize) ? 413 : _code;
|
||||
DBOUT << "max size" << _maxBodySize << ENDL;
|
||||
DBOUT << "_location size" << _location->clientBodySize << ENDL;
|
||||
DBOUT << "_config sieze" << _config->getClientBodySize() << ENDL;
|
||||
DBOUT << "req size " << _request.getContentLength() << ENDL;
|
||||
}
|
||||
|
||||
DBOUT << "fullURI " << _fullURI << ENDL;
|
||||
DBOUT << RED << "code is " << _code << ENDL;
|
||||
if (_request.badCode(_code) || !allowedMethod(_method) || isRedirect())
|
||||
if (_request.badCode(_code) || (!allowedMethod(_method) && _location->cgi_pass.empty()) || isRedirect())
|
||||
{
|
||||
invalidClient();
|
||||
return;
|
||||
@@ -360,18 +371,58 @@ void Response::invalidClient(void)
|
||||
|
||||
void Response::methodGet(void)
|
||||
{
|
||||
generateBody();
|
||||
if (!_location->cgi_pass.empty())
|
||||
{
|
||||
CgiHandle cgi(_request, *this);
|
||||
|
||||
_body = cgi.executeCgi();
|
||||
unsigned long pos = _body.find("\r\n\r\n");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
std::string tmp = _body.substr(0, pos);
|
||||
unsigned long stat = tmp.find("Status: ");
|
||||
unsigned long type = tmp.find("Content-type: ");
|
||||
if (stat != std::string::npos)
|
||||
_code = atoi(tmp.substr(stat + 8, 3).c_str());
|
||||
if (type != std::string::npos)
|
||||
_contentType = tmp.substr(type + 14, tmp.find("\r\n", type+14));
|
||||
_body.erase(_body.begin(), _body.begin() + pos + 4);
|
||||
}
|
||||
}
|
||||
else
|
||||
generateBody();
|
||||
setHeaderBlocks();
|
||||
generateHeader();
|
||||
std::cout << GREEN << "GET method called\n" << ZERO_C;
|
||||
}
|
||||
void Response::methodPost(void)
|
||||
{
|
||||
std::ofstream outfile(_fullURI.c_str(), std::ios::out | std::ios::binary);
|
||||
if (!_location->cgi_pass.empty())
|
||||
{
|
||||
CgiHandle cgi(_request, *this);
|
||||
|
||||
outfile.write(_request.getBody().data(), _request.getBody().size());
|
||||
outfile.close();
|
||||
_code = 204;
|
||||
_body = cgi.executeCgi();
|
||||
unsigned long pos = _body.find("\r\n\r\n");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
std::string tmp = _body.substr(0, pos);
|
||||
unsigned long stat = tmp.find("Status: ");
|
||||
unsigned long type = tmp.find("Content-type: ");
|
||||
if (stat != std::string::npos)
|
||||
_code = atoi(tmp.substr(stat + 8, 3).c_str());
|
||||
if (type != std::string::npos)
|
||||
_contentType = tmp.substr(type + 14, tmp.find("\r\n", type+14));
|
||||
_body.erase(_body.begin(), _body.begin() + pos + 4);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ofstream outfile(_fullURI.c_str(), std::ios::out | std::ios::binary);
|
||||
|
||||
outfile.write(_request.getBody().data(), _request.getBody().size());
|
||||
outfile.close();
|
||||
_code = 204;
|
||||
}
|
||||
setHeaderBlocks();
|
||||
generateHeader();
|
||||
DBOUT << GREEN << "POST method called" << ENDL;
|
||||
@@ -450,7 +501,7 @@ void Response::initErrorCode(void)
|
||||
_errorCode["410"] = "Gone";
|
||||
_errorCode["411"] = "Length Required";
|
||||
_errorCode["412"] = "Precondition Failed";
|
||||
_errorCode["413"] = "Request Entity Too Large";
|
||||
_errorCode["413"] = "Payload Too Large";
|
||||
_errorCode["414"] = "Request-URI Too Long";
|
||||
_errorCode["415"] = "Unsupported Media Type";
|
||||
_errorCode["416"] = "Requested Range Not Satisfiable";
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "webserv.hpp"
|
||||
#include "Request.hpp"
|
||||
#include "CgiHandle.hpp"
|
||||
#include "Autoindex.hpp"
|
||||
|
||||
class Response
|
||||
@@ -25,6 +26,7 @@ private:
|
||||
private:
|
||||
std::string _contentType;
|
||||
unsigned int _contentLength;
|
||||
unsigned int _maxBodySize;
|
||||
std::string _server;
|
||||
std::string _keepAlive;
|
||||
std::string _date;
|
||||
@@ -58,6 +60,7 @@ private:
|
||||
std::string getContentType(void);
|
||||
public:
|
||||
serverListen getListen(void);
|
||||
std::string getCgiPass(void);
|
||||
std::string getHeader(void);
|
||||
std::string getBody(void);
|
||||
static std::string getReasonPhrase(std::string);
|
||||
|
||||
Reference in New Issue
Block a user