diff --git a/Makefile b/Makefile index 65e7816..626bcaf 100644 --- a/Makefile +++ b/Makefile @@ -2,13 +2,12 @@ NAME = webserv CXX = c++ -CXXFLAGS = -Wall -Wextra #-Werror +CXXFLAGS = -Wall -Wextra -Werror CXXFLAGS += $(HEADERS_D:%=-I%) CXXFLAGS += -std=c++98 CXXFLAGS += -g #CXXFLAGS += -fno-limit-debug-info CXXFLAGS += -MMD -MP #header dependencie -#CXXFLAGS += -O3 VPATH = $(SRCS_D) @@ -25,11 +24,9 @@ SRCS = main.cpp \ accept.cpp request.cpp response.cpp \ method_get.cpp method_post.cpp method_delete.cpp \ run_loop.cpp timeout.cpp \ - parser.cpp \ - extraConfig.cpp \ - postProcessing.cpp \ + parser.cpp extraConfig.cpp postProcessing.cpp \ utils.cpp \ - cgi.cpp \ + cgi.cpp cgi_epoll.cpp \ Client.cpp Client_multipart_body.cpp \ OBJS_D = builds diff --git a/memo.txt b/memo.txt index 92ca789..99f9ffe 100644 --- a/memo.txt +++ b/memo.txt @@ -41,7 +41,7 @@ Valgrind error RESOLVED ! : ==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 0x426BC5: Webserv::_read_cgi_output(cgi_pipe_r_from_child&) (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 25596c1..8012801 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -12,7 +12,11 @@ Client::Client() request_complete(false), assigned_server(NULL), assigned_location(NULL), - cgi_pipe_rfd(0), + cgi_state(0), + cgi_pipe_w_to_child(0), + cgi_pipe_r_from_child(0), + cgi_pipe_w_to_parent(0), + cgi_pipe_r_from_parent(0), cgi_pid(0), _fd(0), _port(""), @@ -29,7 +33,11 @@ Client::Client(int afd, listen_socket *lsocket, std::string aport, std::string a request_complete(false), assigned_server(NULL), assigned_location(NULL), - cgi_pipe_rfd(0), + cgi_state(0), + cgi_pipe_w_to_child(0), + cgi_pipe_r_from_child(0), + cgi_pipe_w_to_parent(0), + cgi_pipe_r_from_parent(0), cgi_pid(0), _fd(afd), _port(aport), @@ -87,7 +95,7 @@ void Client::parse_request_headers(std::vector &servers) if (raw_request.find(CRLF CRLF) == NPOS) return ; header_complete = true; - clear_request(); // not mandatory + clear_request_vars(); // not mandatory _parse_request_line(); if (status) @@ -229,7 +237,7 @@ void Client::fill_script_path(std::string &path, size_t pos) void Client::clear() { - clear_request(); + clear_request_vars(); raw_request.clear(); response.clear(); status = 0; @@ -238,12 +246,10 @@ void Client::clear() request_complete = false; assigned_server = NULL; assigned_location = NULL; - cgi_pipe_rfd = 0; - cgi_pid = 0; - cgi_output.clear(); + clear_cgi_vars(); } -void Client::clear_request() +void Client::clear_request_vars() { clear_script(); _request.method = UNKNOWN; @@ -264,6 +270,17 @@ void Client::clear_script() _request.script.info.clear(); } +void Client::clear_cgi_vars() +{ + cgi_state = false; + cgi_pipe_w_to_child = 0; + cgi_pipe_r_from_child = 0; + cgi_pipe_w_to_parent = 0; + cgi_pipe_r_from_parent = 0; + cgi_pid = 0; + cgi_output.clear(); +} + // debug void Client::print_client(std::string message) { diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 2d6e879..0fa8a5d 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -40,6 +40,15 @@ struct Request struct Script script; }; +enum cgi_states +{ + CGI_NO_CGI = 0, + CGI_WAIT_TO_EXEC, + CGI_READY_TO_EXEC, + CGI_WAIT_FOR_OUTPUT, + CGI_OUTPUT_READY +}; + class Client { public: @@ -58,7 +67,13 @@ class Client // 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; + + // CGI variables + int cgi_state; + int cgi_pipe_w_to_child; + int cgi_pipe_r_from_child; + int cgi_pipe_w_to_parent; + int cgi_pipe_r_from_parent; pid_t cgi_pid; std::string cgi_output; @@ -88,7 +103,8 @@ class Client void parse_request_headers(std::vector &servers); void parse_request_body(); void clear(); - void clear_request(); + void clear_request_vars(); + void clear_cgi_vars(); void clear_script(); void fill_script_path(std::string &path, size_t pos); // DEBUG diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index 24ce1fc..d865989 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -105,11 +105,12 @@ class Webserv void _handle_last_signal(); // close.cpp void _close_client(int fd); + void _close_client_cgi_pipes(Client *client); 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_clients_cgi_pipes(); + void _close_cgi_pipe_r_from_child(int fd); + void _close_all_cgi_pipe_r_from_child(); void _close_all_listen_sockets(); void _reopen_lsocket(std::vector::iterator it); void _handle_epoll_error_lsocket(uint32_t events, std::vector::iterator it); @@ -124,6 +125,7 @@ class Webserv // cgi.cpp bool _is_cgi(Client *client, std::string path); size_t _cgi_pos(Client *client, std::string &path, size_t pos); + void _cgi_open_pipes(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); @@ -136,11 +138,14 @@ class Webserv void _check_fields_duplicates(Client *client, std::string & output); void _add_script_body_length_header(std::string & output); void _remove_body_leading_empty_lines(std::string & output); - - 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); + // cgi_epoll.cpp + void _read_cgi_output(Client *client); + void _handle_epollerr_cgi_output(uint32_t events, Client *client); + void _handle_epollhup_cgi_output(uint32_t events, Client *client); + void _cgi_input_ready(Client *client); + void _handle_epollerr_cgi_input(uint32_t events, Client *client); + Client *_find_cgi_output_fd(int fd); + Client *_find_cgi_input_fd(int fd); /////////////////////// diff --git a/srcs/webserv/cgi.cpp b/srcs/webserv/cgi.cpp index a16c3f1..99ffdb3 100644 --- a/srcs/webserv/cgi.cpp +++ b/srcs/webserv/cgi.cpp @@ -66,6 +66,28 @@ size_t Webserv::_cgi_pos(Client *client, std::string &path, size_t pos) return NPOS; } +void Webserv::_cgi_open_pipes(Client *client) +{ + #define R 0 + #define W 1 + + int fd_in[2]; + int fd_out[2]; + ::pipe(fd_in); + ::pipe(fd_out); + + client->cgi_pipe_r_from_parent = fd_in[R]; + client->cgi_pipe_w_to_child = fd_in[W]; + client->cgi_pipe_r_from_child = fd_out[R]; + client->cgi_pipe_w_to_parent = fd_out[W]; + + // epoll add for writing body to child + _epoll_update(client->cgi_pipe_w_to_child, EPOLLOUT, EPOLL_CTL_ADD); + // stop monitoring client->fd until we can write body + _epoll_update(client->get_cl_fd(), 0, EPOLL_CTL_DEL); + client->cgi_state = CGI_WAIT_TO_EXEC; +} + void Webserv::_exec_cgi(Client *client) { char* env_cstr[19] = {NULL}; @@ -152,24 +174,11 @@ void Webserv::_set_env_cstr(char *env_cstr[], std::vector &env_vect void Webserv::_exec_script(Client *client, char *env[]) { - #define RD 0 - #define WR 1 - #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 * const nll[1] = {NULL}; std::string script_output; - std::string body = client->get_rq_body(); - int fd_in[2]; - int fd_out[2]; std::string path; - ::pipe(fd_in); - ::pipe(fd_out); - pid = fork(); if (pid == -1) std::perror("err fork()"); @@ -178,52 +187,57 @@ void Webserv::_exec_script(Client *client, char *env[]) 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) + if (dup2(client->cgi_pipe_r_from_parent, STDIN_FILENO) == -1) { std::perror("err dup2()"); - ::close(FD_RD_FR_PRNT); // Valgind debug, not essential - ::close(FD_WR_TO_PRNT); // Valgind debug, not essential + if (::close(client->cgi_pipe_r_from_parent) == -1) // Valgind debug, not essential + std::perror("err close"); + if (::close(client->cgi_pipe_w_to_parent) == -1) // Valgind debug, not essential + std::perror("err close"); throw ExecFail(); } - if (dup2(FD_WR_TO_PRNT, STDOUT_FILENO) == -1) + if (dup2(client->cgi_pipe_w_to_parent, STDOUT_FILENO) == -1) { std::perror("err dup2()"); - ::close(FD_RD_FR_PRNT); // Valgind debug, not essential - ::close(FD_WR_TO_PRNT); // Valgind debug, not essential + if (::close(client->cgi_pipe_r_from_parent) == -1) // Valgind debug, not essential + std::perror("err close"); + if (::close(client->cgi_pipe_w_to_parent) == -1) // Valgind debug, not essential + std::perror("err close"); throw ExecFail(); } - ::close(FD_RD_FR_PRNT); - ::close(FD_WR_TO_PRNT); + _close_all_clients_fd(); + if (::close(_epfd) == -1) + std::perror("err close"); 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 { std::perror("err execve()"); - ::close(STDIN_FILENO); // Valgind debug, not essential - ::close(STDOUT_FILENO); // Valgind debug, not essential + if (::close(STDIN_FILENO) == -1) // Valgind debug, not essential + std::perror("err close"); + if (::close(STDOUT_FILENO) == -1) // Valgind debug, not essential + std::perror("err close"); throw ExecFail(); } } else //parent { - ::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); + if (::close(client->cgi_pipe_r_from_parent) == -1) + std::perror("err close"); + if (::close(client->cgi_pipe_w_to_parent) == -1) + std::perror("err close"); + if (::close(client->cgi_pipe_w_to_child) == -1) + std::perror("err close"); - // add FD_RD_FR_CHLD to epoll, - _epoll_update(FD_RD_FR_CHLD, EPOLLIN, EPOLL_CTL_ADD); + // add client->cgi_pipe_r_from_child to epoll, + _epoll_update(client->cgi_pipe_r_from_child, 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); - client->cgi_pipe_rfd = FD_RD_FR_CHLD; client->cgi_pid = pid; + client->cgi_state = CGI_WAIT_FOR_OUTPUT; } } @@ -241,15 +255,15 @@ void Webserv::_check_script_output(Client *client, std::string & output) _check_script_status(client, output); if (client->status >= 400 && client->status < 600) return; -/*DEBUG*/ std::cout << "\n" B_PURPLE "[script status]:\n" << "client->status:[" << client->status << "]" RESET "\n"; ::print_special(output); std::cout << B_PURPLE "-----------" RESET "\n\n"; +// /*DEBUG*/ std::cout << "\n" B_PURPLE "[script status]:\n" << "client->status:[" << client->status << "]" RESET "\n"; ::print_special(output); std::cout << B_PURPLE "-----------" RESET "\n\n"; client->status = _check_script_fields(output, client->status); -/*DEBUG*/ std::cout << "\n" B_PURPLE "[script fields]:\n" << "client->status:[" << client->status << "]" RESET "\n"; ::print_special(output); std::cout << B_PURPLE "-----------" RESET "\n\n"; +// /*DEBUG*/ std::cout << "\n" B_PURPLE "[script fields]:\n" << "client->status:[" << client->status << "]" RESET "\n"; ::print_special(output); std::cout << B_PURPLE "-----------" RESET "\n\n"; _check_fields_duplicates(client, output); -/*DEBUG*/ std::cout << "\n" B_PURPLE "[fields duplicates]:\n" << "client->status:[" << client->status << "]" RESET "\n"; ::print_special(output); std::cout << B_PURPLE "-----------" RESET "\n\n"; +// /*DEBUG*/ std::cout << "\n" B_PURPLE "[fields duplicates]:\n" << "client->status:[" << client->status << "]" RESET "\n"; ::print_special(output); std::cout << B_PURPLE "-----------" RESET "\n\n"; _remove_body_leading_empty_lines(output); -/*DEBUG*/ std::cout << "\n" B_PURPLE "[script empty lines]:\n" << "client->status:[" << client->status << "]" RESET "\n"; ::print_special(output); std::cout << B_PURPLE "-----------" RESET "\n\n"; +// /*DEBUG*/ std::cout << "\n" B_PURPLE "[script empty lines]:\n" << "client->status:[" << client->status << "]" RESET "\n"; ::print_special(output); std::cout << B_PURPLE "-----------" RESET "\n\n"; _add_script_body_length_header(output); -/*DEBUG*/ std::cout << "\n" B_PURPLE "[script content length]:\n" << "client->status:[" << client->status << "]" RESET "\n"; ::print_special(output); std::cout << B_PURPLE "-----------" RESET "\n\n"; +// /*DEBUG*/ std::cout << "\n" B_PURPLE "[script content length]:\n" << "client->status:[" << client->status << "]" RESET "\n"; ::print_special(output); std::cout << B_PURPLE "-----------" RESET "\n\n"; } void Webserv::_check_script_status(Client *client, std::string & output) diff --git a/srcs/webserv/cgi_epoll.cpp b/srcs/webserv/cgi_epoll.cpp new file mode 100644 index 0000000..a7d93d9 --- /dev/null +++ b/srcs/webserv/cgi_epoll.cpp @@ -0,0 +1,129 @@ + +#include "Webserv.hpp" + + +#define BUFSIZE 8192 // (8Ko) +#define STATUS_500 std::string("Status: 500" CRLF CRLF); +void Webserv::_read_cgi_output(Client *client) +{ + char buf[BUFSIZE]; + ssize_t ret; + std::cerr << "_read_cgi_output()" << "\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_r_from_child << "\n"; + + ret = ::read(client->cgi_pipe_r_from_child, buf, BUFSIZE); + std::cerr << "cgi read ret = " << ret << "\n"; + if (ret == -1) + { + std::perror("err read(cgi_fd)"); + client->cgi_output = STATUS_500; + } + else if (ret == 0) + std::cerr << "Madame s'il vous plait, du Ketchup pour mon hamburger" << " (AKA:ret=0)" << "\n"; + else + { + std::cerr << "NORMAL BEHAVIOR I THINK!\n"; // debug + client->cgi_output.append(buf, ret); + } +} + +void Webserv::_handle_epollerr_cgi_output(uint32_t events, Client *client) +{ + (void)events; + std::cerr << "cgi EPOLLERR" << "\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_r_from_child << "\n"; + + client->cgi_output = STATUS_500; + + // Common with EPOLLHUP + pid_t wait_ret; + wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG); + std::cerr << "cgi EPOLLERR waitpid ret = " << wait_ret << "\n"; + if (wait_ret == client->cgi_pid) + { + if (client->cgi_pipe_r_from_child) + { + if (::close(client->cgi_pipe_r_from_child) == -1) + std::perror("err close()"); + } + client->cgi_pipe_r_from_child = 0; + _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); + client->cgi_state = CGI_OUTPUT_READY; + } + +} + +void Webserv::_handle_epollhup_cgi_output(uint32_t events, Client *client) +{ + (void)events; + (void)client; + +/* 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_r_from_child << "\n"; */ + + // Common with EPOLLERR + pid_t wait_ret; + wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG); + // std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n"; + if (wait_ret == client->cgi_pid) + { + if (client->cgi_pipe_r_from_child) + { + if (::close(client->cgi_pipe_r_from_child) == -1) + std::perror("err close()"); + } + client->cgi_pipe_r_from_child = 0; + _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); + client->cgi_state = CGI_OUTPUT_READY; + } +} + +void Webserv::_cgi_input_ready(Client *client) +{ + client->cgi_state = CGI_READY_TO_EXEC; + _epoll_update(client->cgi_pipe_w_to_child, 0, EPOLL_CTL_DEL); + _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); +} + +void Webserv::_handle_epollerr_cgi_input(uint32_t events, Client *client) +{ + (void)events; + + client->cgi_output = STATUS_500; + + client->cgi_state = CGI_OUTPUT_READY; + _close_client_cgi_pipes(client); + _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); +} + +Client *Webserv::_find_cgi_output_fd(int fd) +{ + std::vector::iterator it = _clients.begin(); + std::vector::iterator it_end = _clients.end(); + while (it != it_end) + { + if (it->cgi_pipe_r_from_child == fd) + return (&(*it)); + ++it; + } + return (NULL); +} + +Client *Webserv::_find_cgi_input_fd(int fd) +{ + std::vector::iterator it = _clients.begin(); + std::vector::iterator it_end = _clients.end(); + while (it != it_end) + { + if (it->cgi_pipe_w_to_child == fd) + return (&(*it)); + ++it; + } + return (NULL); +} diff --git a/srcs/webserv/close.cpp b/srcs/webserv/close.cpp index 138be7e..18fdd74 100644 --- a/srcs/webserv/close.cpp +++ b/srcs/webserv/close.cpp @@ -13,6 +13,7 @@ void Webserv::_close_client(int fd) std::cerr << "close fd " << fd << "\n"; if (::close(fd) == -1) std::perror("err close()"); + _close_client_cgi_pipes(&(*it)); _clients.erase(it); break; } @@ -20,6 +21,22 @@ void Webserv::_close_client(int fd) } } +void Webserv::_close_client_cgi_pipes(Client *client) +{ + if (client->cgi_state) + { + std::cerr << "close cgi-pipes" << "\n"; + if (::close(client->cgi_pipe_w_to_child) == -1) + std::perror("err close()"); + if (::close(client->cgi_pipe_r_from_child) == -1) + std::perror("err close()"); + if (::close(client->cgi_pipe_w_to_parent) == -1) + std::perror("err close()"); + if (::close(client->cgi_pipe_r_from_parent) == -1) + std::perror("err close()"); + } +} + void Webserv::_close_all_clients() { _close_all_clients_fd(); @@ -28,7 +45,7 @@ void Webserv::_close_all_clients() void Webserv::_close_all_clients_fd() { - _close_all_clients_cgi_fd(); + _close_all_clients_cgi_pipes(); std::vector::iterator it = _clients.begin(); std::vector::iterator it_end = _clients.end(); while (it != it_end) @@ -41,19 +58,14 @@ void Webserv::_close_all_clients_fd() } } -void Webserv::_close_all_clients_cgi_fd() +void Webserv::_close_all_clients_cgi_pipes() { 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()"); - } + _close_client_cgi_pipes(&(*it)); ++it; } } diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 3f574b4..d78c60f 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -43,28 +43,21 @@ int Webserv::_send_response(Client *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_output.empty()) + + if (!client->status) { - /*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(client->cgi_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"; + _construct_response(client); + if (client->cgi_state == CGI_WAIT_FOR_OUTPUT + || client->cgi_state == CGI_WAIT_TO_EXEC) + return SEND_IN_PROGRESS; } _insert_status_line(client); if (client->status >= 400) _error_html_response(client); -/*DEBUG*/ std::cout << "\n" B_PURPLE "[response + output + headers]:" RESET "\n"; ::print_special(client->response); std::cout << "\n" B_PURPLE "-----------" RESET "\n\n"; +// /*DEBUG*/ std::cout << "\n" B_PURPLE "[response + output + headers]:" RESET "\n"; ::print_special(client->response); std::cout << "\n" B_PURPLE "-----------" RESET "\n\n"; // /* 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); @@ -103,12 +96,25 @@ void Webserv::_construct_response(Client *client) std::string script_output; path = _replace_url_root(client, client->get_rq_abs_path()); - if (_is_cgi(client, path)) + if (client->cgi_state == CGI_READY_TO_EXEC) { + std::string body = client->get_rq_body(); + ::write(client->cgi_pipe_w_to_child, body.c_str(), body.size()); _exec_cgi(client); - return; } - _process_method(client, path); + else if (client->cgi_state == CGI_OUTPUT_READY) + { + // /*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(client->cgi_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"; + } + else if (_is_cgi(client, path)) + _cgi_open_pipes(client); + else + _process_method(client, path); } void Webserv::_process_method(Client *client, std::string &path) diff --git a/srcs/webserv/run_loop.cpp b/srcs/webserv/run_loop.cpp index dea6a8e..4c5d752 100644 --- a/srcs/webserv/run_loop.cpp +++ b/srcs/webserv/run_loop.cpp @@ -4,98 +4,6 @@ #define MAX_EVENTS 42 // arbitrary #define TIMEOUT 3000 - -#define BUFSIZE 8192 // (8Ko) -#define STATUS_500 std::string("Status: 500" CRLF CRLF); -void Webserv::_read_cgi_output(Client *client) -{ - char buf[BUFSIZE]; - ssize_t ret; - std::cerr << "_read_cgi_output()" << "\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(client->cgi_pipe_rfd, buf, BUFSIZE); - std::cerr << "cgi read ret = " << ret << "\n"; - if (ret == -1) - { - std::perror("err read(cgi_fd)"); - client->cgi_output = STATUS_500; - } - else if (ret == 0) - std::cerr << "Madame s'il vous plait, du Ketchup pour mon hamburger" << " (AKA:ret=0)" << "\n"; - else - { - std::cerr << "NORMAL BEHAVIOR I THINK!\n"; // debug - client->cgi_output.append(buf, ret); - } -} - -void Webserv::_handle_epoll_error_cgi_fd(uint32_t events, Client *client) -{ - (void)events; - std::cerr << "cgi EPOLLERR" << "\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"; - - client->cgi_output = STATUS_500; - - pid_t wait_ret; - wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG); - 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); - } - -} - -void Webserv::_cgi_epollhup(uint32_t events, Client *client) -{ - (void)events; - (void)client; - -/* 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"; */ - - pid_t wait_ret; - wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG); - // 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); - } -} - -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) - { - if (it->cgi_pipe_rfd == cgi_fd) - return (&(*it)); - ++it; - } - return (NULL); -} - void Webserv::run() { std::cerr << "Server started\n"; @@ -104,7 +12,8 @@ void Webserv::run() int i; int count_loop = 0; std::vector::iterator it_lsocket; - Client *client_cgi = NULL; + Client *client_cgi_output = NULL; + Client *client_cgi_input = NULL; g_run = true; while (g_run) @@ -128,7 +37,8 @@ void Webserv::run() { try { it_lsocket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd); - client_cgi = _find_cgi_fd(events[i].data.fd); + client_cgi_output = _find_cgi_output_fd(events[i].data.fd); + client_cgi_input = _find_cgi_input_fd(events[i].data.fd); if (it_lsocket != _listen_sockets.end()) { if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP) @@ -136,14 +46,21 @@ void Webserv::run() else if (events[i].events & EPOLLIN) _accept_connection(*it_lsocket); } - else if (client_cgi) + else if (client_cgi_input) + { + if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP) + _handle_epollerr_cgi_input(events[i].events, client_cgi_input); + else if (events[i].events & EPOLLOUT) + _cgi_input_ready(client_cgi_input); + } + else if (client_cgi_output) { if (events[i].events & EPOLLERR) - _handle_epoll_error_cgi_fd(events[i].events, client_cgi); + _handle_epollerr_cgi_output(events[i].events, client_cgi_output); else if (events[i].events & EPOLLIN) - _read_cgi_output(client_cgi); + _read_cgi_output(client_cgi_output); else if ( (events[i].events & EPOLLHUP) && !(events[i].events & EPOLLIN) ) - _cgi_epollhup(events[i].events, client_cgi); + _handle_epollhup_cgi_output(events[i].events, client_cgi_output); } else if (std::find(_clients.begin(), _clients.end(), events[i].data.fd) != _clients.end()) // TODO: save the it in var to avoid multiples find() { diff --git a/www/Kermit_the_Frog.jpg b/www/Kermit_the_Frog.jpg new file mode 100644 index 0000000..4dcb88c Binary files /dev/null and b/www/Kermit_the_Frog.jpg differ diff --git a/www/form_cgi.html b/www/form_cgi.html index 2e73f05..388629a 100644 --- a/www/form_cgi.html +++ b/www/form_cgi.html @@ -285,12 +285,8 @@