From 1f18956cb6b8ec171d20e4d4addc072d6254d3df Mon Sep 17 00:00:00 2001 From: adjoly Date: Wed, 26 Mar 2025 08:48:33 +0100 Subject: [PATCH] =?UTF-8?q?=E3=80=8C=E2=9C=A8=E3=80=8D=20feat:=20Finished?= =?UTF-8?q?=20parsing=20(should=20be=20working)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 4 +- exemples/test.toml | 15 --- includes/{config/Config.hpp => cgi.hpp} | 20 ++-- includes/config/Route.hpp | 33 ++---- includes/config/Server.hpp | 73 +++++++++++- includes/config/default.hpp | 46 +++++++- includes/log.hpp | 65 ++++++++--- lib/tomlpp | 2 +- src/config/Route.cpp | 127 ++++++++------------- src/config/Server.cpp | 145 ++++++++++++++++++++++++ src/main.cpp | 4 +- 11 files changed, 384 insertions(+), 150 deletions(-) rename includes/{config/Config.hpp => cgi.hpp} (70%) create mode 100644 src/config/Server.cpp diff --git a/Makefile b/Makefile index 9876588..f191630 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ # By: adjoly +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2024/10/25 16:09:27 by adjoly #+# #+# # -# Updated: 2025/03/19 14:01:12 by adjoly ### ########.fr # +# Updated: 2025/03/25 18:13:53 by adjoly ### ########.fr # # # # **************************************************************************** # @@ -24,7 +24,7 @@ SRCS = $(shell find . -name '*.cpp') OBJS = $(addprefix $(OBJSDIR), $(SRCS:.cpp=.o)) -FLAGS = -Wall -Werror -Wextra -std=c++98 -MMD -MP +FLAGS = -Wall -Werror -Wextra -std=c++98 -MMD -MP -g RED = \033[0;31m GREEN = \033[0;32m diff --git a/exemples/test.toml b/exemples/test.toml index a61f6f4..777ed4b 100644 --- a/exemples/test.toml +++ b/exemples/test.toml @@ -3,17 +3,6 @@ server_names = { "localhost", "2B5.local" } host = "localhost" port = 8080 -root = "/var/www/html" -methods = { "GET", "POST", "DELETE" } - -dirlist = false -uploads = false -cookies = false - -cgi.py = "/usr/bin/python3" - -client_max_body_size = "10M" - [server.error_pages] 404 = "not_found.html" 401 = "unauthorized.html" @@ -25,12 +14,8 @@ root = "/var/www/html" dirlist = true client_max_body_size = "10M" -[server.location./.error_pages] -500 = "uwu.html" - [server.location./api] methods = { "GET", "POST" } -uploads = true root = "/var/www/api" upload_path = "/etc/webserv/up" cgi.go = "/bin/go" diff --git a/includes/config/Config.hpp b/includes/cgi.hpp similarity index 70% rename from includes/config/Config.hpp rename to includes/cgi.hpp index cc340c1..90f9cce 100644 --- a/includes/config/Config.hpp +++ b/includes/cgi.hpp @@ -1,19 +1,23 @@ /* ************************************************************************** */ /* */ /* ::: :::::::: */ -/* Config.hpp :+: :+: :+: */ +/* cgi.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: adjoly +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ -/* Created: 2025/03/23 11:36:01 by adjoly #+# #+# */ -/* Updated: 2025/03/23 12:09:10 by adjoly ### ########.fr */ +/* Created: 2025/03/24 14:17:34 by adjoly #+# #+# */ +/* Updated: 2025/03/24 14:20:00 by adjoly ### ########.fr */ /* */ /* ************************************************************************** */ #pragma once -#include - -namespace webserv { -namespace config {}; -}; // namespace webserv +#include +class cgi { + public: + cgi(); + ~cgi(void); + protected: + private: + std::string _request; +}; diff --git a/includes/config/Route.hpp b/includes/config/Route.hpp index 43159d3..a09e6ed 100644 --- a/includes/config/Route.hpp +++ b/includes/config/Route.hpp @@ -6,7 +6,7 @@ /* By: adjoly +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/03/19 14:59:41 by adjoly #+# #+# */ -/* Updated: 2025/03/24 10:48:37 by adjoly ### ########.fr */ +/* Updated: 2025/03/26 08:31:41 by adjoly ### ########.fr */ /* */ /* ************************************************************************** */ @@ -33,31 +33,20 @@ class Route { private: bool _dirlist; bool _cookies; - bool _uploads; bool _redirect; int32_t _max_body; std::string _root; - std::string _upRoot; + std::string _up_root; + std::string _index; std::map *_cgi; Logger *_log; - bool _methods[3]; ///> A methods boolean array which correspond to - 0: GET, 1: POST, 2: DELETE - std::map *_err_pages; ///> An error pages map to map error specified in the config file - toml::ANode *_table; - - /** - * @brief Can be used to access a value in the _table(ANode *) of a specific type - * - * @param The name of the value to get - * @param The type of the value to get - * - * @return The value got or not_nullptr - */ - void *accessValue(std::string, toml::nodeType); - + bool _methods[3]; ///> A methods boolean array which correspond to - 0: GET, + ///1: POST, 2: DELETE + toml::ANode *_table; /** * @brief Can be used to parse a table of cgi @@ -66,7 +55,8 @@ class Route { * * @return A pointer to a map of cgi */ - std::map *_parseCGI(std::map *); + std::map * + _parseCGI(toml::ANode *); /** * @brief Can be used to parse a table of error pages @@ -75,19 +65,20 @@ class Route { * * @return A pointer to a map of error pages */ - std::map *_parseErrPages(std::map *); + std::map * + _parseErrPages(std::map *); /** * @brief Can be used to parse a array of methods * * @param The table to get the methods from */ - void _parseMethods(std::vector *); + void _parseMethods(std::vector *); /** * @brief Can be used to sed err pages to the default error pages */ - void _defaultErrPages(void); + void _defaultErrPages(void); /** * @brief Can be used to parse a string of a number with a size (ex. 10M) diff --git a/includes/config/Server.hpp b/includes/config/Server.hpp index 955354f..34c3964 100644 --- a/includes/config/Server.hpp +++ b/includes/config/Server.hpp @@ -6,25 +6,86 @@ /* By: adjoly +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/03/19 14:11:28 by adjoly #+# #+# */ -/* Updated: 2025/03/19 23:09:56 by adjoly ### ########.fr */ +/* Updated: 2025/03/25 17:56:34 by adjoly ### ########.fr */ /* */ /* ************************************************************************** */ #pragma once -#include "Route.hpp" +#include "config/default.hpp" +#include "cppeleven.hpp" +#include "node/ANode.hpp" namespace webserv { namespace config { class Server { public: + Server(std::string); + ~Server(); + + /** + * @brief Can be used to get the path of a specific error page or return + * an empty string + * + * @param The http error code for the page + */ + std::string getErrorPage(int page) { + if (_err_pages->find(page) != _err_pages->end()) + return (*_err_pages)[page]; + else + return ""; + } + + /** + * @brief Can be used to get a pointer to a specific route (or not_nullptr + * if not found) + */ + Route *getRoute(std::string route) { + if (_routes->find(route) != _routes->end()) + return (*_routes)[route]; + else + return not_nullptr; + } + + /** + * @brief Can be used to get the Logger pointer + */ + Logger *getLogger(void) { return _log; } + + // @brief Can be used to get a server name + std::vector *getServerNames(void) { return _server_names; } + // @brief Can be used to get the host specified in the config file + std::string getHost(void) { return _host; } + // @brief Can be used to get the port specified in the config file + int getPort(void) { return _port; } + protected: private: - Route *_default; - std::vector *_routes; - std::string host; - std::vector server_names; + std::map + *_routes; ///> A map of all the route present in the config file + std::map *_err_pages; ///> An error pages map to map error + /// specified in the config file + + std::vector + *_server_names; ///> A vector with all the server names + + std::string _host; ///> The host on which the server will be exposed + unsigned short _port; ///> The port on which the server will be exposed + + toml::ANode *_table; ///> The table used for the parsing (is deleted at the + /// end of the constructor) + Logger *_log; ///> A pointer to the logger class + + std::map * + _parseErrPages(std::map *table); + + /** + * @brief Can be used to get the [server] table in _table + * + * @return A pointer to the [server] table as an ANode + */ + toml::ANode *_getServerTable(void); }; } // namespace config diff --git a/includes/config/default.hpp b/includes/config/default.hpp index 6337e52..5ff94dc 100644 --- a/includes/config/default.hpp +++ b/includes/config/default.hpp @@ -6,11 +6,53 @@ /* By: adjoly +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/03/19 14:15:51 by adjoly #+# #+# */ -/* Updated: 2025/03/19 14:16:39 by adjoly ### ########.fr */ +/* Updated: 2025/03/26 08:39:08 by adjoly ### ########.fr */ /* */ /* ************************************************************************** */ #pragma once +#include "Route.hpp" +#include "Server.hpp" +#include "cppeleven.hpp" +#include "node/Table.hpp" +#include "node/default.hpp" #include -#include "Config.hpp" + +namespace webserv { +namespace config { + +/** + * @brief Can be used to access a value in the _table(ANode *) of a specific + *type + * + * @param The name of the value to get + * @param The type of the value to get + * @param The table to search in + * @param A Logger class + * + * @return The value got or not_nullptr + */ +static inline void *accessValue(const std::string &name, toml::nodeType type, + toml::ANode *table, Logger *log) { + void *val; + bool found = false; + + if (table == not_nullptr) + return not_nullptr; + val = dynamic_cast(table)->access(name, type, found); + if (found == true && val != not_nullptr) { + return val; + } else { + if (found == false) { + return not_nullptr; + } else { + log->warn("found - " + name + " but is not " + + toml::nodeTypeToStr(type) + ", skipping..."); + return not_nullptr; + } + } +} + +}; // namespace config +}; // namespace webserv diff --git a/includes/log.hpp b/includes/log.hpp index 755147d..df5e305 100644 --- a/includes/log.hpp +++ b/includes/log.hpp @@ -6,7 +6,7 @@ /* By: adjoly +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/03/20 09:28:27 by adjoly #+# #+# */ -/* Updated: 2025/03/20 14:55:09 by adjoly ### ########.fr */ +/* Updated: 2025/03/25 17:50:45 by adjoly ### ########.fr */ /* */ /* ************************************************************************** */ @@ -21,37 +21,69 @@ namespace webserv { class Logger { public: - Logger(std::string fileName) { + Logger(const std::string &fileName) : _fileName(fileName) { if (fileName.empty()) _ttyOnly = true; else { _file.open(fileName.c_str(), std::ios::app); _ttyOnly = false; } - if (!_file.is_open()) { - throw std::runtime_error("could not open fileeee"); // TODO change that shit but i dont know what to put other than a htrow + if (!_file.is_open() && !_ttyOnly) { + throw std::runtime_error( + "could not open fileeee"); // TODO change that shit but i dont + // know what to put other than a + // htrow } } - ~Logger(void) { _file.close(); } + Logger(const Logger &other) : _ttyOnly(other._ttyOnly) { + if (!other._ttyOnly) { + _file.open(other._fileName.c_str(), std::ios::app); + if (!_file.is_open()) { + throw std::runtime_error("Could not open file: " + + other._fileName); + } + } + } - void info(std::string msg) { - std::stringstream ss = printPogitMsg("✏️", "webserv", "info", msg); + // Copy assignment operator + Logger &operator=(const Logger &other) { + if (this != &other) { + if (_file.is_open()) { + _file.close(); + } + _ttyOnly = other._ttyOnly; + if (!other._ttyOnly) { + _file.open(other._fileName.c_str(), std::ios::app); + if (!_file.is_open()) { + throw std::runtime_error("Could not open file: " + + other._fileName); + } + } + } + return *this; + } + ~Logger(void) { + if (_file.is_open()) + _file.close(); + } + + void info(const std::string &msg) { + std::string ss = printPogitMsg("✏️", "webserv", "info", msg); std::cerr << ss << std::endl; if (!_ttyOnly) { _file << ss << std::endl; } } - void warn(std::string msg) { - std::stringstream ss = printPogitMsg("🔨", "webserv", "warning", msg); + void warn(const std::string &msg) { + std::string ss = printPogitMsg("🔨", "webserv", "warning", msg); std::cerr << ss << std::endl; if (!_ttyOnly) { _file << ss << std::endl; } - } - void error(std::string msg) { - std::stringstream ss = printPogitMsg("🚧", "webserv", "error", msg); + void error(const std::string &msg) { + std::string ss = printPogitMsg("🚧", "webserv", "error", msg); std::cerr << ss << std::endl; if (!_ttyOnly) { _file << ss << std::endl; @@ -60,7 +92,10 @@ class Logger { protected: private: - std::stringstream printPogitMsg(std::string emoji, std::string type, std::string what, std::string msg) { + std::string printPogitMsg(const std::string &emoji, + const std::string &type, + const std::string &what, + const std::string &msg) { std::stringstream os; #ifdef tty if (what.empty()) @@ -73,8 +108,10 @@ class Logger { else os << "「" << emoji << "」" << type << "(" << what << "):" << msg; #endif - return os; + return os.str(); } + + std::string _fileName; bool _ttyOnly; std::ofstream _file; }; diff --git a/lib/tomlpp b/lib/tomlpp index 3131ed3..d9e5070 160000 --- a/lib/tomlpp +++ b/lib/tomlpp @@ -1 +1 @@ -Subproject commit 3131ed3ac4f80a17e0175bff7a0084420cbb7410 +Subproject commit d9e507093a3b37d35d5115d766e6d81044cacb00 diff --git a/src/config/Route.cpp b/src/config/Route.cpp index 0656360..db52d41 100644 --- a/src/config/Route.cpp +++ b/src/config/Route.cpp @@ -1,61 +1,42 @@ -/* ************************************************************************** */ -/* */ /* ::: :::::::: */ /* Route.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: adjoly +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/03/21 20:37:02 by adjoly #+# #+# */ -/* Updated: 2025/03/24 10:51:29 by adjoly ### ########.fr */ +/* Updated: 2025/03/26 08:19:25 by adjoly ### ########.fr */ /* */ /* ************************************************************************** */ #include "cppeleven.hpp" #include "log.hpp" -#include "node/ANode.hpp" #include "node/default.hpp" -#include +#include #include #include using namespace webserv::config; -std::map * -Route::_parseCGI(std::map *table) { +std::map *Route::_parseCGI(toml::ANode *table) { std::map *cgi = new std::map; void *val; - for (std::map::iterator it = table->begin(); - it != table->end(); it++) { - val = accessValue(it->first, toml::STRING); - if (val != not_nullptr) - cgi->insert(it->first, *static_cast(val)); + for (std::map::iterator it = + table->getTable()->begin(); + it != table->getTable()->end(); it++) { + val = accessValue(it->first, toml::STRING, table, _log); + if (val != not_nullptr) { + if (cgi->find(it->first) != cgi->end()) + continue; + else + (*cgi)[it->first] = *static_cast(val); + } } return cgi; } -std::map * -Route::_parseErrPages(std::map *table) { - std::map *errPages = new std::map; - void *val; - int nb; - - for (std::map::iterator it = table->begin(); - it != table->end(); it++) { - val = accessValue(it->first, toml::STRING); - if (val != not_nullptr) { - nb = std::atoi(it->first.c_str()); - if (nb != 0 && (nb >= 400 && nb <= 599)) - (*errPages)[nb] = *static_cast(val); - else - _log->warn("error page - " + it->first + " is not valid :("); - } - } - return errPages; -} - void Route::_parseMethods(std::vector *table) { std::string val; @@ -76,40 +57,46 @@ void Route::_parseMethods(std::vector *table) { } } -void Route::_defaultErrPages(void) { - _err_pages = new std::map; - - (*_err_pages)[400] = _root + "/400.html"; - (*_err_pages)[403] = _root + "/403.html"; - (*_err_pages)[404] = _root + "/404.html"; -} - Route::Route(toml::ANode *table, Logger *logger) : _max_body(10485760), _log(logger) { void *val; + bool found; - _table = table; _log = logger; - val = accessValue("redirect", toml::STRING); + _table = table; + if (_table->type() != toml::TABLE) { + _log->warn("location need to be a table and not a :" + + toml::nodeTypeToStr(_table->type())); + return; + } + val = accessValue("redirect", toml::STRING, _table, _log); if (val != not_nullptr) { _root = *static_cast(val); _redirect = true; return; - } - val = accessValue("dirlist", toml::BOOL); + } else + _redirect = false; + val = accessValue("dirlist", toml::BOOL, _table, _log); if (val != not_nullptr) _dirlist = *static_cast(val); else _dirlist = true; - val = accessValue("cookies", toml::BOOL); + val = accessValue("cookies", toml::BOOL, _table, _log); if (val != not_nullptr) _cookies = *static_cast(val); - else + else _cookies = false; - val = accessValue("uploads", toml::BOOL); + val = accessValue("upload_path", toml::STRING, _table, _log); if (val != not_nullptr) - _uploads = *static_cast(val); - val = accessValue("root", toml::STRING); + _up_root = *static_cast(val); + else + _up_root = ""; + val = accessValue("index", toml::STRING, _table, _log); + if (val != not_nullptr) + _index = *static_cast(val); + else + _index = "index.html"; + val = accessValue("root", toml::STRING, _table, _log); if (val != not_nullptr) _root = *static_cast(val); else @@ -118,25 +105,17 @@ Route::Route(toml::ANode *table, Logger *logger) #else _root = "./html"; #endif - val = accessValue("upload_path", toml::STRING); - if (val != not_nullptr) - _upRoot = *static_cast(val); - val = accessValue("client_max_body_size", toml::STRING); + val = + accessValue("client_max_body_size", toml::STRING, _table, _log); if (val != not_nullptr) _max_body = _parseSize(*static_cast(val)); - val = accessValue("cgi", toml::TABLE); - if (val != not_nullptr) - _cgi = - _parseCGI(static_cast *>(val)); + std::map::iterator it = + _table->accessIt("cgi", toml::TABLE, found); + if (found == true && it != _table->getTable()->end()) + _cgi = _parseCGI(it->second); else _cgi = not_nullptr; - val = accessValue("error_pages", toml::TABLE); - if (val != not_nullptr) - _err_pages = _parseErrPages( - static_cast *>(val)); - else - _err_pages = _defaultErrPages(); - val = accessValue("methods", toml::ARRAY); + val = accessValue("methods", toml::ARRAY, _table, _log); if (val != not_nullptr) _parseMethods(static_cast *>(val)); else { @@ -146,20 +125,8 @@ Route::Route(toml::ANode *table, Logger *logger) } } -void *Route::accessValue(std::string name, toml::nodeType type) { - void *val; - bool found; - - val = _table->access(name, type, found); - if (val != not_nullptr) { - return val; - } else { - if (found == false) { - return not_nullptr; - } else { - _log->warn("found - " + name + " but is not " + - toml::nodeTypeToStr(type) + ", skipping..."); - return not_nullptr; - } - } +Route::~Route(void) { + if (_redirect == false) + if (_cgi != not_nullptr) + delete _cgi; } diff --git a/src/config/Server.cpp b/src/config/Server.cpp new file mode 100644 index 0000000..06b4e77 --- /dev/null +++ b/src/config/Server.cpp @@ -0,0 +1,145 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Server.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: adjoly +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/03/24 15:10:07 by adjoly #+# #+# */ +/* Updated: 2025/03/26 08:47:50 by adjoly ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "config/Server.hpp" +#include "config/Route.hpp" +#include "cppeleven.hpp" +#include "log.hpp" +#include "node/ANode.hpp" +#include "node/Table.hpp" +#include "node/default.hpp" +#include "tomlpp.hpp" +#include +#include +#include +#include + +using namespace webserv::config; + +toml::ANode *Server::_getServerTable(void) { + toml::ANode *serverT; + + std::map::iterator table = + _table->getTable()->find("server"); + if (table == _table->getTable()->end()) + throw std::runtime_error( + "could not find any [server] table in config file :("); + else + serverT = table->second; + return serverT; +} + +Server::Server(std::string file_name) { + toml::Toml *tomlFile = new toml::Toml(file_name); + + try { + tomlFile->parse(); + } catch (std::runtime_error &e) { + throw e; + } + bool found; + + std::map *map; + _table = tomlFile->getParsedFile(); + + void *val = _table->access("log_file", toml::STRING, found); + std::string log_file = ""; + if (found == true && val != not_nullptr) { + std::string log_file = *static_cast(val); + } + _log = new Logger(log_file); + _table = _getServerTable(); + + // host and port parsing + void *host = accessValue("host", toml::STRING, _table, _log); + if (host != not_nullptr) { + _host = *static_cast(host); + } else { + throw std::runtime_error( + "no host specified - please specify one in server.host"); + } + void *port = accessValue("port", toml::INT, _table, _log); + if (host != not_nullptr) { + _port = *static_cast(port); + } else { + throw std::runtime_error( + "no port specified - please specify one in server.port"); + } + + // server_names parsing + std::map::iterator it = + _table->accessIt("server_names", toml::ARRAY, found); + if (found == true && it != _table->getTable()->end()) { + std::vector::iterator vecIt = + it->second->getArray()->begin(); + _server_names = new std::vector; + for (; vecIt != it->second->getArray()->end(); vecIt++) { + std::string str = *static_cast((*vecIt)->getValue()); + _server_names->push_back(str); + } + } else + _log->warn( + "no server_names all request will be accepted from any hostname"); + + // error_pages parsing + map = static_cast *>( + accessValue("error_pages", toml::TABLE, _table, _log)); + if (map != not_nullptr) { + _err_pages = _parseErrPages(map); + } else + _err_pages = not_nullptr; + + // location parsing + it = _table->accessIt("location", toml::TABLE, found); + if (found == true && it != _table->getTable()->end()) { + _routes = new std::map; + std::map *location_table = it->second->getTable(); + for (it = location_table->begin(); it != location_table->end(); it++) { + if (_routes->find(it->first) != _routes->end()) + continue; + (*_routes)[it->first] = new Route(it->second, _log); + } + } + delete tomlFile->getParsedFile(); + delete tomlFile; +} + +Server::~Server(void) { + std::map::iterator it = _routes->begin(); + for (; it != _routes->end(); it++) { + delete it->second; + } + delete _routes; + delete _err_pages; + delete _server_names; + delete _log; // to see if nessecary +} + +std::map * +Server::_parseErrPages(std::map *table) { + std::map *errPages = new std::map; + void *val; + int nb; + + for (std::map::iterator it = table->begin(); + it != table->end(); it++) { + val = accessValue(it->first, toml::STRING, _table, _log); + if (val != not_nullptr) { + nb = std::atoi(it->first.c_str()); + if (nb >= 400 && nb <= 599) + (*errPages)[nb] = *static_cast(val); + else + _log->warn("error page - " + it->first + " is not valid :("); + } + } + return errPages; +} diff --git a/src/main.cpp b/src/main.cpp index 9ced085..7af2e1d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,12 +6,14 @@ /* By: mmoussou int main(int, char **) { + webserv::config::Server serverConf("exemples/test.toml"); return 0; }