merging small fixes andmore telnet tests

This commit is contained in:
Me
2022-08-17 02:51:32 +02:00
9 changed files with 278 additions and 116 deletions

View File

@@ -21,6 +21,10 @@ For non blocking CGI :
// when waitpid() tell us its finish (or maybe when epoll return EPOLLHUP)
// then actually parse the script_output and send it to the client.
- check status in autoindex
- merge changes from hugo5 to master (attention a pas casse svp :clown:)
----Priorité modérée------------------------
- namespace utils ?
@@ -28,7 +32,12 @@ For non blocking CGI :
and add "const" if apropriate.
- peut-être check si ip > 32bits
----Priorité faible------------------------
- idealy, we should not clear() raw_request after a response,
but just the part we actually parsed for this response.
I think the client could send multiples request on the same connection one after the other without waiting for response.
So raw_request could contain more than the first request we handle.
- chunked request (need testing)
- client_body_limit 0 valeur special pour desactiver dans config
- gerer le champ "Accept" du client
@@ -41,3 +50,29 @@ and add "const" if apropriate.
- change "std::string" to reference "std::string &" in most functions
and add "const" if apropriate.
- Il faut vérifier le path de la requête, voir si le serveur est bien censé délivrer cette ressource et si le client y a accès, avant d'appeler le CGI.
Valgrind error RESOLVED ! :
==847174== 1,314 bytes in 1 blocks are definitely lost in loss record 1 of 1
==847174== at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==847174== by 0x49AA35D: std::__cxx11::basic_string<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 0x427962: Webserv::run() (run_loop.cpp:153)
==847174== by 0x4052E9: main (main.cpp:38)
RESOLVED, AGAIN :D !
--loop epoll()
EPOLLHUP on client fd 8
47067----loop epoll()
EPOLLHUP on client fd 8
47068----loop epoll()
EPOLLHUP on client fd 8
47069----loop epoll()
EPOLLHUP on client fd 8
47070----loop epoll()
EPOLLHUP on client fd 8
47071----loop epoll()
EPOLLHUP on client fd 8
47072----loop epoll()
EPOLLHUP on client fd 8
47073----loop epoll()

View File

