diff --git a/default.config b/default.config index 977f9f6..356638f 100644 --- a/default.config +++ b/default.config @@ -21,6 +21,9 @@ server { # error_page 403 ./www/error_pages/error_404.html; + location /kapouet { + root /tmp/www; + } location / { allow_methods GET; @@ -37,6 +40,7 @@ server { autoindex on; } + location /cgi-bin { root ./srcs/cgi-bin/; cgi_ext out php sh; @@ -44,19 +48,7 @@ server { location /upload { allow_methods POST; - # autoindex on; - # root ./www/; - # index upload_form_single.html; - - # upload_dir ./www/user_files/; - # root doesn’t matter if used only with POST and no CGI - } - - location /uploaded { - allow_methods GET; - autoindex on; - # upload_dir ./www/user_files/; - root ./www/user_files; + upload_dir ./www/user_files/; # root doesn’t matter if used only with POST and no CGI } diff --git a/srcs/Client.cpp b/srcs/Client.cpp index 8012801..eec2e52 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -12,13 +12,13 @@ Client::Client() request_complete(false), assigned_server(NULL), assigned_location(NULL), - 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_state(CGI_NO_CGI), + cgi_pipe_w_to_child(-1), + cgi_pipe_r_from_child(-1), + cgi_pipe_w_to_parent(-1), + cgi_pipe_r_from_parent(-1), cgi_pid(0), - _fd(0), + _fd(-1), _port(""), _ip(""), _lsocket(NULL) @@ -33,11 +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_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_state(CGI_NO_CGI), + cgi_pipe_w_to_child(-1), + cgi_pipe_r_from_child(-1), + cgi_pipe_w_to_parent(-1), + cgi_pipe_r_from_parent(-1), cgi_pid(0), _fd(afd), _port(aport), @@ -272,11 +272,11 @@ void Client::clear_script() 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_state = CGI_NO_CGI; + cgi_pipe_w_to_child = -1; + cgi_pipe_r_from_child = -1; + cgi_pipe_w_to_parent = -1; + cgi_pipe_r_from_parent = -1; cgi_pid = 0; cgi_output.clear(); } diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 0fa8a5d..56536d7 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -45,8 +45,8 @@ enum cgi_states CGI_NO_CGI = 0, CGI_WAIT_TO_EXEC, CGI_READY_TO_EXEC, - CGI_WAIT_FOR_OUTPUT, - CGI_OUTPUT_READY + CGI_OUTPUT_READING, + CGI_OUTPUT_COMPLETE }; class Client @@ -69,7 +69,7 @@ class Client const LocationConfig *assigned_location; // CGI variables - int cgi_state; + cgi_states cgi_state; int cgi_pipe_w_to_child; int cgi_pipe_r_from_child; int cgi_pipe_w_to_parent; diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index d865989..ba1514d 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -109,8 +109,6 @@ class Webserv void _close_all_clients(); void _close_all_clients_fd(); 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); @@ -134,7 +132,8 @@ class Webserv 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); - size_t _check_script_fields(const std::string & output, size_t status); + unsigned int + _check_script_fields(const std::string & output, unsigned int status); 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); diff --git a/srcs/webserv/cgi.cpp b/srcs/webserv/cgi.cpp index 99ffdb3..8ad5e90 100644 --- a/srcs/webserv/cgi.cpp +++ b/srcs/webserv/cgi.cpp @@ -70,16 +70,27 @@ 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); + int pipe_fd[2]; - 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]; + if (::pipe(pipe_fd) == -1) + { + std::perror("err pipe"); + client->status = 500; + } + client->cgi_pipe_r_from_parent = pipe_fd[R]; + client->cgi_pipe_w_to_child = pipe_fd[W]; + + if (::pipe(pipe_fd) == -1) + { + std::perror("err pipe"); + if (::close(client->cgi_pipe_r_from_parent) == -1) + std::perror("err close()"); + if (::close(client->cgi_pipe_w_to_child) == -1) + std::perror("err close()"); + client->status = 500; + } + client->cgi_pipe_r_from_child = pipe_fd[R]; + client->cgi_pipe_w_to_parent = pipe_fd[W]; // epoll add for writing body to child _epoll_update(client->cgi_pipe_w_to_child, EPOLLOUT, EPOLL_CTL_ADD); @@ -181,7 +192,11 @@ void Webserv::_exec_script(Client *client, char *env[]) pid = fork(); if (pid == -1) + { std::perror("err fork()"); + client->status = 500; + _close_client_cgi_pipes(client); + } else if (pid == 0) // child { std::signal(SIGPIPE, SIG_DFL); @@ -189,19 +204,13 @@ void Webserv::_exec_script(Client *client, char *env[]) if (dup2(client->cgi_pipe_r_from_parent, STDIN_FILENO) == -1) { - std::perror("err dup2()"); - 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"); + std::perror("err dup2() STDIN_FILENO"); throw ExecFail(); } if (dup2(client->cgi_pipe_w_to_parent, STDOUT_FILENO) == -1) { - std::perror("err dup2()"); - 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 dup2() STDOUT_FILENO"); + if (::close(STDIN_FILENO) == -1) // Valgind debug, not essential std::perror("err close"); throw ExecFail(); } @@ -210,8 +219,8 @@ void Webserv::_exec_script(Client *client, char *env[]) if (::close(_epfd) == -1) std::perror("err close"); - path = client->get_rq_script_path(); // Wut ? Only relative path ? -/*DEBUG*/std::cerr << "execve:[" << path << "]\n"; + path = client->get_rq_script_path(); + std::cerr << "execve:[" << path << "]\n"; // DEBUG if (::execve(path.c_str(), nll, env) == -1) // replace path for debug error forcing { std::perror("err execve()"); @@ -230,18 +239,17 @@ void Webserv::_exec_script(Client *client, char *env[]) std::perror("err close"); if (::close(client->cgi_pipe_w_to_child) == -1) std::perror("err close"); - // 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_pid = pid; - client->cgi_state = CGI_WAIT_FOR_OUTPUT; + client->cgi_state = CGI_OUTPUT_READING; } + } -#define STATUS_500 std::string("Status: 500" CRLF CRLF); void Webserv::_check_script_output(Client *client, std::string & output) { @@ -282,17 +290,16 @@ void Webserv::_check_script_status(Client *client, std::string & output) client->status = 200; } -size_t Webserv::_check_script_fields(const std::string & output, size_t status) +unsigned int Webserv::_check_script_fields(const std::string & output, unsigned int status) { std::string headers; std::string body; size_t pos; -std::cerr << "0\n"; +std::cerr << "_check_script_fields()\n"; pos = output.find(CRLF CRLF); if (pos == NPOS) // there is not empty line return 500; -std::cerr << "1\n"; headers = output.substr(0, pos); body = output.substr(pos + CRLF_SIZE * 2); headers = str_tolower(headers); @@ -301,18 +308,14 @@ std::cerr << "1\n"; { if (!body.empty()) // there is body return 500; -std::cerr << "2\n"; if (headers.find("location") == NPOS) // there is no location field return 500; -std::cerr << "3\n"; } else if (headers.find("location") != NPOS) // there is a location field { if (body.empty()) // there is no body return 500; -std::cerr << "4\n"; } -std::cerr << "5\n"; return status; } diff --git a/srcs/webserv/cgi_epoll.cpp b/srcs/webserv/cgi_epoll.cpp index a7d93d9..3220626 100644 --- a/srcs/webserv/cgi_epoll.cpp +++ b/srcs/webserv/cgi_epoll.cpp @@ -3,30 +3,27 @@ #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"; + std::cerr << "_read_cgi_output()" << "\n"; // Debug + std::cerr << "cgi_pid = " << client->cgi_pid << "\n"; // Debug + std::cerr << "client fd = " << client->get_cl_fd() << "\n"; // Debug + std::cerr << "cgi fd = " << client->cgi_pipe_r_from_child << "\n"; // Debug ret = ::read(client->cgi_pipe_r_from_child, buf, BUFSIZE); - std::cerr << "cgi read ret = " << ret << "\n"; + std::cerr << "cgi read ret = " << ret << "\n"; // Debug if (ret == -1) { std::perror("err read(cgi_fd)"); - client->cgi_output = STATUS_500; + client->status = 500; + client->cgi_state = CGI_NO_CGI; } else if (ret == 0) - std::cerr << "Madame s'il vous plait, du Ketchup pour mon hamburger" << " (AKA:ret=0)" << "\n"; + 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) @@ -37,7 +34,8 @@ void Webserv::_handle_epollerr_cgi_output(uint32_t events, Client *client) 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; + client->status = 500; + client->cgi_state = CGI_NO_CGI; // Common with EPOLLHUP pid_t wait_ret; @@ -45,14 +43,11 @@ void Webserv::_handle_epollerr_cgi_output(uint32_t events, Client *client) 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->cgi_pipe_r_from_child, 0, EPOLL_CTL_DEL); + if (::close(client->cgi_pipe_r_from_child) == -1) + std::perror("err close()"); + client->cgi_pipe_r_from_child = -1; _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); - client->cgi_state = CGI_OUTPUT_READY; } } @@ -73,14 +68,12 @@ void Webserv::_handle_epollhup_cgi_output(uint32_t events, Client *client) // 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->cgi_pipe_r_from_child, 0, EPOLL_CTL_DEL); + if (::close(client->cgi_pipe_r_from_child) == -1) + std::perror("err close()"); + client->cgi_pipe_r_from_child = -1; _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); - client->cgi_state = CGI_OUTPUT_READY; + client->cgi_state = CGI_OUTPUT_COMPLETE; } } @@ -95,9 +88,8 @@ void Webserv::_handle_epollerr_cgi_input(uint32_t events, Client *client) { (void)events; - client->cgi_output = STATUS_500; - - client->cgi_state = CGI_OUTPUT_READY; + client->status = 500; + client->cgi_state = CGI_NO_CGI; _close_client_cgi_pipes(client); _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); } diff --git a/srcs/webserv/close.cpp b/srcs/webserv/close.cpp index 18fdd74..49533df 100644 --- a/srcs/webserv/close.cpp +++ b/srcs/webserv/close.cpp @@ -14,6 +14,7 @@ void Webserv::_close_client(int fd) if (::close(fd) == -1) std::perror("err close()"); _close_client_cgi_pipes(&(*it)); + // it->clear(); // PISTE, debug normalement superflu _clients.erase(it); break; } @@ -24,23 +25,38 @@ void Webserv::_close_client(int fd) void Webserv::_close_client_cgi_pipes(Client *client) { if (client->cgi_state) - { + { // No need to reset the fd to -1 normaly std::cerr << "close cgi-pipes" << "\n"; if (::close(client->cgi_pipe_w_to_child) == -1) std::perror("err close()"); + // client->cgi_pipe_w_to_child = -1; + if (::close(client->cgi_pipe_r_from_child) == -1) std::perror("err close()"); + // client->cgi_pipe_r_from_child = -1; + if (::close(client->cgi_pipe_w_to_parent) == -1) std::perror("err close()"); + // client->cgi_pipe_w_to_parent = -1; + if (::close(client->cgi_pipe_r_from_parent) == -1) std::perror("err close()"); + // client->cgi_pipe_r_from_parent = -1; } } void Webserv::_close_all_clients() { _close_all_clients_fd(); + _clients.clear(); + // REMPLACEMENT -> +/* while (!_clients.empty()) + { + std::cerr << "_clients.pop_back() " << &_clients.back() << "\n"; + _clients.back().clear(); + _clients.pop_back(); + } */ } void Webserv::_close_all_clients_fd() diff --git a/srcs/webserv/request.cpp b/srcs/webserv/request.cpp index 2940d4c..9df7a75 100644 --- a/srcs/webserv/request.cpp +++ b/srcs/webserv/request.cpp @@ -25,8 +25,6 @@ void Webserv::_request(Client *client) } else if (ret == READ_COMPLETE) { - if (client->body_complete && client->get_rq_multi_bodys().empty()) // DEBUG - std::cerr << "______BODY\n" << client->get_rq_body() << "\n______\n"; // DEBUG _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_MOD); client->request_complete = true; } @@ -53,13 +51,10 @@ int Webserv::_read_request(Client *client) // ::print_special(client->raw_request); // std::cerr << "__raw_request__\n" << client->raw_request << "\n______\n"; // DEBUG - print_special(client->raw_request); - - std::cerr << "client header complete: " << client->header_complete << "\n"; // DEBUG + // print_special(client->raw_request); if (!client->header_complete) { - std::cout << "Header not complete\n"; // debug client->parse_request_headers(_servers); if (client->status) return READ_COMPLETE; @@ -78,7 +73,6 @@ int Webserv::_read_request(Client *client) } if (client->header_complete) { - std::cerr << "Client header Complete\n"; // client->read_body_size += ret; // Not accurate, part of body could have been read with headers, unused for now client->parse_request_body(); if (client->status || client->body_complete) diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index d78c60f..e0c1908 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -25,6 +25,7 @@ void Webserv::_response(Client *client) || client->status == 400 // TODO: Refactoring || client->status == 408 || client->status == 413) + // || client->cgi_state == CGI_OUTPUT_COMPLETE) // DEBUG _close_client(client->get_cl_fd()); else { @@ -48,8 +49,8 @@ int Webserv::_send_response(Client *client) if (!client->status) { _construct_response(client); - if (client->cgi_state == CGI_WAIT_FOR_OUTPUT - || client->cgi_state == CGI_WAIT_TO_EXEC) + if (client->cgi_state == CGI_WAIT_TO_EXEC + || client->cgi_state == CGI_OUTPUT_READING) return SEND_IN_PROGRESS; } @@ -72,6 +73,11 @@ int Webserv::_send_response(Client *client) std::cerr << "SEND RET 0 for client.fd =" << client->get_cl_fd() << "\n"; // DEBUG return SEND_CLOSE; } + if (ret < (int)client->response.size()) + { + std::cerr << "send() as not send all data, IT CAN HAPPEN !" << "\n"; // DEBUG + throw ExecFail(); // DEBUG, TODO, A ENLEVER ABSOLEMENT, WHILE TEMP =D + } // /* Debug */ std::cerr << "ret send() = " << ret << "\n"; // DEBUG return SEND_COMPLETE; @@ -99,16 +105,26 @@ void Webserv::_construct_response(Client *client) 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()); + std::cerr << "client.fd for write body =" << client->get_cl_fd() << "\n"; // DEBUG + std::cerr << "client.cgi_pipe_w_to_child for write body =" << client->cgi_pipe_w_to_child << "\n"; // DEBUG + if (::write(client->cgi_pipe_w_to_child, body.c_str(), body.size()) == -1) + { + std::perror("err write()"); + _close_client_cgi_pipes(client); + client->status = 500; + client->cgi_state = CGI_NO_CGI; + return; + } _exec_cgi(client); } - else if (client->cgi_state == CGI_OUTPUT_READY) + else if (client->cgi_state == CGI_OUTPUT_COMPLETE) { // /*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) + if (client->status < 400 || client->status >= 600) client->response += client->cgi_output; + // client->cgi_state = CGI_NO_CGI; // Not indispensable, reset when client.clear() // /*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)) diff --git a/srcs/webserv/run_loop.cpp b/srcs/webserv/run_loop.cpp index 4c5d752..d62856f 100644 --- a/srcs/webserv/run_loop.cpp +++ b/srcs/webserv/run_loop.cpp @@ -12,8 +12,9 @@ void Webserv::run() int i; int count_loop = 0; std::vector::iterator it_lsocket; - Client *client_cgi_output = NULL; + std::vector::iterator it_client; Client *client_cgi_input = NULL; + Client *client_cgi_output = NULL; g_run = true; while (g_run) @@ -37,8 +38,10 @@ void Webserv::run() { try { it_lsocket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd); - client_cgi_output = _find_cgi_output_fd(events[i].data.fd); + it_client = std::find(_clients.begin(), _clients.end(), events[i].data.fd); client_cgi_input = _find_cgi_input_fd(events[i].data.fd); + client_cgi_output = _find_cgi_output_fd(events[i].data.fd); + if (it_lsocket != _listen_sockets.end()) { if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP) @@ -46,6 +49,15 @@ void Webserv::run() else if (events[i].events & EPOLLIN) _accept_connection(*it_lsocket); } + else if (it_client != _clients.end()) + { + if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP) + _handle_epoll_error_client(events[i].events, events[i].data.fd); + else if (events[i].events & EPOLLIN) + _request( &(*it_client) ); + else if (events[i].events & EPOLLOUT) + _response( &(*it_client) ); + } else if (client_cgi_input) { if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP) @@ -62,14 +74,9 @@ void Webserv::run() else if ( (events[i].events & EPOLLHUP) && !(events[i].events & EPOLLIN) ) _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() + else { - if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP) - _handle_epoll_error_client(events[i].events, events[i].data.fd); - else if (events[i].events & EPOLLIN) - _request( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) ); - else if (events[i].events & EPOLLOUT) - _response( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) ); + std::cerr << "NOTHING FOR FD = " << events[i].data.fd << "\n"; // DEBUG } ++i; if (!g_run) diff --git a/urls.txt b/urls.txt index bd87e74..19c3260 100644 --- a/urls.txt +++ b/urls.txt @@ -6,4 +6,3 @@ http://localhost:4040/test http://localhost:4040/test/test_deeper/ http://localhost:4040/test/test_deeper/super_deep/ http://localhost:4040/test/index1.html - diff --git a/urls_cgi.txt b/urls_cgi.txt new file mode 100644 index 0000000..cd2f146 --- /dev/null +++ b/urls_cgi.txt @@ -0,0 +1 @@ +http://localhost:4040/cgi-bin/cgi_cpp_empty.out?fname=John&lname=Doe \ No newline at end of file diff --git a/www/user_files/pepe.jpg b/www/user_files/pepe.jpg new file mode 100644 index 0000000..1877242 Binary files /dev/null and b/www/user_files/pepe.jpg differ