WIP CGI monitered by epoll

+ OK, but some errors case need to be lookup
This commit is contained in:
lperrey
2022-08-16 18:38:58 +02:00
parent ff443c80b1
commit 2c6bc096cc
8 changed files with 232 additions and 101 deletions

View File

@@ -66,9 +66,8 @@ size_t Webserv::_cgi_pos(Client *client, std::string &path, size_t pos)
return NPOS;
}
std::string Webserv::_exec_cgi(Client *client)
void Webserv::_exec_cgi(Client *client)
{
std::string script_output;
char* env_cstr[19] = {NULL};
std::vector<std::string> env_vector;
env_vector.reserve(18);
@@ -77,12 +76,11 @@ std::string Webserv::_exec_cgi(Client *client)
_set_env_vector(client, env_vector);
try {
_set_env_cstr(env_cstr, env_vector);
script_output = _exec_script(client, env_cstr);
_exec_script(client, env_cstr);
while (env_cstr[i] != NULL)
delete[] env_cstr[i++];
return script_output;
return;
}
catch (const Webserv::ExecFail& e)
{
@@ -125,7 +123,7 @@ void Webserv::_set_env_vector(Client *client, std::vector<std::string> &env_vect
env_vector.push_back(_dup_env("QUERY_STRING" , client->get_rq_query()));
env_vector.push_back(_dup_env("REMOTE_ADDR" , client->get_cl_ip()));
env_vector.push_back(_dup_env("REMOTE_HOST" , client->get_cl_ip())); // equal to REMOTE_ADDR or empty
env_vector.push_back(_dup_env("REMOTE_IDENT")); // authentification not supported
env_vector.push_back(_dup_env("REMOTE_IDENT")); // authentification not supported
env_vector.push_back(_dup_env("REMOTE_USER")); // authentification not supported
env_vector.push_back(_dup_env("REQUEST_METHOD" , client->get_rq_method_str()));
env_vector.push_back(_dup_env("SCRIPT_NAME" , client->get_rq_script_path())); // LUKE: To Check
@@ -151,43 +149,17 @@ void Webserv::_set_env_cstr(char *env_cstr[], std::vector<std::string> &env_vect
env_cstr[i] = NULL;
}
/* void Webserv::_set_env_cstr(char *env_cstr[], std::vector<std::string> &env_vector)
{
env_cstr[0] = const_cast<char*>(env_vector[0].c_str());
env_cstr[1] = const_cast<char*>(env_vector[1].c_str());
env_cstr[2] = const_cast<char*>(env_vector[2].c_str());
env_cstr[3] = const_cast<char*>(env_vector[3].c_str());
env_cstr[4] = const_cast<char*>(env_vector[4].c_str());
env_cstr[5] = const_cast<char*>(env_vector[5].c_str());
env_cstr[6] = const_cast<char*>(env_vector[6].c_str());
env_cstr[7] = const_cast<char*>(env_vector[7].c_str());
env_cstr[8] = const_cast<char*>(env_vector[8].c_str());
env_cstr[9] = const_cast<char*>(env_vector[9].c_str());
env_cstr[10] = const_cast<char*>(env_vector[10].c_str());
env_cstr[11] = const_cast<char*>(env_vector[11].c_str());
env_cstr[12] = const_cast<char*>(env_vector[12].c_str());
env_cstr[13] = const_cast<char*>(env_vector[13].c_str());
env_cstr[14] = const_cast<char*>(env_vector[14].c_str());
env_cstr[15] = const_cast<char*>(env_vector[15].c_str());
env_cstr[16] = const_cast<char*>(env_vector[16].c_str());
env_cstr[17] = const_cast<char*>(env_vector[17].c_str());
env_cstr[18] = NULL;
} */
#define STATUS_500 std::string("Status: 500" CRLF CRLF);
std::string Webserv::_exec_script(Client *client, char *env[])
void Webserv::_exec_script(Client *client, char *env[])
{
#define RD 0
#define WR 1
#define CGI_BUF_SIZE 10
#define FD_WR_TO_CHLD fd_in[WR]
#define FD_WR_TO_PRNT fd_out[WR]
#define FD_RD_FR_CHLD fd_out[RD]
#define FD_RD_FR_PRNT fd_in[RD]
pid_t pid;
char buf[CGI_BUF_SIZE]; // WIP define buffer
char * const nll[1] = {NULL};
std::string script_output;
std::string body = client->get_rq_body();
@@ -195,12 +167,12 @@ std::string Webserv::_exec_script(Client *client, char *env[])
int fd_out[2];
std::string path;
pipe(fd_in);
pipe(fd_out);
::pipe(fd_in);
::pipe(fd_out);
pid = fork();
if (pid == -1)
perror("err fork()");
std::perror("err fork()");
else if (pid == 0) // child
{
std::signal(SIGPIPE, SIG_DFL);
@@ -212,14 +184,14 @@ std::string Webserv::_exec_script(Client *client, char *env[])
::close(FD_RD_FR_CHLD);
if (dup2(FD_RD_FR_PRNT, STDIN_FILENO) == -1)
{
perror("err dup2()");
std::perror("err dup2()");
::close(FD_RD_FR_PRNT); // Valgind debug, not essential
::close(FD_WR_TO_PRNT); // Valgind debug, not essential
throw ExecFail();
}
if (dup2(FD_WR_TO_PRNT, STDOUT_FILENO) == -1)
{
perror("err dup2()");
std::perror("err dup2()");
::close(FD_RD_FR_PRNT); // Valgind debug, not essential
::close(FD_WR_TO_PRNT); // Valgind debug, not essential
throw ExecFail();
@@ -230,9 +202,9 @@ std::string Webserv::_exec_script(Client *client, char *env[])
path = "." + client->get_rq_script_path(); // Wut ? Only relative path ?
/*DEBUG*/std::cerr << "execve:[" << path << "]\n";
if (execve(path.c_str(), nll, env) == -1) // replace path for debug error forcing
if (::execve(path.c_str(), nll, env) == -1) // replace path for debug error forcing
{
perror("err execve()");
std::perror("err execve()");
::close(STDIN_FILENO); // Valgind debug, not essential
::close(STDOUT_FILENO); // Valgind debug, not essential
throw ExecFail();
@@ -240,37 +212,23 @@ std::string Webserv::_exec_script(Client *client, char *env[])
}
else //parent
{
close(FD_RD_FR_PRNT);
close(FD_WR_TO_PRNT);
write(FD_WR_TO_CHLD, body.c_str(), body.size());
close(FD_WR_TO_CHLD);
waitpid(-1, NULL, 0);
// We could maybe,
::close(FD_RD_FR_PRNT);
::close(FD_WR_TO_PRNT);
::write(FD_WR_TO_CHLD, body.c_str(), body.size()); // move this before the fork ?
::close(FD_WR_TO_CHLD);
// add FD_RD_FR_CHLD to epoll,
// return to the main loop,
// read FD_RD_FR_CHLD each time epoll say its ready,
// then try waitpid() with WNOHANG after each read.
// when waitpid() tell us its finish (or maybe when epoll return EPOLLHUP)
// then actually parse the script_output and send it to the client.
_epoll_update(FD_RD_FR_CHLD, EPOLLIN, EPOLL_CTL_ADD);
// stop monitoring client->fd until the cgi-script as done is job
_epoll_update(client->get_cl_fd(), 0, EPOLL_CTL_DEL);
ssize_t ret = 1;
while (ret > 0)
{
ret = read(FD_RD_FR_CHLD, buf, CGI_BUF_SIZE);
if (ret == -1)
{
std::perror("err recv()");
script_output = STATUS_500;
break;
}
script_output.append(buf, ret);
}
close(FD_RD_FR_CHLD);
client->cgi_pipe_rfd = FD_RD_FR_CHLD;
struct cgi_pipe_rfd new_cgi_fd;
new_cgi_fd.fd = FD_RD_FR_CHLD;
new_cgi_fd.cgi_pid = pid;
new_cgi_fd.client = client;
_cgi_pipe_rfds.push_back(new_cgi_fd);
}
if (script_output.empty())
script_output = STATUS_500;
return script_output;
}
void Webserv::_check_script_output(Client *client, std::string & output)