_exec_script() close fd and reset signal

+ somes more adjustements in _exec_script()
+ rough notes for non blocking CGI
This commit is contained in:
LuckyLaszlo
2022-08-16 06:50:20 +02:00
parent 4602844f5a
commit ff443c80b1
5 changed files with 107 additions and 26 deletions

View File

@@ -10,6 +10,18 @@
- handle redirection (Work, but weird behavior need deeper test) - handle redirection (Work, but weird behavior need deeper test)
- Ecrire des tests ! - Ecrire des tests !
- cgi_cpp_status.cpp with POST dont show error page. Normal or not ?
For non blocking CGI :
// We could maybe,
// 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.
----Priorité modérée------------------------ ----Priorité modérée------------------------
- namespace utils ? - namespace utils ?
- change "std::string" to reference "std::string &" in most functions - change "std::string" to reference "std::string &" in most functions

View File

@@ -106,6 +106,7 @@ class Webserv
// close.cpp // close.cpp
void _close_client(int fd); void _close_client(int fd);
void _close_all_clients(); void _close_all_clients();
void _close_all_clients_fd();
void _close_all_listen_sockets(); void _close_all_listen_sockets();
void _reopen_lsocket(std::vector<listen_socket>::iterator it); void _reopen_lsocket(std::vector<listen_socket>::iterator it);
void _handle_epoll_error_lsocket(uint32_t events, std::vector<listen_socket>::iterator it); void _handle_epoll_error_lsocket(uint32_t events, std::vector<listen_socket>::iterator it);
@@ -131,6 +132,16 @@ class Webserv
void _check_script_fields(Client *client, std::string & output); void _check_script_fields(Client *client, std::string & output);
void _add_script_body_length_header(std::string & output); void _add_script_body_length_header(std::string & output);
void _remove_body_leading_empty_lines(std::string & output); void _remove_body_leading_empty_lines(std::string & output);
///////////////////////
class ExecFail : public std::exception
{
public :
virtual const char* what() const throw() {
return ("Exec CGI fail");
};
};
}; };
#endif #endif

View File

