From ff443c80b11d775ac6d478db44416670a3fc0d91 Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Tue, 16 Aug 2022 06:50:20 +0200 Subject: [PATCH] _exec_script() close fd and reset signal + somes more adjustements in _exec_script() + rough notes for non blocking CGI --- memo.txt | 12 +++++ srcs/webserv/Webserv.hpp | 11 +++++ srcs/webserv/cgi.cpp | 93 +++++++++++++++++++++++++++++---------- srcs/webserv/close.cpp | 12 ++++- srcs/webserv/run_loop.cpp | 5 +++ 5 files changed, 107 insertions(+), 26 deletions(-) diff --git a/memo.txt b/memo.txt index 6987b8b..b1c8057 100644 --- a/memo.txt +++ b/memo.txt @@ -10,6 +10,18 @@ - handle redirection (Work, but weird behavior need deeper test) - 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------------------------ - namespace utils ? - change "std::string" to reference "std::string &" in most functions diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index c7937cf..0be5e74 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -106,6 +106,7 @@ class Webserv // close.cpp void _close_client(int fd); void _close_all_clients(); + void _close_all_clients_fd(); void _close_all_listen_sockets(); void _reopen_lsocket(std::vector::iterator it); void _handle_epoll_error_lsocket(uint32_t events, std::vector::iterator it); @@ -131,6 +132,16 @@ class Webserv void _check_script_fields(Client *client, std::string & output); void _add_script_body_length_header(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 diff --git a/srcs/webserv/cgi.cpp b/srcs/webserv/cgi.cpp index b28ba05..056d038 100644 --- a/srcs/webserv/cgi.cpp +++ b/srcs/webserv/cgi.cpp @@ -72,16 +72,24 @@ std::string Webserv::_exec_cgi(Client *client) char* env_cstr[19] = {NULL}; std::vector env_vector; env_vector.reserve(18); + int i = 0; _set_env_vector(client, env_vector); - _set_env_cstr(env_cstr, env_vector); - script_output = _exec_script(client, env_cstr); - - int i = 0; - while (env_cstr[i] != NULL) - delete[] env_cstr[i++]; + try { + _set_env_cstr(env_cstr, env_vector); + script_output = _exec_script(client, env_cstr); - return script_output; + while (env_cstr[i] != NULL) + delete[] env_cstr[i++]; + + 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 = "") @@ -166,6 +174,8 @@ void Webserv::_set_env_cstr(char *env_cstr[], std::vector &env_vect env_cstr[18] = NULL; } */ +#define STATUS_500 std::string("Status: 500" CRLF CRLF); + std::string Webserv::_exec_script(Client *client, char *env[]) { #define RD 0 @@ -190,21 +200,43 @@ std::string Webserv::_exec_script(Client *client, char *env[]) pid = fork(); if (pid == -1) - std::cerr << "fork crashed" << std::endl; + perror("err fork()"); else if (pid == 0) // child { - // _close_all_clients(); - close(FD_WR_TO_CHLD); - close(FD_RD_FR_CHLD); - dup2(FD_RD_FR_PRNT, STDIN_FILENO); - dup2(FD_WR_TO_PRNT, STDOUT_FILENO); - path = "." + client->get_rq_script_path(); + std::signal(SIGPIPE, SIG_DFL); + std::signal(SIGINT, SIG_DFL); + + _close_all_clients_fd(); + ::close(_epfd); + ::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"; - execve(path.c_str(), nll, env); - // for tests execve crash : - //execve("wrong", nll, env); - std::cerr << "execve crashed.\n"; - // TODO HUGO : check errno + if (execve(path.c_str(), nll, env) == -1) // replace path for debug error forcing + { + perror("err execve()"); + ::close(STDIN_FILENO); // Valgind debug, not essential + ::close(STDOUT_FILENO); // Valgind debug, not essential + throw ExecFail(); + } } 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()); close(FD_WR_TO_CHLD); 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); - while (read(FD_RD_FR_CHLD, buf, CGI_BUF_SIZE - 1) > 0) + ssize_t ret = 1; + while (ret > 0) { - script_output += buf; - memset(buf, '\0', CGI_BUF_SIZE); + 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); } if (script_output.empty()) - script_output = "Status: 500" CRLF CRLF; + script_output = STATUS_500; return script_output; } diff --git a/srcs/webserv/close.cpp b/srcs/webserv/close.cpp index e0e3893..4404f54 100644 --- a/srcs/webserv/close.cpp +++ b/srcs/webserv/close.cpp @@ -21,13 +21,21 @@ void Webserv::_close_client(int fd) void Webserv::_close_all_clients() { - while (!_clients.empty()) + _close_all_clients_fd(); + _clients.clear(); +} + +void Webserv::_close_all_clients_fd() +{ + std::vector::iterator it = _clients.begin(); + std::vector::iterator it_end = _clients.end(); + while (it != it_end) { // _epoll_update(_clients.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG std::cerr << "close fd " << _clients.back().get_cl_fd() << "\n"; if (::close(_clients.back().get_cl_fd()) == -1) std::perror("err close()"); - _clients.pop_back(); + ++it; } } diff --git a/srcs/webserv/run_loop.cpp b/srcs/webserv/run_loop.cpp index cf54e81..3c93a8f 100644 --- a/srcs/webserv/run_loop.cpp +++ b/srcs/webserv/run_loop.cpp @@ -62,6 +62,11 @@ void Webserv::run() std::vector().swap(_clients); break; } + catch (const Webserv::ExecFail& e) + { + std::cerr << e.what() << '\n'; + throw; + } catch (const std::exception& e) { std::cerr << e.what() << '\n'; ++i;