_exec_script() close fd and reset signal
+ somes more adjustements in _exec_script() + rough notes for non blocking CGI
This commit is contained in:
12
memo.txt
12
memo.txt
@@ -10,6 +10,18 @@
|
|||||||
- handle redirection (Work, but weird behavior need deeper test)
|
- handle redirection (Work, but weird behavior need deeper test)
|
||||||
- Ecrire des tests !
|
- Ecrire des tests !
|
||||||
|
|
||||||
|
- cgi_cpp_status.cpp with POST dont show error page. Normal or not ?
|
||||||
|
|
||||||
|
For non blocking CGI :
|
||||||
|
// We could maybe,
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
|
||||||
----Priorité modérée------------------------
|
----Priorité modérée------------------------
|
||||||
- namespace utils ?
|
- namespace utils ?
|
||||||
- change "std::string" to reference "std::string &" in most functions
|
- change "std::string" to reference "std::string &" in most functions
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ class Webserv
|
|||||||
// close.cpp
|
// close.cpp
|
||||||
void _close_client(int fd);
|
void _close_client(int fd);
|
||||||
void _close_all_clients();
|
void _close_all_clients();
|
||||||
|
void _close_all_clients_fd();
|
||||||
void _close_all_listen_sockets();
|
void _close_all_listen_sockets();
|
||||||
void _reopen_lsocket(std::vector<listen_socket>::iterator it);
|
void _reopen_lsocket(std::vector<listen_socket>::iterator it);
|
||||||
void _handle_epoll_error_lsocket(uint32_t events, std::vector<listen_socket>::iterator it);
|
void _handle_epoll_error_lsocket(uint32_t events, std::vector<listen_socket>::iterator it);
|
||||||
@@ -131,6 +132,16 @@ class Webserv
|
|||||||
void _check_script_fields(Client *client, std::string & output);
|
void _check_script_fields(Client *client, std::string & output);
|
||||||
void _add_script_body_length_header(std::string & output);
|
void _add_script_body_length_header(std::string & output);
|
||||||
void _remove_body_leading_empty_lines(std::string & output);
|
void _remove_body_leading_empty_lines(std::string & output);
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
class ExecFail : public std::exception
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return ("Exec CGI fail");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -72,16 +72,24 @@ std::string Webserv::_exec_cgi(Client *client)
|
|||||||
char* env_cstr[19] = {NULL};
|
char* env_cstr[19] = {NULL};
|
||||||
std::vector<std::string> env_vector;
|
std::vector<std::string> env_vector;
|
||||||
env_vector.reserve(18);
|
env_vector.reserve(18);
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
_set_env_vector(client, env_vector);
|
_set_env_vector(client, env_vector);
|
||||||
_set_env_cstr(env_cstr, env_vector);
|
try {
|
||||||
script_output = _exec_script(client, env_cstr);
|
_set_env_cstr(env_cstr, env_vector);
|
||||||
|
script_output = _exec_script(client, env_cstr);
|
||||||
|
|
||||||
int i = 0;
|
while (env_cstr[i] != NULL)
|
||||||
while (env_cstr[i] != NULL)
|
delete[] env_cstr[i++];
|
||||||
delete[] env_cstr[i++];
|
|
||||||
|
|
||||||
return script_output;
|
return script_output;
|
||||||
|
}
|
||||||
|
catch (const Webserv::ExecFail& e)
|
||||||
|
{
|
||||||
|
while (env_cstr[i] != NULL)
|
||||||
|
delete[] env_cstr[i++];
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Webserv::_dup_env(std::string var, std::string val = "")
|
std::string Webserv::_dup_env(std::string var, std::string val = "")
|
||||||
@@ -166,6 +174,8 @@ void Webserv::_set_env_cstr(char *env_cstr[], std::vector<std::string> &env_vect
|
|||||||
env_cstr[18] = NULL;
|
env_cstr[18] = NULL;
|
||||||
} */
|
} */
|
||||||
|
|
||||||
|
#define STATUS_500 std::string("Status: 500" CRLF CRLF);
|
||||||
|
|
||||||
std::string Webserv::_exec_script(Client *client, char *env[])
|
std::string Webserv::_exec_script(Client *client, char *env[])
|
||||||
{
|
{
|
||||||
#define RD 0
|
#define RD 0
|
||||||
@@ -190,21 +200,43 @@ std::string Webserv::_exec_script(Client *client, char *env[])
|
|||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid == -1)
|
if (pid == -1)
|
||||||
std::cerr << "fork crashed" << std::endl;
|
perror("err fork()");
|
||||||
else if (pid == 0) // child
|
else if (pid == 0) // child
|
||||||
{
|
{
|
||||||
// _close_all_clients();
|
std::signal(SIGPIPE, SIG_DFL);
|
||||||
close(FD_WR_TO_CHLD);
|
std::signal(SIGINT, SIG_DFL);
|
||||||
close(FD_RD_FR_CHLD);
|
|
||||||
dup2(FD_RD_FR_PRNT, STDIN_FILENO);
|
_close_all_clients_fd();
|
||||||
dup2(FD_WR_TO_PRNT, STDOUT_FILENO);
|
::close(_epfd);
|
||||||
path = "." + client->get_rq_script_path();
|
::close(FD_WR_TO_CHLD);
|
||||||
|
::close(FD_RD_FR_CHLD);
|
||||||
|
if (dup2(FD_RD_FR_PRNT, STDIN_FILENO) == -1)
|
||||||
|
{
|
||||||
|
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()");
|
||||||
|
::close(FD_RD_FR_PRNT); // Valgind debug, not essential
|
||||||
|
::close(FD_WR_TO_PRNT); // Valgind debug, not essential
|
||||||
|
throw ExecFail();
|
||||||
|
}
|
||||||
|
|
||||||
|
::close(FD_RD_FR_PRNT);
|
||||||
|
::close(FD_WR_TO_PRNT);
|
||||||
|
|
||||||
|
path = "." + client->get_rq_script_path(); // Wut ? Only relative path ?
|
||||||
/*DEBUG*/std::cerr << "execve:[" << path << "]\n";
|
/*DEBUG*/std::cerr << "execve:[" << path << "]\n";
|
||||||
execve(path.c_str(), nll, env);
|
if (execve(path.c_str(), nll, env) == -1) // replace path for debug error forcing
|
||||||
// for tests execve crash :
|
{
|
||||||
//execve("wrong", nll, env);
|
perror("err execve()");
|
||||||
std::cerr << "execve crashed.\n";
|
::close(STDIN_FILENO); // Valgind debug, not essential
|
||||||
// TODO HUGO : check errno
|
::close(STDOUT_FILENO); // Valgind debug, not essential
|
||||||
|
throw ExecFail();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else //parent
|
else //parent
|
||||||
{
|
{
|
||||||
@@ -213,17 +245,30 @@ std::string Webserv::_exec_script(Client *client, char *env[])
|
|||||||
write(FD_WR_TO_CHLD, body.c_str(), body.size());
|
write(FD_WR_TO_CHLD, body.c_str(), body.size());
|
||||||
close(FD_WR_TO_CHLD);
|
close(FD_WR_TO_CHLD);
|
||||||
waitpid(-1, NULL, 0);
|
waitpid(-1, NULL, 0);
|
||||||
|
// We could maybe,
|
||||||
|
// 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.
|
||||||
|
|
||||||
memset(buf, '\0', CGI_BUF_SIZE);
|
ssize_t ret = 1;
|
||||||
while (read(FD_RD_FR_CHLD, buf, CGI_BUF_SIZE - 1) > 0)
|
while (ret > 0)
|
||||||
{
|
{
|
||||||
script_output += buf;
|
ret = read(FD_RD_FR_CHLD, buf, CGI_BUF_SIZE);
|
||||||
memset(buf, '\0', 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);
|
close(FD_RD_FR_CHLD);
|
||||||
}
|
}
|
||||||
if (script_output.empty())
|
if (script_output.empty())
|
||||||
script_output = "Status: 500" CRLF CRLF;
|
script_output = STATUS_500;
|
||||||
|
|
||||||
return script_output;
|
return script_output;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,21 @@ void Webserv::_close_client(int fd)
|
|||||||
|
|
||||||
void Webserv::_close_all_clients()
|
void Webserv::_close_all_clients()
|
||||||
{
|
{
|
||||||
while (!_clients.empty())
|
_close_all_clients_fd();
|
||||||
|
_clients.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webserv::_close_all_clients_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
|
// _epoll_update(_clients.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
|
||||||
std::cerr << "close fd " << _clients.back().get_cl_fd() << "\n";
|
std::cerr << "close fd " << _clients.back().get_cl_fd() << "\n";
|
||||||
if (::close(_clients.back().get_cl_fd()) == -1)
|
if (::close(_clients.back().get_cl_fd()) == -1)
|
||||||
std::perror("err close()");
|
std::perror("err close()");
|
||||||
_clients.pop_back();
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,11 @@ void Webserv::run()
|
|||||||
std::vector<Client>().swap(_clients);
|
std::vector<Client>().swap(_clients);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
catch (const Webserv::ExecFail& e)
|
||||||
|
{
|
||||||
|
std::cerr << e.what() << '\n';
|
||||||
|
throw;
|
||||||
|
}
|
||||||
catch (const std::exception& e) {
|
catch (const std::exception& e) {
|
||||||
std::cerr << e.what() << '\n';
|
std::cerr << e.what() << '\n';
|
||||||
++i;
|
++i;
|
||||||
|
|||||||
Reference in New Issue
Block a user