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

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