#include "Webserv.hpp" bool Webserv::_is_cgi(Client *client) { // TODO see how it works with config if (client->fill_script_path("/cgi-bin/php-cgi")) return true; if (client->fill_script_path("/cgi-bin/cgi_cpp.cgi")) return true; return false; } std::string Webserv::_exec_cgi(Client *client) { char** env; std::string script_output; env = _set_env(client); script_output = _exec_script(client, env); for (int i = 0; env[i]; i++) delete[] env[i]; delete[] env; return script_output; } char* Webserv::_dup_env(std::string var, std::string val = "") { std::string str; str = var + "=" + val; return ( strdup(str.c_str()) ); } char* Webserv::_dup_env(std::string var, int i) { std::string str; std::string val; val = ::itos(i); str = var + "=" + val; // TODO change strdup for something with new return ( strdup(str.c_str()) ); } char** Webserv::_set_env(Client *client) { char** env = new char*[19]; env[0] = _dup_env("AUTH_TYPE"); // authentification not supported env[1] = _dup_env("CONTENT_LENGTH" , client->get_rq_body().size()); env[2] = _dup_env("CONTENT_TYPE" , client->get_rq_headers("Content-Type")); env[3] = _dup_env("GATEWAY_INTERFACE" , "CGI/1.1"); // https://www.rfc-editor.org/rfc/rfc3875 env[4] = _dup_env("PATH_INFO" , client->get_rq_script_info()); env[5] = _dup_env("PATH_TRANSLATED"); // not supported env[6] = _dup_env("QUERY_STRING" , client->get_rq_query()); env[7] = _dup_env("REMOTE_ADDR" , client->get_cl_ip()); env[8] = _dup_env("REMOTE_HOST" , client->get_rq_headers("Host")); // just test env[9] = _dup_env("REMOTE_IDENT"); // authentification not supported env[10] = _dup_env("REMOTE_USER"); // authentification not supported env[11] = _dup_env("REQUEST_METHOD" , client->get_rq_method_str()); env[12] = _dup_env("SCRIPT_NAME" , client->get_rq_script_path()); env[13] = _dup_env("SERVER_NAME" , client->get_rq_hostname()); env[14] = _dup_env("SERVER_PORT" , client->get_rq_port()); env[15] = _dup_env("SERVER_PROTOCOL" , client->get_rq_version()); env[16] = _dup_env("SERVER_SOFTWARE" , "webser/1.0"); env[17] = _dup_env("REDIRECT_STATUS" , "200"); env[18] = NULL; return env; } std::string 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 = NULL; std::string script_output; std::string body = client->get_rq_body(); int fd_in[2]; int fd_out[2]; pipe(fd_in); pipe(fd_out); pid = fork(); if (pid == -1) std::cerr << "fork crashed" << std::endl; else if (pid == 0) { close(FD_WR_TO_CHLD); close(FD_RD_FR_CHLD); dup2(FD_RD_FR_PRNT, STDIN_FILENO); dup2(FD_WR_TO_PRNT, STDOUT_FILENO); // DEBUG std::cerr << "execve:\n"; execve(client->get_rq_script_path().c_str(), nll, env); // for tests execve crash : //execve("wrong", nll, env); std::cerr << "execve crashed.\n"; } else { 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); memset(buf, '\0', CGI_BUF_SIZE); while (read(FD_RD_FR_CHLD, buf, CGI_BUF_SIZE - 1) > 0) { script_output += buf; memset(buf, '\0', CGI_BUF_SIZE); } close(FD_RD_FR_CHLD); } if (script_output.empty()) script_output = "Status: 500\r\n\r\n"; return script_output; } void Webserv::_check_script_output(Client *client, std::string output) { // TODO: it doesn't work with execve error, i don't know why yet ? _check_script_status(client, output); _check_script_fields(client, output); } void Webserv::_check_script_status(Client *client, std::string output) { size_t pos; int status_pos; pos = output.find("Status:"); if (pos != std::string::npos) { status_pos = pos + std::string("Status:").size(); client->status = atoi(output.c_str() + status_pos); ::del_line_in_str(&output, pos, CRLF); } client->status = 200; } void Webserv::_check_script_fields(Client *client, std::string output) { std::map srv_fld; // server_field std::map scr_fld; // script_field std::map::iterator it_srv; std::map::iterator it_scr; size_t pos; srv_fld = parse_http_headers(client->response); scr_fld = parse_http_headers(output); // wip: compare both map to supress duplicates for (it_srv = srv_fld.begin(); it_srv != srv_fld.end(); it_srv++) { for (it_scr = scr_fld.begin(); it_scr != scr_fld.end(); it_scr++) { if (it_srv->first == it_scr->first) { pos = client->response.find(it_srv->first); ::del_line_in_str(&client->response, pos, CRLF); } } } }