@@ -10,9 +10,10 @@ Client::Client()
header_complete(false),
body_complete(false),
request_complete(false),
read_body_size(0),
assigned_server(NULL),
assigned_location(NULL),
cgi_pipe_rfd(0),
cgi_pid(0),
_fd(0),
_port(""),
_ip(""),
@@ -26,9 +27,10 @@ Client::Client(int afd, listen_socket *lsocket, std::string aport, std::string a
header_complete(false),
body_complete(false),
request_complete(false),
read_body_size(0),
assigned_server(NULL),
assigned_location(NULL),
cgi_pipe_rfd(0),
cgi_pid(0),
_fd(afd),
_port(aport),
_ip(aip),
@@ -45,7 +47,6 @@ Client::~Client() {
Client::Client( Client const & src )
: status ( src.status ),
header_complete ( src.header_complete ),
read_body_size ( src.read_body_size ),
assigned_server ( src.assigned_server ),
assigned_location ( src.assigned_location ),
_fd ( src._fd ),
@@ -232,15 +233,17 @@ void Client::fill_script_path(std::string &path, size_t pos)
void Client::clear()
{
clear_request();
header_complete = false;
body_complete = false;
request_complete = false;
read_body_size = 0;
assigned_server = NULL;
assigned_location = NULL;
raw_request.clear();
response.clear();
status = 0;
header_complete = false;
body_complete = false;
request_complete = false;
assigned_server = NULL;
assigned_location = NULL;
cgi_pipe_rfd = 0;
cgi_pid = 0;
cgi_output.clear();
}
void Client::clear_request()
@@ -415,9 +418,9 @@ void Client::_parse_port_hostname(std::string host)
void Client::_check_request_errors()
{
std::cerr << "Content-Length=" << get_rq_headers("Content-Length") << "\n";
std::cerr << "strtoul=" << std::strtoul(get_rq_headers("Content-Length").c_str(), NULL, 10) << "\n";
std::cerr << "client_body_limit=" << assigned_server->client_body_limit << "\n";
// /* Debug */ std::cerr << "Content-Length=" << get_rq_headers("Content-Length") << "\n";
// /* Debug */ std::cerr << "strtoul=" << std::strtoul(get_rq_headers("Content-Length").c_str(), NULL, 10) << "\n";
// /* Debug */ std::cerr << "client_body_limit=" << assigned_server->client_body_limit << "\n";
///////////////////////
// Request line checks
if (_request.method == UNKNOWN)
@@ -466,11 +469,11 @@ ServerConfig *Client::_determine_process_server(Client *client, std::vector<Serv
*/
std::string server_name = client->get_rq_headers("Host");
std::cerr << "server_name = " << server_name << "\n";
// /* Debug */ std::cerr << "server_name = " << server_name << "\n";
size_t pos = server_name.rfind(':');
if (pos != NPOS)
server_name.erase(pos);
std::cerr << "server_name = " << server_name << "\n";
// /* Debug */ std::cerr << "server_name = " << server_name << "\n";
std::vector<ServerConfig>::iterator it = servers.begin();
std::vector<ServerConfig>::iterator default_server = servers.end();

View File

@@ -55,9 +55,12 @@ class Client
bool header_complete;
bool body_complete;
bool request_complete;
size_t read_body_size; // unused for now
// size_t read_body_size; // unused for now
ServerConfig *assigned_server; // cant be const cause of error_pages.operator[]
const LocationConfig *assigned_location;
int cgi_pipe_rfd;
pid_t cgi_pid;
std::string cgi_output;
// getters
int get_cl_fd() const;

View File

@@ -1,5 +1,7 @@
# include "cgi_utils.hpp"
# include <unistd.h>
# include <cstdio>
int main (int ac, char **av, char ** env)
{
@@ -9,9 +11,19 @@ int main (int ac, char **av, char ** env)
(void)ac;
(void)av;
// ::sleep(5);
fill_response_basic(env, http_body, http_header);
std::cout << http_header << CRLF CRLF << http_body;
std::cout << http_header;
std::flush(std::cout);
::sleep(2);
std::cout << CRLF CRLF;
std::flush(std::cout);
::sleep(2);
std::cout << http_body;
std::flush(std::cout);
::sleep(2);
return 0;
}

View File

@@ -107,6 +107,9 @@ class Webserv
void _close_client(int fd);
void _close_all_clients();
void _close_all_clients_fd();
void _close_all_clients_cgi_fd();
void _close_cgi_pipe_rfd(int fd);
void _close_all_cgi_pipe_rfd();
void _close_all_listen_sockets();
void _reopen_lsocket(std::vector<listen_socket>::iterator it);
void _handle_epoll_error_lsocket(uint32_t events, std::vector<listen_socket>::iterator it);
@@ -121,18 +124,27 @@ class Webserv
// cgi.cpp
bool _is_cgi(Client *client, std::string path);
size_t _cgi_pos(Client *client, std::string &path, size_t pos);
std::string _exec_cgi(Client *client);
void _exec_cgi(Client *client);
void _set_env_vector(Client *client, std::vector<std::string> &env_vector);
void _set_env_cstr(char *env_cstr[], std::vector<std::string> &env_vector);
std::string _dup_env(std::string var, std::string val);
std::string _dup_env(std::string var, int i);
std::string _exec_script(Client *client, char *env[]);
void _exec_script(Client *client, char *env[]);
void _check_script_output(Client *client, std::string & output);
void _check_script_status(Client *client, std::string & output);
void _check_script_fields(Client *client, std::string & output);
void _add_script_body_length_header(std::string & output);
void _remove_body_leading_empty_lines(std::string & output);
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);
///////////////////////
class ExecFail : public std::exception
{

View File

@@ -66,9 +66,8 @@ size_t Webserv::_cgi_pos(Client *client, std::string &path, size_t pos)
return NPOS;
}
std::string Webserv::_exec_cgi(Client *client)
void Webserv::_exec_cgi(Client *client)
{
std::string script_output;
char* env_cstr[19] = {NULL};
std::vector<std::string> env_vector;
env_vector.reserve(18);
@@ -77,12 +76,11 @@ std::string Webserv::_exec_cgi(Client *client)
_set_env_vector(client, env_vector);
try {
_set_env_cstr(env_cstr, env_vector);
script_output = _exec_script(client, env_cstr);
_exec_script(client, env_cstr);
while (env_cstr[i] != NULL)
delete[] env_cstr[i++];
return script_output;
return;
}
catch (const Webserv::ExecFail& e)
{
@@ -125,7 +123,7 @@ void Webserv::_set_env_vector(Client *client, std::vector<std::string> &env_vect
env_vector.push_back(_dup_env("QUERY_STRING" , client->get_rq_query()));
env_vector.push_back(_dup_env("REMOTE_ADDR" , client->get_cl_ip()));
env_vector.push_back(_dup_env("REMOTE_HOST" , client->get_cl_ip())); // equal to REMOTE_ADDR or empty
env_vector.push_back(_dup_env("REMOTE_IDENT")); // authentification not supported
env_vector.push_back(_dup_env("REMOTE_IDENT")); // authentification not supported
env_vector.push_back(_dup_env("REMOTE_USER")); // authentification not supported
env_vector.push_back(_dup_env("REQUEST_METHOD" , client->get_rq_method_str()));
env_vector.push_back(_dup_env("SCRIPT_NAME" , client->get_rq_script_path())); // LUKE: To Check
@@ -151,43 +149,17 @@ void Webserv::_set_env_cstr(char *env_cstr[], std::vector<std::string> &env_vect
env_cstr[i] = NULL;
}
/* void Webserv::_set_env_cstr(char *env_cstr[], std::vector<std::string> &env_vector)
{
env_cstr[0] = const_cast<char*>(env_vector[0].c_str());
env_cstr[1] = const_cast<char*>(env_vector[1].c_str());
env_cstr[2] = const_cast<char*>(env_vector[2].c_str());
env_cstr[3] = const_cast<char*>(env_vector[3].c_str());
env_cstr[4] = const_cast<char*>(env_vector[4].c_str());
env_cstr[5] = const_cast<char*>(env_vector[5].c_str());
env_cstr[6] = const_cast<char*>(env_vector[6].c_str());
env_cstr[7] = const_cast<char*>(env_vector[7].c_str());
env_cstr[8] = const_cast<char*>(env_vector[8].c_str());
env_cstr[9] = const_cast<char*>(env_vector[9].c_str());
env_cstr[10] = const_cast<char*>(env_vector[10].c_str());
env_cstr[11] = const_cast<char*>(env_vector[11].c_str());
env_cstr[12] = const_cast<char*>(env_vector[12].c_str());
env_cstr[13] = const_cast<char*>(env_vector[13].c_str());
env_cstr[14] = const_cast<char*>(env_vector[14].c_str());
env_cstr[15] = const_cast<char*>(env_vector[15].c_str());
env_cstr[16] = const_cast<char*>(env_vector[16].c_str());
env_cstr[17] = const_cast<char*>(env_vector[17].c_str());
env_cstr[18] = NULL;
} */
#define STATUS_500 std::string("Status: 500" CRLF CRLF);
std::string Webserv::_exec_script(Client *client, char *env[])
void Webserv::_exec_script(Client *client, char *env[])
{
#define RD 0
#define WR 1
#define CGI_BUF_SIZE 10
#define FD_WR_TO_CHLD fd_in[WR]
#define FD_WR_TO_PRNT fd_out[WR]
#define FD_RD_FR_CHLD fd_out[RD]
#define FD_RD_FR_PRNT fd_in[RD]
pid_t pid;
char buf[CGI_BUF_SIZE]; // WIP define buffer
char * const nll[1] = {NULL};
std::string script_output;
std::string body = client->get_rq_body();
@@ -195,12 +167,12 @@ std::string Webserv::_exec_script(Client *client, char *env[])
int fd_out[2];
std::string path;
pipe(fd_in);
pipe(fd_out);
::pipe(fd_in);
::pipe(fd_out);
pid = fork();
if (pid == -1)
perror("err fork()");
std::perror("err fork()");
else if (pid == 0) // child
{
std::signal(SIGPIPE, SIG_DFL);
@@ -212,14 +184,14 @@ std::string Webserv::_exec_script(Client *client, char *env[])
::close(FD_RD_FR_CHLD);
if (dup2(FD_RD_FR_PRNT, STDIN_FILENO) == -1)
{
perror("err dup2()");
std::perror("err dup2()");
::close(FD_RD_FR_PRNT); // Valgind debug, not essential
::close(FD_WR_TO_PRNT); // Valgind debug, not essential
throw ExecFail();
}
if (dup2(FD_WR_TO_PRNT, STDOUT_FILENO) == -1)
{
perror("err dup2()");
std::perror("err dup2()");
::close(FD_RD_FR_PRNT); // Valgind debug, not essential
::close(FD_WR_TO_PRNT); // Valgind debug, not essential
throw ExecFail();
@@ -230,9 +202,9 @@ std::string Webserv::_exec_script(Client *client, char *env[])
path = "." + client->get_rq_script_path(); // Wut ? Only relative path ?
/*DEBUG*/std::cerr << "execve:[" << path << "]\n";
if (execve(path.c_str(), nll, env) == -1) // replace path for debug error forcing
if (::execve(path.c_str(), nll, env) == -1) // replace path for debug error forcing
{
perror("err execve()");
std::perror("err execve()");
::close(STDIN_FILENO); // Valgind debug, not essential
::close(STDOUT_FILENO); // Valgind debug, not essential
throw ExecFail();
@@ -240,41 +212,32 @@ std::string Webserv::_exec_script(Client *client, char *env[])
}
else //parent
{
close(FD_RD_FR_PRNT);
close(FD_WR_TO_PRNT);
write(FD_WR_TO_CHLD, body.c_str(), body.size());
close(FD_WR_TO_CHLD);
waitpid(-1, NULL, 0);
// We could maybe,
::close(FD_RD_FR_PRNT);
::close(FD_WR_TO_PRNT);
::write(FD_WR_TO_CHLD, body.c_str(), body.size()); // move this before the fork ?
::close(FD_WR_TO_CHLD);
// add FD_RD_FR_CHLD to epoll,
// return to the main loop,
// read FD_RD_FR_CHLD each time epoll say its ready,
// then try waitpid() with WNOHANG after each read.
// when waitpid() tell us its finish (or maybe when epoll return EPOLLHUP)
// then actually parse the script_output and send it to the client.
_epoll_update(FD_RD_FR_CHLD, EPOLLIN, EPOLL_CTL_ADD);
// stop monitoring client->fd until the cgi-script as done is job
_epoll_update(client->get_cl_fd(), 0, EPOLL_CTL_DEL);
ssize_t ret = 1;
while (ret > 0)
{
ret = read(FD_RD_FR_CHLD, buf, CGI_BUF_SIZE);
if (ret == -1)
{
std::perror("err recv()");
script_output = STATUS_500;
break;
}
script_output.append(buf, ret);
}
close(FD_RD_FR_CHLD);
client->cgi_pipe_rfd = FD_RD_FR_CHLD;
client->cgi_pid = pid;
}
if (script_output.empty())
script_output = STATUS_500;
return script_output;
}
#define STATUS_500 std::string("Status: 500" CRLF CRLF);
void Webserv::_check_script_output(Client *client, std::string & output)
{
size_t pos;
pos = client->cgi_output.find(CRLF CRLF);
if (pos == 0 || pos == NPOS)
{
client->status = 500;;
return;
}
_check_script_status(client, output);
if (client->status >= 400 && client->status < 600)
return;

View File

@@ -4,7 +4,8 @@
void Webserv::_close_client(int fd)
{
std::vector<Client>::iterator it = _clients.begin();
while (it != _clients.end())
std::vector<Client>::iterator it_end = _clients.end();
while (it != it_end)
{
if (*it == fd)
{
@@ -27,20 +28,39 @@ void Webserv::_close_all_clients()
void Webserv::_close_all_clients_fd()
{
_close_all_clients_cgi_fd();
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
std::cerr << "close fd " << _clients.back().get_cl_fd() << "\n";
if (::close(_clients.back().get_cl_fd()) == -1)
std::cerr << "close fd " << it->get_cl_fd() << "\n";
if (::close(it->get_cl_fd()) == -1)
std::perror("err close()");
++it;
}
}
void Webserv::_close_all_listen_sockets()
void Webserv::_close_all_clients_cgi_fd()
{
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()");
}
++it;
}
}
void Webserv::_close_all_listen_sockets()
{ // TODO : change like clients (clear in place of pop_back)
while (!_listen_sockets.empty())
{
// _epoll_update(_listen_sockets.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
@@ -116,5 +136,8 @@ void Webserv::_handle_epoll_error_client(uint32_t events, int fd)
std::cerr << "EPOLLERR on client fd " << fd << "\n"; // DEBUG
if (events & EPOLLHUP)
std::cerr << "EPOLLHUP on client fd " << fd << "\n"; // DEBUG
_close_client(fd);
if (std::find(_clients.begin(), _clients.end(), fd) != _clients.end())
std::cerr << "Found the client in _clients" << "\n"; // DEBUG
_close_client(fd); // " EPOLLHUP on client fd 8 " en boucle quand on mattraque un peu les CGI, donc il ne le trouve pas dans _clients. Etrange.
}

View File

@@ -3,7 +3,7 @@
enum send_return
{
SEND_IN_PROGRESS, // unused
SEND_IN_PROGRESS,
SEND_COMPLETE,
SEND_CLOSE,
};
@@ -40,16 +40,33 @@ int Webserv::_send_response(Client *client)
std::cerr << "send()\n";
_append_base_headers(client);
if (!client->status)
_construct_response(client);
if (client->response.empty())
{
_append_base_headers(client);
if (!client->status)
{
_construct_response(client);
if (client->cgi_pipe_rfd)
return SEND_IN_PROGRESS;
}
}
else if (!client->cgi_output.empty())
{
// /*DEBUG*/ std::cout << "\n" B_PURPLE "[response]:" RESET "\n"; ::print_special(client->response); std::cout << B_PURPLE "-----------" RESET "\n\n";
// /*DEBUG*/ std::cout << "\n" B_PURPLE "[script output]:" RESET "\n"; ::print_special(script_output); std::cout << B_PURPLE "-----------" RESET "\n\n";
_check_script_output(client, client->cgi_output); // FD_CGI : adjust for client->cgi_output;
if (client->status < 400)
client->response += client->cgi_output;
// /*DEBUG*/ std::cout << "\n" B_PURPLE "[response + output]:" RESET "\n"; ::print_special(client->response); std::cout << B_PURPLE "-----------" RESET "\n\n";
}
_insert_status_line(client);
if (client->status >= 400)
_error_html_response(client);
//*DEBUG*/ std::cout << "\n" B_PURPLE "[response + output + headers]:" RESET "\n"; ::print_special(client->response); std::cout << "\n" B_PURPLE "-----------" RESET "\n\n";
std::cerr << "client->response.size() = " << client->response.size() << "\n"; // DEBUG
// /* Debug */ std::cerr << "client->response.size() = " << client->response.size() << "\n"; // DEBUG
ret = ::send(client->get_cl_fd(), client->response.c_str(), client->response.size(), 0);
if (ret == -1)
{
@@ -62,7 +79,7 @@ int Webserv::_send_response(Client *client)
std::cerr << "SEND RET 0 for client.fd =" << client->get_cl_fd() << "\n"; // DEBUG
return SEND_CLOSE;
}
std::cerr << "ret send() = " << ret << "\n"; // DEBUG
// /* Debug */ std::cerr << "ret send() = " << ret << "\n"; // DEBUG
return SEND_COMPLETE;
}
@@ -89,14 +106,7 @@ void Webserv::_construct_response(Client *client)
path = _replace_url_root(client, client->get_rq_abs_path());
if (_is_cgi(client, path))
{
script_output = _exec_cgi(client);
//*DEBUG*/ std::cout << "\n" B_PURPLE "[response]:" RESET "\n"; ::print_special(client->response); std::cout << B_PURPLE "-----------" RESET "\n\n";
//*DEBUG*/ std::cout << "\n" B_PURPLE "[script output]:" RESET "\n"; ::print_special(script_output); std::cout << B_PURPLE "-----------" RESET "\n\n";
_check_script_output(client, script_output);
if (client->status < 400)
client->response += script_output;
//*DEBUG*/ std::cout << "\n" B_PURPLE "[response + output]:" RESET "\n"; ::print_special(client->response); std::cout << B_PURPLE "-----------" RESET "\n\n";
_exec_cgi(client);
return;
}
_process_method(client, path);
@@ -104,7 +114,7 @@ void Webserv::_construct_response(Client *client)
void Webserv::_process_method(Client *client, std::string &path)
{
std::cerr << "allow_methods = " << http_methods_to_str(client->assigned_location->allow_methods) << "\n"; // debug
// std::cerr << "allow_methods = " << http_methods_to_str(client->assigned_location->allow_methods) << "\n"; // debug
std::cerr << "Path again: " << path << '\n'; // debug
switch (client->get_rq_method())
@@ -122,13 +132,13 @@ void Webserv::_process_method(Client *client, std::string &path)
std::string Webserv::_replace_url_root(Client *client, std::string path)
{
std::cerr << "assigned_location->path = " << client->assigned_location->path << "\n"; // debug
std::cerr << "path before = " << path << "\n"; // DEBUG
// /* Debug */ std::cerr << "assigned_location->path = " << client->assigned_location->path << "\n"; // debug
// /* Debug */ std::cerr << "path before = " << path << "\n"; // DEBUG
if (client->assigned_location->path == "/")
path.insert(0, client->assigned_location->root);
else
path.replace(0, client->assigned_location->path.size(), client->assigned_location->root);
std::cerr << "path after = " << path << "\n"; // DEBUG
// /* Debug */ std::cerr << "path after = " << path << "\n"; // DEBUG
return path;
}

View File

@@ -4,6 +4,95 @@
#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
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";
@@ -11,13 +100,15 @@ void Webserv::run()
int nfds;
int i;
int count_loop = 0;
std::vector<listen_socket>::iterator it_socket;
std::vector<listen_socket>::iterator it_lsocket;
Client *client_cgi = NULL;
g_run = true;
while (g_run)
{
std::cerr << ++count_loop << "----loop epoll()\n";
std::cerr << ++count_loop << "----loop epoll() ";
nfds = ::epoll_wait(_epfd, events, MAX_EVENTS, TIMEOUT);
std::cerr << "(nfds=" << nfds << ")\n";
if (nfds == -1)
{
int errno_copy = errno;
@@ -33,15 +124,25 @@ void Webserv::run()
while (i < nfds)
{
try {
it_socket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd);
if (it_socket != _listen_sockets.end())
it_lsocket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd);
client_cgi = _find_cgi_fd(events[i].data.fd);
if (it_lsocket != _listen_sockets.end())
{
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP)
_handle_epoll_error_lsocket(events[i].events, it_socket);
_handle_epoll_error_lsocket(events[i].events, it_lsocket);
else if (events[i].events & EPOLLIN)
_accept_connection(*it_socket);
_accept_connection(*it_lsocket);
}
else
else if (client_cgi)
{
if (events[i].events & EPOLLERR)
_handle_epoll_error_cgi_fd(events[i].events, client_cgi);
else if (events[i].events & EPOLLIN)
_read_cgi_output(client_cgi);
else if ( (events[i].events & EPOLLHUP) && !(events[i].events & EPOLLIN) )
_cgi_epollhup(events[i].events, client_cgi);
}
else if (std::find(_clients.begin(), _clients.end(), events[i].data.fd) != _clients.end()) // TODO: save the it in var to avoid multiples find()
{
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP)
_handle_epoll_error_client(events[i].events, events[i].data.fd);