@@ -72,16 +72,24 @@ std::string Webserv::_exec_cgi(Client *client)
char* env_cstr[19] = {NULL}; char* env_cstr[19] = {NULL};
std::vector<std::string> env_vector; std::vector<std::string> env_vector;
env_vector.reserve(18); env_vector.reserve(18);
int i = 0;
_set_env_vector(client, env_vector); _set_env_vector(client, env_vector);
_set_env_cstr(env_cstr, env_vector); try {
script_output = _exec_script(client, env_cstr); _set_env_cstr(env_cstr, env_vector);
script_output = _exec_script(client, env_cstr);
int i = 0; while (env_cstr[i] != NULL)
while (env_cstr[i] != NULL) delete[] env_cstr[i++];
delete[] env_cstr[i++];
return script_output; return script_output;
}
catch (const Webserv::ExecFail& e)
{
while (env_cstr[i] != NULL)
delete[] env_cstr[i++];
throw;
}
} }
std::string Webserv::_dup_env(std::string var, std::string val = "") std::string Webserv::_dup_env(std::string var, std::string val = "")
@@ -166,6 +174,8 @@ void Webserv::_set_env_cstr(char *env_cstr[], std::vector<std::string> &env_vect
env_cstr[18] = NULL; env_cstr[18] = NULL;
} */ } */
#define STATUS_500 std::string("Status: 500" CRLF CRLF);
std::string Webserv::_exec_script(Client *client, char *env[]) std::string Webserv::_exec_script(Client *client, char *env[])
{ {
#define RD 0 #define RD 0
@@ -190,21 +200,43 @@ std::string Webserv::_exec_script(Client *client, char *env[])
pid = fork(); pid = fork();
if (pid == -1) if (pid == -1)
std::cerr << "fork crashed" << std::endl; perror("err fork()");
else if (pid == 0) // child else if (pid == 0) // child
{ {
// _close_all_clients(); std::signal(SIGPIPE, SIG_DFL);
close(FD_WR_TO_CHLD); std::signal(SIGINT, SIG_DFL);
close(FD_RD_FR_CHLD);
dup2(FD_RD_FR_PRNT, STDIN_FILENO); _close_all_clients_fd();
dup2(FD_WR_TO_PRNT, STDOUT_FILENO); ::close(_epfd);
path = "." + client->get_rq_script_path(); ::close(FD_WR_TO_CHLD);
::close(FD_RD_FR_CHLD);
if (dup2(FD_RD_FR_PRNT, STDIN_FILENO) == -1)
{
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()");
::close(FD_RD_FR_PRNT); // Valgind debug, not essential
::close(FD_WR_TO_PRNT); // Valgind debug, not essential
throw ExecFail();
}
::close(FD_RD_FR_PRNT);
::close(FD_WR_TO_PRNT);
path = "." + client->get_rq_script_path(); // Wut ? Only relative path ?
/*DEBUG*/std::cerr << "execve:[" << path << "]\n"; /*DEBUG*/std::cerr << "execve:[" << path << "]\n";
execve(path.c_str(), nll, env); if (execve(path.c_str(), nll, env) == -1) // replace path for debug error forcing
// for tests execve crash : {
//execve("wrong", nll, env); perror("err execve()");
std::cerr << "execve crashed.\n"; ::close(STDIN_FILENO); // Valgind debug, not essential
// TODO HUGO : check errno ::close(STDOUT_FILENO); // Valgind debug, not essential
throw ExecFail();
}
} }
else //parent else //parent
{ {
@@ -213,17 +245,30 @@ std::string Webserv::_exec_script(Client *client, char *env[])
write(FD_WR_TO_CHLD, body.c_str(), body.size()); write(FD_WR_TO_CHLD, body.c_str(), body.size());
close(FD_WR_TO_CHLD); close(FD_WR_TO_CHLD);
waitpid(-1, NULL, 0); waitpid(-1, NULL, 0);
// We could maybe,
// 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.
memset(buf, '\0', CGI_BUF_SIZE); ssize_t ret = 1;
while (read(FD_RD_FR_CHLD, buf, CGI_BUF_SIZE - 1) > 0) while (ret > 0)
{ {
script_output += buf; ret = read(FD_RD_FR_CHLD, buf, CGI_BUF_SIZE);
memset(buf, '\0', 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); close(FD_RD_FR_CHLD);
} }
if (script_output.empty()) if (script_output.empty())
script_output = "Status: 500" CRLF CRLF; script_output = STATUS_500;
return script_output; return script_output;
} }

View File

@@ -21,13 +21,21 @@ void Webserv::_close_client(int fd)
void Webserv::_close_all_clients() void Webserv::_close_all_clients()
{ {
while (!_clients.empty()) _close_all_clients_fd();
_clients.clear();
}
void Webserv::_close_all_clients_fd()
{
std::vector<Client>::iterator it = _clients.begin();
std::vector<Client>::iterator it_end = _clients.end();
while (it != it_end)
{ {
// _epoll_update(_clients.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG // _epoll_update(_clients.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
std::cerr << "close fd " << _clients.back().get_cl_fd() << "\n"; std::cerr << "close fd " << _clients.back().get_cl_fd() << "\n";
if (::close(_clients.back().get_cl_fd()) == -1) if (::close(_clients.back().get_cl_fd()) == -1)
std::perror("err close()"); std::perror("err close()");
_clients.pop_back(); ++it;
} }
} }

View File

@@ -62,6 +62,11 @@ void Webserv::run()
std::vector<Client>().swap(_clients); std::vector<Client>().swap(_clients);
break; break;
} }
catch (const Webserv::ExecFail& e)
{
std::cerr << e.what() << '\n';
throw;
}
catch (const std::exception& e) { catch (const std::exception& e) {
std::cerr << e.what() << '\n'; std::cerr << e.what() << '\n';
++i; ++i;