body write to CGI now monitored by epoll

+ kermit.jpg :)
This commit is contained in:
lperrey
2022-08-17 23:42:12 +02:00
parent 2613ca2e1a
commit b34e49311b
13 changed files with 302 additions and 193 deletions

View File

@@ -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

View File

@@ -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<char, std::char_traits<char>, std::allocator<char> >::_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<char, std::char_traits<char>, std::allocator<char> >::_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)

View File

@@ -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<ServerConfig> &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)
{

View File

@@ -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<ServerConfig> &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

View File

@@ -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<listen_socket>::iterator it);
void _handle_epoll_error_lsocket(uint32_t events, std::vector<listen_socket>::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<std::string> &env_vector);
void _set_env_cstr(char *env_cstr[], std::vector<std::string> &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);
///////////////////////

View File

@@ -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<std::string> &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)

129
srcs/webserv/cgi_epoll.cpp Normal file
View File

@@ -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<Client>::iterator it = _clients.begin();
std::vector<Client>::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<Client>::iterator it = _clients.begin();
std::vector<Client>::iterator it_end = _clients.end();
while (it != it_end)
{
if (it->cgi_pipe_w_to_child == fd)
return (&(*it));
++it;
}
return (NULL);
}

View File

@@ -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<Client>::iterator it = _clients.begin();
std::vector<Client>::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<Client>::iterator it = _clients.begin();
std::vector<Client>::iterator it_end = _clients.end();
while (it != it_end)
{
// _epoll_update(_clients.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
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;
}
}

View File

@@ -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)

View File

@@ -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<Client>::iterator it = _clients.begin();
std::vector<Client>::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<listen_socket>::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()
{

BIN
www/Kermit_the_Frog.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -285,12 +285,8 @@
<label for="fdownload">download file:</label><br>
<input type="file" id="fupload" name="fupload">
<select name="file">
<option value="Cagneyc_intro.gif" >Cagneyc_intro.gif </option>
<option value="file.md" >file.md </option>
<option value="index.html" >index.html </option>
<option value="kermit.ico" >kermit.ico </option>
<option value="punpun.png" selected>punpun.png </option>
<option value="subject.pdf" >subject.pdf </option>
<option value="Kermit_the_Frog.jpg" selected >Kermit_the_Frog.jpg</option>
<option value="kermit_tea.jpg" >kermit_tea.jpg</option>
<option value="Van_Eyck_Portrait_Arnolfini.jpg" >Van_Eyck_Portrait_Arnolfini.jpg</option>
<option value="directory" >directory </option>
<option value="DOESNT_EXIST.BAD" >DOESNT_EXIST.BAD </option>

BIN
www/kermit_tea.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB