body write to CGI now monitored by epoll
+ kermit.jpg :)
This commit is contained in:
9
Makefile
9
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
|
||||
|
||||
2
memo.txt
2
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<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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
///////////////////////
|
||||
|
||||
@@ -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
129
srcs/webserv/cgi_epoll.cpp
Normal 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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
BIN
www/Kermit_the_Frog.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
@@ -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
BIN
www/kermit_tea.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 110 KiB |
Reference in New Issue
Block a user