From 2c6bc096cc3c456a81eeee53a2c477557e94a5a1 Mon Sep 17 00:00:00 2001 From: lperrey Date: Tue, 16 Aug 2022 18:38:58 +0200 Subject: [PATCH 1/4] WIP CGI monitered by epoll + OK, but some errors case need to be lookup --- memo.txt | 6 +++ srcs/Client.cpp | 18 +++---- srcs/Client.hpp | 4 +- srcs/webserv/Webserv.hpp | 24 ++++++++- srcs/webserv/cgi.cpp | 94 +++++++++----------------------- srcs/webserv/close.cpp | 42 +++++++++++++-- srcs/webserv/response.cpp | 34 +++++++----- srcs/webserv/run_loop.cpp | 111 ++++++++++++++++++++++++++++++++++++-- 8 files changed, 232 insertions(+), 101 deletions(-) diff --git a/memo.txt b/memo.txt index b1c8057..5d901c0 100644 --- a/memo.txt +++ b/memo.txt @@ -21,6 +21,7 @@ For non blocking CGI : // when waitpid() tell us its finish (or maybe when epoll return EPOLLHUP) // then actually parse the script_output and send it to the client. +- check status in autoindex ----Priorité modérée------------------------ - namespace utils ? @@ -28,7 +29,12 @@ For non blocking CGI : and add "const" if apropriate. - peut-être check si ip > 32bits + ----Priorité faible------------------------ +- idealy, we should not clear() raw_request after a response, + but just the part we actually parsed for this response. + I think the client could send multiples request on the same connection one after the other without waiting for response. + So raw_request could contain more than the first request we handle. - chunked request (need testing) - client_body_limit 0 valeur special pour desactiver dans config - gerer le champ "Accept" du client diff --git a/srcs/Client.cpp b/srcs/Client.cpp index 06d0de5..8bd1ae5 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -10,9 +10,9 @@ Client::Client() header_complete(false), body_complete(false), request_complete(false), - read_body_size(0), assigned_server(NULL), assigned_location(NULL), + cgi_pipe_rfd(0), _fd(0), _port(""), _ip(""), @@ -26,9 +26,9 @@ Client::Client(int afd, listen_socket *lsocket, std::string aport, std::string a header_complete(false), body_complete(false), request_complete(false), - read_body_size(0), assigned_server(NULL), assigned_location(NULL), + cgi_pipe_rfd(0), _fd(afd), _port(aport), _ip(aip), @@ -45,7 +45,6 @@ Client::~Client() { Client::Client( Client const & src ) : status ( src.status ), header_complete ( src.header_complete ), - read_body_size ( src.read_body_size ), assigned_server ( src.assigned_server ), assigned_location ( src.assigned_location ), _fd ( src._fd ), @@ -232,15 +231,16 @@ void Client::fill_script_path(std::string &path, size_t pos) void Client::clear() { clear_request(); - header_complete = false; - body_complete = false; - request_complete = false; - read_body_size = 0; - assigned_server = NULL; - assigned_location = NULL; raw_request.clear(); response.clear(); status = 0; + header_complete = false; + body_complete = false; + request_complete = false; + assigned_server = NULL; + assigned_location = NULL; + cgi_pipe_rfd = 0; + cgi_output.clear(); } void Client::clear_request() diff --git a/srcs/Client.hpp b/srcs/Client.hpp index eac8c44..a99c020 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -55,9 +55,11 @@ class Client bool header_complete; bool body_complete; bool request_complete; - size_t read_body_size; // unused for now + // size_t read_body_size; // unused for now ServerConfig *assigned_server; // cant be const cause of error_pages.operator[] const LocationConfig *assigned_location; + int cgi_pipe_rfd; + std::string cgi_output; // getters int get_cl_fd() const; diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index 0be5e74..d15b8c5 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -44,6 +44,15 @@ void signal_handler(int signum); # define MIME_TYPE_DEFAULT "application/octet-stream" +struct cgi_pipe_rfd +{ + int fd; + pid_t cgi_pid; + Client *client; +}; +bool operator==(const cgi_pipe_rfd& lhs, int fd); +bool operator==(int fd, const cgi_pipe_rfd& rhs); + class Webserv { public: @@ -65,6 +74,7 @@ class Webserv private: int _epfd; std::vector _listen_sockets; + std::vector _cgi_pipe_rfds; std::vector _servers; std::vector _clients; std::map _http_status; @@ -107,6 +117,8 @@ class Webserv void _close_client(int fd); void _close_all_clients(); void _close_all_clients_fd(); + void _close_cgi_pipe_rfd(int fd); + void _close_all_cgi_pipe_rfd(); void _close_all_listen_sockets(); void _reopen_lsocket(std::vector::iterator it); void _handle_epoll_error_lsocket(uint32_t events, std::vector::iterator it); @@ -121,18 +133,26 @@ class Webserv // cgi.cpp bool _is_cgi(Client *client, std::string path); size_t _cgi_pos(Client *client, std::string &path, size_t pos); - std::string _exec_cgi(Client *client); + void _exec_cgi(Client *client); void _set_env_vector(Client *client, std::vector &env_vector); void _set_env_cstr(char *env_cstr[], std::vector &env_vector); std::string _dup_env(std::string var, std::string val); std::string _dup_env(std::string var, int i); - std::string _exec_script(Client *client, char *env[]); + void _exec_script(Client *client, char *env[]); void _check_script_output(Client *client, std::string & output); void _check_script_status(Client *client, std::string & output); 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); + + + void _read_cgi_output(cgi_pipe_rfd &cgi_fd); + void _handle_epoll_error_cgi_fd(uint32_t events, std::vector::iterator it); + void _cgi_epollhup(uint32_t events, std::vector::iterator it); + + + /////////////////////// class ExecFail : public std::exception { diff --git a/srcs/webserv/cgi.cpp b/srcs/webserv/cgi.cpp index 056d038..16b7fc1 100644 --- a/srcs/webserv/cgi.cpp +++ b/srcs/webserv/cgi.cpp @@ -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 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 &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 &env_vect env_cstr[i] = NULL; } -/* void Webserv::_set_env_cstr(char *env_cstr[], std::vector &env_vector) -{ - env_cstr[0] = const_cast(env_vector[0].c_str()); - env_cstr[1] = const_cast(env_vector[1].c_str()); - env_cstr[2] = const_cast(env_vector[2].c_str()); - env_cstr[3] = const_cast(env_vector[3].c_str()); - env_cstr[4] = const_cast(env_vector[4].c_str()); - env_cstr[5] = const_cast(env_vector[5].c_str()); - env_cstr[6] = const_cast(env_vector[6].c_str()); - env_cstr[7] = const_cast(env_vector[7].c_str()); - env_cstr[8] = const_cast(env_vector[8].c_str()); - env_cstr[9] = const_cast(env_vector[9].c_str()); - env_cstr[10] = const_cast(env_vector[10].c_str()); - env_cstr[11] = const_cast(env_vector[11].c_str()); - env_cstr[12] = const_cast(env_vector[12].c_str()); - env_cstr[13] = const_cast(env_vector[13].c_str()); - env_cstr[14] = const_cast(env_vector[14].c_str()); - env_cstr[15] = const_cast(env_vector[15].c_str()); - env_cstr[16] = const_cast(env_vector[16].c_str()); - env_cstr[17] = const_cast(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) diff --git a/srcs/webserv/close.cpp b/srcs/webserv/close.cpp index 4404f54..f9bbea3 100644 --- a/srcs/webserv/close.cpp +++ b/srcs/webserv/close.cpp @@ -4,7 +4,8 @@ void Webserv::_close_client(int fd) { std::vector::iterator it = _clients.begin(); - while (it != _clients.end()) + std::vector::iterator it_end = _clients.end(); + while (it != it_end) { if (*it == fd) { @@ -32,15 +33,48 @@ void Webserv::_close_all_clients_fd() 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::cerr << "close fd " << it->get_cl_fd() << "\n"; + if (::close(it->get_cl_fd()) == -1) std::perror("err close()"); ++it; } } -void Webserv::_close_all_listen_sockets() +// TODO : not sure for zombie cgi-proccess, need to verif +void Webserv::_close_cgi_pipe_rfd(int fd) { + std::vector::iterator it = _cgi_pipe_rfds.begin(); + std::vector::iterator it_end = _cgi_pipe_rfds.end(); + while (it != it_end) + { + if (*it == fd) + { + std::cerr << "close cgi-fd " << fd << "\n"; + if (::close(fd) == -1) + std::perror("err close()"); + _cgi_pipe_rfds.erase(it); + break; + } + ++it; + } +} + +void Webserv::_close_all_cgi_pipe_rfd() +{ + std::vector::iterator it = _cgi_pipe_rfds.begin(); + std::vector::iterator it_end = _cgi_pipe_rfds.end(); + while (it != it_end) + { + std::cerr << "close cgi-fd " << it->fd << "\n"; + if (::close(it->fd) == -1) + std::perror("err close()"); + ++it; + } + _cgi_pipe_rfds.clear(); +} + +void Webserv::_close_all_listen_sockets() +{ // TODO : change like clients (clear in place of pop_back) while (!_listen_sockets.empty()) { // _epoll_update(_listen_sockets.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 9e8357e..ae08df7 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -3,7 +3,7 @@ enum send_return { - SEND_IN_PROGRESS, // unused + SEND_IN_PROGRESS, SEND_COMPLETE, SEND_CLOSE, }; @@ -40,9 +40,26 @@ int Webserv::_send_response(Client *client) std::cerr << "send()\n"; - _append_base_headers(client); - if (!client->status) - _construct_response(client); + if (client->response.empty()) + { + _append_base_headers(client); + if (!client->status) + { + _construct_response(client); + if (client->cgi_pipe_rfd) + return SEND_IN_PROGRESS; + } + } + else if (client->cgi_pipe_rfd) + { + // /*DEBUG*/ std::cout << "\n" B_PURPLE "[response]:" RESET "\n"; ::print_special(client->response); std::cout << B_PURPLE "-----------" RESET "\n\n"; + // /*DEBUG*/ std::cout << "\n" B_PURPLE "[script output]:" RESET "\n"; ::print_special(script_output); std::cout << B_PURPLE "-----------" RESET "\n\n"; + _check_script_output(client, client->cgi_output); // FD_CGI : adjust for client->cgi_output; + if (client->status < 400) + client->response += client->cgi_output; + // /*DEBUG*/ std::cout << "\n" B_PURPLE "[response + output]:" RESET "\n"; ::print_special(client->response); std::cout << B_PURPLE "-----------" RESET "\n\n"; + } + _insert_status_line(client); if (client->status >= 400) _error_html_response(client); @@ -89,14 +106,7 @@ void Webserv::_construct_response(Client *client) path = _replace_url_root(client, client->get_rq_abs_path()); if (_is_cgi(client, path)) { - script_output = _exec_cgi(client); -//*DEBUG*/ std::cout << "\n" B_PURPLE "[response]:" RESET "\n"; ::print_special(client->response); std::cout << B_PURPLE "-----------" RESET "\n\n"; -//*DEBUG*/ std::cout << "\n" B_PURPLE "[script output]:" RESET "\n"; ::print_special(script_output); std::cout << B_PURPLE "-----------" RESET "\n\n"; - _check_script_output(client, script_output); - if (client->status < 400) - client->response += script_output; -//*DEBUG*/ std::cout << "\n" B_PURPLE "[response + output]:" RESET "\n"; ::print_special(client->response); std::cout << B_PURPLE "-----------" RESET "\n\n"; - + _exec_cgi(client); return; } _process_method(client, path); diff --git a/srcs/webserv/run_loop.cpp b/srcs/webserv/run_loop.cpp index 3c93a8f..69c449a 100644 --- a/srcs/webserv/run_loop.cpp +++ b/srcs/webserv/run_loop.cpp @@ -4,6 +4,96 @@ #define MAX_EVENTS 42 // arbitrary #define TIMEOUT 3000 +// TODO: temp to move in own file +bool operator==(const cgi_pipe_rfd& lhs, int fd) + { return lhs.fd == fd; } + +bool operator==(int fd, const cgi_pipe_rfd& rhs) + { return fd == rhs.fd; } + +#define BUFSIZE 8192 // (8Ko) +#define STATUS_500 std::string("Status: 500" CRLF CRLF); +void Webserv::_read_cgi_output(cgi_pipe_rfd &cgi_fd) +{ + char buf[BUFSIZE]; + ssize_t ret; + pid_t wait_ret; + + ret = ::read(cgi_fd.fd, buf, BUFSIZE); + std::cerr << "cgi read ret = " << ret << "\n"; + if (ret == -1) + { + std::perror("err read(cgi_fd)"); + cgi_fd.client->cgi_output = STATUS_500; + } + else if (ret == 0) + { + (void)0; + } + else + { + cgi_fd.client->cgi_output.append(buf, ret); + } + + + wait_ret = ::waitpid(cgi_fd.cgi_pid, NULL, WNOHANG); + std::cerr << "cgi waitpid ret = " << wait_ret << "\n"; + if (wait_ret == 0 && ret == -1) + { + _epoll_update(cgi_fd.client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); + _close_cgi_pipe_rfd(cgi_fd.fd); + // TODO: kill the child :) + } + else if (wait_ret == cgi_fd.cgi_pid) + { + _epoll_update(cgi_fd.client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); + _close_cgi_pipe_rfd(cgi_fd.fd); + } + return; +} + +void Webserv::_handle_epoll_error_cgi_fd(uint32_t events, std::vector::iterator it) +{ + (void)events; + std::cerr << "cgi EPOLLERR" << "\n"; + + pid_t wait_ret; + wait_ret = ::waitpid(it->cgi_pid, NULL, WNOHANG); + std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n"; + if (wait_ret == 0) + { + _epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); + _close_cgi_pipe_rfd(it->fd); + // TODO: kill the child :) + } + else if (wait_ret == it->cgi_pid) + { + _epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); + _close_cgi_pipe_rfd(it->fd); + } +} + +void Webserv::_cgi_epollhup(uint32_t events, std::vector::iterator it) +{ + (void)events; + std::cerr << "cgi EPOLLHUP" << "\n"; + + pid_t wait_ret; + wait_ret = ::waitpid(it->cgi_pid, NULL, WNOHANG); + std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n"; + if (wait_ret == 0) + { + _epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); + _close_cgi_pipe_rfd(it->fd); + // TODO: kill the child :) + } + else if (wait_ret == it->cgi_pid) + { + _epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); + _close_cgi_pipe_rfd(it->fd); + } +} + void Webserv::run() { std::cerr << "Server started\n"; @@ -11,7 +101,8 @@ void Webserv::run() int nfds; int i; int count_loop = 0; - std::vector::iterator it_socket; + std::vector::iterator it_lsocket; + std::vector::iterator it_cgi_fd; g_run = true; while (g_run) @@ -33,13 +124,23 @@ void Webserv::run() while (i < nfds) { try { - it_socket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd); - if (it_socket != _listen_sockets.end()) + it_lsocket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd); + it_cgi_fd = std::find(_cgi_pipe_rfds.begin(), _cgi_pipe_rfds.end(), events[i].data.fd); // Could be moved in the loop to avoid useless find() call + if (it_lsocket != _listen_sockets.end()) { if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP) - _handle_epoll_error_lsocket(events[i].events, it_socket); + _handle_epoll_error_lsocket(events[i].events, it_lsocket); else if (events[i].events & EPOLLIN) - _accept_connection(*it_socket); + _accept_connection(*it_lsocket); + } + else if (it_cgi_fd != _cgi_pipe_rfds.end()) + { + if (events[i].events & EPOLLERR) + _handle_epoll_error_cgi_fd(events[i].events, it_cgi_fd); + else if (events[i].events & EPOLLHUP) + _cgi_epollhup(events[i].events, it_cgi_fd); + else if (events[i].events & EPOLLIN) + _read_cgi_output(*it_cgi_fd); } else { From 4dc70373f86e18a4179f81ae87bf6b751437f06b Mon Sep 17 00:00:00 2001 From: lperrey Date: Tue, 16 Aug 2022 20:58:48 +0200 Subject: [PATCH 2/4] debug message --- srcs/Client.cpp | 10 +++++----- srcs/cgi-bin/cgi_cpp.cpp | 3 +++ srcs/webserv/response.cpp | 12 ++++++------ srcs/webserv/run_loop.cpp | 12 +++++++++++- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/srcs/Client.cpp b/srcs/Client.cpp index 8bd1ae5..e7be9f6 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -413,9 +413,9 @@ void Client::_parse_port_hostname(std::string host) void Client::_check_request_errors() { - std::cerr << "Content-Length=" << get_rq_headers("Content-Length") << "\n"; - std::cerr << "strtoul=" << std::strtoul(get_rq_headers("Content-Length").c_str(), NULL, 10) << "\n"; - std::cerr << "client_body_limit=" << assigned_server->client_body_limit << "\n"; + // /* Debug */ std::cerr << "Content-Length=" << get_rq_headers("Content-Length") << "\n"; + // /* Debug */ std::cerr << "strtoul=" << std::strtoul(get_rq_headers("Content-Length").c_str(), NULL, 10) << "\n"; + // /* Debug */ std::cerr << "client_body_limit=" << assigned_server->client_body_limit << "\n"; /////////////////////// // Request line checks if (_request.method == UNKNOWN) @@ -464,11 +464,11 @@ ServerConfig *Client::_determine_process_server(Client *client, std::vectorget_rq_headers("Host"); - std::cerr << "server_name = " << server_name << "\n"; + // /* Debug */ std::cerr << "server_name = " << server_name << "\n"; size_t pos = server_name.rfind(':'); if (pos != NPOS) server_name.erase(pos); - std::cerr << "server_name = " << server_name << "\n"; + // /* Debug */ std::cerr << "server_name = " << server_name << "\n"; std::vector::iterator it = servers.begin(); std::vector::iterator default_server = servers.end(); diff --git a/srcs/cgi-bin/cgi_cpp.cpp b/srcs/cgi-bin/cgi_cpp.cpp index ea66df3..e35824b 100644 --- a/srcs/cgi-bin/cgi_cpp.cpp +++ b/srcs/cgi-bin/cgi_cpp.cpp @@ -1,5 +1,6 @@ # include "cgi_utils.hpp" +# include int main (int ac, char **av, char ** env) { @@ -9,6 +10,8 @@ int main (int ac, char **av, char ** env) (void)ac; (void)av; + ::sleep(30); + fill_response_basic(env, http_body, http_header); std::cout << http_header << CRLF CRLF << http_body; diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index ae08df7..dc80171 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -66,7 +66,7 @@ int Webserv::_send_response(Client *client) //*DEBUG*/ std::cout << "\n" B_PURPLE "[response + output + headers]:" RESET "\n"; ::print_special(client->response); std::cout << "\n" B_PURPLE "-----------" RESET "\n\n"; - std::cerr << "client->response.size() = " << client->response.size() << "\n"; // DEBUG + // /* Debug */ std::cerr << "client->response.size() = " << client->response.size() << "\n"; // DEBUG ret = ::send(client->get_cl_fd(), client->response.c_str(), client->response.size(), 0); if (ret == -1) { @@ -79,7 +79,7 @@ int Webserv::_send_response(Client *client) std::cerr << "SEND RET 0 for client.fd =" << client->get_cl_fd() << "\n"; // DEBUG return SEND_CLOSE; } - std::cerr << "ret send() = " << ret << "\n"; // DEBUG + // /* Debug */ std::cerr << "ret send() = " << ret << "\n"; // DEBUG return SEND_COMPLETE; } @@ -114,7 +114,7 @@ void Webserv::_construct_response(Client *client) void Webserv::_process_method(Client *client, std::string &path) { - std::cerr << "allow_methods = " << http_methods_to_str(client->assigned_location->allow_methods) << "\n"; // debug + // /* Debug */ std::cerr << "allow_methods = " << http_methods_to_str(client->assigned_location->allow_methods) << "\n"; // debug switch (client->get_rq_method()) { @@ -131,13 +131,13 @@ void Webserv::_process_method(Client *client, std::string &path) std::string Webserv::_replace_url_root(Client *client, std::string path) { - std::cerr << "assigned_location->path = " << client->assigned_location->path << "\n"; // debug - std::cerr << "path before = " << path << "\n"; // DEBUG + // /* Debug */ std::cerr << "assigned_location->path = " << client->assigned_location->path << "\n"; // debug + // /* Debug */ std::cerr << "path before = " << path << "\n"; // DEBUG if (client->assigned_location->path == "/") path.insert(0, client->assigned_location->root); else path.replace(0, client->assigned_location->path.size(), client->assigned_location->root); - std::cerr << "path after = " << path << "\n"; // DEBUG + // /* Debug */ std::cerr << "path after = " << path << "\n"; // DEBUG return path; } diff --git a/srcs/webserv/run_loop.cpp b/srcs/webserv/run_loop.cpp index 69c449a..b63b3f7 100644 --- a/srcs/webserv/run_loop.cpp +++ b/srcs/webserv/run_loop.cpp @@ -18,6 +18,10 @@ void Webserv::_read_cgi_output(cgi_pipe_rfd &cgi_fd) char buf[BUFSIZE]; ssize_t ret; pid_t wait_ret; + std::cerr << "_read_cgi_output()" << "\n"; + std::cerr << "cgi_pid = " << cgi_fd.cgi_pid << "\n"; + std::cerr << "client fd = " << cgi_fd.client->get_cl_fd() << "\n"; + std::cerr << "cgi fd = " << cgi_fd.fd << "\n"; ret = ::read(cgi_fd.fd, buf, BUFSIZE); std::cerr << "cgi read ret = " << ret << "\n"; @@ -28,7 +32,7 @@ void Webserv::_read_cgi_output(cgi_pipe_rfd &cgi_fd) } else if (ret == 0) { - (void)0; + std::cerr << "cgi read 0 :o" << "\n"; } else { @@ -56,6 +60,9 @@ void Webserv::_handle_epoll_error_cgi_fd(uint32_t events, std::vectorcgi_pid, NULL, WNOHANG); @@ -77,6 +84,9 @@ void Webserv::_cgi_epollhup(uint32_t events, std::vector::iterator { (void)events; std::cerr << "cgi EPOLLHUP" << "\n"; + std::cerr << "cgi_pid = " << it->cgi_pid << "\n"; + std::cerr << "client fd = " << it->client->get_cl_fd() << "\n"; + std::cerr << "cgi fd = " << it->fd << "\n"; pid_t wait_ret; wait_ret = ::waitpid(it->cgi_pid, NULL, WNOHANG); From ccc542f52bdf264a4525b48ffada30967a311f52 Mon Sep 17 00:00:00 2001 From: lperrey Date: Wed, 17 Aug 2022 01:11:20 +0200 Subject: [PATCH 3/4] Fixed big problem with CGI handling + remains somes minors problems --- memo.txt | 12 ++++ srcs/Client.cpp | 3 + srcs/Client.hpp | 1 + srcs/cgi-bin/cgi_cpp.cpp | 13 ++++- srcs/webserv/Webserv.hpp | 17 ++---- srcs/webserv/cgi.cpp | 15 +++-- srcs/webserv/close.cpp | 33 ----------- srcs/webserv/response.cpp | 2 +- srcs/webserv/run_loop.cpp | 118 +++++++++++++++++--------------------- 9 files changed, 96 insertions(+), 118 deletions(-) diff --git a/memo.txt b/memo.txt index 5d901c0..dd8e42a 100644 --- a/memo.txt +++ b/memo.txt @@ -23,6 +23,9 @@ For non blocking CGI : - check status in autoindex +- merge changes from hugo5 to master (attention a pas casse svp :clown:) + + ----Priorité modérée------------------------ - namespace utils ? - change "std::string" to reference "std::string &" in most functions @@ -47,3 +50,12 @@ and add "const" if apropriate. - change "std::string" to reference "std::string &" in most functions and add "const" if apropriate. - Il faut vérifier le path de la requête, voir si le serveur est bien censé délivrer cette ressource et si le client y a accès, avant d'appeler le CGI. + +Valgrind error RESOLVED ! : +==847174== 1,314 bytes in 1 blocks are definitely lost in loss record 1 of 1 +==847174== at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) +==847174== by 0x49AA35D: std::__cxx11::basic_string, std::allocator >::_M_mutate(unsigned long, unsigned long, char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28) +==847174== by 0x49ABB52: std::__cxx11::basic_string, std::allocator >::_M_append(char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28) +==847174== by 0x426BC5: Webserv::_read_cgi_output(cgi_pipe_rfd&) (run_loop.cpp:39) // (LUKE: its an string.append() call) +==847174== by 0x427962: Webserv::run() (run_loop.cpp:153) +==847174== by 0x4052E9: main (main.cpp:38) diff --git a/srcs/Client.cpp b/srcs/Client.cpp index e7be9f6..60ebc9a 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -13,6 +13,7 @@ Client::Client() assigned_server(NULL), assigned_location(NULL), cgi_pipe_rfd(0), + cgi_pid(0), _fd(0), _port(""), _ip(""), @@ -29,6 +30,7 @@ Client::Client(int afd, listen_socket *lsocket, std::string aport, std::string a assigned_server(NULL), assigned_location(NULL), cgi_pipe_rfd(0), + cgi_pid(0), _fd(afd), _port(aport), _ip(aip), @@ -240,6 +242,7 @@ void Client::clear() assigned_server = NULL; assigned_location = NULL; cgi_pipe_rfd = 0; + cgi_pid = 0; cgi_output.clear(); } diff --git a/srcs/Client.hpp b/srcs/Client.hpp index a99c020..2d6e879 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -59,6 +59,7 @@ class Client ServerConfig *assigned_server; // cant be const cause of error_pages.operator[] const LocationConfig *assigned_location; int cgi_pipe_rfd; + pid_t cgi_pid; std::string cgi_output; // getters diff --git a/srcs/cgi-bin/cgi_cpp.cpp b/srcs/cgi-bin/cgi_cpp.cpp index e35824b..36845cc 100644 --- a/srcs/cgi-bin/cgi_cpp.cpp +++ b/srcs/cgi-bin/cgi_cpp.cpp @@ -1,6 +1,7 @@ # include "cgi_utils.hpp" # include +# include int main (int ac, char **av, char ** env) { @@ -10,11 +11,19 @@ int main (int ac, char **av, char ** env) (void)ac; (void)av; - ::sleep(30); + // ::sleep(5); fill_response_basic(env, http_body, http_header); - std::cout << http_header << CRLF CRLF << http_body; + std::cout << http_header; + std::flush(std::cout); + ::sleep(2); + std::cout << CRLF CRLF; + std::flush(std::cout); + ::sleep(2); + std::cout << http_body; + std::flush(std::cout); + ::sleep(2); return 0; } diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index d15b8c5..1b8ce8e 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -44,15 +44,6 @@ void signal_handler(int signum); # define MIME_TYPE_DEFAULT "application/octet-stream" -struct cgi_pipe_rfd -{ - int fd; - pid_t cgi_pid; - Client *client; -}; -bool operator==(const cgi_pipe_rfd& lhs, int fd); -bool operator==(int fd, const cgi_pipe_rfd& rhs); - class Webserv { public: @@ -74,7 +65,6 @@ class Webserv private: int _epfd; std::vector _listen_sockets; - std::vector _cgi_pipe_rfds; std::vector _servers; std::vector _clients; std::map _http_status; @@ -147,9 +137,10 @@ class Webserv - void _read_cgi_output(cgi_pipe_rfd &cgi_fd); - void _handle_epoll_error_cgi_fd(uint32_t events, std::vector::iterator it); - void _cgi_epollhup(uint32_t events, std::vector::iterator it); + Client *_find_cgi_fd(int cgi_fd); + void _read_cgi_output(Client *client); + void _handle_epoll_error_cgi_fd(uint32_t events, Client *client); + void _cgi_epollhup(uint32_t events, Client *client); diff --git a/srcs/webserv/cgi.cpp b/srcs/webserv/cgi.cpp index 16b7fc1..af77b75 100644 --- a/srcs/webserv/cgi.cpp +++ b/srcs/webserv/cgi.cpp @@ -223,16 +223,21 @@ void Webserv::_exec_script(Client *client, char *env[]) _epoll_update(client->get_cl_fd(), 0, EPOLL_CTL_DEL); 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); + client->cgi_pid = pid; } } +#define STATUS_500 std::string("Status: 500" CRLF CRLF); + void Webserv::_check_script_output(Client *client, std::string & output) { + size_t pos; + pos = client->cgi_output.find(CRLF CRLF); + if (pos == 0 || pos == NPOS) + { + client->status = 500;; + return; + } _check_script_status(client, output); if (client->status >= 400 && client->status < 600) return; diff --git a/srcs/webserv/close.cpp b/srcs/webserv/close.cpp index f9bbea3..145287c 100644 --- a/srcs/webserv/close.cpp +++ b/srcs/webserv/close.cpp @@ -40,39 +40,6 @@ void Webserv::_close_all_clients_fd() } } -// TODO : not sure for zombie cgi-proccess, need to verif -void Webserv::_close_cgi_pipe_rfd(int fd) -{ - std::vector::iterator it = _cgi_pipe_rfds.begin(); - std::vector::iterator it_end = _cgi_pipe_rfds.end(); - while (it != it_end) - { - if (*it == fd) - { - std::cerr << "close cgi-fd " << fd << "\n"; - if (::close(fd) == -1) - std::perror("err close()"); - _cgi_pipe_rfds.erase(it); - break; - } - ++it; - } -} - -void Webserv::_close_all_cgi_pipe_rfd() -{ - std::vector::iterator it = _cgi_pipe_rfds.begin(); - std::vector::iterator it_end = _cgi_pipe_rfds.end(); - while (it != it_end) - { - std::cerr << "close cgi-fd " << it->fd << "\n"; - if (::close(it->fd) == -1) - std::perror("err close()"); - ++it; - } - _cgi_pipe_rfds.clear(); -} - void Webserv::_close_all_listen_sockets() { // TODO : change like clients (clear in place of pop_back) while (!_listen_sockets.empty()) diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index dc80171..e278988 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -50,7 +50,7 @@ int Webserv::_send_response(Client *client) return SEND_IN_PROGRESS; } } - else if (client->cgi_pipe_rfd) + else if (!client->cgi_output.empty()) { // /*DEBUG*/ std::cout << "\n" B_PURPLE "[response]:" RESET "\n"; ::print_special(client->response); std::cout << B_PURPLE "-----------" RESET "\n\n"; // /*DEBUG*/ std::cout << "\n" B_PURPLE "[script output]:" RESET "\n"; ::print_special(script_output); std::cout << B_PURPLE "-----------" RESET "\n\n"; diff --git a/srcs/webserv/run_loop.cpp b/srcs/webserv/run_loop.cpp index b63b3f7..6301c6e 100644 --- a/srcs/webserv/run_loop.cpp +++ b/srcs/webserv/run_loop.cpp @@ -4,104 +4,94 @@ #define MAX_EVENTS 42 // arbitrary #define TIMEOUT 3000 -// TODO: temp to move in own file -bool operator==(const cgi_pipe_rfd& lhs, int fd) - { return lhs.fd == fd; } - -bool operator==(int fd, const cgi_pipe_rfd& rhs) - { return fd == rhs.fd; } #define BUFSIZE 8192 // (8Ko) #define STATUS_500 std::string("Status: 500" CRLF CRLF); -void Webserv::_read_cgi_output(cgi_pipe_rfd &cgi_fd) +void Webserv::_read_cgi_output(Client *client) { char buf[BUFSIZE]; ssize_t ret; pid_t wait_ret; std::cerr << "_read_cgi_output()" << "\n"; - std::cerr << "cgi_pid = " << cgi_fd.cgi_pid << "\n"; - std::cerr << "client fd = " << cgi_fd.client->get_cl_fd() << "\n"; - std::cerr << "cgi fd = " << cgi_fd.fd << "\n"; + std::cerr << "cgi_pid = " << client->cgi_pid << "\n"; + std::cerr << "client fd = " << client->get_cl_fd() << "\n"; + std::cerr << "cgi fd = " << client->cgi_pipe_rfd << "\n"; - ret = ::read(cgi_fd.fd, buf, BUFSIZE); + ret = ::read(client->cgi_pipe_rfd, buf, BUFSIZE); std::cerr << "cgi read ret = " << ret << "\n"; if (ret == -1) { std::perror("err read(cgi_fd)"); - cgi_fd.client->cgi_output = STATUS_500; + client->cgi_output = STATUS_500; } else if (ret == 0) - { - std::cerr << "cgi read 0 :o" << "\n"; - } + std::cerr << "Madame s'il vous plait, du Ketchup pour mon hamburger" << " (AKA:ret=0)" << "\n"; else - { - cgi_fd.client->cgi_output.append(buf, ret); - } - - - wait_ret = ::waitpid(cgi_fd.cgi_pid, NULL, WNOHANG); - std::cerr << "cgi waitpid ret = " << wait_ret << "\n"; - if (wait_ret == 0 && ret == -1) - { - _epoll_update(cgi_fd.client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); - _close_cgi_pipe_rfd(cgi_fd.fd); - // TODO: kill the child :) - } - else if (wait_ret == cgi_fd.cgi_pid) - { - _epoll_update(cgi_fd.client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); - _close_cgi_pipe_rfd(cgi_fd.fd); - } - return; + client->cgi_output.append(buf, ret); } -void Webserv::_handle_epoll_error_cgi_fd(uint32_t events, std::vector::iterator it) +void Webserv::_handle_epoll_error_cgi_fd(uint32_t events, Client *client) { (void)events; std::cerr << "cgi EPOLLERR" << "\n"; - std::cerr << "cgi_pid = " << it->cgi_pid << "\n"; - std::cerr << "client fd = " << it->client->get_cl_fd() << "\n"; - std::cerr << "cgi fd = " << it->fd << "\n"; + std::cerr << "cgi_pid = " << client->cgi_pid << "\n"; + std::cerr << "client fd = " << client->get_cl_fd() << "\n"; + std::cerr << "cgi fd = " << client->cgi_pipe_rfd << "\n"; pid_t wait_ret; - wait_ret = ::waitpid(it->cgi_pid, NULL, WNOHANG); + wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG); std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n"; if (wait_ret == 0) { - _epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); - _close_cgi_pipe_rfd(it->fd); + _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); + if (::close(client->cgi_pipe_rfd) == -1) + std::perror("err close()"); // TODO: kill the child :) } - else if (wait_ret == it->cgi_pid) + else if (wait_ret == client->cgi_pid) { - _epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); - _close_cgi_pipe_rfd(it->fd); + _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); + if (::close(client->cgi_pipe_rfd) == -1) + std::perror("err close()"); } } -void Webserv::_cgi_epollhup(uint32_t events, std::vector::iterator it) +void Webserv::_cgi_epollhup(uint32_t events, Client *client) { (void)events; + (void)client; + std::cerr << "cgi EPOLLHUP" << "\n"; - std::cerr << "cgi_pid = " << it->cgi_pid << "\n"; - std::cerr << "client fd = " << it->client->get_cl_fd() << "\n"; - std::cerr << "cgi fd = " << it->fd << "\n"; + std::cerr << "cgi_pid = " << client->cgi_pid << "\n"; + std::cerr << "client fd = " << client->get_cl_fd() << "\n"; + std::cerr << "cgi fd = " << client->cgi_pipe_rfd << "\n"; + if (client->cgi_pipe_rfd) + { + if (::close(client->cgi_pipe_rfd) == -1) + std::perror("err close()"); + } + client->cgi_pipe_rfd = 0; pid_t wait_ret; - wait_ret = ::waitpid(it->cgi_pid, NULL, WNOHANG); + wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG); std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n"; - if (wait_ret == 0) + if (wait_ret == client->cgi_pid) { - _epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); - _close_cgi_pipe_rfd(it->fd); - // TODO: kill the child :) + _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); } - else if (wait_ret == it->cgi_pid) +} + +Client *Webserv::_find_cgi_fd(int cgi_fd) +{ + std::vector::iterator it = _clients.begin(); + std::vector::iterator it_end = _clients.end(); + while (it != it_end) { - _epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); - _close_cgi_pipe_rfd(it->fd); - } + if (it->cgi_pipe_rfd == cgi_fd) + return (&(*it)); + ++it; + } + return (NULL); } void Webserv::run() @@ -112,7 +102,7 @@ void Webserv::run() int i; int count_loop = 0; std::vector::iterator it_lsocket; - std::vector::iterator it_cgi_fd; + Client *client_cgi = NULL; g_run = true; while (g_run) @@ -135,7 +125,7 @@ void Webserv::run() { try { it_lsocket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd); - it_cgi_fd = std::find(_cgi_pipe_rfds.begin(), _cgi_pipe_rfds.end(), events[i].data.fd); // Could be moved in the loop to avoid useless find() call + client_cgi = _find_cgi_fd(events[i].data.fd); if (it_lsocket != _listen_sockets.end()) { if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP) @@ -143,14 +133,14 @@ void Webserv::run() else if (events[i].events & EPOLLIN) _accept_connection(*it_lsocket); } - else if (it_cgi_fd != _cgi_pipe_rfds.end()) + else if (client_cgi) { if (events[i].events & EPOLLERR) - _handle_epoll_error_cgi_fd(events[i].events, it_cgi_fd); - else if (events[i].events & EPOLLHUP) - _cgi_epollhup(events[i].events, it_cgi_fd); + _handle_epoll_error_cgi_fd(events[i].events, client_cgi); else if (events[i].events & EPOLLIN) - _read_cgi_output(*it_cgi_fd); + _read_cgi_output(client_cgi); + else if ( (events[i].events & EPOLLHUP) && !(events[i].events & EPOLLIN) ) + _cgi_epollhup(events[i].events, client_cgi); } else { From 9f3903d4970de003e6c13f5636198a9420cb012a Mon Sep 17 00:00:00 2001 From: lperrey Date: Wed, 17 Aug 2022 01:49:31 +0200 Subject: [PATCH 4/4] Fixed, close() forgottens fds after fork + minors changes + Super new epoll loop output :) --- memo.txt | 17 ++++++++++++++ srcs/webserv/Webserv.hpp | 1 + srcs/webserv/close.cpp | 24 +++++++++++++++++++- srcs/webserv/run_loop.cpp | 48 +++++++++++++++++++-------------------- 4 files changed, 65 insertions(+), 25 deletions(-) diff --git a/memo.txt b/memo.txt index dd8e42a..d86090a 100644 --- a/memo.txt +++ b/memo.txt @@ -59,3 +59,20 @@ Valgrind error RESOLVED ! : ==847174== by 0x426BC5: Webserv::_read_cgi_output(cgi_pipe_rfd&) (run_loop.cpp:39) // (LUKE: its an string.append() call) ==847174== by 0x427962: Webserv::run() (run_loop.cpp:153) ==847174== by 0x4052E9: main (main.cpp:38) + +RESOLVED, AGAIN :D ! +--loop epoll() +EPOLLHUP on client fd 8 +47067----loop epoll() +EPOLLHUP on client fd 8 +47068----loop epoll() +EPOLLHUP on client fd 8 +47069----loop epoll() +EPOLLHUP on client fd 8 +47070----loop epoll() +EPOLLHUP on client fd 8 +47071----loop epoll() +EPOLLHUP on client fd 8 +47072----loop epoll() +EPOLLHUP on client fd 8 +47073----loop epoll() diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index 1b8ce8e..d7ecf42 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -107,6 +107,7 @@ class Webserv void _close_client(int fd); void _close_all_clients(); void _close_all_clients_fd(); + void _close_all_clients_cgi_fd(); void _close_cgi_pipe_rfd(int fd); void _close_all_cgi_pipe_rfd(); void _close_all_listen_sockets(); diff --git a/srcs/webserv/close.cpp b/srcs/webserv/close.cpp index 145287c..138be7e 100644 --- a/srcs/webserv/close.cpp +++ b/srcs/webserv/close.cpp @@ -28,6 +28,7 @@ void Webserv::_close_all_clients() void Webserv::_close_all_clients_fd() { + _close_all_clients_cgi_fd(); std::vector::iterator it = _clients.begin(); std::vector::iterator it_end = _clients.end(); while (it != it_end) @@ -40,6 +41,24 @@ void Webserv::_close_all_clients_fd() } } +void Webserv::_close_all_clients_cgi_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 + if (it->cgi_pipe_rfd) + { + std::cerr << "close cgi-fd " << it->cgi_pipe_rfd << "\n"; + if (::close(it->cgi_pipe_rfd) == -1) + std::perror("err close()"); + } + ++it; + } +} + + void Webserv::_close_all_listen_sockets() { // TODO : change like clients (clear in place of pop_back) while (!_listen_sockets.empty()) @@ -117,5 +136,8 @@ void Webserv::_handle_epoll_error_client(uint32_t events, int fd) std::cerr << "EPOLLERR on client fd " << fd << "\n"; // DEBUG if (events & EPOLLHUP) std::cerr << "EPOLLHUP on client fd " << fd << "\n"; // DEBUG - _close_client(fd); + if (std::find(_clients.begin(), _clients.end(), fd) != _clients.end()) + std::cerr << "Found the client in _clients" << "\n"; // DEBUG + + _close_client(fd); // " EPOLLHUP on client fd 8 " en boucle quand on mattraque un peu les CGI, donc il ne le trouve pas dans _clients. Etrange. } diff --git a/srcs/webserv/run_loop.cpp b/srcs/webserv/run_loop.cpp index 6301c6e..1b1e644 100644 --- a/srcs/webserv/run_loop.cpp +++ b/srcs/webserv/run_loop.cpp @@ -11,7 +11,6 @@ void Webserv::_read_cgi_output(Client *client) { char buf[BUFSIZE]; ssize_t ret; - pid_t wait_ret; std::cerr << "_read_cgi_output()" << "\n"; std::cerr << "cgi_pid = " << client->cgi_pid << "\n"; std::cerr << "client fd = " << client->get_cl_fd() << "\n"; @@ -37,23 +36,23 @@ void Webserv::_handle_epoll_error_cgi_fd(uint32_t events, Client *client) std::cerr << "cgi_pid = " << client->cgi_pid << "\n"; std::cerr << "client fd = " << client->get_cl_fd() << "\n"; std::cerr << "cgi fd = " << client->cgi_pipe_rfd << "\n"; - + + client->cgi_output = STATUS_500; + pid_t wait_ret; wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG); - std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n"; - if (wait_ret == 0) + std::cerr << "cgi EPOLLERR waitpid ret = " << wait_ret << "\n"; + if (wait_ret == client->cgi_pid) { + if (client->cgi_pipe_rfd) + { + if (::close(client->cgi_pipe_rfd) == -1) + std::perror("err close()"); + } + client->cgi_pipe_rfd = 0; _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); - if (::close(client->cgi_pipe_rfd) == -1) - std::perror("err close()"); - // TODO: kill the child :) } - else if (wait_ret == client->cgi_pid) - { - _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); - if (::close(client->cgi_pipe_rfd) == -1) - std::perror("err close()"); - } + } void Webserv::_cgi_epollhup(uint32_t events, Client *client) @@ -61,22 +60,22 @@ void Webserv::_cgi_epollhup(uint32_t events, Client *client) (void)events; (void)client; - std::cerr << "cgi EPOLLHUP" << "\n"; +/* std::cerr << "cgi EPOLLHUP" << "\n"; std::cerr << "cgi_pid = " << client->cgi_pid << "\n"; std::cerr << "client fd = " << client->get_cl_fd() << "\n"; - std::cerr << "cgi fd = " << client->cgi_pipe_rfd << "\n"; - if (client->cgi_pipe_rfd) - { - if (::close(client->cgi_pipe_rfd) == -1) - std::perror("err close()"); - } - client->cgi_pipe_rfd = 0; + std::cerr << "cgi fd = " << client->cgi_pipe_rfd << "\n"; */ pid_t wait_ret; wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG); - std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n"; + // std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n"; if (wait_ret == client->cgi_pid) { + if (client->cgi_pipe_rfd) + { + if (::close(client->cgi_pipe_rfd) == -1) + std::perror("err close()"); + } + client->cgi_pipe_rfd = 0; _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); } } @@ -107,8 +106,9 @@ void Webserv::run() g_run = true; while (g_run) { - std::cerr << ++count_loop << "----loop epoll()\n"; + std::cerr << ++count_loop << "----loop epoll() "; nfds = ::epoll_wait(_epfd, events, MAX_EVENTS, TIMEOUT); + std::cerr << "(nfds=" << nfds << ")\n"; if (nfds == -1) { int errno_copy = errno; @@ -142,7 +142,7 @@ void Webserv::run() else if ( (events[i].events & EPOLLHUP) && !(events[i].events & EPOLLIN) ) _cgi_epollhup(events[i].events, client_cgi); } - else + else if (std::find(_clients.begin(), _clients.end(), events[i].data.fd) != _clients.end()) // TODO: save the it in var to avoid multiples find() { if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP) _handle_epoll_error_client(events[i].events, events[i].data.fd);