diff --git a/.gitignore b/.gitignore index 27e0584..f3ab56d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,14 @@ !default.json !.gitignore +!public/ +!public/images/ +!public/images/* +!public/testsite/ +!public/testsite/* +!public/documents/ +!public/documents/* + !includes/ !includes/*.hpp diff --git a/default.json b/default.json index 9611322..3674d70 100644 --- a/default.json +++ b/default.json @@ -5,13 +5,15 @@ { "server_name": "localhost", "listens": ["localhost:8080"], + "root": "tester/", "return": "301 https://$host$uri" }, { "server_name": "localhost", "listens": ["192.168.62.61:8080", "localhost", "555"], - "root": "public/", - "indexs": ["index.html"], + "root": "public/testsite", + "indexs": ["basique.html"], + "cgi": "cgi.sh", "locations": { "docs/": diff --git a/includes/Env.hpp b/includes/Env.hpp index d7e2ab7..3c3100a 100644 --- a/includes/Env.hpp +++ b/includes/Env.hpp @@ -2,12 +2,12 @@ #include "webserv.hpp" class Env { - std::vector _servers; - std::vector _sockets; - public: + std::vector _servers; + std::vector _sockets; Env(JSONNode *conf); void set_fds(void); void refresh(void); - Server *choose_server(Socket *sock, string host); + Server *choose_server(Socket *sock, string host); + ~Env(); }; diff --git a/includes/Server.hpp b/includes/Server.hpp index 4d57949..3040440 100644 --- a/includes/Server.hpp +++ b/includes/Server.hpp @@ -9,6 +9,6 @@ class Server : public Route { Server(JSONNode *server); ~Server(void); std::vector get_sockets(JSONNode *server); - Route *get_route(string uri); + Route *choose_route(string uri); string getName(void); }; diff --git a/includes/Socket.hpp b/includes/Socket.hpp index faaaaf2..819bd4d 100644 --- a/includes/Socket.hpp +++ b/includes/Socket.hpp @@ -16,6 +16,7 @@ class Socket { int answer(Env *env); void send_answer(string msg); bool waitHeader(); + Server *choose_server(Env *env, string host); public: Socket(listen_t listen); Socket(int fd, Socket *parent); diff --git a/public/documents/test1 b/public/documents/test1 new file mode 100644 index 0000000..e69de29 diff --git a/public/documents/test2 b/public/documents/test2 new file mode 100644 index 0000000..e69de29 diff --git a/public/images/a_file b/public/images/a_file new file mode 100644 index 0000000..458a936 --- /dev/null +++ b/public/images/a_file @@ -0,0 +1,2 @@ +jdkslaj\njkdsa;jfd\njdkaj;fjd +jdkslaj\njkdsa;jfd\njdkaj;fjd diff --git a/srcs/load/Env.cpp b/srcs/load/Env.cpp index 082932e..c728434 100644 --- a/srcs/load/Env.cpp +++ b/srcs/load/Env.cpp @@ -1,20 +1,21 @@ #include "webserv.hpp" +/*|=======================| + * Environment constructor: + * + * Input: The JSONParser output + * Output: The env object containing servers and sockets vectors defined inside + * conf file by servers blocks and listens. + */ Env::Env(JSONNode *conf) { try { JSONList servers = conf->obj()["servers"]->lst(); - int i = 0; - string th[8] = {"first", "second", "third", "fourth", - "fifth", "sixth", "seventh", "eigth"}; for (std::vector::iterator it = servers.begin(); it < servers.end(); it++) { Server *server = new Server(*it); _servers.push_back(server); std::vector tmp_s = server->get_sockets(*it); _sockets.insert(_sockets.end(), tmp_s.begin(), tmp_s.end()); - // delete *it; - cout << th[i] << " server launched.\n"; - i++; } } catch (std::exception &e) { cout << e.what(); @@ -22,52 +23,10 @@ Env::Env(JSONNode *conf) { delete conf; } -Server *Env::choose_server(Socket *sock, string host) { - std::vector exact; - std::vector inrange; - std::vector ip_listen; - std::vector ip_required; - // string ip = inet_ntoa(sock->_address.sin_addr); - // int port = ntohs(sock->_address.sin_port); - - // cout << "Which server for " << ip << ":" << port << "?\n"; - cout << "Socket: " << sock->_listen.ip << ":" << sock->_listen.port << "\n"; - ip_required = split(sock->_listen.ip, '.'); - for (std::vector::iterator sit = _servers.begin(); - sit < _servers.end(); sit++) { - - std::vector serv_listens = (*sit)->_listens; - for (std::vector::iterator it = serv_listens.begin(); - it < serv_listens.end(); it++) { - - if (sock->_listen.port != (*it).port) - continue; - if (sock->_listen.ip == (*it).ip) { - exact.push_back(*sit); - continue; - } - bool is_inrange = true; - ip_listen = split((*it).ip, '.'); - std::vector::iterator r = ip_required.begin(); - for (std::vector::iterator l = ip_listen.begin(); - l < ip_listen.end(); l++) { - if (*l != *r && *l != "0") - is_inrange = false; - } - if (is_inrange == true) - inrange.push_back(*sit); - } - } - if (exact.size() == 0) { - for (std::vector::iterator sit = inrange.begin(); - sit < inrange.end(); sit++) { - if (host == (*sit)->getName()) - return *sit; - } - return inrange.front(); - } else - return exact.front(); -} +/*|=======================| + * Append each master_sockets and their clients to list of fds SELECT must look + * at. + */ void Env::set_fds(void) { for (std::vector::iterator it = _sockets.begin(); @@ -75,8 +34,29 @@ void Env::set_fds(void) { (*it)->set_fds(); } +/*|=======================| + * Refresh all master_sockets and their clients datas (disconnect, new + * connection, etc..) and parse requests recieved. + */ + void Env::refresh(void) { for (std::vector::iterator it = _sockets.begin(); it < _sockets.end(); it++) (*it)->refresh(this); } + +/*|=======================| + * Environment destructor: + * + * The destructor call all servers and sockets destructors. + */ +Env::~Env() { + for (std::vector::iterator it = _servers.begin(); + it < _servers.end(); it++) { + delete *it; + } + for (std::vector::iterator it = _sockets.begin(); + it < _sockets.end(); it++) { + delete *it; + } +} diff --git a/srcs/load/Server.cpp b/srcs/load/Server.cpp index e6c5d65..8019148 100644 --- a/srcs/load/Server.cpp +++ b/srcs/load/Server.cpp @@ -1,5 +1,13 @@ #include "webserv.hpp" + +/*|=======================| + * Server constructor: + * + * Input: A server block node given by JSONParser. + * Output: A Server class object and also a Route one as Server herite from Route. + * The Route constructor scrap the routing informations (index, root, autoindex ...) and the Server one the others ones (server_name, sub-routes) + */ Server::Server(JSONNode *server) : Route(NULL, "/", server) { JSONObject datas = server->obj(); if (datas["server_name"]) @@ -14,10 +22,17 @@ Server::Server(JSONNode *server) : Route(NULL, "/", server) { } } -Server::~Server(void) { cout << "Server destroyed!\n"; } +/* Get the server name (_server_name)*/ string Server::getName(void) { return _name; } + +/*|=======================| + * 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. + */ std::vector Server::get_sockets(JSONNode *server) { JSONObject datas = server->obj(); std::vector ret; @@ -50,7 +65,13 @@ std::vector Server::get_sockets(JSONNode *server) { return ret; } -Route *Server::get_route(string uri) { +/*|=======================| + * 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. + */ +Route *Server::choose_route(string uri) { // cout << uri << "\n"; std::vector req = split(uri, '/'); std::vector root; @@ -72,3 +93,17 @@ Route *Server::get_route(string uri) { } return this; } + + +/*|=======================| +* Server destructor: +* +* delete all routes owned by the server; +*/ + +Server::~Server(void) { + for (std::map::iterator it = _routes.begin(); + it != _routes.end(); it++) + delete (*it).second; + cout << "Server destroyed!\n"; +} diff --git a/srcs/load/Socket.cpp b/srcs/load/Socket.cpp index 37b0ba0..3d17ba7 100644 --- a/srcs/load/Socket.cpp +++ b/srcs/load/Socket.cpp @@ -2,7 +2,6 @@ Socket::Socket(listen_t listen) : _listen(listen) {} Socket::Socket(int fd, Socket *parent) : _fd(fd), _parent(parent) {} - Socket::~Socket(void) { close(_fd); cout << "Socket destroyed!\n"; @@ -47,8 +46,9 @@ int Socket::launch(void) { } void Socket::set_fds(void) { - int child_fd; FD_SET(_fd, &_readfds); + + int child_fd; for (std::vector::iterator it = _childs.begin(); it < _childs.end(); it++) { child_fd = (*it)->_fd; @@ -100,18 +100,68 @@ void Socket::refresh(Env *env) { } } +Server *Socket::choose_server(Env *env, string host) { + std::vector exact; + std::vector inrange; + std::vector ip_listen; + std::vector ip_required; + // string ip = inet_ntoa(sock->_address.sin_addr); + // int port = ntohs(sock->_address.sin_port); + + // cout << "Which server for " << ip << ":" << port << "?\n"; + cout << "Socket: " << _listen.ip << ":" << _listen.port << "\n"; + ip_required = split(_listen.ip, '.'); + for (std::vector::iterator sit = env->_servers.begin(); + sit < env->_servers.end(); sit++) { + + std::vector serv_listens = (*sit)->_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(*sit); + continue; + } + bool is_inrange = true; + ip_listen = split((*it).ip, '.'); + std::vector::iterator r = ip_required.begin(); + for (std::vector::iterator l = ip_listen.begin(); + l < ip_listen.end(); l++) { + if (*l != *r && *l != "0") + is_inrange = false; + } + if (is_inrange == true) + inrange.push_back(*sit); + } + } + if (exact.size() == 0) { + for (std::vector::iterator sit = inrange.begin(); + sit < inrange.end(); sit++) { + if (host == (*sit)->getName()) + return *sit; + } + return inrange.front(); + } else + return exact.front(); +} bool Socket::parseHeader() { std::vector lines = split(_header, '\n'); std::vector line; if (lines.size() > 0) { - for (std::vector::iterator it = lines.begin() + 1; it < lines.end(); it++) { + for (std::vector::iterator it = lines.begin() + 1; + it < lines.end(); it++) { line = split(*it, ' '); cout << line.at(0) << "scraped from header\n"; - _request[line.at(0)] = std::vector(line.begin() + 1, line.end()); + _request[line.at(0)] = + std::vector(line.begin() + 1, line.end()); } } std::vector method = split(lines.at(0), ' '); - if (method.at(0) == "POST" && _request.find("Content-Length:") == _request.end() && _request.find("Transfer-Encoding:") ==_request.end()) + if (method.at(0) == "POST" && + _request.find("Content-Length:") == _request.end() && + _request.find("Transfer-Encoding:") == _request.end()) return false; _request["Method:"] = method; return true; @@ -119,12 +169,17 @@ bool Socket::parseHeader() { bool Socket::getRequest(string paquet) { cout << "|===|paquet|===>" << paquet << "|===||\n"; - if (paquet.length() < 1) //HTTPS? + if (paquet.length() < 1) // HTTPS? return false; std::vector lines = split(paquet, '\n'); - long chunk_len = (_content.length() > 0 && _request["Transfer-Encoding:"].size() && _request["Transfer-Encoding:"].at(0) == "chunked") ? std::strtol(lines.at(0).substr(1).c_str(), 0, 16) : -1; + long chunk_len = + (_content.length() > 0 && _request["Transfer-Encoding:"].size() && + _request["Transfer-Encoding:"].at(0) == "chunked") + ? std::strtol(lines.at(0).substr(1).c_str(), 0, 16) + : -1; cout << "Chunk length: " << chunk_len << "\n"; - for (std::vector::iterator it = lines.begin(); it < lines.end(); it++) { + for (std::vector::iterator it = lines.begin(); it < lines.end(); + it++) { if (*it == "\r" && _content.length() == 0) this->parseHeader(); if (*it != "\r" && _content.length() == 0) @@ -136,7 +191,10 @@ bool Socket::getRequest(string paquet) { cout << "Content: \n-|" << _content << "|-\n"; if (_content.length() > 0) { _content.resize(_content.length() - 1); - if ( _request["Method:"].at(0) == "GET" || (chunk_len == 0 || std::strtoul(_request["Content-Length:"].at(0).c_str(), 0, 10) <= _content.length() ) ) { + if (_request["Method:"].at(0) == "GET" || + (chunk_len == 0 || + std::strtoul(_request["Content-Length:"].at(0).c_str(), 0, 10) <= + _content.length())) { cout << "Request received\n"; return true; } @@ -153,8 +211,8 @@ int Socket::answer(Env *env) { std::stringstream answer; answer << "HTTP/1.1"; - Server *server = env->choose_server(_parent, _request["Host:"].at(0)); - Route *route = server->get_route(_request["Method:"].at(1)); + Server *server = _parent->choose_server(env, _request["Host:"].at(0)); + Route *route = server->choose_route(_request["Method:"].at(1)); string method = _request["Method:"].at(0); std::vector allowed; if (method != "GET" && method != "POST" && method != "DELETE") @@ -162,11 +220,14 @@ int Socket::answer(Env *env) { "HTTP/1.1 405 Method Not Allowed\r\nContent-length: 0\r\n\r\n"); else if ((allowed = route->getHeadersLst()).size() > 0) { if (std::find(allowed.begin(), allowed.end(), method) == allowed.end()) - send_answer("HTTP/1.1 405 Method Not Allowed\r\nContent-length: 0\r\n\r\n"); + send_answer( + "HTTP/1.1 405 Method Not Allowed\r\nContent-length: 0\r\n\r\n"); } else if ((allowed = server->getHeadersLst()).size() > 0) { if (std::find(allowed.begin(), allowed.end(), method) == allowed.end()) - send_answer("HTTP/1.1 405 Method Not Allowed\r\nContent-length: 0\r\n\r\n"); + send_answer( + "HTTP/1.1 405 Method Not Allowed\r\nContent-length: 0\r\n\r\n"); } + string path = route->correctUri(_request["Method:"].at(1)); cout << "Path: " << path << "\n"; ret = route->getIndex(_request["Method:"].at(1), path); diff --git a/srcs/webserv.cpp b/srcs/webserv.cpp index 5d087c4..dacfbe3 100644 --- a/srcs/webserv.cpp +++ b/srcs/webserv.cpp @@ -7,26 +7,30 @@ int Socket::_amount = 0; int main(int ac, char **av) { - if (ac > 1) { - - cout << "Parsing configuration file...\n"; + if (ac < 2) { + cout << "Usage:\n"; + cout << "./webserv CONF.json\n"; + cout << "WARNING: You must use a correct json syntax and a correct " + "server configuration or don't expect it to work correctly."; + } else if (ac == 2) { + cout << "Parsing configuration file from JSON conf file.\n"; + cout << "You must be sure the syntax is correct\n"; JSONParser parser(av[1]); JSONNode *conf = parser.parse(); - cout << "Configuration parsed.\n"; - - cout << "Setting environment...\n"; + cout << "Initialization of server...\n"; Env env(conf); - cout << "Environement setup.\n"; while (1) { FD_ZERO(&Socket::_readfds); Socket::_max_fd = Socket::_min_fd; + cout << "==> Check sockets still alive to listen\n"; env.set_fds(); - cout << "|===|===|===| SELECT |===|===|===|\n"; + cout << "|===||===| Waiting some HTTP request... |===||===|\n"; int activity = select(Socket::_max_fd + Socket::_amount, &(Socket::_readfds), NULL, NULL, NULL); if ((activity < 0) && (errno != EINTR)) cout << "Select: " << strerror(errno) << "\n"; + cout << "==> Handle requests and answers:\n"; env.refresh(); } }