From 66beaba729c2681dc1ba76a3d580ed8228ef7de3 Mon Sep 17 00:00:00 2001 From: nicolas-arnaud Date: Sun, 13 Nov 2022 18:23:22 +0100 Subject: [PATCH] save 22-11-13-4 --- includes/Route.hpp | 7 +--- srcs/load/Env.cpp | 1 - srcs/load/Route.cpp | 61 ++++++++++++++------------- srcs/load/Server.cpp | 61 ++++++++++++++------------- srcs/sock/Client.cpp | 98 +++++++++++++++++--------------------------- srcs/sock/Master.cpp | 72 +++++++++++++------------------- srcs/tools.cpp | 67 +++++++++++++++--------------- srcs/webserv.cpp | 7 +++- 8 files changed, 169 insertions(+), 205 deletions(-) diff --git a/includes/Route.hpp b/includes/Route.hpp index e009456..a406958 100644 --- a/includes/Route.hpp +++ b/includes/Route.hpp @@ -4,14 +4,11 @@ class Route { protected: Server *_server; - string _location; - string _root; - string _ret; + string _location, _root, _ret; bool _autoindex; public: - vec_string _indexs; - vec_string _allowed_methods; + vec_string _indexs, _allowed_methods; std::map< string, string > _cgi; int _client_max_body_size; diff --git a/srcs/load/Env.cpp b/srcs/load/Env.cpp index 705303e..8a17d8e 100644 --- a/srcs/load/Env.cpp +++ b/srcs/load/Env.cpp @@ -25,7 +25,6 @@ Env::~Env() { */ Env::Env(JSONNode *conf) { try { - JSONList servers = conf->obj()["servers"]->lst(); for (std::vector< JSONNode * >::iterator it = servers.begin(); it < servers.end(); it++) { diff --git a/srcs/load/Route.cpp b/srcs/load/Route.cpp index 73b09b7..4efdb21 100644 --- a/srcs/load/Route.cpp +++ b/srcs/load/Route.cpp @@ -51,15 +51,17 @@ string Route::getLocation(void) { return _location; } string Route::getRoot(void) { return _root; } string Route::getReturn(void) { return _ret; } /* |==========| - * Find either an autoindex or an index into the directory required by request + * Generate the autoindex of folder. + * If while generating it an index file is found, it return the opened file. + * Else it finish generating autoindex and return it finally if autoindex is + * enable on this route. * - * Input: The uri client asked, the real local path to the directory - * Output: The file or the autoindex page to display + * Input: The uri client asked and the real local path to the directory + * Output: The index or the autoindex page to display */ string Route::getIndex(string uri, string path) { - std::stringstream content; - std::stringstream ret; + std::stringstream body, ret; DIR *dir; struct dirent *entry; struct stat info; @@ -68,9 +70,9 @@ string Route::getIndex(string uri, string path) { if ((dir = opendir(path.c_str())) == NULL) { return ""; } else { - cout << "get index(): path=" << path << "\n"; - content << "

" << path - << " files :

\n"; closedir(dir); } if (!_autoindex) return ""; - cout << "Getting autoindex\n"; + // cout << "Getting autoindex\n"; ret << "Content-type: text/html \r\n"; - ret << "Content-length: " << content.str().length() << "\r\n"; - ret << "\r\n" << content.str(); + ret << "Content-length: " << body.str().length() << "\r\n"; + ret << "\r\n" << body.str(); return ret.str(); } /* |==========| @@ -104,24 +106,21 @@ string Route::getIndex(string uri, string path) { string Route::correctUri(string uri) { std::stringstream ret; - vec_string::iterator it; - vec_string::iterator it2; - - ret << "./" << _root; - vec_string loc_split = split(_location, "/"); - vec_string uri_split = split(uri, "/"); - it2 = uri_split.begin(); - for (it = loc_split.begin(); it < loc_split.end(); it++) { - while (it2 < uri_split.end() && *it2 == "") - it2++; - while (it < loc_split.end() && *it == "") - it++; - if (it != loc_split.end()) - it2++; - } + vec_string::iterator loc_word, uri_word; - while (it2 < uri_split.end()) { - ret << "/" << *(it2++); + 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/load/Server.cpp b/srcs/load/Server.cpp index 5f25289..27f4398 100644 --- a/srcs/load/Server.cpp +++ b/srcs/load/Server.cpp @@ -33,7 +33,6 @@ Server::Server(JSONNode *server) : Route(NULL, "/", server) { } } } - /* Get the server name (_server_name)*/ string Server::getName(void) { return _name; } @@ -46,31 +45,31 @@ string Server::getName(void) { return _name; } Master *Server::create_master(string str) { ip_port_t listen = get_ip_port_t(str); - if (listen.ip.at(0) == '[') { + if (listen.ip.at(0) != '[') { + try { + _listens.push_back(listen); + Master *sock = new Master(listen); + return (sock); + } catch (std::exception &e) { + std::cerr << e.what() << '\n'; + } + } else cout << "Listen: IPv6 isn't supported\n"; - } - try { - _listens.push_back(listen); - Master *sock = new Master(listen); - return (sock); - } catch (std::exception &e) { - std::cerr << e.what() << '\n'; - return NULL; - } + return NULL; } /*|===========| * Create server's defined sockets: * * Input: A server block node from JSONParser. - * Output: A vector containing all the succesfull created sockets using listens - * from the server block. + * Output: A vector containing all the succesfull created sockets using + * listens from the server block. */ std::vector< Master * > Server::get_sockets(JSONNode *server) { JSONObject datas = server->obj(); std::vector< Master * > ret; - ip_port_t listen; Master *tmp; + ip_port_t listen; if (datas["listens"]) { JSONList listens = datas["listens"]->lst(); for (JSONList::iterator it = listens.begin(); it != listens.end(); @@ -86,27 +85,27 @@ std::vector< Master * > Server::get_sockets(JSONNode *server) { * Choose the route an uri asked to the server must lead to. * * Intput: The uri asked by the client to the server. - * Output: The route object choosen or the server itself if no location block is - * adapted. + * Output: The route object choosen or the server itself if no location + * block is adapted. */ Route *Server::choose_route(string uri) { - vec_string req = split(uri, "/"); - vec_string root; - for (std::map< string, Route * >::iterator rit = _routes.begin(); - rit != _routes.end(); rit++) { - root = split((*rit).first, "/"); - cout << "Route: " << (*rit).first << "\n"; - vec_string::iterator root_it = root.begin(); - for (vec_string::iterator it = req.begin(); it < req.end(); it++) { - while (it != req.end() && *it == "") - it++; - if (*it != *(root_it++)) + vec_string uri_words, loc_words; + uri_words = split(uri, "/"); + for (std::map< string, Route * >::iterator loc_it = _routes.begin(); + loc_it != _routes.end(); loc_it++) { + loc_words = split((*loc_it).first, "/"); + vec_string::iterator loc_word = loc_words.begin(); + for (vec_string::iterator uri_word = uri_words.begin(); + uri_word < uri_words.end(); uri_word++) { + while (uri_word != uri_words.end() && *uri_word == "") + uri_word++; + if (*uri_word != *(loc_word++)) break; - while (root_it != root.end() && *root_it == "") - root_it++; - if (root_it == root.end()) - return ((*rit).second); + while (loc_word != loc_words.end() && *loc_word == "") + loc_word++; + if (loc_word == loc_words.end()) + return ((*loc_it).second); } } return this; diff --git a/srcs/sock/Client.cpp b/srcs/sock/Client.cpp index d1bf8fc..3d9e7b4 100644 --- a/srcs/sock/Client.cpp +++ b/srcs/sock/Client.cpp @@ -37,14 +37,10 @@ bool Client::getHeader(Env *env, string paquet) { else paquet.clear(); _header += *it + (it + 1 != lines.end() ? "\r\n" : ""); - if (_header.find("\r\n\r\n") != string::npos) { - print_block("HEADER: ", _header); - if (!this->parseHeader(env)) - return false; - if (paquet.length() > 0) - return getBody(paquet); - return true; - } + if (_header.find("\r\n\r\n") != string::npos) + return !this->parseHeader(env) + ? false + : (paquet.length() > 0 ? getBody(paquet) : true); } return false; } @@ -54,25 +50,19 @@ bool Client::getBody(string paquet) { vec_string::iterator it; for (it = lines.begin(); it < lines.end(); it++) { - // cout << "line: " << *it << "\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; - // +2 for the final \r\n closing chunk } else if (_len > 0 || it != lines.begin()) { _body += *it + "\r\n"; _len -= ((*it).length() + 2); } } - if (_body.size()) - _body.resize(_body.length() - 2); + // if (_body.size()) + _body.resize(_body.length() - 2); _len += 2; - if (_last_chunk && _len == 0) { - print_block("BODY: ", _body); - return true; - } - return false; + return (_last_chunk && _len == 0) ? true : false; } bool Client::parseHeader(Env *env) { @@ -104,66 +94,55 @@ bool Client::parseHeader(Env *env) { if (len != "") { _len = std::atoi(len.c_str()); _last_chunk = true; - if (_len > _route->_client_max_body_size) { - send_error(413); - return false; - } + if (_len > _route->_client_max_body_size) + return (send_error(413), false); } return true; } bool Client::check_method(void) { vec_string allowed; - if (_method != "GET" && _method != "POST" && _method != "DELETE" && - _method != "PUT") - send_error(405); - else if ((allowed = _route->_allowed_methods).size() > 0) { - if (std::find(allowed.begin(), allowed.end(), _method) == allowed.end()) - send_error(405); - else - return true; - } else if ((allowed = _server->_allowed_methods).size() > 0) { - if (std::find(allowed.begin(), allowed.end(), _method) == allowed.end()) - send_error(405); - else - return true; - } else + if ((allowed = _route->_allowed_methods).size() > 0 || + (allowed = _server->_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); } string Client::header_pick(string key, size_t id) { - if (_request[key].size() <= id) - return ""; - return _request[key].at(id); + return _request[key].size() <= id ? "" : _request[key].at(id); } void Client::answer(void) { - cout << "Method: " << _method << "\n"; - cout << "URI: " << _uri << "\n"; - cout << "Host: " << _host << "\n"; + print_block("Header: ", _header); + print_block("Body: ", _body); string ret; string path = _route->correctUri(_uri); - string cgi = - _route->_cgi.size() - ? _route->_cgi[get_extension(path)] - : (_server->_cgi.size() ? _server->_cgi[get_extension(path)] : ""); + string cgi = _route->_cgi.size() ? _route->_cgi[get_extension(path)] + : _server->_cgi.size() ? _server->_cgi[get_extension(path)] + : ""; cout << "Path: " << path << "\n"; if (_method == "PUT") create_file(path); - if (cgi == "") { - if (check_method()) { - if ((ret = _route->getIndex(_uri, path)) == "") - ret = read_file(path); - if (ret == "404") - send_error(404); - else if (ret == "403") - send_error(403); - else - send_answer("HTTP/1.1 200 OK\r\n" + ret); - } - } else + if (cgi != "") send_cgi(cgi, path); + else if (!check_method()) + send_error(405); + else { + if ((ret = _route->getIndex(_uri, path)) == "") + ret = read_file(path); + if (ret == "404") + send_error(404); + else if (ret == "403") + send_error(403); + else + send_answer("HTTP/1.1 200 OK\r\n" + ret); + } } void Client::create_file(string path) { @@ -186,8 +165,7 @@ void Client::send_cgi(string cgi, string path) { if (!std::ifstream(cgi.c_str()).good()) return send_error(404); pipe(fd); - int pid = fork(); - if (pid == 0) { + if (fork() == 0) { const char **args = new const char *[cgi.length() + path.length() + 2]; args[0] = cgi.c_str(); args[1] = path.c_str(); @@ -202,7 +180,7 @@ void Client::send_cgi(string cgi, string path) { execve(cgi.c_str(), (char **)args, (char **)env); } close(fd[1]); - waitpid(pid, &status, 0); + waitpid(-1, &status, 0); char buffer[10000]; buffer[read(fd[0], buffer, 10000)] = 0; ret = string(buffer); diff --git a/srcs/sock/Master.cpp b/srcs/sock/Master.cpp index dcc03f7..8e5ac28 100644 --- a/srcs/sock/Master.cpp +++ b/srcs/sock/Master.cpp @@ -16,34 +16,27 @@ Master::~Master(void) { */ Master::Master(ip_port_t list) : _listen(list) { - int opt = 1; + int x = 1, port = _listen.port; string ip = _listen.ip; - int port = _listen.port; _fd = socket(AF_INET, SOCK_STREAM, 0); if (_fd == 0) throw std::runtime_error("socket() error" + string(strerror(errno))); - int opt_ret = - setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)); - if (opt_ret < 0) { - close(_fd); + 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)) < 0) { - close(_fd); + 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); + if (listen(_fd, 3) < 0 && close(_fd) <= 0) throw std::runtime_error("listen() error: " + string(strerror(errno))); - } cout << "New master socket with fd " << _fd << " which listen " << ip << ":" << port << "\n"; if (_fd < _min_fd) @@ -54,14 +47,12 @@ Master::Master(ip_port_t list) : _listen(list) { void Master::set_fds(void) { FD_SET(_fd, &_readfds); - int child_fd; - for (std::vector< Client * >::iterator it = _childs.begin(); - it < _childs.end(); it++) { - child_fd = (*it)->_fd; - FD_SET(child_fd, &_readfds); - if (child_fd > _max_fd) - _max_fd = child_fd; + for (std::vector< Client * >::iterator child = _childs.begin(); + child < _childs.end(); child++) { + FD_SET((*child)->_fd, &_readfds); + if ((*child)->_fd > _max_fd) + _max_fd = (*child)->_fd; } } /* |==========| @@ -101,11 +92,8 @@ void Master::refresh(Env *env) { (socklen_t *)&addrlen); delete (*it); _childs.erase(it); - } else { - // print_block("Paquet: ", buffer); - if ((*it)->getHeader(env, buffer)) - (*it)->answer(); - } + } else if ((*it)->getHeader(env, buffer)) + (*it)->answer(); } } } @@ -126,21 +114,19 @@ void Master::refresh(Env *env) { */ Server *Master::choose_server(Env *env, string host) { - std::vector< Server * > exact; - std::vector< Server * > inrange; - vec_string ip_listen; - vec_string ip_required; + std::vector< Server * > exact, inrange; + vec_string ip_listen, ip_required; ip_required = split(_listen.ip, "."); - for (std::vector< Server * >::iterator sit = env->_servers.begin(); - sit < env->_servers.end(); sit++) { - std::vector< ip_port_t > serv_listens = (*sit)->_listens; + for (std::vector< Server * >::iterator server = env->_servers.begin(); + server < env->_servers.end(); server++) { + std::vector< ip_port_t > serv_listens = (*server)->_listens; for (std::vector< ip_port_t >::iterator it = serv_listens.begin(); it < serv_listens.end(); it++) { if (_listen.port != (*it).port) continue; if (_listen.ip == (*it).ip) { - exact.push_back(*sit); + exact.push_back(*server); continue; } bool is_inrange = true; @@ -151,22 +137,22 @@ Server *Master::choose_server(Env *env, string host) { if (*l != *r && *l != "0") is_inrange = false; } - if (is_inrange == true) - inrange.push_back(*sit); + if (is_inrange) + inrange.push_back(*server); } } if (exact.size() == 0) { - for (std::vector< Server * >::iterator sit = inrange.begin(); - sit < inrange.end(); sit++) { - if (host == (*sit)->getName()) - return *sit; + for (std::vector< Server * >::iterator server = inrange.begin(); + server < inrange.end(); server++) { + if (host == (*server)->getName()) + return *server; } return inrange.front(); } else { - for (std::vector< Server * >::iterator sit = exact.begin(); - sit < exact.end(); sit++) { - if (host == (*sit)->getName()) - return *sit; + for (std::vector< Server * >::iterator server = exact.begin(); + server < exact.end(); server++) { + if (host == (*server)->getName()) + return *server; } return exact.front(); } diff --git a/srcs/tools.cpp b/srcs/tools.cpp index 5d8e1db..e7e644f 100644 --- a/srcs/tools.cpp +++ b/srcs/tools.cpp @@ -1,14 +1,12 @@ #include "webserv.hpp" void *ft_memset(void *b, int c, size_t len) { - size_t i; unsigned char *b_cpy; b_cpy = (unsigned char *)b; - i = 0; - while (i < len) - *(unsigned char *)(b_cpy + i++) = (unsigned char)c; - return ((void *)b); + for (size_t i = 0; i < len; i++) + *(unsigned char *)(b_cpy + i) = (unsigned char)c; + return (b); } bool isInt(string str) { @@ -19,10 +17,10 @@ bool isInt(string str) { } vec_string split(string str, string delim) { - string temp(str); - string token; - size_t pos; - std::vector< std::string > tokens; + string temp(str); + string token; + size_t pos; + vec_string tokens; while ((pos = temp.find(delim)) != string::npos) { token = temp.substr(0, pos); @@ -51,6 +49,33 @@ ip_port_t get_ip_port_t(string ip, int port) { return ret; } +string read_file(string path) { + struct stat info; + if (stat(path.c_str(), &info) != 0) { + std::cerr << "stat() error on " << path << ": " << strerror(errno) + << "\n"; + return "404"; + } else if (S_ISDIR(info.st_mode)) + return "404"; + + std::ifstream file(path.c_str()); + if (!file.good()) + return "404"; + + string str, body; + while (file) { + std::getline(file, str); + body += str + "\n"; + } + + std::stringstream ret; + ret << "Content-type: " << getMime(path) << "\r\n" + << "Content-length: " << body.length() << "\r\n" + << "\r\n" + << body; + return (ret.str()); +} + string getMime(string path) { size_t pos = path.rfind('.'); string extension = (pos == string::npos) ? "txt" : path.substr(pos + 1); @@ -221,27 +246,3 @@ string getMime(string path) { else return ("text/plain"); } - -string read_file(string path) { - string str; - string content; - std::stringstream ret; - struct stat info; - if (stat(path.c_str(), &info) != 0) { - std::cerr << "stat() error on " << path << ": " << strerror(errno) - << "\n"; - return "404"; - } else if (S_ISDIR(info.st_mode)) - return "404"; - std::ifstream file(path.c_str()); - if (!file.good()) - return "404"; - while (file) { - std::getline(file, str); - content += str + "\n"; - } - ret << "Content-type: " << getMime(path) << "\r\n"; - ret << "Content-length: " << content.length() << "\r\n"; - ret << "\r\n" << content; - return (ret.str()); -} diff --git a/srcs/webserv.cpp b/srcs/webserv.cpp index a6514d7..ca3ffad 100644 --- a/srcs/webserv.cpp +++ b/srcs/webserv.cpp @@ -1,30 +1,35 @@ #include "webserv.hpp" fd_set Master::_readfds; -int Master::_max_fd; int Master::_min_fd = INT_MAX; +int Master::_max_fd = 0; int Master::_amount = 0; int main(int ac, char **av) { try { if (ac > 2) throw std::runtime_error("Too many arguments"); + std::string config_file = "default.json"; if (ac == 2) config_file = av[1]; + std::ifstream file(config_file.c_str()); if (!file.good()) throw std::runtime_error("File not found"); + cout << "Parsing configuration file from JSON conf file.\n"; cout << "You must be sure the syntax is correct\n"; JSONParser parser(config_file); JSONNode *conf = parser.parse(); + cout << "Initialization of server...\n"; Env env(conf); while (1) env.cycle(); } catch (const std::exception &e) { std::cerr << e.what() << '\n'; + return EXIT_FAILURE; } return EXIT_SUCCESS; }