#include "Webserv.hpp" bool Webserv::_is_cgi(Client *client, std::string path) { size_t file_type; size_t file_mode; size_t pos = 0; while (pos != NPOS) { pos = _cgi_pos(client, path, pos); /*DEBUG*/ std::cout << "pos:" << pos << "\n&path[pos]:" << &path[pos] << "\n" << B_YELLOW << "fin debug _cgi_pos()\n\n" << RESET; if (pos == NPOS) break; client->fill_script_path(path, pos); file_type = ::eval_file_type(client->get_rq_script_path()); if (file_type == IS_DIR) // but what if it's a symlink ? continue; if (file_type == IS_FILE) { file_mode = ::eval_file_mode( client->get_rq_script_path(), X_OK ); if (!file_mode) return true; } } client->clear_script(); client->status = file_mode; // 404 not_found OR 403 forbidden return false; } size_t Webserv::_cgi_pos(Client *client, std::string &path, size_t pos) { std::vector v_ext; std::vector::const_iterator it; std::vector::const_iterator it_end; size_t len; std::locale loc; // for isalpha() /*DEBUG*/ it = client->assigned_location->cgi_ext.begin(); std::cout << B_YELLOW << "\nDEBUG _cgi_pos()\n" << RESET << "vector_ext.size():[" << client->assigned_location->cgi_ext.size() << "]\n\n"; v_ext = client->assigned_location->cgi_ext; if (v_ext.empty()) return NPOS; /*DEBUG*/ std::cout << "ext:[" << *it << "]\n" << "path:[" << path << "]\n\n"; it_end = client->assigned_location->cgi_ext.end(); while (pos < path.size()) { /*DEBUG*/ std::cout << "\nwhile\n"; if (path.compare(pos, 2, "./") == 0) pos += 2; /*DEBUG*/ std::cout << "&path[pos]:[" << &path[pos] << "]\n"; pos = path.find('.', pos); if (pos == NPOS) return pos; it = client->assigned_location->cgi_ext.begin(); for ( ; it != it_end; ++it) { /*DEBUG*/ std::cout << " for\n"; std::cout << " &path[pos]:[" << &path[pos] << "]\n" << " *it:[" << *it << "]\n" << " (*it).size():[" << (*it).size() << "]\n" << " path.substr(pos, (*it).size()):[" << path.substr(pos + 1, (*it).size()) << "]\n\n"; len = (*it).size(); if (path.compare(pos + 1, len, *it) == 0) if ( !std::isalpha(path[pos + 1 + len], loc) ) return pos + 1 + len; } pos++; } return NPOS; } 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]; int save_in = dup(STDIN_FILENO); int save_out = dup(STDOUT_FILENO); std::string path; 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); path = "." + client->get_rq_script_path(); /*DEBUG*/std::cerr << "execve\n" << "path:[" << path << "]\n"; execve(path.c_str(), nll, env); // for tests execve crash : //execve("wrong", nll, env); std::cerr << "execve crashed.\n"; // TODO HUGO : check errno } 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"; dup2(save_in, STDIN_FILENO); dup2(save_out, STDOUT_FILENO); return script_output; } void Webserv::_check_script_output(Client *client, std::string & output) { _check_script_status(client, output); _check_script_fields(client, output); // _check_script_empty_lines(client, output); // _check_script_space_colons(client, output); // _check_script_new_lines(client, output); } void Webserv::_check_script_status(Client *client, std::string & output) { size_t pos; int status_pos; pos = output.find("Status:"); if (pos != NPOS) { status_pos = pos + std::string("Status:").size(); client->status = std::strtoul(output.c_str() + status_pos, NULL, 10); ::extract_line(output, pos, CRLF); } else 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; std::string tmp; size_t pos; // put server headers in map tmp = client->response; pos = tmp.find(CRLF CRLF); if (pos != NPOS) tmp.erase(pos); ::parse_http_headers(tmp, srv_fld); // put script headers in map tmp = output; pos = tmp.find(CRLF CRLF); if (pos != NPOS) tmp.erase(pos); ::parse_http_headers(tmp, scr_fld); // 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 (str_tolower(it_srv->first) == str_tolower(it_scr->first)) { pos = client->response.find(it_srv->first); ::extract_line(client->response, pos, CRLF); } } } }