Debug in progress, somes fix but not the main problem

This commit is contained in:
lperrey
2022-08-18 06:03:09 +02:00
parent a008c12058
commit 3d17db996a
13 changed files with 136 additions and 117 deletions

View File

@@ -21,6 +21,9 @@ server {
# error_page 403 ./www/error_pages/error_404.html;
location /kapouet {
root /tmp/www;
}
location / {
allow_methods GET;
@@ -37,6 +40,7 @@ server {
autoindex on;
}
location /cgi-bin {
root ./srcs/cgi-bin/;
cgi_ext out php sh;
@@ -44,19 +48,7 @@ server {
location /upload {
allow_methods POST;
# autoindex on;
# root ./www/;
# index upload_form_single.html;
# upload_dir ./www/user_files/;
# root doesnt matter if used only with POST and no CGI
}
location /uploaded {
allow_methods GET;
autoindex on;
# upload_dir ./www/user_files/;
root ./www/user_files;
upload_dir ./www/user_files/;
# root doesnt matter if used only with POST and no CGI
}

View File

@@ -12,13 +12,13 @@ Client::Client()
request_complete(false),
assigned_server(NULL),
assigned_location(NULL),
cgi_state(0),
cgi_pipe_w_to_child(0),
cgi_pipe_r_from_child(0),
cgi_pipe_w_to_parent(0),
cgi_pipe_r_from_parent(0),
cgi_state(CGI_NO_CGI),
cgi_pipe_w_to_child(-1),
cgi_pipe_r_from_child(-1),
cgi_pipe_w_to_parent(-1),
cgi_pipe_r_from_parent(-1),
cgi_pid(0),
_fd(0),
_fd(-1),
_port(""),
_ip(""),
_lsocket(NULL)
@@ -33,11 +33,11 @@ Client::Client(int afd, listen_socket *lsocket, std::string aport, std::string a
request_complete(false),
assigned_server(NULL),
assigned_location(NULL),
cgi_state(0),
cgi_pipe_w_to_child(0),
cgi_pipe_r_from_child(0),
cgi_pipe_w_to_parent(0),
cgi_pipe_r_from_parent(0),
cgi_state(CGI_NO_CGI),
cgi_pipe_w_to_child(-1),
cgi_pipe_r_from_child(-1),
cgi_pipe_w_to_parent(-1),
cgi_pipe_r_from_parent(-1),
cgi_pid(0),
_fd(afd),
_port(aport),
@@ -272,11 +272,11 @@ void Client::clear_script()
void Client::clear_cgi_vars()
{
cgi_state = false;
cgi_pipe_w_to_child = 0;
cgi_pipe_r_from_child = 0;
cgi_pipe_w_to_parent = 0;
cgi_pipe_r_from_parent = 0;
cgi_state = CGI_NO_CGI;
cgi_pipe_w_to_child = -1;
cgi_pipe_r_from_child = -1;
cgi_pipe_w_to_parent = -1;
cgi_pipe_r_from_parent = -1;
cgi_pid = 0;
cgi_output.clear();
}

View File

@@ -45,8 +45,8 @@ enum cgi_states
CGI_NO_CGI = 0,
CGI_WAIT_TO_EXEC,
CGI_READY_TO_EXEC,
CGI_WAIT_FOR_OUTPUT,
CGI_OUTPUT_READY
CGI_OUTPUT_READING,
CGI_OUTPUT_COMPLETE
};
class Client
@@ -69,7 +69,7 @@ class Client
const LocationConfig *assigned_location;
// CGI variables
int cgi_state;
cgi_states cgi_state;
int cgi_pipe_w_to_child;
int cgi_pipe_r_from_child;
int cgi_pipe_w_to_parent;

View File

@@ -109,8 +109,6 @@ class Webserv
void _close_all_clients();
void _close_all_clients_fd();
void _close_all_clients_cgi_pipes();
void _close_cgi_pipe_r_from_child(int fd);
void _close_all_cgi_pipe_r_from_child();
void _close_all_listen_sockets();
void _reopen_lsocket(std::vector<listen_socket>::iterator it);
void _handle_epoll_error_lsocket(uint32_t events, std::vector<listen_socket>::iterator it);
@@ -134,7 +132,8 @@ class Webserv
void _exec_script(Client *client, char *env[]);
void _check_script_output(Client *client, std::string & output);
void _check_script_status(Client *client, std::string & output);
size_t _check_script_fields(const std::string & output, size_t status);
unsigned int
_check_script_fields(const std::string & output, unsigned int status);
void _check_fields_duplicates(Client *client, std::string & output);
void _add_script_body_length_header(std::string & output);
void _remove_body_leading_empty_lines(std::string & output);

View File

@@ -70,16 +70,27 @@ void Webserv::_cgi_open_pipes(Client *client)
{
#define R 0
#define W 1
int fd_in[2];
int fd_out[2];
::pipe(fd_in);
::pipe(fd_out);
int pipe_fd[2];
client->cgi_pipe_r_from_parent = fd_in[R];
client->cgi_pipe_w_to_child = fd_in[W];
client->cgi_pipe_r_from_child = fd_out[R];
client->cgi_pipe_w_to_parent = fd_out[W];
if (::pipe(pipe_fd) == -1)
{
std::perror("err pipe");
client->status = 500;
}
client->cgi_pipe_r_from_parent = pipe_fd[R];
client->cgi_pipe_w_to_child = pipe_fd[W];
if (::pipe(pipe_fd) == -1)
{
std::perror("err pipe");
if (::close(client->cgi_pipe_r_from_parent) == -1)
std::perror("err close()");
if (::close(client->cgi_pipe_w_to_child) == -1)
std::perror("err close()");
client->status = 500;
}
client->cgi_pipe_r_from_child = pipe_fd[R];
client->cgi_pipe_w_to_parent = pipe_fd[W];
// epoll add for writing body to child
_epoll_update(client->cgi_pipe_w_to_child, EPOLLOUT, EPOLL_CTL_ADD);
@@ -181,7 +192,11 @@ void Webserv::_exec_script(Client *client, char *env[])
pid = fork();
if (pid == -1)
{
std::perror("err fork()");
client->status = 500;
_close_client_cgi_pipes(client);
}
else if (pid == 0) // child
{
std::signal(SIGPIPE, SIG_DFL);
@@ -189,19 +204,13 @@ void Webserv::_exec_script(Client *client, char *env[])
if (dup2(client->cgi_pipe_r_from_parent, STDIN_FILENO) == -1)
{
std::perror("err dup2()");
if (::close(client->cgi_pipe_r_from_parent) == -1) // Valgind debug, not essential
std::perror("err close");
if (::close(client->cgi_pipe_w_to_parent) == -1) // Valgind debug, not essential
std::perror("err close");
std::perror("err dup2() STDIN_FILENO");
throw ExecFail();
}
if (dup2(client->cgi_pipe_w_to_parent, STDOUT_FILENO) == -1)
{
std::perror("err dup2()");
if (::close(client->cgi_pipe_r_from_parent) == -1) // Valgind debug, not essential
std::perror("err close");
if (::close(client->cgi_pipe_w_to_parent) == -1) // Valgind debug, not essential
std::perror("err dup2() STDOUT_FILENO");
if (::close(STDIN_FILENO) == -1) // Valgind debug, not essential
std::perror("err close");
throw ExecFail();
}
@@ -210,8 +219,8 @@ void Webserv::_exec_script(Client *client, char *env[])
if (::close(_epfd) == -1)
std::perror("err close");
path = client->get_rq_script_path(); // Wut ? Only relative path ?
/*DEBUG*/std::cerr << "execve:[" << path << "]\n";
path = client->get_rq_script_path();
std::cerr << "execve:[" << path << "]\n"; // DEBUG
if (::execve(path.c_str(), nll, env) == -1) // replace path for debug error forcing
{
std::perror("err execve()");
@@ -230,18 +239,17 @@ void Webserv::_exec_script(Client *client, char *env[])
std::perror("err close");
if (::close(client->cgi_pipe_w_to_child) == -1)
std::perror("err close");
// add client->cgi_pipe_r_from_child to epoll,
_epoll_update(client->cgi_pipe_r_from_child, EPOLLIN, EPOLL_CTL_ADD);
// stop monitoring client->fd until the cgi-script as done is job
_epoll_update(client->get_cl_fd(), 0, EPOLL_CTL_DEL);
client->cgi_pid = pid;
client->cgi_state = CGI_WAIT_FOR_OUTPUT;
client->cgi_state = CGI_OUTPUT_READING;
}
}
#define STATUS_500 std::string("Status: 500" CRLF CRLF);
void Webserv::_check_script_output(Client *client, std::string & output)
{
@@ -282,17 +290,16 @@ void Webserv::_check_script_status(Client *client, std::string & output)
client->status = 200;
}
size_t Webserv::_check_script_fields(const std::string & output, size_t status)
unsigned int Webserv::_check_script_fields(const std::string & output, unsigned int status)
{
std::string headers;
std::string body;
size_t pos;
std::cerr << "0\n";
std::cerr << "_check_script_fields()\n";
pos = output.find(CRLF CRLF);
if (pos == NPOS) // there is not empty line
return 500;
std::cerr << "1\n";
headers = output.substr(0, pos);
body = output.substr(pos + CRLF_SIZE * 2);
headers = str_tolower(headers);
@@ -301,18 +308,14 @@ std::cerr << "1\n";
{
if (!body.empty()) // there is body
return 500;
std::cerr << "2\n";
if (headers.find("location") == NPOS) // there is no location field
return 500;
std::cerr << "3\n";
}
else if (headers.find("location") != NPOS) // there is a location field
{
if (body.empty()) // there is no body
return 500;
std::cerr << "4\n";
}
std::cerr << "5\n";
return status;
}

View File

@@ -3,30 +3,27 @@
#define BUFSIZE 8192 // (8Ko)
#define STATUS_500 std::string("Status: 500" CRLF CRLF);
void Webserv::_read_cgi_output(Client *client)
{
char buf[BUFSIZE];
ssize_t ret;
std::cerr << "_read_cgi_output()" << "\n";
std::cerr << "cgi_pid = " << client->cgi_pid << "\n";
std::cerr << "client fd = " << client->get_cl_fd() << "\n";
std::cerr << "cgi fd = " << client->cgi_pipe_r_from_child << "\n";
std::cerr << "_read_cgi_output()" << "\n"; // Debug
std::cerr << "cgi_pid = " << client->cgi_pid << "\n"; // Debug
std::cerr << "client fd = " << client->get_cl_fd() << "\n"; // Debug
std::cerr << "cgi fd = " << client->cgi_pipe_r_from_child << "\n"; // Debug
ret = ::read(client->cgi_pipe_r_from_child, buf, BUFSIZE);
std::cerr << "cgi read ret = " << ret << "\n";
std::cerr << "cgi read ret = " << ret << "\n"; // Debug
if (ret == -1)
{
std::perror("err read(cgi_fd)");
client->cgi_output = STATUS_500;
client->status = 500;
client->cgi_state = CGI_NO_CGI;
}
else if (ret == 0)
std::cerr << "Madame s'il vous plait, du Ketchup pour mon hamburger" << " (AKA:ret=0)" << "\n";
std::cerr << "Madame s'il vous plait, du Ketchup pour mon hamburger" << " (AKA:ret=0)" << "\n"; // :)
else
{
std::cerr << "NORMAL BEHAVIOR I THINK!\n"; // debug
client->cgi_output.append(buf, ret);
}
}
void Webserv::_handle_epollerr_cgi_output(uint32_t events, Client *client)
@@ -37,7 +34,8 @@ void Webserv::_handle_epollerr_cgi_output(uint32_t events, Client *client)
std::cerr << "client fd = " << client->get_cl_fd() << "\n";
std::cerr << "cgi fd = " << client->cgi_pipe_r_from_child << "\n";
client->cgi_output = STATUS_500;
client->status = 500;
client->cgi_state = CGI_NO_CGI;
// Common with EPOLLHUP
pid_t wait_ret;
@@ -45,14 +43,11 @@ void Webserv::_handle_epollerr_cgi_output(uint32_t events, Client *client)
std::cerr << "cgi EPOLLERR waitpid ret = " << wait_ret << "\n";
if (wait_ret == client->cgi_pid)
{
if (client->cgi_pipe_r_from_child)
{
if (::close(client->cgi_pipe_r_from_child) == -1)
std::perror("err close()");
}
client->cgi_pipe_r_from_child = 0;
_epoll_update(client->cgi_pipe_r_from_child, 0, EPOLL_CTL_DEL);
if (::close(client->cgi_pipe_r_from_child) == -1)
std::perror("err close()");
client->cgi_pipe_r_from_child = -1;
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
client->cgi_state = CGI_OUTPUT_READY;
}
}
@@ -73,14 +68,12 @@ void Webserv::_handle_epollhup_cgi_output(uint32_t events, Client *client)
// std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n";
if (wait_ret == client->cgi_pid)
{
if (client->cgi_pipe_r_from_child)
{
if (::close(client->cgi_pipe_r_from_child) == -1)
std::perror("err close()");
}
client->cgi_pipe_r_from_child = 0;
_epoll_update(client->cgi_pipe_r_from_child, 0, EPOLL_CTL_DEL);
if (::close(client->cgi_pipe_r_from_child) == -1)
std::perror("err close()");
client->cgi_pipe_r_from_child = -1;
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
client->cgi_state = CGI_OUTPUT_READY;
client->cgi_state = CGI_OUTPUT_COMPLETE;
}
}
@@ -95,9 +88,8 @@ void Webserv::_handle_epollerr_cgi_input(uint32_t events, Client *client)
{
(void)events;
client->cgi_output = STATUS_500;
client->cgi_state = CGI_OUTPUT_READY;
client->status = 500;
client->cgi_state = CGI_NO_CGI;
_close_client_cgi_pipes(client);
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
}

View File

@@ -14,6 +14,7 @@ void Webserv::_close_client(int fd)
if (::close(fd) == -1)
std::perror("err close()");
_close_client_cgi_pipes(&(*it));
// it->clear(); // PISTE, debug normalement superflu
_clients.erase(it);
break;
}
@@ -24,23 +25,38 @@ void Webserv::_close_client(int fd)
void Webserv::_close_client_cgi_pipes(Client *client)
{
if (client->cgi_state)
{
{ // No need to reset the fd to -1 normaly
std::cerr << "close cgi-pipes" << "\n";
if (::close(client->cgi_pipe_w_to_child) == -1)
std::perror("err close()");
// client->cgi_pipe_w_to_child = -1;
if (::close(client->cgi_pipe_r_from_child) == -1)
std::perror("err close()");
// client->cgi_pipe_r_from_child = -1;
if (::close(client->cgi_pipe_w_to_parent) == -1)
std::perror("err close()");
// client->cgi_pipe_w_to_parent = -1;
if (::close(client->cgi_pipe_r_from_parent) == -1)
std::perror("err close()");
// client->cgi_pipe_r_from_parent = -1;
}
}
void Webserv::_close_all_clients()
{
_close_all_clients_fd();
_clients.clear();
// REMPLACEMENT ->
/* while (!_clients.empty())
{
std::cerr << "_clients.pop_back() " << &_clients.back() << "\n";
_clients.back().clear();
_clients.pop_back();
} */
}
void Webserv::_close_all_clients_fd()

View File

@@ -25,8 +25,6 @@ void Webserv::_request(Client *client)
}
else if (ret == READ_COMPLETE)
{
if (client->body_complete && client->get_rq_multi_bodys().empty()) // DEBUG
std::cerr << "______BODY\n" << client->get_rq_body() << "\n______\n"; // DEBUG
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_MOD);
client->request_complete = true;
}
@@ -53,13 +51,10 @@ int Webserv::_read_request(Client *client)
// ::print_special(client->raw_request);
// std::cerr << "__raw_request__\n" << client->raw_request << "\n______\n"; // DEBUG
print_special(client->raw_request);
std::cerr << "client header complete: " << client->header_complete << "\n"; // DEBUG
// print_special(client->raw_request);
if (!client->header_complete)
{
std::cout << "Header not complete\n"; // debug
client->parse_request_headers(_servers);
if (client->status)
return READ_COMPLETE;
@@ -78,7 +73,6 @@ int Webserv::_read_request(Client *client)
}
if (client->header_complete)
{
std::cerr << "Client header Complete\n";
// client->read_body_size += ret; // Not accurate, part of body could have been read with headers, unused for now
client->parse_request_body();
if (client->status || client->body_complete)

View File

@@ -25,6 +25,7 @@ void Webserv::_response(Client *client)
|| client->status == 400 // TODO: Refactoring
|| client->status == 408
|| client->status == 413)
// || client->cgi_state == CGI_OUTPUT_COMPLETE) // DEBUG
_close_client(client->get_cl_fd());
else
{
@@ -48,8 +49,8 @@ int Webserv::_send_response(Client *client)
if (!client->status)
{
_construct_response(client);
if (client->cgi_state == CGI_WAIT_FOR_OUTPUT
|| client->cgi_state == CGI_WAIT_TO_EXEC)
if (client->cgi_state == CGI_WAIT_TO_EXEC
|| client->cgi_state == CGI_OUTPUT_READING)
return SEND_IN_PROGRESS;
}
@@ -72,6 +73,11 @@ int Webserv::_send_response(Client *client)
std::cerr << "SEND RET 0 for client.fd =" << client->get_cl_fd() << "\n"; // DEBUG
return SEND_CLOSE;
}
if (ret < (int)client->response.size())
{
std::cerr << "send() as not send all data, IT CAN HAPPEN !" << "\n"; // DEBUG
throw ExecFail(); // DEBUG, TODO, A ENLEVER ABSOLEMENT, WHILE TEMP =D
}
// /* Debug */ std::cerr << "ret send() = " << ret << "\n"; // DEBUG
return SEND_COMPLETE;
@@ -99,16 +105,26 @@ void Webserv::_construct_response(Client *client)
if (client->cgi_state == CGI_READY_TO_EXEC)
{
std::string body = client->get_rq_body();
::write(client->cgi_pipe_w_to_child, body.c_str(), body.size());
std::cerr << "client.fd for write body =" << client->get_cl_fd() << "\n"; // DEBUG
std::cerr << "client.cgi_pipe_w_to_child for write body =" << client->cgi_pipe_w_to_child << "\n"; // DEBUG
if (::write(client->cgi_pipe_w_to_child, body.c_str(), body.size()) == -1)
{
std::perror("err write()");
_close_client_cgi_pipes(client);
client->status = 500;
client->cgi_state = CGI_NO_CGI;
return;
}
_exec_cgi(client);
}
else if (client->cgi_state == CGI_OUTPUT_READY)
else if (client->cgi_state == CGI_OUTPUT_COMPLETE)
{
// /*DEBUG*/ std::cout << "\n" B_PURPLE "[response]:" RESET "\n"; ::print_special(client->response); std::cout << B_PURPLE "-----------" RESET "\n\n";
// /*DEBUG*/ std::cout << "\n" B_PURPLE "[script output]:" RESET "\n"; ::print_special(client->cgi_output); std::cout << B_PURPLE "-----------" RESET "\n\n";
_check_script_output(client, client->cgi_output); // FD_CGI : adjust for client->cgi_output;
if (client->status < 400)
if (client->status < 400 || client->status >= 600)
client->response += client->cgi_output;
// client->cgi_state = CGI_NO_CGI; // Not indispensable, reset when client.clear()
// /*DEBUG*/ std::cout << "\n" B_PURPLE "[response + output]:" RESET "\n"; ::print_special(client->response); std::cout << B_PURPLE "-----------" RESET "\n\n";
}
else if (_is_cgi(client, path))

View File

@@ -12,8 +12,9 @@ void Webserv::run()
int i;
int count_loop = 0;
std::vector<listen_socket>::iterator it_lsocket;
Client *client_cgi_output = NULL;
std::vector<Client>::iterator it_client;
Client *client_cgi_input = NULL;
Client *client_cgi_output = NULL;
g_run = true;
while (g_run)
@@ -37,8 +38,10 @@ void Webserv::run()
{
try {
it_lsocket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd);
client_cgi_output = _find_cgi_output_fd(events[i].data.fd);
it_client = std::find(_clients.begin(), _clients.end(), events[i].data.fd);
client_cgi_input = _find_cgi_input_fd(events[i].data.fd);
client_cgi_output = _find_cgi_output_fd(events[i].data.fd);
if (it_lsocket != _listen_sockets.end())
{
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP)
@@ -46,6 +49,15 @@ void Webserv::run()
else if (events[i].events & EPOLLIN)
_accept_connection(*it_lsocket);
}
else if (it_client != _clients.end())
{
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP)
_handle_epoll_error_client(events[i].events, events[i].data.fd);
else if (events[i].events & EPOLLIN)
_request( &(*it_client) );
else if (events[i].events & EPOLLOUT)
_response( &(*it_client) );
}
else if (client_cgi_input)
{
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP)
@@ -62,14 +74,9 @@ void Webserv::run()
else if ( (events[i].events & EPOLLHUP) && !(events[i].events & EPOLLIN) )
_handle_epollhup_cgi_output(events[i].events, client_cgi_output);
}
else if (std::find(_clients.begin(), _clients.end(), events[i].data.fd) != _clients.end()) // TODO: save the it in var to avoid multiples find()
else
{
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP)
_handle_epoll_error_client(events[i].events, events[i].data.fd);
else if (events[i].events & EPOLLIN)
_request( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) );
else if (events[i].events & EPOLLOUT)
_response( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) );
std::cerr << "NOTHING FOR FD = " << events[i].data.fd << "\n"; // DEBUG
}
++i;
if (!g_run)

View File

@@ -6,4 +6,3 @@ http://localhost:4040/test
http://localhost:4040/test/test_deeper/
http://localhost:4040/test/test_deeper/super_deep/
http://localhost:4040/test/index1.html

1
urls_cgi.txt Normal file
View File

@@ -0,0 +1 @@
http://localhost:4040/cgi-bin/cgi_cpp_empty.out?fname=John&lname=Doe

BIN
www/user_files/pepe.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB