From 4282a88b8a6ab1c264d1dbeb44c101b27ba0327e Mon Sep 17 00:00:00 2001 From: nicolas-arnaud Date: Thu, 26 Jan 2023 16:40:05 +0100 Subject: [PATCH] reformat --- includes/Route.hpp | 40 ++-- includes/Token.hpp | 25 +- srcs/load/Env.cpp | 4 +- srcs/load/Route.cpp | 171 ++++++-------- srcs/sock/Client.cpp | 544 +++++++++++++++++++------------------------ srcs/sock/Master.cpp | 218 ++++++++--------- 6 files changed, 442 insertions(+), 560 deletions(-) diff --git a/includes/Route.hpp b/includes/Route.hpp index 9281f18..2584baa 100644 --- a/includes/Route.hpp +++ b/includes/Route.hpp @@ -3,27 +3,27 @@ class Route { protected: - Server *_server; - string _location, _root; - bool _autoindex; + Server *_server; + string _location, _root; + bool _autoindex; public: - vec_string _indexs, _allowed_methods; - std::map _cgi; - int _client_max_body_size; - int _timeout; - int _max_requests; - int _ret_code; - string _ret_uri; - std::map _err_page; + vec_string _indexs, _allowed_methods; + std::map _cgi; + int _client_max_body_size; + int _timeout; + int _max_requests; + int _ret_code; + string _ret_uri; + std::map _err_page; - Route(Server *server, string location, JSONNode *datas); - ~Route(void); - string getLocation(void); - string get_custom_err(int error_code); - string getRoot(void); - string getReturn(void); - Server *getServer(void); - string getIndex(string uri, string path); - string correctUri(string uri); + Route(Server *server, string location, JSONNode *datas); + ~Route(void); + string getLocation(void); + string get_custom_err(int error_code); + string getRoot(void); + string getReturn(void); + Server *getServer(void); + string getIndex(string uri, string path); + string correctUri(string uri); }; diff --git a/includes/Token.hpp b/includes/Token.hpp index 06facd7..a16fbc0 100644 --- a/includes/Token.hpp +++ b/includes/Token.hpp @@ -1,32 +1,21 @@ #pragma once #include "webserv.hpp" -enum TOKEN { - CURLY_OPEN, - CURLY_CLOSE, - COLON, - STRING, - NUMBER, - ARRAY_OPEN, - ARRAY_CLOSE, - COMMA, - BOOLEAN, - NULL_TYPE -}; +enum TOKEN { CURLY_OPEN, CURLY_CLOSE, COLON, STRING, NUMBER, ARRAY_OPEN, ARRAY_CLOSE, COMMA, BOOLEAN, NULL_TYPE }; typedef struct Token_s { string value; - TOKEN type; + TOKEN type; } Token; class Tokenizer { std::fstream file; - size_t prevPos; + size_t prevPos; - public: +public: Tokenizer(string fileName); - bool hasMoreTokens(); - char getWithoutWhiteSpace(); - void rollBackToken(); + bool hasMoreTokens(); + char getWithoutWhiteSpace(); + void rollBackToken(); Token getToken(); }; diff --git a/srcs/load/Env.cpp b/srcs/load/Env.cpp index 1469a7e..5c2f384 100644 --- a/srcs/load/Env.cpp +++ b/srcs/load/Env.cpp @@ -54,11 +54,11 @@ Env::~Env() { * - for each master socket, call his own post_poll method to check and handle the sockets flaged. */ void Env::cycle(void) { - //if (!SILENT) cout << "|===||===| Waiting some HTTP request... |===||===|\n"; + // if (!SILENT) cout << "|===||===| Waiting some HTTP request... |===||===|\n"; int pollResult = poll(Master::_pollfds, Master::_poll_id_amount + 1, 5000); if ((pollResult < 0) && (errno != EINTR)) std::cerr << "Select: " << strerror(errno) << "\n"; if (pollResult > 0) { - //if (!SILENT) cout << "==> Handle requests and answers:\n"; + // if (!SILENT) cout << "==> Handle requests and answers:\n"; for (std::vector::iterator it = this->_masters.begin(); it < this->_masters.end(); it++) try { (*it)->check_socket(); (*it)->check_childs(this); diff --git a/srcs/load/Route.cpp b/srcs/load/Route.cpp index d49ee5b..b23fc43 100644 --- a/srcs/load/Route.cpp +++ b/srcs/load/Route.cpp @@ -18,53 +18,41 @@ * @param location The uri associatied to the route. * @param datas The JSONNode giving configuration. */ -Route::Route(Server *server, string location, JSONNode *datas) - : _server(server), _location(location) { - JSONObject object = datas->obj(); - JSONNode *tmp; - _autoindex = false; - _client_max_body_size = -1; - if ((tmp = object["root"])) - _root = tmp->str(); - if ((tmp = object["return"])) { - _ret_code = tmp->lst()[0]->nbr(); - _ret_uri = tmp->lst()[1]->str(); - } - if ((tmp = object["autoindex"])) - _autoindex = tmp->boo(); - if ((tmp = object["keepalive_time"])) - _timeout = tmp->nbr(); - else - _timeout = 0; - if ((tmp = object["keepalive_requests"])) - _max_requests = tmp->nbr(); - else - _max_requests = 0; - if ((tmp = object["error_pages"])) { - JSONObject pages = tmp->obj(); - for (JSONObject::iterator it = pages.begin(); it != pages.end(); it++) { - JSONList err = (*it).second->lst(); - for (JSONList::iterator it2 = err.begin(); it2 != err.end(); it2++) - _err_page[(*it2)->nbr()] = (*it).first; - } - } - if ((tmp = object["indexs"])) { - JSONList indexs = tmp->lst(); - for (JSONList::iterator it = indexs.begin(); it < indexs.end(); it++) - _indexs.push_back((*it)->str()); - } - if ((tmp = object["allowed_methods"])) { - JSONList headers = tmp->lst(); - for (JSONList::iterator it = headers.begin(); it < headers.end(); it++) - _allowed_methods.push_back((*it)->str()); - } - if ((tmp = object["cgi"])) { - JSONObject cgis = tmp->obj(); - for (JSONObject::iterator it = cgis.begin(); it != cgis.end(); it++) - _cgi[(*it).first] = (*it).second->str(); - } - if ((tmp = object["client_max_body_size"])) - _client_max_body_size = tmp->nbr(); +Route::Route(Server *server, string location, JSONNode *datas) : _server(server), _location(location) { + JSONObject object = datas->obj(); + JSONNode *tmp; + _autoindex = false; + _client_max_body_size = -1; + if ((tmp = object["root"])) _root = tmp->str(); + if ((tmp = object["return"])) { + _ret_code = tmp->lst()[0]->nbr(); + _ret_uri = tmp->lst()[1]->str(); + } + if ((tmp = object["autoindex"])) _autoindex = tmp->boo(); + if ((tmp = object["keepalive_time"])) _timeout = tmp->nbr(); + else _timeout = 0; + if ((tmp = object["keepalive_requests"])) _max_requests = tmp->nbr(); + else _max_requests = 0; + if ((tmp = object["error_pages"])) { + JSONObject pages = tmp->obj(); + for (JSONObject::iterator it = pages.begin(); it != pages.end(); it++) { + JSONList err = (*it).second->lst(); + for (JSONList::iterator it2 = err.begin(); it2 != err.end(); it2++) _err_page[(*it2)->nbr()] = (*it).first; + } + } + if ((tmp = object["indexs"])) { + JSONList indexs = tmp->lst(); + for (JSONList::iterator it = indexs.begin(); it < indexs.end(); it++) _indexs.push_back((*it)->str()); + } + if ((tmp = object["allowed_methods"])) { + JSONList headers = tmp->lst(); + for (JSONList::iterator it = headers.begin(); it < headers.end(); it++) _allowed_methods.push_back((*it)->str()); + } + if ((tmp = object["cgi"])) { + JSONObject cgis = tmp->obj(); + for (JSONObject::iterator it = cgis.begin(); it != cgis.end(); it++) _cgi[(*it).first] = (*it).second->str(); + } + if ((tmp = object["client_max_body_size"])) _client_max_body_size = tmp->nbr(); } /// @brief Destructor @@ -84,41 +72,32 @@ string Route::getRoot(void) { return _root; } * nothing for him. */ string Route::getIndex(string uri, string path) { - std::stringstream body, ret; - DIR *dir; - struct dirent *entry; - struct stat info; - vec_string::iterator it; + std::stringstream body, ret; + DIR *dir; + struct dirent *entry; + struct stat info; + vec_string::iterator it; - if ((dir = opendir(path.c_str()))) { - if (DEBUG) - cout << "get index(): path=" << path << "\n"; - body << "

" << path - << " files :

\n
    \n"; - while ((entry = readdir(dir)) != NULL) { - if (entry->d_name[0] == '.') - continue; - for (it = _indexs.begin(); it < _indexs.end(); it++) { - if (entry->d_name == *it) - return (file_answer(path + "/" + *it)); - } - body << "
  • d_name << "\">" - << entry->d_name << "
  • \n"; - if (stat(path.c_str(), &info) != 0) - std::cerr << "stat() error on " << path << ": " << strerror(errno) - << "\n"; - } - body << "
"; - closedir(dir); - } - if (!dir || !_autoindex) - return ""; - if (DEBUG) - cout << "Getting autoindex\n"; - ret << "Content-type: text/html \r\n"; - ret << "Content-length: " << body.str().length() << "\r\n"; - ret << "\r\n" << body.str(); - return ret.str(); + if ((dir = opendir(path.c_str()))) { + if (DEBUG) cout << "get index(): path=" << path << "\n"; + body << "

" << path << " files :

\n
    \n"; + while ((entry = readdir(dir)) != NULL) { + if (entry->d_name[0] == '.') continue; + for (it = _indexs.begin(); it < _indexs.end(); it++) { + if (entry->d_name == *it) return (file_answer(path + "/" + *it)); + } + body << "
  • d_name << "\">" << entry->d_name << "
  • \n"; + if (stat(path.c_str(), &info) != 0) std::cerr << "stat() error on " << path << ": " << strerror(errno) << "\n"; + } + body << "
"; + closedir(dir); + } + if (!dir || !_autoindex) return ""; + if (DEBUG) cout << "Getting autoindex\n"; + ret << "Content-type: text/html \r\n"; + ret << "Content-length: " << body.str().length() << "\r\n"; + ret << "\r\n" << body.str(); + return ret.str(); } /** @@ -130,22 +109,18 @@ string Route::getIndex(string uri, string path) { * @deprecated Not used by nginx until config use rewrite keyword. */ string Route::correctUri(string uri) { - std::stringstream ret; - vec_string::iterator loc_word, uri_word; + std::stringstream ret; + vec_string::iterator loc_word, uri_word; - vec_string loc_words = split(_location, "/"); - vec_string uri_words = split(uri, "/"); - uri_word = uri_words.begin(); - for (loc_word = loc_words.begin(); loc_word < loc_words.end(); loc_word++) { - while (uri_word < uri_words.end() && *uri_word == "") - uri_word++; - while (loc_word < loc_words.end() && *loc_word == "") - loc_word++; - if (loc_word != loc_words.end()) - uri_word++; - } - ret << "./" << _root; - while (uri_word < uri_words.end()) - ret << "/" << *(uri_word++); - return ret.str(); + vec_string loc_words = split(_location, "/"); + vec_string uri_words = split(uri, "/"); + uri_word = uri_words.begin(); + for (loc_word = loc_words.begin(); loc_word < loc_words.end(); loc_word++) { + while (uri_word < uri_words.end() && *uri_word == "") uri_word++; + while (loc_word < loc_words.end() && *loc_word == "") loc_word++; + if (loc_word != loc_words.end()) uri_word++; + } + ret << "./" << _root; + while (uri_word < uri_words.end()) ret << "/" << *(uri_word++); + return ret.str(); } diff --git a/srcs/sock/Client.cpp b/srcs/sock/Client.cpp index 55ccfcd..49ba578 100644 --- a/srcs/sock/Client.cpp +++ b/srcs/sock/Client.cpp @@ -11,260 +11,216 @@ #include inline string get_extension(string str) { - size_t pos = str.rfind('.'); - if (pos != string::npos) - return str.substr(pos); - else - return ""; + size_t pos = str.rfind('.'); + if (pos != string::npos) return str.substr(pos); + else return ""; } -Client::Client(int fd, ip_port_t ip_port, Master *parent) - : _fd(fd), _ip_port(ip_port), _parent(parent) { - _requests_done = 0; - _death_time = 0; - _finish = false; - _route = NULL; - _server = NULL; - init(); - if (!SILENT) - cout << "New connection, socket fd is " << fd << ", ip is : " << _ip_port.ip - << ", port : " << _ip_port.port << "\n"; +Client::Client(int fd, ip_port_t ip_port, Master *parent) : _fd(fd), _ip_port(ip_port), _parent(parent) { + _requests_done = 0; + _death_time = 0; + _finish = false; + _route = NULL; + _server = NULL; + init(); + if (!SILENT) + cout << "New connection, socket fd is " << fd << ", ip is : " << _ip_port.ip << ", port : " << _ip_port.port + << "\n"; } Client::~Client(void) { - close(_fd); - Master::_pollfds[_poll_id].fd = 0; - Master::_pollfds[_poll_id].events = 0; - Master::_pollfds[_poll_id].revents = 0; - Master::_poll_id_amount--; - _headers.clear(); - if (!SILENT) - cout << "Host disconnected, ip " << _ip_port.ip << ", port " - << _ip_port.port << "\n"; + close(_fd); + Master::_pollfds[_poll_id].fd = 0; + Master::_pollfds[_poll_id].events = 0; + Master::_pollfds[_poll_id].revents = 0; + Master::_poll_id_amount--; + _headers.clear(); + if (!SILENT) cout << "Host disconnected, ip " << _ip_port.ip << ", port " << _ip_port.port << "\n"; } void Client::init(void) { - _requests_done++; - if (_route && _route->_max_requests > 0) { - if (_requests_done > _route->_max_requests) - _finish = true; - } else if (_server && _server->_max_requests > 0) { - if (_requests_done > _server->_max_requests) - _finish = true; - } - _method = _uri = _host = _header = _body = ""; - _len = 0; - _last_chunk = false; - _headers.clear(); + _requests_done++; + if (_route && _route->_max_requests > 0) { + if (_requests_done > _route->_max_requests) _finish = true; + } else if (_server && _server->_max_requests > 0) { + if (_requests_done > _server->_max_requests) _finish = true; + } + _method = _uri = _host = _header = _body = ""; + _len = 0; + _last_chunk = false; + _headers.clear(); } template void tab(T t, const int &width) { - std::cout << std::left << std::setw(width) << std::setfill(' ') << t; + std::cout << std::left << std::setw(width) << std::setfill(' ') << t; } void Client::debug(bool head) { - if (head) { - std::cout << "Client " << _poll_id - << " debug ===================================\n"; - tab("Fd", 4); - tab("Ip", 12); - tab("Port", 6); - tab("Servername", 12); - tab("Route", 12); - tab("Method", 6); - tab("URI", 20); - tab("Query", 12); - tab("Host", 12); - tab("Len", 6); - tab("Keep", 4); - tab("Death", 6); - tab("Request", 6); - tab("Finish", 6); - std::cout << "\n"; - } - tab(_fd, 4); - tab(_ip_port.ip, 12); - tab(_ip_port.port, 6); - tab(_server->getName(), 12); - tab(_route->getLocation(), 12); - tab(_method, 6); - tab(_uri, 20); - tab(_query, 12); - tab(_host, 12); - tab(_len, 6); - tab(_keepalive, 4); - tab(_death_time, 6); - tab(_requests_done, 6); - tab(_finish, 6); - std::cout << "\n"; + if (head) { + std::cout << "Client " << _poll_id << " debug ===================================\n"; + tab("Fd", 4); + tab("Ip", 12); + tab("Port", 6); + tab("Servername", 12); + tab("Route", 12); + tab("Method", 6); + tab("URI", 20); + tab("Query", 12); + tab("Host", 12); + tab("Len", 6); + tab("Keep", 4); + tab("Death", 6); + tab("Request", 6); + tab("Finish", 6); + std::cout << "\n"; + } + tab(_fd, 4); + tab(_ip_port.ip, 12); + tab(_ip_port.port, 6); + tab(_server->getName(), 12); + tab(_route->getLocation(), 12); + tab(_method, 6); + tab(_uri, 20); + tab(_query, 12); + tab(_host, 12); + tab(_len, 6); + tab(_keepalive, 4); + tab(_death_time, 6); + tab(_requests_done, 6); + tab(_finish, 6); + std::cout << "\n"; } bool Client::getRequest(Env *env, string paquet) { - if (DEBUG) - debug_block("Paquet: ", paquet); - if (header_pick("Method:", 0) != "") - return getBody(paquet); - vec_string lines = split(paquet, "\r\n"); - for (vec_string::iterator it = lines.begin(); it < lines.end(); it++) { - size_t pos = paquet.find("\r\n"); - if (pos != string::npos) - paquet.erase(0, pos + 2); - else - paquet.clear(); - _header += *it + (it + 1 != lines.end() ? "\r\n" : ""); - if (_header.find("\r\n\r\n") != string::npos) - return !parseHeader(env) ? false : (_len != 0 ? getBody(paquet) : true); - } - return false; + if (DEBUG) debug_block("Paquet: ", paquet); + if (header_pick("Method:", 0) != "") return getBody(paquet); + vec_string lines = split(paquet, "\r\n"); + for (vec_string::iterator it = lines.begin(); it < lines.end(); it++) { + size_t pos = paquet.find("\r\n"); + if (pos != string::npos) paquet.erase(0, pos + 2); + else paquet.clear(); + _header += *it + (it + 1 != lines.end() ? "\r\n" : ""); + if (_header.find("\r\n\r\n") != string::npos) + return !parseHeader(env) ? false : (_len != 0 ? getBody(paquet) : true); + } + return false; } bool Client::getBody(string paquet) { - vec_string lines = split(paquet, "\r\n"); - vec_string::iterator it; + vec_string lines = split(paquet, "\r\n"); + vec_string::iterator it; - for (it = lines.begin(); it < lines.end(); it++) { - if (DEBUG) - cout << "Remaining length: " << _len << "\n"; - if ((*it).length() && _len <= 0 && - header_pick("Transfer-Encoding:", 0) == "chunked") { - _len = std::strtol((*it).c_str(), 0, 16) + 2; - _last_chunk = _len == 2 ? true : false; - } else if (_len > 0 || it != lines.begin()) { - _body += *it + "\r\n"; - _len -= ((*it).length() + 2); - } - } - // if (_body.size()) - _body.resize(_body.length() - 2); - _len += 2; - return (_last_chunk && _len == 0) ? true : false; + for (it = lines.begin(); it < lines.end(); it++) { + if (DEBUG) cout << "Remaining length: " << _len << "\n"; + if ((*it).length() && _len <= 0 && header_pick("Transfer-Encoding:", 0) == "chunked") { + _len = std::strtol((*it).c_str(), 0, 16) + 2; + _last_chunk = _len == 2 ? true : false; + } else if (_len > 0 || it != lines.begin()) { + _body += *it + "\r\n"; + _len -= ((*it).length() + 2); + } + } + // if (_body.size()) + _body.resize(_body.length() - 2); + _len += 2; + return (_last_chunk && _len == 0) ? true : false; } bool Client::parseHeader(Env *env) { - vec_string lines, method, line; - if (DEBUG) - cout << "Parsing header...\n"; - lines = split(_header, "\r\n"); - method = split(lines.at(0), " "); - _headers["Method:"] = method; - if (lines.size() > 0) { - for (vec_string::iterator it = lines.begin() + 1; it < lines.end(); it++) { - line = split(*it, " "); - _headers[line.at(0)] = vec_string(line.begin() + 1, line.end()); - } - } - _method = header_pick("Method:", 0); - if ((_method == "POST" || _method == "PUT") && - header_pick("Content-Length:", 0) == "" && - header_pick("Transfer-Encoding:", 0) != "chunked") - return (send_error(400), false); - vec_string uri_split = split(header_pick("Method:", 1), "?"); - _uri = uri_split.at(0); - if (uri_split.size() > 1) - _query = uri_split.at(1); - _host = header_pick("Host:", 0); - _keepalive = header_pick("Connection:", 0) == "keep-alive"; - _env = env; - struct timeval t; - gettimeofday(&t, NULL); - _server = _parent->choose_server(env, _host); - if (_server->_timeout) - _death_time = _server->_timeout + t.tv_sec; - _route = _server->choose_route(_uri); - if (_route->_timeout) - _death_time = _route->_timeout + t.tv_sec; - if (DEBUG) - debug_header(); - string len = header_pick("Content-Length:", 0).c_str(); - if (len != "") { - _len = std::atoi(len.c_str()); - _last_chunk = true; - int max_len = - _route->_client_max_body_size > 0 ? _route->_client_max_body_size - : _server->_client_max_body_size > 0 ? _server->_client_max_body_size - : INT_MAX; - if (_len > max_len) - return (send_error(413), false); - } else - _len = 0; - return true; + vec_string lines, method, line; + if (DEBUG) cout << "Parsing header...\n"; + lines = split(_header, "\r\n"); + method = split(lines.at(0), " "); + _headers["Method:"] = method; + if (lines.size() > 0) { + for (vec_string::iterator it = lines.begin() + 1; it < lines.end(); it++) { + line = split(*it, " "); + _headers[line.at(0)] = vec_string(line.begin() + 1, line.end()); + } + } + _method = header_pick("Method:", 0); + if ((_method == "POST" || _method == "PUT") && header_pick("Content-Length:", 0) == "" && + header_pick("Transfer-Encoding:", 0) != "chunked") + return (send_error(400), false); + vec_string uri_split = split(header_pick("Method:", 1), "?"); + _uri = uri_split.at(0); + if (uri_split.size() > 1) _query = uri_split.at(1); + _host = header_pick("Host:", 0); + _keepalive = header_pick("Connection:", 0) == "keep-alive"; + _env = env; + struct timeval t; + gettimeofday(&t, NULL); + _server = _parent->choose_server(env, _host); + if (_server->_timeout) _death_time = _server->_timeout + t.tv_sec; + _route = _server->choose_route(_uri); + if (_route->_timeout) _death_time = _route->_timeout + t.tv_sec; + if (DEBUG) debug_header(); + string len = header_pick("Content-Length:", 0).c_str(); + if (len != "") { + _len = std::atoi(len.c_str()); + _last_chunk = true; + int max_len = _route->_client_max_body_size > 0 ? _route->_client_max_body_size + : _server->_client_max_body_size > 0 ? _server->_client_max_body_size + : INT_MAX; + if (_len > max_len) return (send_error(413), false); + } else _len = 0; + return true; } -string Client::header_pick(string key, size_t id) { - return _headers[key].size() <= id ? "" : _headers[key].at(id); -} +string Client::header_pick(string key, size_t id) { return _headers[key].size() <= id ? "" : _headers[key].at(id); } bool Client::check_method(void) { - vec_string allowed; - if ((_route && (allowed = _route->_allowed_methods).size() > 0) || - (_server && (allowed = _server->_allowed_methods).size() > 0) || - ((allowed = _env->_allowed_methods).size() > 0)) - return std::find(allowed.begin(), allowed.end(), _method) < allowed.end() - ? true - : false; - else if (_method == "GET" || _method == "POST" || _method == "DELETE" || - _method == "PUT") - return (true); - return (false); + vec_string allowed; + if ((_route && (allowed = _route->_allowed_methods).size() > 0) || + (_server && (allowed = _server->_allowed_methods).size() > 0) || ((allowed = _env->_allowed_methods).size() > 0)) + return std::find(allowed.begin(), allowed.end(), _method) < allowed.end() ? true : false; + else if (_method == "GET" || _method == "POST" || _method == "DELETE" || _method == "PUT") return (true); + return (false); } void Client::handleRequest(void) { - if (DEBUG) { - debug_block("Header: ", _header); - debug_block("Body: ", _body); - } - if (_route->_ret_uri != "") - send_error(_route->_ret_code, _route->_ret_uri); - else if (_server->_ret_uri != "") - send_error(_server->_ret_code, _server->_ret_uri); - else { - string ret; - struct timeval t; - gettimeofday(&t, NULL); - if (_death_time && t.tv_sec > _death_time) { - send_error(408); - _finish = true; - return; - } - string req_path = _route->getRoot() + _uri; - if (!SILENT) - std::cout << "||-> Request for " << req_path << " received <-||\n"; - string cgi_path = - _route->_cgi.size() ? _route->_cgi[get_extension(req_path)] - : _server->_cgi.size() ? _server->_cgi[get_extension(req_path)] - : ""; - if (DEBUG) - cout << "Path: " << req_path << "\n"; - if (!check_method()) - send_error(405); - else { - if ((ret = _route->getIndex(_uri, req_path)) == "") - ret = file_answer(req_path); - if (ret == "404") { - if (_method == "POST" || _method == "PUT") - create_file(req_path); - else - send_error(404); - } else if (ret == "403") - send_error(403); - else if (_method == "DELETE") - std::remove(req_path.c_str()); - else if (cgi_path != "") - cgi(cgi_path, req_path); - else - send_answer("HTTP/1.1 200 OK\r\n" + ret); - } - } + if (DEBUG) { + debug_block("Header: ", _header); + debug_block("Body: ", _body); + } + if (_route->_ret_uri != "") send_error(_route->_ret_code, _route->_ret_uri); + else if (_server->_ret_uri != "") send_error(_server->_ret_code, _server->_ret_uri); + else { + string ret; + struct timeval t; + gettimeofday(&t, NULL); + if (_death_time && t.tv_sec > _death_time) { + send_error(408); + _finish = true; + return; + } + string req_path = _route->getRoot() + _uri; + if (!SILENT) std::cout << "||-> Request for " << req_path << " received <-||\n"; + string cgi_path = _route->_cgi.size() ? _route->_cgi[get_extension(req_path)] + : _server->_cgi.size() ? _server->_cgi[get_extension(req_path)] + : ""; + if (DEBUG) cout << "Path: " << req_path << "\n"; + if (!check_method()) send_error(405); + else { + if ((ret = _route->getIndex(_uri, req_path)) == "") ret = file_answer(req_path); + if (ret == "404") { + if (_method == "POST" || _method == "PUT") create_file(req_path); + else send_error(404); + } else if (ret == "403") send_error(403); + else if (_method == "DELETE") std::remove(req_path.c_str()); + else if (cgi_path != "") cgi(cgi_path, req_path); + else send_answer("HTTP/1.1 200 OK\r\n" + ret); + } + } } void Client::create_file(string path) { - std::ofstream file(path.c_str()); - if (!file.good()) - send_error(403); - else { - file << _body; - file.close(); - send_answer("HTTP/1.1 201 Accepted\r\n\r\n"); - } + std::ofstream file(path.c_str()); + if (!file.good()) send_error(403); + else { + file << _body; + file.close(); + send_answer("HTTP/1.1 201 Accepted\r\n\r\n"); + } } /** @@ -275,38 +231,35 @@ void Client::create_file(string path) { * @param path The path to the file requested. */ void Client::cgi(string cgi_path, string path) { - int pipe_in[2]; + int pipe_in[2]; - send(_fd, "HTTP/1.1 200 OK\r\n", 17, MSG_NOSIGNAL); - if (!std::ifstream(cgi_path.c_str()).good()) - return send_error(404); - if (DEBUG) - std::cout << "Send cgi\n"; - if (fork() == 0) { - const char **args = new const char *[cgi_path.length() + 1]; - args[0] = cgi_path.c_str(); - args[1] = NULL; - string path_info = "PATH_INFO=" + _route->getRoot(); - string query = "QUERY_STRING=" + _query; - const char **env = - new const char *[path_info.length() + query.length() + 2]; - env[0] = path_info.c_str(); - env[1] = query.c_str(); - env[2] = NULL; - pipe(pipe_in); - std::stringstream tmp; - tmp << std::ifstream(path.c_str()).rdbuf(); - string file = tmp.str(); - write(pipe_in[1], file.c_str(), file.size()); - close(pipe_in[1]); - dup2(pipe_in[0], STDIN_FILENO); - close(pipe_in[0]); - dup2(_fd, STDOUT_FILENO); - close(_fd); - execve(cgi_path.c_str(), (char **)args, (char **)env); - exit(1); - } - _finish = true; + send(_fd, "HTTP/1.1 200 OK\r\n", 17, MSG_NOSIGNAL); + if (!std::ifstream(cgi_path.c_str()).good()) return send_error(404); + if (DEBUG) std::cout << "Send cgi\n"; + if (fork() == 0) { + const char **args = new const char *[cgi_path.length() + 1]; + args[0] = cgi_path.c_str(); + args[1] = NULL; + string path_info = "PATH_INFO=" + _route->getRoot(); + string query = "QUERY_STRING=" + _query; + const char **env = new const char *[path_info.length() + query.length() + 2]; + env[0] = path_info.c_str(); + env[1] = query.c_str(); + env[2] = NULL; + pipe(pipe_in); + std::stringstream tmp; + tmp << std::ifstream(path.c_str()).rdbuf(); + string file = tmp.str(); + write(pipe_in[1], file.c_str(), file.size()); + close(pipe_in[1]); + dup2(pipe_in[0], STDIN_FILENO); + close(pipe_in[0]); + dup2(_fd, STDOUT_FILENO); + close(_fd); + execve(cgi_path.c_str(), (char **)args, (char **)env); + exit(1); + } + _finish = true; } /** @@ -315,50 +268,39 @@ void Client::cgi(string cgi_path, string path) { * @param error_code The HTTP response code to send. */ void Client::send_error(int error_code, string opt) { - string error_path, body; - error_path = _route->_err_page[error_code]; - if (error_path == "") { - error_path = _server->_err_page[error_code]; - if (error_path != "") - body = file_answer(_server->correctUri(error_path)); - } else - body = file_answer(_route->correctUri(error_path)); + string error_path, body; + error_path = _route->_err_page[error_code]; + if (error_path == "") { + error_path = _server->_err_page[error_code]; + if (error_path != "") body = file_answer(_server->correctUri(error_path)); + } else body = file_answer(_route->correctUri(error_path)); - switch (error_code) { - case 301: - return send_answer("HTTP/1.1 301 Moved Permanently\r\nLocation: " + opt + - "\r\n" + body + "\r\n"); - case 302: - return send_answer("HTTP/1.1 302 Found\r\nLocation: " + opt + "\r\n" + - body + "\r\n"); - case 307: - return send_answer("HTTP/1.1 307 Temporary Redirect\r\nLocation: " + opt + - "\r\n" + body + "\r\n"); - case 308: - return send_answer("HTTP/1.1 308 Permanent Redirect\r\nLocation: " + opt + - "\r\n" + body + "\r\n"); - case 400: - return send_answer("HTTP/1.1 400 Bad Request\r\n" + body + "\r\n"); - case 403: - return send_answer("HTTP/1.1 403 Forbidden\r\n" + body + "\r\n"); - case 404: - return send_answer("HTTP/1.1 404 Not Found\r\n" + body + "\r\n"); - case 405: - return send_answer("HTTP/1.1 405 Method Not Allowed\r\nConnection: " - "close\r\n" + - body + "\r\n"); - case 408: - return send_answer("HTTP/1.1 408 Request Timeout\r\nConnection: close\r\n" + - body + "\r\n"); - case 413: - return send_answer( - "HTTP/1.1 413 Payload Too Large\r\nConnection: close\r\n" + body + - "\r\n"); - case 429: - return send_answer( - "HTTP/1.1 429 Too Many Requests\r\nConnection: close\r\n" + body + - "\r\n"); - } + switch (error_code) { + case 301: + return send_answer("HTTP/1.1 301 Moved Permanently\r\nLocation: " + opt + "\r\n" + body + "\r\n"); + case 302: + return send_answer("HTTP/1.1 302 Found\r\nLocation: " + opt + "\r\n" + body + "\r\n"); + case 307: + return send_answer("HTTP/1.1 307 Temporary Redirect\r\nLocation: " + opt + "\r\n" + body + "\r\n"); + case 308: + return send_answer("HTTP/1.1 308 Permanent Redirect\r\nLocation: " + opt + "\r\n" + body + "\r\n"); + case 400: + return send_answer("HTTP/1.1 400 Bad Request\r\n" + body + "\r\n"); + case 403: + return send_answer("HTTP/1.1 403 Forbidden\r\n" + body + "\r\n"); + case 404: + return send_answer("HTTP/1.1 404 Not Found\r\n" + body + "\r\n"); + case 405: + return send_answer("HTTP/1.1 405 Method Not Allowed\r\nConnection: " + "close\r\n" + + body + "\r\n"); + case 408: + return send_answer("HTTP/1.1 408 Request Timeout\r\nConnection: close\r\n" + body + "\r\n"); + case 413: + return send_answer("HTTP/1.1 413 Payload Too Large\r\nConnection: close\r\n" + body + "\r\n"); + case 429: + return send_answer("HTTP/1.1 429 Too Many Requests\r\nConnection: close\r\n" + body + "\r\n"); + } } /** @@ -367,14 +309,12 @@ void Client::send_error(int error_code, string opt) { * @param msg The HTTP message to send. */ void Client::send_answer(string msg) { - if (DEBUG) - debug_block("ANSWER: ", msg); + if (DEBUG) debug_block("ANSWER: ", msg); #ifdef __linux__ - send(_fd, msg.c_str(), msg.length(), MSG_NOSIGNAL); + send(_fd, msg.c_str(), msg.length(), MSG_NOSIGNAL); #elif __APPLE__ - write(_fd, msg.c_str(), msg.length()); + write(_fd, msg.c_str(), msg.length()); #endif - init(); - if (!_keepalive) - _finish = true; + init(); + if (!_keepalive) _finish = true; } diff --git a/srcs/sock/Master.cpp b/srcs/sock/Master.cpp index 6a8b4d9..b8b3776 100644 --- a/srcs/sock/Master.cpp +++ b/srcs/sock/Master.cpp @@ -11,9 +11,8 @@ * @brief Destructor Close master socket descriptor. */ Master::~Master(void) { - close(_fd); - if (DEBUG) - cout << "Destroyed master socket\n"; + close(_fd); + if (DEBUG) cout << "Destroyed master socket\n"; } /** @@ -26,67 +25,58 @@ Master::~Master(void) { * listen. */ Master::Master(ip_port_t list) : _listen(list) { - int x = 1, port = _listen.port; - string ip = _listen.ip; + int x = 1, port = _listen.port; + string ip = _listen.ip; - _fd = socket(AF_INET, SOCK_STREAM, 0); - if (_fd == 0) - throw std::runtime_error("socket() error" + string(strerror(errno))); - if (setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&x, sizeof(x)) < 0 && - close(_fd) <= 0) - throw std::runtime_error("setsockopt() error: " + string(strerror(errno))); - _address.sin_family = AF_INET; - _address.sin_addr.s_addr = inet_addr(ip.c_str()); - _address.sin_port = htons(port); - if (bind(_fd, (struct sockaddr *)&_address, sizeof(_address)) && - close(_fd) <= 0) - throw std::runtime_error("bind() error: " + string(strerror(errno))); - if (listen(_fd, 3) < 0 && close(_fd) <= 0) - throw std::runtime_error("listen() error: " + string(strerror(errno))); + _fd = socket(AF_INET, SOCK_STREAM, 0); + if (_fd == 0) throw std::runtime_error("socket() error" + string(strerror(errno))); + if (setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&x, sizeof(x)) < 0 && close(_fd) <= 0) + throw std::runtime_error("setsockopt() error: " + string(strerror(errno))); + _address.sin_family = AF_INET; + _address.sin_addr.s_addr = inet_addr(ip.c_str()); + _address.sin_port = htons(port); + if (bind(_fd, (struct sockaddr *)&_address, sizeof(_address)) && close(_fd) <= 0) + throw std::runtime_error("bind() error: " + string(strerror(errno))); + if (listen(_fd, 3) < 0 && close(_fd) <= 0) throw std::runtime_error("listen() error: " + string(strerror(errno))); #ifdef __APPLE__ - fcntl(socket, F_SETFL, O_NONBLOCK); + fcntl(socket, F_SETFL, O_NONBLOCK); #endif - cout << "New master socket with fd " << _fd << " which listen " << ip << ":" - << port << "\n"; - _pollfds[_poll_id_amount].fd = _fd; - _pollfds[_poll_id_amount].events = POLLIN | POLLPRI; - _poll_id = _poll_id_amount; - _poll_id_amount++; + cout << "New master socket with fd " << _fd << " which listen " << ip << ":" << port << "\n"; + _pollfds[_poll_id_amount].fd = _fd; + _pollfds[_poll_id_amount].events = POLLIN | POLLPRI; + _poll_id = _poll_id_amount; + _poll_id_amount++; } /** * @brief Check master and his clients sockets after poll performed. */ void Master::check_socket(void) { - int addrlen = sizeof(_address); + int addrlen = sizeof(_address); - if (_pollfds[_poll_id].revents & POLLIN) { /// < incomming master request - int new_socket = - accept(_fd, (struct sockaddr *)&_address, (socklen_t *)&addrlen); - if (new_socket < 0) - throw std::runtime_error("accept() error:" + string(strerror(errno))); + if (_pollfds[_poll_id].revents & POLLIN) { /// < incomming master request + int new_socket = accept(_fd, (struct sockaddr *)&_address, (socklen_t *)&addrlen); + if (new_socket < 0) throw std::runtime_error("accept() error:" + string(strerror(errno))); #ifdef __APPLE__ - fcntl(new_socket, F_SETFL, O_NONBLOCK); + fcntl(new_socket, F_SETFL, O_NONBLOCK); #endif - ip_port_t cli_listen = - get_ip_port_t(inet_ntoa(_address.sin_addr), ntohs(_address.sin_port)); - Client *new_cli = new Client(new_socket, cli_listen, this); - if (_poll_id_amount > MAX_CLIENTS) { - new_cli->send_error(503); - delete new_cli; - } else { - _childs.push_back(new_cli); - for (int i = _first_cli_id; i < MAX_CLIENTS; i++) { - if (_pollfds[i].fd != 0) - continue; - _pollfds[i].fd = new_socket; - _pollfds[i].events = POLLIN | POLLPRI; - new_cli->_poll_id = i; - _poll_id_amount++; - break; - } - } - } + ip_port_t cli_listen = get_ip_port_t(inet_ntoa(_address.sin_addr), ntohs(_address.sin_port)); + Client *new_cli = new Client(new_socket, cli_listen, this); + if (_poll_id_amount > MAX_CLIENTS) { + new_cli->send_error(503); + delete new_cli; + } else { + _childs.push_back(new_cli); + for (int i = _first_cli_id; i < MAX_CLIENTS; i++) { + if (_pollfds[i].fd != 0) continue; + _pollfds[i].fd = new_socket; + _pollfds[i].events = POLLIN | POLLPRI; + new_cli->_poll_id = i; + _poll_id_amount++; + break; + } + } + } } /** @@ -101,31 +91,29 @@ void Master::check_socket(void) { * @param env The environment object. */ void Master::check_childs(Env *env) { - int child_fd; - for (std::vector::iterator it = _childs.begin(); it < _childs.end(); - it++) { - child_fd = (*it)->_fd; - int i = (*it)->_poll_id; - if (_pollfds[i].fd > 0 && _pollfds[i].revents & POLLIN) { - char buffer[1024]; - int valread = read(child_fd, buffer, 1023); - buffer[valread] = '\0'; - if (valread == 0) { - delete (*it); - _childs.erase(it); - } else if ((*it)->getRequest(env, buffer)) { - (*it)->debug(true); - (*it)->handleRequest(); - _pollfds[i].events = POLLIN | POLLPRI | POLLOUT; - (*it)->debug(false); - if ((*it)->_finish) { - delete (*it); - _childs.erase(it); - } - } else - _pollfds[i].events = POLLIN | POLLPRI; - } - } + int child_fd; + for (std::vector::iterator it = _childs.begin(); it < _childs.end(); it++) { + child_fd = (*it)->_fd; + int i = (*it)->_poll_id; + if (_pollfds[i].fd > 0 && _pollfds[i].revents & POLLIN) { + char buffer[1024]; + int valread = read(child_fd, buffer, 1023); + buffer[valread] = '\0'; + if (valread == 0) { + delete (*it); + _childs.erase(it); + } else if ((*it)->getRequest(env, buffer)) { + (*it)->debug(true); + (*it)->handleRequest(); + _pollfds[i].events = POLLIN | POLLPRI | POLLOUT; + (*it)->debug(false); + if ((*it)->_finish) { + delete (*it); + _childs.erase(it); + } + } else _pollfds[i].events = POLLIN | POLLPRI; + } + } } /** @@ -147,48 +135,38 @@ void Master::check_childs(Env *env) { * @return The server object choosen to handle the request. */ Server *Master::choose_server(Env *env, string host) { - std::vector exact, inrange; - vec_string ip_listen, ip_required; + std::vector exact, inrange; + vec_string ip_listen, ip_required; - ip_required = split(_listen.ip, "."); - for (std::vector::iterator server = env->_servers.begin(); - server < env->_servers.end(); server++) { - std::vector serv_listens = (*server)->_listens; - for (std::vector::iterator it = serv_listens.begin(); - it < serv_listens.end(); it++) { - if (_listen.port != (*it).port) - continue; - if (_listen.ip == (*it).ip) { - exact.push_back(*server); - continue; - } - bool is_inrange = true; - ip_listen = split((*it).ip, "."); - vec_string::iterator r = ip_required.end(); - vec_string::iterator l = ip_listen.end(); - while (r > ip_required.begin()) { - if (*(--l) != *(--r) && *l != "0") - is_inrange = false; - } - if (is_inrange) - inrange.push_back(*server); - } - } - if (DEBUG) - std::cout << "req: " << _listen.ip << ":" << _listen.port << "\n"; - if (exact.size() == 0) { - for (std::vector::iterator server = inrange.begin(); - server < inrange.end(); server++) { - if (host == (*server)->getName()) - return *server; - } - return inrange.front(); - } else { - for (std::vector::iterator server = exact.begin(); - server < exact.end(); server++) { - if (host == (*server)->getName()) - return *server; - } - return exact.front(); - } + ip_required = split(_listen.ip, "."); + for (std::vector::iterator server = env->_servers.begin(); server < env->_servers.end(); server++) { + std::vector serv_listens = (*server)->_listens; + for (std::vector::iterator it = serv_listens.begin(); it < serv_listens.end(); it++) { + if (_listen.port != (*it).port) continue; + if (_listen.ip == (*it).ip) { + exact.push_back(*server); + continue; + } + bool is_inrange = true; + ip_listen = split((*it).ip, "."); + vec_string::iterator r = ip_required.end(); + vec_string::iterator l = ip_listen.end(); + while (r > ip_required.begin()) { + if (*(--l) != *(--r) && *l != "0") is_inrange = false; + } + if (is_inrange) inrange.push_back(*server); + } + } + if (DEBUG) std::cout << "req: " << _listen.ip << ":" << _listen.port << "\n"; + if (exact.size() == 0) { + for (std::vector::iterator server = inrange.begin(); server < inrange.end(); server++) { + if (host == (*server)->getName()) return *server; + } + return inrange.front(); + } else { + for (std::vector::iterator server = exact.begin(); server < exact.end(); server++) { + if (host == (*server)->getName()) return *server; + } + return exact.front(); + } }