Fixed big problem with CGI handling
+ remains somes minors problems
This commit is contained in:
12
memo.txt
12
memo.txt
@@ -23,6 +23,9 @@ For non blocking CGI :
|
||||
|
||||
- check status in autoindex
|
||||
|
||||
- merge changes from hugo5 to master (attention a pas casse svp :clown:)
|
||||
|
||||
|
||||
----Priorité modérée------------------------
|
||||
- namespace utils ?
|
||||
- change "std::string" to reference "std::string &" in most functions
|
||||
@@ -47,3 +50,12 @@ 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)
|
||||
|
||||
@@ -13,6 +13,7 @@ Client::Client()
|
||||
assigned_server(NULL),
|
||||
assigned_location(NULL),
|
||||
cgi_pipe_rfd(0),
|
||||
cgi_pid(0),
|
||||
_fd(0),
|
||||
_port(""),
|
||||
_ip(""),
|
||||
@@ -29,6 +30,7 @@ Client::Client(int afd, listen_socket *lsocket, std::string aport, std::string a
|
||||
assigned_server(NULL),
|
||||
assigned_location(NULL),
|
||||
cgi_pipe_rfd(0),
|
||||
cgi_pid(0),
|
||||
_fd(afd),
|
||||
_port(aport),
|
||||
_ip(aip),
|
||||
@@ -240,6 +242,7 @@ void Client::clear()
|
||||
assigned_server = NULL;
|
||||
assigned_location = NULL;
|
||||
cgi_pipe_rfd = 0;
|
||||
cgi_pid = 0;
|
||||
cgi_output.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ class Client
|
||||
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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
# include "cgi_utils.hpp"
|
||||
# include <unistd.h>
|
||||
# include <cstdio>
|
||||
|
||||
int main (int ac, char **av, char ** env)
|
||||
{
|
||||
@@ -10,11 +11,19 @@ int main (int ac, char **av, char ** env)
|
||||
(void)ac;
|
||||
(void)av;
|
||||
|
||||
::sleep(30);
|
||||
// ::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;
|
||||
}
|
||||
|
||||
@@ -44,15 +44,6 @@ void signal_handler(int signum);
|
||||
|
||||
# define MIME_TYPE_DEFAULT "application/octet-stream"
|
||||
|
||||
struct cgi_pipe_rfd
|
||||
{
|
||||
int fd;
|
||||
pid_t cgi_pid;
|
||||
Client *client;
|
||||
};
|
||||
bool operator==(const cgi_pipe_rfd& lhs, int fd);
|
||||
bool operator==(int fd, const cgi_pipe_rfd& rhs);
|
||||
|
||||
class Webserv
|
||||
{
|
||||
public:
|
||||
@@ -74,7 +65,6 @@ class Webserv
|
||||
private:
|
||||
int _epfd;
|
||||
std::vector<listen_socket> _listen_sockets;
|
||||
std::vector<cgi_pipe_rfd> _cgi_pipe_rfds;
|
||||
std::vector<ServerConfig> _servers;
|
||||
std::vector<Client> _clients;
|
||||
std::map<int, std::string> _http_status;
|
||||
@@ -147,9 +137,10 @@ class Webserv
|
||||
|
||||
|
||||
|
||||
void _read_cgi_output(cgi_pipe_rfd &cgi_fd);
|
||||
void _handle_epoll_error_cgi_fd(uint32_t events, std::vector<cgi_pipe_rfd>::iterator it);
|
||||
void _cgi_epollhup(uint32_t events, std::vector<cgi_pipe_rfd>::iterator it);
|
||||
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);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -223,16 +223,21 @@ void Webserv::_exec_script(Client *client, char *env[])
|
||||
_epoll_update(client->get_cl_fd(), 0, EPOLL_CTL_DEL);
|
||||
|
||||
client->cgi_pipe_rfd = FD_RD_FR_CHLD;
|
||||
struct cgi_pipe_rfd new_cgi_fd;
|
||||
new_cgi_fd.fd = FD_RD_FR_CHLD;
|
||||
new_cgi_fd.cgi_pid = pid;
|
||||
new_cgi_fd.client = client;
|
||||
_cgi_pipe_rfds.push_back(new_cgi_fd);
|
||||
client->cgi_pid = pid;
|
||||
}
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
@@ -40,39 +40,6 @@ void Webserv::_close_all_clients_fd()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO : not sure for zombie cgi-proccess, need to verif
|
||||
void Webserv::_close_cgi_pipe_rfd(int fd)
|
||||
{
|
||||
std::vector<cgi_pipe_rfd>::iterator it = _cgi_pipe_rfds.begin();
|
||||
std::vector<cgi_pipe_rfd>::iterator it_end = _cgi_pipe_rfds.end();
|
||||
while (it != it_end)
|
||||
{
|
||||
if (*it == fd)
|
||||
{
|
||||
std::cerr << "close cgi-fd " << fd << "\n";
|
||||
if (::close(fd) == -1)
|
||||
std::perror("err close()");
|
||||
_cgi_pipe_rfds.erase(it);
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void Webserv::_close_all_cgi_pipe_rfd()
|
||||
{
|
||||
std::vector<cgi_pipe_rfd>::iterator it = _cgi_pipe_rfds.begin();
|
||||
std::vector<cgi_pipe_rfd>::iterator it_end = _cgi_pipe_rfds.end();
|
||||
while (it != it_end)
|
||||
{
|
||||
std::cerr << "close cgi-fd " << it->fd << "\n";
|
||||
if (::close(it->fd) == -1)
|
||||
std::perror("err close()");
|
||||
++it;
|
||||
}
|
||||
_cgi_pipe_rfds.clear();
|
||||
}
|
||||
|
||||
void Webserv::_close_all_listen_sockets()
|
||||
{ // TODO : change like clients (clear in place of pop_back)
|
||||
while (!_listen_sockets.empty())
|
||||
|
||||
@@ -50,7 +50,7 @@ int Webserv::_send_response(Client *client)
|
||||
return SEND_IN_PROGRESS;
|
||||
}
|
||||
}
|
||||
else if (client->cgi_pipe_rfd)
|
||||
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";
|
||||
|
||||
@@ -4,104 +4,94 @@
|
||||
#define MAX_EVENTS 42 // arbitrary
|
||||
#define TIMEOUT 3000
|
||||
|
||||
// TODO: temp to move in own file
|
||||
bool operator==(const cgi_pipe_rfd& lhs, int fd)
|
||||
{ return lhs.fd == fd; }
|
||||
|
||||
bool operator==(int fd, const cgi_pipe_rfd& rhs)
|
||||
{ return fd == rhs.fd; }
|
||||
|
||||
#define BUFSIZE 8192 // (8Ko)
|
||||
#define STATUS_500 std::string("Status: 500" CRLF CRLF);
|
||||
void Webserv::_read_cgi_output(cgi_pipe_rfd &cgi_fd)
|
||||
void Webserv::_read_cgi_output(Client *client)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
ssize_t ret;
|
||||
pid_t wait_ret;
|
||||
std::cerr << "_read_cgi_output()" << "\n";
|
||||
std::cerr << "cgi_pid = " << cgi_fd.cgi_pid << "\n";
|
||||
std::cerr << "client fd = " << cgi_fd.client->get_cl_fd() << "\n";
|
||||
std::cerr << "cgi fd = " << cgi_fd.fd << "\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(cgi_fd.fd, buf, BUFSIZE);
|
||||
ret = ::read(client->cgi_pipe_rfd, buf, BUFSIZE);
|
||||
std::cerr << "cgi read ret = " << ret << "\n";
|
||||
if (ret == -1)
|
||||
{
|
||||
std::perror("err read(cgi_fd)");
|
||||
cgi_fd.client->cgi_output = STATUS_500;
|
||||
client->cgi_output = STATUS_500;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
std::cerr << "cgi read 0 :o" << "\n";
|
||||
}
|
||||
std::cerr << "Madame s'il vous plait, du Ketchup pour mon hamburger" << " (AKA:ret=0)" << "\n";
|
||||
else
|
||||
{
|
||||
cgi_fd.client->cgi_output.append(buf, ret);
|
||||
}
|
||||
|
||||
|
||||
wait_ret = ::waitpid(cgi_fd.cgi_pid, NULL, WNOHANG);
|
||||
std::cerr << "cgi waitpid ret = " << wait_ret << "\n";
|
||||
if (wait_ret == 0 && ret == -1)
|
||||
{
|
||||
_epoll_update(cgi_fd.client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
||||
_close_cgi_pipe_rfd(cgi_fd.fd);
|
||||
// TODO: kill the child :)
|
||||
}
|
||||
else if (wait_ret == cgi_fd.cgi_pid)
|
||||
{
|
||||
_epoll_update(cgi_fd.client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
||||
_close_cgi_pipe_rfd(cgi_fd.fd);
|
||||
}
|
||||
return;
|
||||
client->cgi_output.append(buf, ret);
|
||||
}
|
||||
|
||||
void Webserv::_handle_epoll_error_cgi_fd(uint32_t events, std::vector<cgi_pipe_rfd>::iterator it)
|
||||
void Webserv::_handle_epoll_error_cgi_fd(uint32_t events, Client *client)
|
||||
{
|
||||
(void)events;
|
||||
std::cerr << "cgi EPOLLERR" << "\n";
|
||||
std::cerr << "cgi_pid = " << it->cgi_pid << "\n";
|
||||
std::cerr << "client fd = " << it->client->get_cl_fd() << "\n";
|
||||
std::cerr << "cgi fd = " << it->fd << "\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(it->cgi_pid, NULL, WNOHANG);
|
||||
wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG);
|
||||
std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n";
|
||||
if (wait_ret == 0)
|
||||
{
|
||||
_epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
||||
_close_cgi_pipe_rfd(it->fd);
|
||||
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
||||
if (::close(client->cgi_pipe_rfd) == -1)
|
||||
std::perror("err close()");
|
||||
// TODO: kill the child :)
|
||||
}
|
||||
else if (wait_ret == it->cgi_pid)
|
||||
else if (wait_ret == client->cgi_pid)
|
||||
{
|
||||
_epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
||||
_close_cgi_pipe_rfd(it->fd);
|
||||
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
||||
if (::close(client->cgi_pipe_rfd) == -1)
|
||||
std::perror("err close()");
|
||||
}
|
||||
}
|
||||
|
||||
void Webserv::_cgi_epollhup(uint32_t events, std::vector<cgi_pipe_rfd>::iterator it)
|
||||
void Webserv::_cgi_epollhup(uint32_t events, Client *client)
|
||||
{
|
||||
(void)events;
|
||||
(void)client;
|
||||
|
||||
std::cerr << "cgi EPOLLHUP" << "\n";
|
||||
std::cerr << "cgi_pid = " << it->cgi_pid << "\n";
|
||||
std::cerr << "client fd = " << it->client->get_cl_fd() << "\n";
|
||||
std::cerr << "cgi fd = " << it->fd << "\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";
|
||||
if (client->cgi_pipe_rfd)
|
||||
{
|
||||
if (::close(client->cgi_pipe_rfd) == -1)
|
||||
std::perror("err close()");
|
||||
}
|
||||
client->cgi_pipe_rfd = 0;
|
||||
|
||||
pid_t wait_ret;
|
||||
wait_ret = ::waitpid(it->cgi_pid, NULL, WNOHANG);
|
||||
wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG);
|
||||
std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n";
|
||||
if (wait_ret == 0)
|
||||
if (wait_ret == client->cgi_pid)
|
||||
{
|
||||
_epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
||||
_close_cgi_pipe_rfd(it->fd);
|
||||
// TODO: kill the child :)
|
||||
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
||||
}
|
||||
else if (wait_ret == it->cgi_pid)
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
_epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
||||
_close_cgi_pipe_rfd(it->fd);
|
||||
}
|
||||
if (it->cgi_pipe_rfd == cgi_fd)
|
||||
return (&(*it));
|
||||
++it;
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void Webserv::run()
|
||||
@@ -112,7 +102,7 @@ void Webserv::run()
|
||||
int i;
|
||||
int count_loop = 0;
|
||||
std::vector<listen_socket>::iterator it_lsocket;
|
||||
std::vector<cgi_pipe_rfd>::iterator it_cgi_fd;
|
||||
Client *client_cgi = NULL;
|
||||
|
||||
g_run = true;
|
||||
while (g_run)
|
||||
@@ -135,7 +125,7 @@ void Webserv::run()
|
||||
{
|
||||
try {
|
||||
it_lsocket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd);
|
||||
it_cgi_fd = std::find(_cgi_pipe_rfds.begin(), _cgi_pipe_rfds.end(), events[i].data.fd); // Could be moved in the loop to avoid useless find() call
|
||||
client_cgi = _find_cgi_fd(events[i].data.fd);
|
||||
if (it_lsocket != _listen_sockets.end())
|
||||
{
|
||||
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP)
|
||||
@@ -143,14 +133,14 @@ void Webserv::run()
|
||||
else if (events[i].events & EPOLLIN)
|
||||
_accept_connection(*it_lsocket);
|
||||
}
|
||||
else if (it_cgi_fd != _cgi_pipe_rfds.end())
|
||||
else if (client_cgi)
|
||||
{
|
||||
if (events[i].events & EPOLLERR)
|
||||
_handle_epoll_error_cgi_fd(events[i].events, it_cgi_fd);
|
||||
else if (events[i].events & EPOLLHUP)
|
||||
_cgi_epollhup(events[i].events, it_cgi_fd);
|
||||
_handle_epoll_error_cgi_fd(events[i].events, client_cgi);
|
||||
else if (events[i].events & EPOLLIN)
|
||||
_read_cgi_output(*it_cgi_fd);
|
||||
_read_cgi_output(client_cgi);
|
||||
else if ( (events[i].events & EPOLLHUP) && !(events[i].events & EPOLLIN) )
|
||||
_cgi_epollhup(events[i].events, client_cgi);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user