From b9ccf0908983bec0f3343e41cbfb02d6a36b43b2 Mon Sep 17 00:00:00 2001 From: Me Date: Mon, 25 Jul 2022 03:10:42 +0200 Subject: [PATCH 1/9] ok we started moving stuff over but for now it's not all working yet --- srcs/ConfigParser.cpp | 352 ++++++++++++++++++++++++++++++++++++++++ srcs/ConfigParser.hpp | 59 +++++++ srcs/LocationConfig.hpp | 51 ++++++ srcs/ServerConfig.hpp | 66 ++++++++ srcs/Webserv.hpp | 3 + 5 files changed, 531 insertions(+) create mode 100644 srcs/ConfigParser.cpp create mode 100644 srcs/ConfigParser.hpp create mode 100644 srcs/LocationConfig.hpp create mode 100644 srcs/ServerConfig.hpp diff --git a/srcs/ConfigParser.cpp b/srcs/ConfigParser.cpp new file mode 100644 index 0000000..1d748b6 --- /dev/null +++ b/srcs/ConfigParser.cpp @@ -0,0 +1,352 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ConfigParser.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: me +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2022/07/13 22:11:17 by me #+# #+# */ +/* Updated: 2022/07/25 02:56:26 by me ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "ConfigParser.hpp" + + +/***** Stuf to rework + +I don't love the use of EMPTY and FAILURE and those + +I would rather throw exceptions everywhere... + + + + +*/ + + + + +// Default +ConfigParser::ConfigParser() +{ + std::cout << "Default Constructor\n"; + // don't use yet, you have no idea what the defaults are +} + +//ConfigParser::ConfigParser(std::string &path) +//ConfigParser::ConfigParser(char & path) +ConfigParser::ConfigParser(const char* path) +{ + std::cout << "Param Constructor\n"; + + std::ifstream file; + std::string buf; +// std::string tmp; // maybe there's a reason we redeclare vars... + size_t comment; // just a number so fine to reset + + _content.clear(); + file.open(path); + if (file.is_open()) + { + while (!file.eof()) + { + getline(file, buf); + // remove # comments here. + if ((comment = buf.find_first_of("#")) == std::string::npos) + { + _content.append(buf + '\n'); + } +// else if (comment > 0 && (buf.find_first_not_of(" \t")) != std::string::npos) + // i think this works cuz it will find # no matter what, so it will find + // something else first if there is non comment stuff. + else if (comment > 0 && (buf.find_first_not_of(" \t")) < comment) + { + // is there a comment at the end of the line + std::string tmp = buf.substr(0, comment - 1); + _content.append(tmp + '\n'); + } + } + file.close(); + } + else + throw std::invalid_argument("open config"); +} + +ConfigParser::~ConfigParser() +{ + // do i need to destroy anything, won't it handle itself? +} + +/* +ConfigParser & ConfigParser::operator=(const ConfigParser& rhs) +{ + if (this == rhs) // * & ? + return (*this); // * ? + + // make some stuff equal + return (*this); +} +*/ + + +std::vector * ConfigParser::parse() +{ + // is this the best way to do this? new? + std::vector *ret = new std::vector(); + + size_t prev = 0; + size_t curr = _content.find_first_not_of(" \t\n", prev); + + + if (curr == std::string::npos) + throw std::invalid_argument("empty config file"); + while (cur != std::string::npos) + { + // ok i don't love her way of scoping out the "server" strings... + prev = _content.find_first_not_of(" \t\n", curr); + curr = _content.find_first_of(" \t\n", prev); + std::string key = _conent.substr(prev, curr - prev); + if (key != "server") + throw std::invalid_argument("bad config file arguments"); +// Server server = parse_server(&curr); +// ret->push_back(server); + // why not this? + ret->push_back(parse_server(&curr); + } + return (ret); +} + +// could we return a ref instead? + // i think no +Server ConfigParser::parse_server(size_t *start) +{ + Server ret; + size_t key_start; + size_t value_end; + size_t prev = _content.find_first_not_of(" \t\n", *start); + + if (prev == std::string::npos || _content[prev] != '{') + throw std::invalid_argument("bad config file syntax"); + + size_t curr = _content.find_first_of(" \t\n", ++prev); + while (curr != std::string::npos) + { + _check_proper_line_end(&prev, &curr); // nope, not an option i think... +/* if ((prev = _content.find_first_not_of(" \t\n", curr)) == std::string::npos) + throw std::invalid_argument("bad config file arguments"); + if ((curr = _content.find_first_of(" \t\n", prev)) == std::string::npos) + throw std::invalid_argument("bad config file arguments"); +*/ key_start = prev; + + std::string key = _content.substr(prev, curr - prev); + switch (key) + { + case "}": + *start = _content.find_first_not_of(" \t\n" curr + 1); + break ; + case "location": + // this does assume we have locations in Server... we could change + // the name but it's so clear... + ret.location.push_back(parse_location(&curr)); + default: + _check_proper_line_end(&prev, &curr); + /* if ((prev = _content.find_first_not_of(" \t\n", curr)) == std::string::npos) + throw std::invalid_argument("bad config file arguments"); + if ((curr = _content.find_first_of(" \t\n", prev)) == std::string::npos) + throw std::invalid_argument("bad config file arguments"); + */ + // why bother with the if.. why not throw exception in check_line... + if ((value_end = check_line_syntax(_content.substr(key_start, curr - key_start))) == FAILED) + throw std::invalid_argument("bad config file arguments"); + if ((int)value_end == EMPTY) + continue ; + std::string value = _content.substr(prev, value_end - prev + key_start + 1) + // I might need to catch here, or i could do nothing and trow all the way to the top! + if (_set_server_value(&ret, key, value) == FAILED) + throw std::invalid_argument("bad config file arguments"); + } + } + return (ret); +} + + + +Location ConfigParser::parse_location(size_t *start) +{ + Location ret; + size_t key_start; + size_t value_end; + size_t prev = _content.find_first_not_of(" \t\n", *start); + + if (prev == std::string::npos || _content[prev] != '{') + throw std::invalid_argument("bad config file syntax"); + + size_t curr = _content.find_first_of(" \t\n", ++prev); + while (curr != std::string::npos) + { + _check_proper_line_end(&prev, &curr); + key_start = prev; + + std::string key = _content.substr(prev, curr - prev); + switch (key) + { + case "}": + *start = curr; + break ; + default: + _check_proper_line_end(&prev, &curr); + // why bother with the if.. why not throw exception in check_line... + if ((value_end = check_line_syntax(_content.substr(key_start, curr - key_start))) == FAILED) + throw std::invalid_argument("bad config file arguments"); + if ((int)value_end == EMPTY) + continue ; + std::string value = _content.substr(prev, value_end - prev + key_start + 1) + if (_set_location_value(&ret, key, value) == FAILED) + throw std::invalid_argument("bad config file arguments"); + } + } + return (ret); +} + +// not convinced i want to return an int... +// but could be helpful to get more feed back +// maybe use a throw... but catch in parse_server... +int ConfigParser::_set_server_value(Server *server, const std::string key, const std::string value) +{ + switch (key) + { + case "server_name": + server->server_name = value; + case "listen": + if (value.find_first_of(":") == std::string::npos) + { + // why not store as vector [4] ? + server->host = "0.0.0.0"; + server->value = value; + } + else + { + // maybe do this differently? + std::vector tmp = split(value, ':'); + // i might take issue with this, will see + if (server->host != "" && server->host != tmp[0]) + throw std::invalid_argument("bad config file arguments"); + server->host = tmp[0]; + server->port = tmp[1]; + } + case "root": + server->root = value; + case "index": + std::vector tmp = split(value, ' '); + for (unsigned long i = 0; i != tmp.size(); i++) + server->index.push_back(tmp[i]); + case "allow_methods": + std::vector tmp = split(value, ' '); + // might do something different here + // like change how methods are stored? + for (unsigned long i = 0; i != tmp.size(); i++) + server->allow_methods.push_back(str_to_method_type(tmp[i])); + case "autoindex": + server->autoindex = (value == "on" ? true : false); + case "client_body_limit": + server->client_body_limit = atoi(value.c_str()); + case "recv_timeout": + // what is tv_sec and do i need it? + server->recv_timeout.tv_sec = atoi(value.c_str()); + case "send_timeout": + server->send_timeout.tv_sec = atoi(value.c_str()); + case "return": + std::vector tmp = split(value, ' '); + server->redirect_status = atoi(tmp[0].c_str()); + server->redirect_uri = tmp[1]; + case "error_page": + std::vector tmp = split(value, ' '); + std::string path = tmp[tmp.size() - 1]; + for (unsigned long i = 0; i != tmp.size() - 1; i++) + { + int status_code = atoi(tmp[i].c_str()); + // yea IDK i might not want to store this like that... + if (server->error_pages.find(status_code) != server->error_pages.end()) + continue ; + server->error_pages[status_code] = path; + } + default : + throw std::invalid_argument("bad config file arguments"); + } + return (1); // for now but prolly will change... +} + +// again not sure i want an int ret +int ConfigParser::_set_location_value(Location *location, const std::string key, const std::string value) +{ + switch (key) + { + case "root": + location->root = value; + case "index": + std::vector tmp = split(value, ' '); + for (unsigned long i = 0; i != tmp.size(); i++) + location->index.push_back(tmp[i]); + case "allow_methods": + std::vector tmp = split(value, ' '); + for (unsigned long i = 0; i != tmp.size(); i++) + location->allow_methods.push_back(str_to_methodtype(tmp[i])); + case "cgi_info": + // ok wtf is all this even doing, figure that out + unsigned long i = value.find_first_of(" "); + if (i == std::string::npos) + throw std::invalid_argument("bad config file arguments"); + // ok why an int now, we gotta be more consistent! + int j = value.find_first_not_of(" ", i); + location->cgi_info[value.substr(0, i)] = value.substr(j, value.length()); + case "client_body_limit": + location->client_body_limit = atoi(value.c_str()); + default : + throw std::invalid_argument("bad config file arguments"); + } + return (1); // again prolly want to change this... +} + + +// shit, this doesn't work... + // wait it might... +void ConfigParser::_check_proper_line_end(size_t *prev, size_t *curr) +{ + if ((*prev = _content.find_first_not_of(" \t\n", *curr)) == std::string::npos) + throw std::invalid_argument("bad config file arguments"); + if ((*curr = _content.find_first_of(" \t\n", *prev)) == std::string::npos) + throw std::invalid_argument("bad config file arguments"); +} + +// i'm not sure i like this... + // and it needs to be _check_... +// rework this whole thing... +int ConfigParser::check_line_syntax(std::string line) +{ + + // line must be end with semicolon + size_t semicol; + size_t find; + + semicol = line.find_first_of(";"); + if (semicol == std::string::npos) + return FAILED; + find = line.find_first_not_of(" \t\n", semicol + 1, line.length() - semicol - 1); + if (find != std::string::npos) + return FAILED; + find = line.find_last_not_of(" \t", semicol - 1); + return find; +} + + + +// I might need to make my own Exceptions to throw... + + + + + + + + diff --git a/srcs/ConfigParser.hpp b/srcs/ConfigParser.hpp new file mode 100644 index 0000000..b9ce28b --- /dev/null +++ b/srcs/ConfigParser.hpp @@ -0,0 +1,59 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ConfigParser.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: me +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2022/07/11 23:01:41 by me #+# #+# */ +/* Updated: 2022/07/23 15:53:19 by me ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef CONFIGPARSER_HPP +# define CONFIGPARSER_HPP + +# include "Webserv.hpp" // easier to just do this? + + +class ConfigParser { + +public: + + // canonical + + ConfigParser(const char* path); // a string? + ~ConfigParser(); + + // ideally i wouldn't have one cuz it makes no sense, when would i use it? +// ConfigParser & operator=(const ConfigParser& rhs); + +// void parse(); // return void cuz throw exceptions. + std::vector * parse(); // const? + + // other parses? + + +private: + std::string _content; + + // explicit? + // what exaclty does explicit do again? + ConfigParser(); // might need a path as arg? + // should this be in private since it always needs a path? + + + void _check_proper_line_end(size_t prev, size_t curr); // const? + + +}; + + + + + +#endif + + + + diff --git a/srcs/LocationConfig.hpp b/srcs/LocationConfig.hpp new file mode 100644 index 0000000..db45ddb --- /dev/null +++ b/srcs/LocationConfig.hpp @@ -0,0 +1,51 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* LocationConfig.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: me +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2022/07/23 16:08:00 by me #+# #+# */ +/* Updated: 2022/07/23 16:14:01 by me ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef LOCATIONCONFIG_HPP +# define LOCATIONCONFIG_HPP + +// includes +# include "Webserv.hpp" + +// again, struct instead? +class LocationConfig +{ +public: + // canonic stuff? + + + int client_body_limit; + std::string path; + std::string root; + std::vector index; + std::vector allow_methods; + std::map cgi_info; + + + + + + +}; + + + + +#endif + + + + + + + + diff --git a/srcs/ServerConfig.hpp b/srcs/ServerConfig.hpp new file mode 100644 index 0000000..6935720 --- /dev/null +++ b/srcs/ServerConfig.hpp @@ -0,0 +1,66 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ServerConfig.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: me +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2022/07/23 15:55:16 by me #+# #+# */ +/* Updated: 2022/07/23 16:19:43 by me ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef SERVERCONFIG_HPP +# define SERVERCONFIG_HPP + +# include "LocationConfig.hpp" +//other includes + +// a class that's all public? just so we have options? +class ServerConfig +{ +public: + + // i mean i guess i need some canonic stuff? + // although maybe if i make it a struct i can barebones it? + + + std::string server_name; + std::string root; + + std::vector index; + std::map error_pages; + + // i'm tempted to do something diff for storing method types... + std::vector allow_methods; + + std::vector locations; + + // might do something diff + struct timeval send_timeout; + struct timeval recv_timeout; + + int client_body_limit; + bool autoindex; + + // not sure what these look like in config file + int redirect_status; + std::string redirect_uri; + + // is this the best way? + std::string host; + std::string port; + +}; + + + + +#endif + + + + + + + diff --git a/srcs/Webserv.hpp b/srcs/Webserv.hpp index c9acb5f..5076f8e 100644 --- a/srcs/Webserv.hpp +++ b/srcs/Webserv.hpp @@ -11,6 +11,8 @@ # include // close # include // cout, cin # include // memset +# include +# include # include // socket, accept, listen, send, recv, bind, connect, setsockopt, getsockname # include // sockaddr_in @@ -39,6 +41,7 @@ class Webserv private: int _socket_fd; // TODO: replace with vector of "Server" struct + std::vector _servers; int _epfd; // WIP global buffer. Need one variable set per "Client" From 35ac55b5e8298580191c55d628258f7bed345b39 Mon Sep 17 00:00:00 2001 From: Me Date: Mon, 25 Jul 2022 21:00:04 +0200 Subject: [PATCH 2/9] still working on integrating the config file stuff --- Makefile | 12 +++++- default.config | 16 ++++++++ srcs/ConfigParser.cpp | 87 +++++++++++++++++++++++++++-------------- srcs/ConfigParser.hpp | 3 +- srcs/LocationConfig.hpp | 2 +- srcs/Webserv.cpp | 15 +++++++ srcs/Webserv.hpp | 13 +++++- srcs/main.cpp | 14 ++++++- www/index.html | 16 ++++++++ 9 files changed, 142 insertions(+), 36 deletions(-) create mode 100644 default.config create mode 100644 www/index.html diff --git a/Makefile b/Makefile index 1666787..e56a403 100644 --- a/Makefile +++ b/Makefile @@ -13,11 +13,19 @@ VPATH = $(DIR_SRCS) DIR_SRCS = srcs HEADERS_D = ./srcs -HEADERS = Webserv.hpp +HEADERS = Webserv.hpp \ + ConfigParser.hpp \ + ServerConfig.hpp \ + LocationConfig.hpp \ DEPENDENCIES = $(HEADERS:%=$(HEADERS_D)/%) -SRCS = main.cpp Webserv.cpp +SRCS = main.cpp \ + Webserv.cpp \ + ConfigParser.cpp \ + ServerConfig.cpp \ + LocationConfig.cpp \ + DIR_OBJS = builds OBJS = $(SRCS:%.cpp=$(DIR_OBJS)/%.o) diff --git a/default.config b/default.config new file mode 100644 index 0000000..8c5ff14 --- /dev/null +++ b/default.config @@ -0,0 +1,16 @@ +server { + + server_name our_server; + + listen 0.0.0.0:80; + + + index index.html; + root ./www/; + + allow_methods GET; + + + + +} diff --git a/srcs/ConfigParser.cpp b/srcs/ConfigParser.cpp index 1d748b6..2a6be83 100644 --- a/srcs/ConfigParser.cpp +++ b/srcs/ConfigParser.cpp @@ -6,7 +6,7 @@ /* By: me +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/07/13 22:11:17 by me #+# #+# */ -/* Updated: 2022/07/25 02:56:26 by me ### ########.fr */ +/* Updated: 2022/07/25 20:56:51 by me ### ########.fr */ /* */ /* ************************************************************************** */ @@ -20,6 +20,13 @@ I don't love the use of EMPTY and FAILURE and those I would rather throw exceptions everywhere... +where do i check if there is only a ";" + +we could make a print _content just to make sure it works properly... + +need to figure out why return std::vector * rather than just simple + not a pointer... + is there a good reason? */ @@ -51,11 +58,14 @@ ConfigParser::ConfigParser(const char* path) { while (!file.eof()) { +// if we remove the Emtpy lines as well it simplifies things later... getline(file, buf); // remove # comments here. if ((comment = buf.find_first_of("#")) == std::string::npos) { - _content.append(buf + '\n'); + // remove empty lines, i think... + if ((buf.find_first_not_of(" \t")) != std::string::npos) + _content.append(buf + '\n'); } // else if (comment > 0 && (buf.find_first_not_of(" \t")) != std::string::npos) // i think this works cuz it will find # no matter what, so it will find @@ -90,15 +100,17 @@ ConfigParser & ConfigParser::operator=(const ConfigParser& rhs) */ +// ok what exactly is the benefit of returning a pointer here... std::vector * ConfigParser::parse() { // is this the best way to do this? new? - std::vector *ret = new std::vector(); + std::vector *ret = new std::vector(); + // yea i could do + std::vector ret; size_t prev = 0; size_t curr = _content.find_first_not_of(" \t\n", prev); - if (curr == std::string::npos) throw std::invalid_argument("empty config file"); while (cur != std::string::npos) @@ -115,16 +127,18 @@ std::vector * ConfigParser::parse() ret->push_back(parse_server(&curr); } return (ret); + // or +// return (&ret); // wait no, that doesn't work... } // could we return a ref instead? // i think no -Server ConfigParser::parse_server(size_t *start) +ServerConfig ConfigParser::parse_server(size_t *start) { - Server ret; - size_t key_start; - size_t value_end; - size_t prev = _content.find_first_not_of(" \t\n", *start); + ServerConfig ret; + size_t key_start; + size_t value_end; + size_t prev = _content.find_first_not_of(" \t\n", *start); if (prev == std::string::npos || _content[prev] != '{') throw std::invalid_argument("bad config file syntax"); @@ -159,12 +173,14 @@ Server ConfigParser::parse_server(size_t *start) // why bother with the if.. why not throw exception in check_line... if ((value_end = check_line_syntax(_content.substr(key_start, curr - key_start))) == FAILED) throw std::invalid_argument("bad config file arguments"); - if ((int)value_end == EMPTY) - continue ; +// if ((int)value_end == EMPTY) +// continue ; + // could i shove this in the _set_server_value() func call? std::string value = _content.substr(prev, value_end - prev + key_start + 1) - // I might need to catch here, or i could do nothing and trow all the way to the top! - if (_set_server_value(&ret, key, value) == FAILED) - throw std::invalid_argument("bad config file arguments"); +// since there's not return anymore +// if (_set_server_value(&ret, key, value) == FAILED) +// throw std::invalid_argument("bad config file arguments"); + _set_server_value(&ret, key, value); // it handles the throws } } return (ret); @@ -172,12 +188,12 @@ Server ConfigParser::parse_server(size_t *start) -Location ConfigParser::parse_location(size_t *start) +LocationConfig ConfigParser::parse_location(size_t *start) { - Location ret; - size_t key_start; - size_t value_end; - size_t prev = _content.find_first_not_of(" \t\n", *start); + LocationConfig ret; + size_t key_start; + size_t value_end; + size_t prev = _content.find_first_not_of(" \t\n", *start); if (prev == std::string::npos || _content[prev] != '{') throw std::invalid_argument("bad config file syntax"); @@ -196,14 +212,18 @@ Location ConfigParser::parse_location(size_t *start) break ; default: _check_proper_line_end(&prev, &curr); - // why bother with the if.. why not throw exception in check_line... - if ((value_end = check_line_syntax(_content.substr(key_start, curr - key_start))) == FAILED) + // why bother with the if.. why not throw exception in check_line... + // ok no we need the if cuz have to set value_end + if ((value_end = _check_for_semicolon(_content.substr(key_start, curr - key_start))) == FAILED) throw std::invalid_argument("bad config file arguments"); - if ((int)value_end == EMPTY) - continue ; + // if we remove all empty lines at the start no need for this +// if ((int)value_end == EMPTY) +// continue ; + // shove this in _set_location_value() func call? std::string value = _content.substr(prev, value_end - prev + key_start + 1) - if (_set_location_value(&ret, key, value) == FAILED) - throw std::invalid_argument("bad config file arguments"); +// if (_set_location_value(&ret, key, value) == FAILED) +// throw std::invalid_argument("bad config file arguments"); + _set_location_value(&ret, key, value); } } return (ret); @@ -212,8 +232,12 @@ Location ConfigParser::parse_location(size_t *start) // not convinced i want to return an int... // but could be helpful to get more feed back // maybe use a throw... but catch in parse_server... -int ConfigParser::_set_server_value(Server *server, const std::string key, const std::string value) +// yea i don't see any reason to return an int +//int ConfigParser::_set_server_value(Server *server, const std::string key, const std::string value) +void ConfigParser::_set_server_value(Server *server, const std::string key, const std::string value) { + // i could do some checks at the start for value being bad or empty? or is + // that unnecessary since in theory i've already checked that it's good... switch (key) { case "server_name": @@ -274,7 +298,7 @@ int ConfigParser::_set_server_value(Server *server, const std::string key, const default : throw std::invalid_argument("bad config file arguments"); } - return (1); // for now but prolly will change... +// return (1); // for now but prolly will change... } // again not sure i want an int ret @@ -322,9 +346,14 @@ void ConfigParser::_check_proper_line_end(size_t *prev, size_t *curr) // i'm not sure i like this... // and it needs to be _check_... // rework this whole thing... -int ConfigParser::check_line_syntax(std::string line) -{ +// no longer returning an int +// fuck no we have to return an int... + // ok keep FAILED as being -1 +// i mean we could send a pointer to value_end and then ret void, but why + // bother chaning it now... +int ConfigParser::_check_for_semicolon(std::string line) +{ // line must be end with semicolon size_t semicol; size_t find; diff --git a/srcs/ConfigParser.hpp b/srcs/ConfigParser.hpp index b9ce28b..b0605d5 100644 --- a/srcs/ConfigParser.hpp +++ b/srcs/ConfigParser.hpp @@ -6,7 +6,7 @@ /* By: me +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/07/11 23:01:41 by me #+# #+# */ -/* Updated: 2022/07/23 15:53:19 by me ### ########.fr */ +/* Updated: 2022/07/25 20:56:53 by me ### ########.fr */ /* */ /* ************************************************************************** */ @@ -45,6 +45,7 @@ private: void _check_proper_line_end(size_t prev, size_t curr); // const? + int _check_for_semicolon(std::string line); // const? }; diff --git a/srcs/LocationConfig.hpp b/srcs/LocationConfig.hpp index db45ddb..0f6b345 100644 --- a/srcs/LocationConfig.hpp +++ b/srcs/LocationConfig.hpp @@ -6,7 +6,7 @@ /* By: me +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/07/23 16:08:00 by me #+# #+# */ -/* Updated: 2022/07/23 16:14:01 by me ### ########.fr */ +/* Updated: 2022/07/25 20:09:48 by me ### ########.fr */ /* */ /* ************************************************************************** */ diff --git a/srcs/Webserv.cpp b/srcs/Webserv.cpp index 92a85c0..367dd1f 100644 --- a/srcs/Webserv.cpp +++ b/srcs/Webserv.cpp @@ -18,6 +18,21 @@ Webserv::Webserv() } */ +Webserv::Webserv(std::vector* servers) +: _servers(servers) +{ + // talk to luke about what all this does + // the Param Constructor might need to do dif stuff + std::cout << "Server init\n"; + + _epfd = ::epoll_create1(0); // (EPOLL_CLOEXEC) for CGI fork ? + if (_epfd == -1) + { + std::perror("err epoll_create1(): "); + throw std::runtime_error("Epoll init"); + } +} + Webserv::~Webserv() { close(_socket_fd); diff --git a/srcs/Webserv.hpp b/srcs/Webserv.hpp index 5076f8e..b931e60 100644 --- a/srcs/Webserv.hpp +++ b/srcs/Webserv.hpp @@ -28,11 +28,20 @@ #define MSG_TEST "Le Webserv / 20 =D\n" #define MSG_BOUNCE "bounced properly ;)\n" // placeholder +// these might only be TMP +# define FAILURE -1 +# define SUCCESS 1 + class Webserv { public: + Webserv(); // Webserv(Webserv const &src); + + // what should it take as arg, *, &, ? + Webserv(std::vector& servers); + ~Webserv(); // Webserv &operator=(Webserv const &rhs); @@ -41,7 +50,9 @@ class Webserv private: int _socket_fd; // TODO: replace with vector of "Server" struct - std::vector _servers; + + std::vector _servers; // should these be const? + int _epfd; // WIP global buffer. Need one variable set per "Client" diff --git a/srcs/main.cpp b/srcs/main.cpp index 5121ac7..addedd9 100644 --- a/srcs/main.cpp +++ b/srcs/main.cpp @@ -4,11 +4,21 @@ #include #include -int main(void) +int main(int ac, char **av) { try { - Webserv serv; + std::string config = (ac == 2 ? av[1] : "./default.config"); + + // like this just looks kinda gross, why bother creating an instance + // and not immediately parsing? like it servers no other purpose... + // what if i call parse directly in the constructor? + // oh because the constructor has no return, but still + // is there a better way? + + ConfigParser configParser(config.c_str()); + Webserv serv(configParser.parse()); + // is this better or worse than using serv.init_virtual_servers(); serv.start(); diff --git a/www/index.html b/www/index.html new file mode 100644 index 0000000..7de0cd1 --- /dev/null +++ b/www/index.html @@ -0,0 +1,16 @@ + + + + + + + + + +

My First Heading

+

My first paragraph.

+ + + + + From 6265019d3ea135019db09fd875d8597dd36e965b Mon Sep 17 00:00:00 2001 From: Me Date: Thu, 28 Jul 2022 18:07:16 +0200 Subject: [PATCH 3/9] a few good ideas as to how to better handle the config parsing --- srcs/ConfigParser.cpp | 50 +++++++++++++++++++++++++++++++++---------- srcs/ConfigParser.hpp | 21 +++++++++++++++++- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/srcs/ConfigParser.cpp b/srcs/ConfigParser.cpp index 2a6be83..dd32f7a 100644 --- a/srcs/ConfigParser.cpp +++ b/srcs/ConfigParser.cpp @@ -6,7 +6,7 @@ /* By: me +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/07/13 22:11:17 by me #+# #+# */ -/* Updated: 2022/07/25 20:56:51 by me ### ########.fr */ +/* Updated: 2022/07/27 19:27:55 by me ### ########.fr */ /* */ /* ************************************************************************** */ @@ -16,18 +16,20 @@ /***** Stuf to rework I don't love the use of EMPTY and FAILURE and those + slowly transitioning away... I would rather throw exceptions everywhere... where do i check if there is only a ";" -we could make a print _content just to make sure it works properly... need to figure out why return std::vector * rather than just simple not a pointer... is there a good reason? +I need to better understand what check_proper_line does + */ @@ -133,6 +135,7 @@ std::vector * ConfigParser::parse() // could we return a ref instead? // i think no +// might need new names for Prev and Curr, not super descriptive... ServerConfig ConfigParser::parse_server(size_t *start) { ServerConfig ret; @@ -144,8 +147,11 @@ ServerConfig ConfigParser::parse_server(size_t *start) throw std::invalid_argument("bad config file syntax"); size_t curr = _content.find_first_of(" \t\n", ++prev); + if (curr == std::string::npos) // are there other things to check for? + throw std::invalid_argument("bad config file syntax"); while (curr != std::string::npos) { + _get_key(&word_start, &blank_start); _check_proper_line_end(&prev, &curr); // nope, not an option i think... /* if ((prev = _content.find_first_not_of(" \t\n", curr)) == std::string::npos) throw std::invalid_argument("bad config file arguments"); @@ -154,6 +160,7 @@ ServerConfig ConfigParser::parse_server(size_t *start) */ key_start = prev; std::string key = _content.substr(prev, curr - prev); + std::string key = _get_key(&word_start, &blank_start); switch (key) { case "}": @@ -164,6 +171,15 @@ ServerConfig ConfigParser::parse_server(size_t *start) // the name but it's so clear... ret.location.push_back(parse_location(&curr)); default: + + // ok i figured it out, there's a slight difference! + + // curr below is this actually, she does go all the way to the end of the line... + // there has to be a better way of doing this, just like + // get me the first word, get me all the rest... but like in sub functions... + if ((curr = _content.find_first_of("\n", prev)) == std::string::npos) + throw std::invalid_argument("bad config file arguments"); + _check_proper_line_end(&prev, &curr); /* if ((prev = _content.find_first_not_of(" \t\n", curr)) == std::string::npos) throw std::invalid_argument("bad config file arguments"); @@ -171,7 +187,7 @@ ServerConfig ConfigParser::parse_server(size_t *start) throw std::invalid_argument("bad config file arguments"); */ // why bother with the if.. why not throw exception in check_line... - if ((value_end = check_line_syntax(_content.substr(key_start, curr - key_start))) == FAILED) + if ((value_end = _check_for_semicolon(_content.substr(key_start, curr - key_start))) == FAILED) throw std::invalid_argument("bad config file arguments"); // if ((int)value_end == EMPTY) // continue ; @@ -229,13 +245,16 @@ LocationConfig ConfigParser::parse_location(size_t *start) return (ret); } -// not convinced i want to return an int... -// but could be helpful to get more feed back -// maybe use a throw... but catch in parse_server... -// yea i don't see any reason to return an int -//int ConfigParser::_set_server_value(Server *server, const std::string key, const std::string value) +// yea ok new plan, this is where a lot of the checks will happen... + + void ConfigParser::_set_server_value(Server *server, const std::string key, const std::string value) { + // so turns out here is where i should be checking for the semicolon i think + // and also making sure there are the right number of values depending on which key it is... + // like for error page there can be a bunch but you can't have say 1 error code and several error files + // it's 1 error file per line and + // i could do some checks at the start for value being bad or empty? or is // that unnecessary since in theory i've already checked that it's good... switch (key) @@ -335,6 +354,9 @@ int ConfigParser::_set_location_value(Location *location, const std::string key, // shit, this doesn't work... // wait it might... + // definitely need a better name... +// _check_proper_word_break ? +// get next word ? void ConfigParser::_check_proper_line_end(size_t *prev, size_t *curr) { if ((*prev = _content.find_first_not_of(" \t\n", *curr)) == std::string::npos) @@ -343,9 +365,6 @@ void ConfigParser::_check_proper_line_end(size_t *prev, size_t *curr) throw std::invalid_argument("bad config file arguments"); } -// i'm not sure i like this... - // and it needs to be _check_... -// rework this whole thing... // no longer returning an int // fuck no we have to return an int... @@ -354,6 +373,8 @@ void ConfigParser::_check_proper_line_end(size_t *prev, size_t *curr) // bother chaning it now... int ConfigParser::_check_for_semicolon(std::string line) { + // yea ok i just don't like this... + // line must be end with semicolon size_t semicol; size_t find; @@ -369,6 +390,13 @@ int ConfigParser::_check_for_semicolon(std::string line) } +void ConfigParser::_print_content() const +{ + std::cout << _content; +} + + + // I might need to make my own Exceptions to throw... diff --git a/srcs/ConfigParser.hpp b/srcs/ConfigParser.hpp index b0605d5..378f987 100644 --- a/srcs/ConfigParser.hpp +++ b/srcs/ConfigParser.hpp @@ -6,7 +6,7 @@ /* By: me +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/07/11 23:01:41 by me #+# #+# */ -/* Updated: 2022/07/25 20:56:53 by me ### ########.fr */ +/* Updated: 2022/07/27 19:27:57 by me ### ########.fr */ /* */ /* ************************************************************************** */ @@ -16,6 +16,21 @@ # include "Webserv.hpp" // easier to just do this? +// This is gonna be temporary cuz i don't konw if i like it +#define MAX_REQUEST_SIZE 2048 +#define MAX_URI_SIZE 64 +#define BSIZE 1024 + +enum MethodType +{ + GET, + POST, + DELETE, + INVALID, +}; + + + class ConfigParser { public: @@ -47,6 +62,10 @@ private: int _check_for_semicolon(std::string line); // const? + // just for testing purposes + void _print_content() const; + + }; From 846c478142c98ac531e86e3ce8324c787375406c Mon Sep 17 00:00:00 2001 From: Me Date: Fri, 29 Jul 2022 03:15:08 +0200 Subject: [PATCH 4/9] ok so it's still a little blocky, could prolly improve more, and i haven't compiled yet, no doubt many issues, but, i did my idea for a better config parser, and it went pretty well --- srcs/ConfigParser.cpp | 420 +++++++++++++++++++++++------------------- 1 file changed, 226 insertions(+), 194 deletions(-) diff --git a/srcs/ConfigParser.cpp b/srcs/ConfigParser.cpp index dd32f7a..0a44dc4 100644 --- a/srcs/ConfigParser.cpp +++ b/srcs/ConfigParser.cpp @@ -15,21 +15,11 @@ /***** Stuf to rework -I don't love the use of EMPTY and FAILURE and those - slowly transitioning away... - -I would rather throw exceptions everywhere... - - -where do i check if there is only a ";" - need to figure out why return std::vector * rather than just simple not a pointer... is there a good reason? -I need to better understand what check_proper_line does - */ @@ -103,11 +93,11 @@ ConfigParser & ConfigParser::operator=(const ConfigParser& rhs) // ok what exactly is the benefit of returning a pointer here... -std::vector * ConfigParser::parse() +//std::vector * ConfigParser::parse() +std::vector ConfigParser::parse() { // is this the best way to do this? new? - std::vector *ret = new std::vector(); - // yea i could do +// std::vector *ret = new std::vector(); std::vector ret; size_t prev = 0; @@ -115,7 +105,7 @@ std::vector * ConfigParser::parse() if (curr == std::string::npos) throw std::invalid_argument("empty config file"); - while (cur != std::string::npos) + while (curr != std::string::npos) { // ok i don't love her way of scoping out the "server" strings... prev = _content.find_first_not_of(" \t\n", curr); @@ -126,44 +116,36 @@ std::vector * ConfigParser::parse() // Server server = parse_server(&curr); // ret->push_back(server); // why not this? - ret->push_back(parse_server(&curr); + ret.push_back(parse_server(&curr); } return (ret); - // or -// return (&ret); // wait no, that doesn't work... } -// could we return a ref instead? - // i think no // might need new names for Prev and Curr, not super descriptive... ServerConfig ConfigParser::parse_server(size_t *start) { ServerConfig ret; - size_t key_start; - size_t value_end; +// size_t key_start; +// size_t value_end; size_t prev = _content.find_first_not_of(" \t\n", *start); + if (prev == std::string::npos || _content[prev] != '{') throw std::invalid_argument("bad config file syntax"); size_t curr = _content.find_first_of(" \t\n", ++prev); - if (curr == std::string::npos) // are there other things to check for? - throw std::invalid_argument("bad config file syntax"); - while (curr != std::string::npos) +// if (curr == std::string::npos) // are there other things to check for? +// throw std::invalid_argument("bad config file syntax"); + while (curr != std::string::npos) // here curr == { + 1 { - _get_key(&word_start, &blank_start); - _check_proper_line_end(&prev, &curr); // nope, not an option i think... -/* if ((prev = _content.find_first_not_of(" \t\n", curr)) == std::string::npos) - throw std::invalid_argument("bad config file arguments"); - if ((curr = _content.find_first_of(" \t\n", prev)) == std::string::npos) - throw std::invalid_argument("bad config file arguments"); -*/ key_start = prev; - std::string key = _content.substr(prev, curr - prev); - std::string key = _get_key(&word_start, &blank_start); + // so this moves curr to past the word... + std::string key = _get_first_word(&curr); + // now curr is on space after 1st word. switch (key) { case "}": + // why +1 curr is already after it no? *start = _content.find_first_not_of(" \t\n" curr + 1); break ; case "location": @@ -171,32 +153,11 @@ ServerConfig ConfigParser::parse_server(size_t *start) // the name but it's so clear... ret.location.push_back(parse_location(&curr)); default: + std::string values = _get_rest_of_line(&curr); + // curr now should be \n + // checking for ; in _set_value, check key and value - // ok i figured it out, there's a slight difference! - - // curr below is this actually, she does go all the way to the end of the line... - // there has to be a better way of doing this, just like - // get me the first word, get me all the rest... but like in sub functions... - if ((curr = _content.find_first_of("\n", prev)) == std::string::npos) - throw std::invalid_argument("bad config file arguments"); - - _check_proper_line_end(&prev, &curr); - /* if ((prev = _content.find_first_not_of(" \t\n", curr)) == std::string::npos) - throw std::invalid_argument("bad config file arguments"); - if ((curr = _content.find_first_of(" \t\n", prev)) == std::string::npos) - throw std::invalid_argument("bad config file arguments"); - */ - // why bother with the if.. why not throw exception in check_line... - if ((value_end = _check_for_semicolon(_content.substr(key_start, curr - key_start))) == FAILED) - throw std::invalid_argument("bad config file arguments"); -// if ((int)value_end == EMPTY) -// continue ; - // could i shove this in the _set_server_value() func call? - std::string value = _content.substr(prev, value_end - prev + key_start + 1) -// since there's not return anymore -// if (_set_server_value(&ret, key, value) == FAILED) -// throw std::invalid_argument("bad config file arguments"); - _set_server_value(&ret, key, value); // it handles the throws + _set_server_values(&ret, key, values); // it handles the throws } } return (ret); @@ -215,181 +176,252 @@ LocationConfig ConfigParser::parse_location(size_t *start) throw std::invalid_argument("bad config file syntax"); size_t curr = _content.find_first_of(" \t\n", ++prev); +// if (curr == std::string::npos) // are there other things to check for? +// throw std::invalid_argument("bad config file syntax"); while (curr != std::string::npos) { - _check_proper_line_end(&prev, &curr); - key_start = prev; + // so this moves curr to past the word... + std::string key = _get_first_word(&curr); + // now curr is on space after 1st word. - std::string key = _content.substr(prev, curr - prev); switch (key) { case "}": *start = curr; break ; default: - _check_proper_line_end(&prev, &curr); - // why bother with the if.. why not throw exception in check_line... - // ok no we need the if cuz have to set value_end - if ((value_end = _check_for_semicolon(_content.substr(key_start, curr - key_start))) == FAILED) - throw std::invalid_argument("bad config file arguments"); - // if we remove all empty lines at the start no need for this -// if ((int)value_end == EMPTY) -// continue ; - // shove this in _set_location_value() func call? - std::string value = _content.substr(prev, value_end - prev + key_start + 1) -// if (_set_location_value(&ret, key, value) == FAILED) -// throw std::invalid_argument("bad config file arguments"); - _set_location_value(&ret, key, value); + std::string values = _get_rest_of_line(&curr); + // curr now should be \n + // checking for ; in _set_value, check key and value + + _set_location_values(&ret, key, values); // it handles the throws } } return (ret); } -// yea ok new plan, this is where a lot of the checks will happen... -void ConfigParser::_set_server_value(Server *server, const std::string key, const std::string value) +// ok you need to think through these throws, when will each occur? + + + +void ConfigParser::_set_server_values(Server *server, const std::string key, const std::string value) { - // so turns out here is where i should be checking for the semicolon i think - // and also making sure there are the right number of values depending on which key it is... - // like for error page there can be a bunch but you can't have say 1 error code and several error files - // it's 1 error file per line and - // i could do some checks at the start for value being bad or empty? or is - // that unnecessary since in theory i've already checked that it's good... - switch (key) + // check key for ; + // check values for ; at end and right number of words depending on key + + if (key.find_first_of(";") != std::string::npos) + throw std::invalid_argument("bad config file arguments"); + + // there shouldn't be any tabs, right? not between values... + if (value.find_first_of("\t") != std::string::npos) + throw std::invalid_argument("bad config file arguments"); + + size_t i = value.find_first_of(";"); + // so you can't have no ; + // you can't have just ; + // and you can't have a ; not at the end or several ; + // in theory value_find_last_of should find the only ; + if (i == std::string::npos || (value.find_last_not_of(" \n")) != i \ + || value.compare(";") == 0) + throw std::invalid_argument("bad config file arguments"); + + + // we Trim value. + // is this valid? + value = value.substr(0, i - 1); + + std::vector tmp = ::split(value, ' '); + + if (tmp.size() == 1) { - case "server_name": - server->server_name = value; - case "listen": - if (value.find_first_of(":") == std::string::npos) - { - // why not store as vector [4] ? - server->host = "0.0.0.0"; - server->value = value; - } - else - { - // maybe do this differently? - std::vector tmp = split(value, ':'); - // i might take issue with this, will see - if (server->host != "" && server->host != tmp[0]) - throw std::invalid_argument("bad config file arguments"); - server->host = tmp[0]; - server->port = tmp[1]; - } - case "root": - server->root = value; - case "index": - std::vector tmp = split(value, ' '); - for (unsigned long i = 0; i != tmp.size(); i++) - server->index.push_back(tmp[i]); - case "allow_methods": - std::vector tmp = split(value, ' '); - // might do something different here - // like change how methods are stored? - for (unsigned long i = 0; i != tmp.size(); i++) - server->allow_methods.push_back(str_to_method_type(tmp[i])); - case "autoindex": - server->autoindex = (value == "on" ? true : false); - case "client_body_limit": - server->client_body_limit = atoi(value.c_str()); - case "recv_timeout": - // what is tv_sec and do i need it? - server->recv_timeout.tv_sec = atoi(value.c_str()); - case "send_timeout": - server->send_timeout.tv_sec = atoi(value.c_str()); - case "return": - std::vector tmp = split(value, ' '); - server->redirect_status = atoi(tmp[0].c_str()); - server->redirect_uri = tmp[1]; - case "error_page": - std::vector tmp = split(value, ' '); - std::string path = tmp[tmp.size() - 1]; - for (unsigned long i = 0; i != tmp.size() - 1; i++) - { - int status_code = atoi(tmp[i].c_str()); - // yea IDK i might not want to store this like that... - if (server->error_pages.find(status_code) != server->error_pages.end()) - continue ; - server->error_pages[status_code] = path; - } - default : - throw std::invalid_argument("bad config file arguments"); + switch (key) + { + case "server_name": + server->server_name = value; + case "listen": + // ok yea i don't get this one anymore.. + if (value.find_first_of(":") == std::string::npos) + { + // why not store as vector [4] ? + server->host = "0.0.0.0"; + server->value = value; + } + else + { + // maybe do this differently? + std::vector tmp2 = split(value, ':'); + // i might take issue with this, will see + if (server->host != "" && server->host != tmp2[0]) + throw std::invalid_argument("bad listen"); + server->host = tmp[0]; + server->port = tmp[1]; + } + case "root": + server->root = value; + case "autoindex": + server->autoindex = (value == "on" ? true : false); + case "client_body_limit": + server->client_body_limit = atoi(value.c_str()); + case "recv_timeout": + // what is tv_sec and do i need it? + server->recv_timeout.tv_sec = atoi(value.c_str()); + case "send_timeout": + server->send_timeout.tv_sec = atoi(value.c_str()); + default : + throw std::invalid_argument("should only have 1 value"); + // yea ok but it could also be something else like too many + // args + } } -// return (1); // for now but prolly will change... + else if (tmp.size() > 1) + { + switch (key) + { + case "index": + // could run more tests on value content but meh... + for (unsigned long i = 0; i != tmp.size(); i++) + server->index.push_back(tmp[i]); + case "allow_methods": + // might do something different here + // like change how methods are stored? + for (unsigned long i = 0; i != tmp.size(); i++) + server->allow_methods.push_back(str_to_method_type(tmp[i])); + case "return": + // could run more checks here too + // like tmp.size() must be 2 + // and tmp[0] should be a number and tmp[1] a string? + server->redirect_status = atoi(tmp[0].c_str()); + server->redirect_uri = tmp[1]; + case "error_page": + // something more complicated? + // like make sure ints then 1 string? + std::string path = tmp[tmp.size() - 1]; + for (unsigned long i = 0; i != tmp.size() - 1; i++) + { + int status_code = atoi(tmp[i].c_str()); + // yea IDK i might not want to store this like that... + if (server->error_pages.find(status_code) != server->error_pages.end()) + continue ; + server->error_pages[status_code] = path; + } + default : + throw std::invalid_argument("bad config file arguments"); + } + } + else + throw std::invalid_argument("missing value"); + } // again not sure i want an int ret -int ConfigParser::_set_location_value(Location *location, const std::string key, const std::string value) +int ConfigParser::_set_location_values(Location *location, const std::string key, const std::string value) { - switch (key) + // check key for ; + // check values for ; at end and right number of words depending on key + + if (key.find_first_of(";") != std::string::npos) + throw std::invalid_argument("bad config file arguments"); + + // there shouldn't be any tabs, right? not between values... + if (value.find_first_of("\t") != std::string::npos) + throw std::invalid_argument("bad config file arguments"); + + size_t i = value.find_first_of(";"); + // so you can't have no ; + // you can't have just ; + // and you can't have a ; not at the end or several ; + // in theory value_find_last_of should find the only ; + if (i == std::string::npos || (value.find_last_not_of(" \n")) != i \ + || value.compare(";") == 0) + throw std::invalid_argument("bad config file arguments"); + + + // we Trim value. + // is this valid? + value = value.substr(0, i - 1); + + std::vector tmp = ::split(value, ' '); + + if (tmp.size() == 1) { - case "root": - location->root = value; - case "index": - std::vector tmp = split(value, ' '); - for (unsigned long i = 0; i != tmp.size(); i++) - location->index.push_back(tmp[i]); - case "allow_methods": - std::vector tmp = split(value, ' '); - for (unsigned long i = 0; i != tmp.size(); i++) - location->allow_methods.push_back(str_to_methodtype(tmp[i])); - case "cgi_info": - // ok wtf is all this even doing, figure that out - unsigned long i = value.find_first_of(" "); - if (i == std::string::npos) - throw std::invalid_argument("bad config file arguments"); - // ok why an int now, we gotta be more consistent! - int j = value.find_first_not_of(" ", i); - location->cgi_info[value.substr(0, i)] = value.substr(j, value.length()); - case "client_body_limit": - location->client_body_limit = atoi(value.c_str()); - default : - throw std::invalid_argument("bad config file arguments"); + switch (key) + { + case "root": + location->root = value; + case "client_body_limit": + location->client_body_limit = atoi(value.c_str()); + default : + throw std::invalid_argument("should only have 1 argument"); + + } } - return (1); // again prolly want to change this... + else if (tmp.size() > 1) + { + switch (key) + { + case "index": + std::vector tmp = split(value, ' '); + for (unsigned long i = 0; i != tmp.size(); i++) + location->index.push_back(tmp[i]); + case "allow_methods": + std::vector tmp = split(value, ' '); + for (unsigned long i = 0; i != tmp.size(); i++) + location->allow_methods.push_back(str_to_methodtype(tmp[i])); + case "cgi_info": + // ok wtf is all this even doing, figure that out + unsigned long i = value.find_first_of(" "); + if (i == std::string::npos) + throw std::invalid_argument("bad config file arguments"); + // ok why an int now, we gotta be more consistent! + int j = value.find_first_not_of(" ", i); + location->cgi_info[value.substr(0, i)] = value.substr(j, value.length()); + default : + throw std::invalid_argument("bad config file arguments"); + + } + } + else + throw std::invalid_argument("missing a value"); + } - -// shit, this doesn't work... - // wait it might... - // definitely need a better name... -// _check_proper_word_break ? -// get next word ? -void ConfigParser::_check_proper_line_end(size_t *prev, size_t *curr) +// assumes curr is on a space or \t or \n +// get first word? next word? word? +std::string ConfigParser::_get_first_word(size_t *curr) { - if ((*prev = _content.find_first_not_of(" \t\n", *curr)) == std::string::npos) + size_t start; + +// are these checks excessive? + if ((start = _content.find_first_not_of(" \t\n", *curr)) == std::string::npos) throw std::invalid_argument("bad config file arguments"); - if ((*curr = _content.find_first_of(" \t\n", *prev)) == std::string::npos) + if ((*curr = _content.find_first_of(" \t\n", start)) == std::string::npos) throw std::invalid_argument("bad config file arguments"); + + std::string key = _content.substr(start, *curr - start); + + return (key); } - -// no longer returning an int -// fuck no we have to return an int... - // ok keep FAILED as being -1 -// i mean we could send a pointer to value_end and then ret void, but why - // bother chaning it now... -int ConfigParser::_check_for_semicolon(std::string line) +// also assumes curr is on a space \t or \n +std::string ConfigParser::_get_rest_of_line(size_t *curr) { - // yea ok i just don't like this... + size_t start; - // line must be end with semicolon - size_t semicol; - size_t find; + if ((start = _content.find_first_not_of(" \t\n", *curr)) == std::string::npos) + throw std::invalid_argument("bad config file arguments"); + if ((*curr = _content.find_first_of("\n", start)) == std::string::npos) + throw std::invalid_argument("bad config file arguments"); - semicol = line.find_first_of(";"); - if (semicol == std::string::npos) - return FAILED; - find = line.find_first_not_of(" \t\n", semicol + 1, line.length() - semicol - 1); - if (find != std::string::npos) - return FAILED; - find = line.find_last_not_of(" \t", semicol - 1); - return find; + std::string values = _content.substr(start, *curr); + + return (values); } + void ConfigParser::_print_content() const { std::cout << _content; From 3ff62f5ddcfc61e79ce0372c6902aac06a2fdc29 Mon Sep 17 00:00:00 2001 From: Me Date: Fri, 29 Jul 2022 22:17:10 +0200 Subject: [PATCH 5/9] The Config Parser looks a lot better, cleaner, made a lot of decisions and added i think everything to the apropriate header files, now working on testing but since new install of Ubuntu testing make on something i expect is working, the main branch, so brb --- srcs/ConfigParser.cpp | 167 +++++++++++++++++++++------------------- srcs/ConfigParser.hpp | 19 ++++- srcs/LocationConfig.hpp | 8 +- srcs/ServerConfig.hpp | 35 ++++++++- srcs/main.cpp | 14 +++- 5 files changed, 152 insertions(+), 91 deletions(-) diff --git a/srcs/ConfigParser.cpp b/srcs/ConfigParser.cpp index 0a44dc4..15d3c0c 100644 --- a/srcs/ConfigParser.cpp +++ b/srcs/ConfigParser.cpp @@ -41,16 +41,16 @@ ConfigParser::ConfigParser(const char* path) std::ifstream file; std::string buf; -// std::string tmp; // maybe there's a reason we redeclare vars... - size_t comment; // just a number so fine to reset + size_t comment; _content.clear(); file.open(path); if (file.is_open()) { + // are there more throws i need to add in case of errors, what would + // those errors be? while (!file.eof()) { -// if we remove the Emtpy lines as well it simplifies things later... getline(file, buf); // remove # comments here. if ((comment = buf.find_first_of("#")) == std::string::npos) @@ -59,11 +59,9 @@ ConfigParser::ConfigParser(const char* path) if ((buf.find_first_not_of(" \t")) != std::string::npos) _content.append(buf + '\n'); } -// else if (comment > 0 && (buf.find_first_not_of(" \t")) != std::string::npos) - // i think this works cuz it will find # no matter what, so it will find - // something else first if there is non comment stuff. else if (comment > 0 && (buf.find_first_not_of(" \t")) < comment) { +// else if (comment > 0 && (buf.find_first_not_of(" \t")) != std::string::npos) // is there a comment at the end of the line std::string tmp = buf.substr(0, comment - 1); _content.append(tmp + '\n'); @@ -92,25 +90,22 @@ ConfigParser & ConfigParser::operator=(const ConfigParser& rhs) */ -// ok what exactly is the benefit of returning a pointer here... -//std::vector * ConfigParser::parse() -std::vector ConfigParser::parse() +std::vector ConfigParser::parse() { - // is this the best way to do this? new? -// std::vector *ret = new std::vector(); std::vector ret; - size_t prev = 0; - size_t curr = _content.find_first_not_of(" \t\n", prev); + size_t start = 0; + size_t curr = _content.find_first_not_of(" \t\n", 0); if (curr == std::string::npos) throw std::invalid_argument("empty config file"); while (curr != std::string::npos) { - // ok i don't love her way of scoping out the "server" strings... - prev = _content.find_first_not_of(" \t\n", curr); - curr = _content.find_first_of(" \t\n", prev); - std::string key = _conent.substr(prev, curr - prev); +// why no checks here +// if not here do i need them elsewhere? + start = _content.find_first_not_of(" \t\n", curr); + curr = _content.find_first_of(" \t\n", start); + std::string key = _conent.substr(start, curr - start); if (key != "server") throw std::invalid_argument("bad config file arguments"); // Server server = parse_server(&curr); @@ -125,20 +120,16 @@ std::vector ConfigParser::parse() ServerConfig ConfigParser::parse_server(size_t *start) { ServerConfig ret; -// size_t key_start; -// size_t value_end; - size_t prev = _content.find_first_not_of(" \t\n", *start); + size_t curr = _content.find_first_not_of(" \t\n", *start); - - if (prev == std::string::npos || _content[prev] != '{') + if (curr == std::string::npos || _content[curr] != '{') throw std::invalid_argument("bad config file syntax"); - size_t curr = _content.find_first_of(" \t\n", ++prev); + curr = _content.find_first_of(" \t\n", curr + 1); // if (curr == std::string::npos) // are there other things to check for? // throw std::invalid_argument("bad config file syntax"); while (curr != std::string::npos) // here curr == { + 1 { - // so this moves curr to past the word... std::string key = _get_first_word(&curr); // now curr is on space after 1st word. @@ -149,15 +140,14 @@ ServerConfig ConfigParser::parse_server(size_t *start) *start = _content.find_first_not_of(" \t\n" curr + 1); break ; case "location": - // this does assume we have locations in Server... we could change - // the name but it's so clear... - ret.location.push_back(parse_location(&curr)); + // this does assume we have locations in Server... + // could change the name but it's so clear... + ret.location.push_back(_parse_location(&curr)); default: std::string values = _get_rest_of_line(&curr); // curr now should be \n // checking for ; in _set_value, check key and value - - _set_server_values(&ret, key, values); // it handles the throws + _set_server_values(&ret, key, values); // handles the throws } } return (ret); @@ -165,17 +155,15 @@ ServerConfig ConfigParser::parse_server(size_t *start) -LocationConfig ConfigParser::parse_location(size_t *start) +LocationConfig ConfigParser::_parse_location(size_t *start) { LocationConfig ret; - size_t key_start; - size_t value_end; - size_t prev = _content.find_first_not_of(" \t\n", *start); + size_t curr = _content.find_first_not_of(" \t\n", *start); - if (prev == std::string::npos || _content[prev] != '{') + if (curr == std::string::npos || _content[curr] != '{') throw std::invalid_argument("bad config file syntax"); - size_t curr = _content.find_first_of(" \t\n", ++prev); + size_t curr = _content.find_first_of(" \t\n", curr + 1); // if (curr == std::string::npos) // are there other things to check for? // throw std::invalid_argument("bad config file syntax"); while (curr != std::string::npos) @@ -183,7 +171,6 @@ LocationConfig ConfigParser::parse_location(size_t *start) // so this moves curr to past the word... std::string key = _get_first_word(&curr); // now curr is on space after 1st word. - switch (key) { case "}": @@ -194,7 +181,7 @@ LocationConfig ConfigParser::parse_location(size_t *start) // curr now should be \n // checking for ; in _set_value, check key and value - _set_location_values(&ret, key, values); // it handles the throws + _set_location_values(&ret, key, values); //handles the throws } } return (ret); @@ -206,7 +193,8 @@ LocationConfig ConfigParser::parse_location(size_t *start) -void ConfigParser::_set_server_values(Server *server, const std::string key, const std::string value) +void ConfigParser::_set_server_values(ServerConfig *server, \ + const std::string key, std::string value) { // check key for ; @@ -231,84 +219,88 @@ void ConfigParser::_set_server_values(Server *server, const std::string key, con // we Trim value. // is this valid? + // would it be better to shove the result directly in tmp_val? + // like call substr in split? value = value.substr(0, i - 1); - std::vector tmp = ::split(value, ' '); + std::vector tmp_val = ::split(value, ' '); - if (tmp.size() == 1) + if (tmp_val.size() == 1) { switch (key) { case "server_name": - server->server_name = value; + server->server_name = tmp_val[0]; case "listen": - // ok yea i don't get this one anymore.. - if (value.find_first_of(":") == std::string::npos) + if (tmp_val[0].find_first_of(":") == std::string::npos) { // why not store as vector [4] ? server->host = "0.0.0.0"; - server->value = value; + server->value = tmp_val[0]; } else { // maybe do this differently? - std::vector tmp2 = split(value, ':'); + std::vector tmp2 = split(tmp_val[0], ':'); // i might take issue with this, will see if (server->host != "" && server->host != tmp2[0]) throw std::invalid_argument("bad listen"); - server->host = tmp[0]; - server->port = tmp[1]; + server->host = tmp2[0]; + server->port = tmp2[1]; } case "root": - server->root = value; + server->root = tmp_val[0]; case "autoindex": - server->autoindex = (value == "on" ? true : false); + server->autoindex = (tmp_val[0] == "on" ? true : false); case "client_body_limit": - server->client_body_limit = atoi(value.c_str()); + server->client_body_limit = atoi(tmp_val[0].c_str()); + case "recv_timeout": // what is tv_sec and do i need it? - server->recv_timeout.tv_sec = atoi(value.c_str()); + // ok so i don't fully understand this part but ok, keep for now... + server->recv_timeout.tv_sec = atoi(tmp_val[0].c_str()); case "send_timeout": - server->send_timeout.tv_sec = atoi(value.c_str()); + server->send_timeout.tv_sec = atoi(tmp_val[0].c_str()); + default : throw std::invalid_argument("should only have 1 value"); // yea ok but it could also be something else like too many // args } } - else if (tmp.size() > 1) + else if (tmp_val.size() > 1) { switch (key) { case "index": // could run more tests on value content but meh... - for (unsigned long i = 0; i != tmp.size(); i++) - server->index.push_back(tmp[i]); + for (unsigned long i = 0; i != tmp_val.size(); i++) + server->index.push_back(tmp_val[i]); case "allow_methods": // might do something different here // like change how methods are stored? - for (unsigned long i = 0; i != tmp.size(); i++) - server->allow_methods.push_back(str_to_method_type(tmp[i])); + for (unsigned long i = 0; i != tmp_val.size(); i++) + server->allow_methods.push_back(_str_to_method_type(tmp_val[i])); case "return": // could run more checks here too - // like tmp.size() must be 2 - // and tmp[0] should be a number and tmp[1] a string? - server->redirect_status = atoi(tmp[0].c_str()); - server->redirect_uri = tmp[1]; + // like tmp_val.size() must be 2 + // and tmp_val[0] should be a number and tmp_val[1] a string? + server->redirect_status = atoi(tmp_val[0].c_str()); + server->redirect_uri = tmp_val[1]; case "error_page": // something more complicated? // like make sure ints then 1 string? - std::string path = tmp[tmp.size() - 1]; - for (unsigned long i = 0; i != tmp.size() - 1; i++) + std::string path = tmp_val[tmp_val.size() - 1]; + for (unsigned long i = 0; i != tmp_val.size() - 1; i++) { - int status_code = atoi(tmp[i].c_str()); + int status_code = atoi(tmp_val[i].c_str()); // yea IDK i might not want to store this like that... if (server->error_pages.find(status_code) != server->error_pages.end()) continue ; server->error_pages[status_code] = path; } default : - throw std::invalid_argument("bad config file arguments"); + throw std::invalid_argument("wrong number of values"); } } else @@ -317,7 +309,8 @@ void ConfigParser::_set_server_values(Server *server, const std::string key, con } // again not sure i want an int ret -int ConfigParser::_set_location_values(Location *location, const std::string key, const std::string value) +int ConfigParser::_set_location_values(LocationConfig *location, \ + const std::string key, std::string value) { // check key for ; // check values for ; at end and right number of words depending on key @@ -341,41 +334,39 @@ int ConfigParser::_set_location_values(Location *location, const std::string key // we Trim value. // is this valid? + // could do like above? value = value.substr(0, i - 1); - std::vector tmp = ::split(value, ' '); + std::vector tmp_val = ::split(value, ' '); - if (tmp.size() == 1) + if (tmp_val.size() == 1) { switch (key) { case "root": - location->root = value; + location->root = tmp_val[0]; case "client_body_limit": - location->client_body_limit = atoi(value.c_str()); + location->client_body_limit = atoi(tmp_val[0].c_str()); default : throw std::invalid_argument("should only have 1 argument"); - } } - else if (tmp.size() > 1) + else if (tmp_val.size() > 1) { switch (key) { case "index": - std::vector tmp = split(value, ' '); - for (unsigned long i = 0; i != tmp.size(); i++) - location->index.push_back(tmp[i]); + for (unsigned long i = 0; i != tmp_val.size(); i++) + location->index.push_back(tmp_val[i]); case "allow_methods": - std::vector tmp = split(value, ' '); - for (unsigned long i = 0; i != tmp.size(); i++) - location->allow_methods.push_back(str_to_methodtype(tmp[i])); + for (unsigned long i = 0; i != tmp_val.size(); i++) + location->allow_methods.push_back(_str_to_methodtype(tmp_val[i])); case "cgi_info": - // ok wtf is all this even doing, figure that out +// ok wtf is all this even doing, figure that out unsigned long i = value.find_first_of(" "); if (i == std::string::npos) throw std::invalid_argument("bad config file arguments"); - // ok why an int now, we gotta be more consistent! + // ok why an int now, we gotta be more consistent! int j = value.find_first_not_of(" ", i); location->cgi_info[value.substr(0, i)] = value.substr(j, value.length()); default : @@ -421,6 +412,22 @@ std::string ConfigParser::_get_rest_of_line(size_t *curr) } +MethodType ConfigParser::_str_to_methodtype(std::string str) +{ + switch (str) + { + case ("GET"): + return GET; + case ("POST"): + return POST; + case ("DELETE"): + return DELETE; + default : + return INVALID; + } +} + + void ConfigParser::_print_content() const { diff --git a/srcs/ConfigParser.hpp b/srcs/ConfigParser.hpp index 378f987..8ef686a 100644 --- a/srcs/ConfigParser.hpp +++ b/srcs/ConfigParser.hpp @@ -14,6 +14,7 @@ # define CONFIGPARSER_HPP # include "Webserv.hpp" // easier to just do this? +// add includes properly // This is gonna be temporary cuz i don't konw if i like it @@ -44,7 +45,8 @@ public: // ConfigParser & operator=(const ConfigParser& rhs); // void parse(); // return void cuz throw exceptions. - std::vector * parse(); // const? + //std::vector * parse(); // const? + std::vector parse(); // const? // other parses? @@ -58,9 +60,20 @@ private: // should this be in private since it always needs a path? - void _check_proper_line_end(size_t prev, size_t curr); // const? + ServerConfig _parse_server(size_t *start); + LocationConfig _parse_location(size_t *start); - int _check_for_semicolon(std::string line); // const? + + void _set_server_values(ServerConfig *server, const std::string key, std::string value); + void _set_location_values(LocationConfig *location, const std::string key, std::string value); + + + std::string _get_first_word(size_t *curr); // const? + std::string _get_rest_of_line(size_t *curr); // const? + + + // why static? it's an enum... + static MethodType _str_to_method_type(std::string str); // just for testing purposes void _print_content() const; diff --git a/srcs/LocationConfig.hpp b/srcs/LocationConfig.hpp index 0f6b345..72ab187 100644 --- a/srcs/LocationConfig.hpp +++ b/srcs/LocationConfig.hpp @@ -14,6 +14,10 @@ # define LOCATIONCONFIG_HPP // includes + // add includes properly +# include +# include +# include # include "Webserv.hpp" // again, struct instead? @@ -31,10 +35,6 @@ public: std::map cgi_info; - - - - }; diff --git a/srcs/ServerConfig.hpp b/srcs/ServerConfig.hpp index 6935720..a6cdc6b 100644 --- a/srcs/ServerConfig.hpp +++ b/srcs/ServerConfig.hpp @@ -13,8 +13,9 @@ #ifndef SERVERCONFIG_HPP # define SERVERCONFIG_HPP +// add includes properly... +# include "Webserv.hpp" # include "LocationConfig.hpp" -//other includes // a class that's all public? just so we have options? class ServerConfig @@ -51,6 +52,38 @@ public: std::string host; std::string port; + + // do i need a print all for testing? + + + void print_all() + { + std::cout << "PRINTING A FULL SERVER CONFIG\n\n"; + + std::cout << "Server_name: " << server_name << '\n'; + std::cout << "root: " << root << '\n'; + std::cout << "index: "; + for (int i = 0; i < index.size(); i++) + std::cout << index[i] << " "; + std::cout << "\nerror_pages: "; + for (int i = 0; i < error_pages.size(); i++) + std::cout << error_pages.first << "--" << error_pages.second << " "; + std::cout << "\nallow_methods: "; + for (int i = 0; i < allow_methods.size(); i++) + std::cout << allow_methods[i] << " "; + std::cout << "\nskiping Locations for now...\n"; + std::cout << "also skiping send_timeout and recv\n"; + std::cout << "autoindex: " << autoindex << '\n'; + std::cout << "client_body_limit: " << client_body_limit << '\n'; + std::cout << "redirect_status: " << redirect_status << '\n'; + std::cout << "redirect_uri: " << redirect_uri << '\n'; + std::cout << "host: " << host << '\n'; + std::cout << "port: " << port << '\n'; + + std::cout << "\n----------\n"; + } + + }; diff --git a/srcs/main.cpp b/srcs/main.cpp index c9e1df7..7cf49d9 100644 --- a/srcs/main.cpp +++ b/srcs/main.cpp @@ -17,11 +17,19 @@ int main(int ac, char **av) // is there a better way? ConfigParser configParser(config.c_str()); - Webserv serv(configParser.parse()); + + configParser._print_content(); + + std::vector servers = configParser.parse(); + + for (int i = 0; i < server.size(); i++) + servers[i].print_all(); + +// Webserv serv(configParser.parse()); // is this better or worse than using - serv.init_virtual_servers(); - serv.start(); +// serv.init_virtual_servers(); +// serv.start(); } catch (std::exception& e) { From 001ad6becfa56a1d37a434f001b3b285eb364421 Mon Sep 17 00:00:00 2001 From: Me Date: Fri, 29 Jul 2022 23:29:19 +0200 Subject: [PATCH 6/9] Still trying to get it to compile --- Makefile | 3 +- srcs/ConfigParser.cpp | 293 +++++++++++++++++++++++------------------- srcs/ConfigParser.hpp | 13 +- srcs/MethodType.hpp | 15 +++ srcs/ServerConfig.hpp | 13 +- srcs/Webserv.cpp | 3 + srcs/Webserv.hpp | 10 +- srcs/main.cpp | 6 +- 8 files changed, 209 insertions(+), 147 deletions(-) create mode 100644 srcs/MethodType.hpp diff --git a/Makefile b/Makefile index b8324f3..3e4486d 100644 --- a/Makefile +++ b/Makefile @@ -19,14 +19,13 @@ HEADERS = Webserv.hpp \ LocationConfig.hpp \ Client.hpp \ Server.hpp \ + MethodType.hpp \ DEPENDENCIES = $(HEADERS:%=$(HEADERS_D)/%) SRCS = main.cpp \ Webserv.cpp \ ConfigParser.cpp \ - ServerConfig.cpp \ - LocationConfig.cpp \ DIR_OBJS = builds diff --git a/srcs/ConfigParser.cpp b/srcs/ConfigParser.cpp index 15d3c0c..d1144e9 100644 --- a/srcs/ConfigParser.cpp +++ b/srcs/ConfigParser.cpp @@ -90,9 +90,10 @@ ConfigParser & ConfigParser::operator=(const ConfigParser& rhs) */ -std::vector ConfigParser::parse() +std::vector * ConfigParser::parse() { - std::vector ret; + std::vector * ret = new std::vector(); +// std::vector ret; size_t start = 0; size_t curr = _content.find_first_not_of(" \t\n", 0); @@ -105,19 +106,19 @@ std::vector ConfigParser::parse() // if not here do i need them elsewhere? start = _content.find_first_not_of(" \t\n", curr); curr = _content.find_first_of(" \t\n", start); - std::string key = _conent.substr(start, curr - start); + std::string key = _content.substr(start, curr - start); if (key != "server") throw std::invalid_argument("bad config file arguments"); // Server server = parse_server(&curr); // ret->push_back(server); // why not this? - ret.push_back(parse_server(&curr); + ret->push_back(_parse_server(&curr)); } return (ret); } // might need new names for Prev and Curr, not super descriptive... -ServerConfig ConfigParser::parse_server(size_t *start) +ServerConfig ConfigParser::_parse_server(size_t *start) { ServerConfig ret; size_t curr = _content.find_first_not_of(" \t\n", *start); @@ -133,21 +134,24 @@ ServerConfig ConfigParser::parse_server(size_t *start) // so this moves curr to past the word... std::string key = _get_first_word(&curr); // now curr is on space after 1st word. - switch (key) + if (key == "}") { - case "}": - // why +1 curr is already after it no? - *start = _content.find_first_not_of(" \t\n" curr + 1); - break ; - case "location": - // this does assume we have locations in Server... - // could change the name but it's so clear... - ret.location.push_back(_parse_location(&curr)); - default: - std::string values = _get_rest_of_line(&curr); - // curr now should be \n - // checking for ; in _set_value, check key and value - _set_server_values(&ret, key, values); // handles the throws + // why +1 curr is already after it no? + *start = _content.find_first_not_of(" \t\n", curr + 1); + break ; + } + else if (key == "location") + { + // this does assume we have locations in Server... + // could change the name but it's so clear... + ret.locations.push_back(_parse_location(&curr)); + } + else + { + std::string values = _get_rest_of_line(&curr); + // curr now should be \n + // checking for ; in _set_value, check key and value + _set_server_values(&ret, key, values); // handles the throws } } return (ret); @@ -163,7 +167,7 @@ LocationConfig ConfigParser::_parse_location(size_t *start) if (curr == std::string::npos || _content[curr] != '{') throw std::invalid_argument("bad config file syntax"); - size_t curr = _content.find_first_of(" \t\n", curr + 1); + curr = _content.find_first_of(" \t\n", curr + 1); // if (curr == std::string::npos) // are there other things to check for? // throw std::invalid_argument("bad config file syntax"); while (curr != std::string::npos) @@ -171,17 +175,18 @@ LocationConfig ConfigParser::_parse_location(size_t *start) // so this moves curr to past the word... std::string key = _get_first_word(&curr); // now curr is on space after 1st word. - switch (key) + if (key == "}") { - case "}": - *start = curr; - break ; - default: - std::string values = _get_rest_of_line(&curr); - // curr now should be \n - // checking for ; in _set_value, check key and value + *start = curr; + break ; + } + else + { + std::string values = _get_rest_of_line(&curr); + // curr now should be \n + // checking for ; in _set_value, check key and value - _set_location_values(&ret, key, values); //handles the throws + _set_location_values(&ret, key, values); //handles the throws } } return (ret); @@ -223,94 +228,112 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ // like call substr in split? value = value.substr(0, i - 1); - std::vector tmp_val = ::split(value, ' '); + std::vector tmp_val = split(value, ' '); if (tmp_val.size() == 1) { - switch (key) + if (key == "server_name") { - case "server_name": - server->server_name = tmp_val[0]; - case "listen": - if (tmp_val[0].find_first_of(":") == std::string::npos) - { - // why not store as vector [4] ? - server->host = "0.0.0.0"; - server->value = tmp_val[0]; - } - else - { - // maybe do this differently? - std::vector tmp2 = split(tmp_val[0], ':'); - // i might take issue with this, will see - if (server->host != "" && server->host != tmp2[0]) - throw std::invalid_argument("bad listen"); - server->host = tmp2[0]; - server->port = tmp2[1]; - } - case "root": - server->root = tmp_val[0]; - case "autoindex": - server->autoindex = (tmp_val[0] == "on" ? true : false); - case "client_body_limit": - server->client_body_limit = atoi(tmp_val[0].c_str()); - - case "recv_timeout": - // what is tv_sec and do i need it? + server->server_name = tmp_val[0]; + } + else if (key == "listen") + { + if (tmp_val[0].find_first_of(":") == std::string::npos) + { + // why not store as vector [4] ? + server->host = "0.0.0.0"; + server->port = tmp_val[0]; + } + else + { + // maybe do this differently? + std::vector tmp2 = split(tmp_val[0], ':'); + // i might take issue with this, will see + if (server->host != "" && server->host != tmp2[0]) + throw std::invalid_argument("bad listen"); + server->host = tmp2[0]; + server->port = tmp2[1]; + } + } + else if (key == "root") + { + server->root = tmp_val[0]; + } + else if (key == "autoindex") + { + server->autoindex = (tmp_val[0] == "on" ? true : false); + } + else if (key == "client_body_limit") + { + server->client_body_limit = atoi(tmp_val[0].c_str()); + } + else if (key == "recv_timeout") + { + // what is tv_sec and do i need it? // ok so i don't fully understand this part but ok, keep for now... - server->recv_timeout.tv_sec = atoi(tmp_val[0].c_str()); - case "send_timeout": - server->send_timeout.tv_sec = atoi(tmp_val[0].c_str()); - - default : - throw std::invalid_argument("should only have 1 value"); + server->recv_timeout.tv_sec = atoi(tmp_val[0].c_str()); + } + else if (key == "send_timeout") + { + server->send_timeout.tv_sec = atoi(tmp_val[0].c_str()); + } + else + { + throw std::invalid_argument("should only have 1 value"); // yea ok but it could also be something else like too many // args + } } else if (tmp_val.size() > 1) { - switch (key) + if (key == "index") { - case "index": - // could run more tests on value content but meh... - for (unsigned long i = 0; i != tmp_val.size(); i++) - server->index.push_back(tmp_val[i]); - case "allow_methods": - // might do something different here - // like change how methods are stored? - for (unsigned long i = 0; i != tmp_val.size(); i++) - server->allow_methods.push_back(_str_to_method_type(tmp_val[i])); - case "return": - // could run more checks here too - // like tmp_val.size() must be 2 - // and tmp_val[0] should be a number and tmp_val[1] a string? - server->redirect_status = atoi(tmp_val[0].c_str()); - server->redirect_uri = tmp_val[1]; - case "error_page": - // something more complicated? - // like make sure ints then 1 string? - std::string path = tmp_val[tmp_val.size() - 1]; - for (unsigned long i = 0; i != tmp_val.size() - 1; i++) - { - int status_code = atoi(tmp_val[i].c_str()); - // yea IDK i might not want to store this like that... - if (server->error_pages.find(status_code) != server->error_pages.end()) - continue ; - server->error_pages[status_code] = path; - } - default : - throw std::invalid_argument("wrong number of values"); + // could run more tests on value content but meh... + for (unsigned long i = 0; i != tmp_val.size(); i++) + server->index.push_back(tmp_val[i]); + } + else if (key == "allow_methods") + { + // might do something different here + // like change how methods are stored? + for (unsigned long i = 0; i != tmp_val.size(); i++) + server->allow_methods.push_back(_str_to_method_type(tmp_val[i])); + } + else if (key == "return") + { + // could run more checks here too + // like tmp_val.size() must be 2 + // and tmp_val[0] should be a number and tmp_val[1] a string? + server->redirect_status = atoi(tmp_val[0].c_str()); + server->redirect_uri = tmp_val[1]; + } + else if (key == "error_page") + { + // something more complicated? + // like make sure ints then 1 string? + std::string path = tmp_val[tmp_val.size() - 1]; + for (unsigned long i = 0; i != tmp_val.size() - 1; i++) + { + int status_code = atoi(tmp_val[i].c_str()); + // yea IDK i might not want to store this like that... + if (server->error_pages.find(status_code) != server->error_pages.end()) + continue ; + server->error_pages[status_code] = path; + } + } + else + { + throw std::invalid_argument("wrong number of values"); } } else throw std::invalid_argument("missing value"); - } // again not sure i want an int ret -int ConfigParser::_set_location_values(LocationConfig *location, \ - const std::string key, std::string value) +void ConfigParser::_set_location_values(LocationConfig *location, \ + const std::string key, std::string value) { // check key for ; // check values for ; at end and right number of words depending on key @@ -341,37 +364,44 @@ int ConfigParser::_set_location_values(LocationConfig *location, \ if (tmp_val.size() == 1) { - switch (key) + if (key == "root") { - case "root": - location->root = tmp_val[0]; - case "client_body_limit": - location->client_body_limit = atoi(tmp_val[0].c_str()); - default : - throw std::invalid_argument("should only have 1 argument"); + location->root = tmp_val[0]; + } + else if (key == "client_body_limit") + { + location->client_body_limit = atoi(tmp_val[0].c_str()); + } + else + { + throw std::invalid_argument("should only have 1 argument"); } } else if (tmp_val.size() > 1) { - switch (key) + if (key == "index") + { + for (unsigned long i = 0; i != tmp_val.size(); i++) + location->index.push_back(tmp_val[i]); + } + else if (key == "allow_methods") + { + for (unsigned long i = 0; i != tmp_val.size(); i++) + location->allow_methods.push_back(_str_to_method_type(tmp_val[i])); + } + else if (key == "cgi_info") { - case "index": - for (unsigned long i = 0; i != tmp_val.size(); i++) - location->index.push_back(tmp_val[i]); - case "allow_methods": - for (unsigned long i = 0; i != tmp_val.size(); i++) - location->allow_methods.push_back(_str_to_methodtype(tmp_val[i])); - case "cgi_info": // ok wtf is all this even doing, figure that out - unsigned long i = value.find_first_of(" "); - if (i == std::string::npos) - throw std::invalid_argument("bad config file arguments"); - // ok why an int now, we gotta be more consistent! - int j = value.find_first_not_of(" ", i); - location->cgi_info[value.substr(0, i)] = value.substr(j, value.length()); - default : + unsigned long i = value.find_first_of(" "); + if (i == std::string::npos) throw std::invalid_argument("bad config file arguments"); - + // ok why an int now, we gotta be more consistent! + int j = value.find_first_not_of(" ", i); + location->cgi_info[value.substr(0, i)] = value.substr(j, value.length()); + } + else + { + throw std::invalid_argument("bad config file arguments"); } } else @@ -412,23 +442,20 @@ std::string ConfigParser::_get_rest_of_line(size_t *curr) } -MethodType ConfigParser::_str_to_methodtype(std::string str) +MethodType ConfigParser::_str_to_method_type(std::string str) { - switch (str) - { - case ("GET"): - return GET; - case ("POST"): - return POST; - case ("DELETE"): - return DELETE; - default : - return INVALID; - } + if (str == "GET") + return GET; + else if (str == "POST") + return POST; + else if (str == "DELETE") + return DELETE; + return INVALID; } + void ConfigParser::_print_content() const { std::cout << _content; diff --git a/srcs/ConfigParser.hpp b/srcs/ConfigParser.hpp index 8ef686a..81b1cdf 100644 --- a/srcs/ConfigParser.hpp +++ b/srcs/ConfigParser.hpp @@ -14,6 +14,7 @@ # define CONFIGPARSER_HPP # include "Webserv.hpp" // easier to just do this? +# include "ServerConfig.hpp" // add includes properly @@ -22,6 +23,8 @@ #define MAX_URI_SIZE 64 #define BSIZE 1024 +/* +// this can't be here... enum MethodType { GET, @@ -29,7 +32,7 @@ enum MethodType DELETE, INVALID, }; - +*/ class ConfigParser { @@ -45,11 +48,14 @@ public: // ConfigParser & operator=(const ConfigParser& rhs); // void parse(); // return void cuz throw exceptions. - //std::vector * parse(); // const? - std::vector parse(); // const? + std::vector * parse(); // const? +// std::vector parse(); // const? // other parses? +// i thought if it were an instance of this class you could call +// private member functions from anywhere... + void _print_content() const; private: std::string _content; @@ -76,7 +82,6 @@ private: static MethodType _str_to_method_type(std::string str); // just for testing purposes - void _print_content() const; }; diff --git a/srcs/MethodType.hpp b/srcs/MethodType.hpp new file mode 100644 index 0000000..9c815f5 --- /dev/null +++ b/srcs/MethodType.hpp @@ -0,0 +1,15 @@ + + +#ifndef METHODTYPE_HPP +# define METHODTYPE_HPP + +enum MethodType +{ + GET, + POST, + DELETE, + INVALID, +}; + + +#endif diff --git a/srcs/ServerConfig.hpp b/srcs/ServerConfig.hpp index a6cdc6b..a08d8a1 100644 --- a/srcs/ServerConfig.hpp +++ b/srcs/ServerConfig.hpp @@ -15,6 +15,8 @@ // add includes properly... # include "Webserv.hpp" +# include "MethodType.hpp" +//# include "ConfigParser.hpp" # include "LocationConfig.hpp" // a class that's all public? just so we have options? @@ -63,13 +65,16 @@ public: std::cout << "Server_name: " << server_name << '\n'; std::cout << "root: " << root << '\n'; std::cout << "index: "; - for (int i = 0; i < index.size(); i++) + for (size_t i = 0; i < index.size(); i++) std::cout << index[i] << " "; std::cout << "\nerror_pages: "; - for (int i = 0; i < error_pages.size(); i++) - std::cout << error_pages.first << "--" << error_pages.second << " "; + for(std::map::iterator it = error_pages.begin(); \ + it != error_pages.end(); it++) + std::cout << it->first << "--" << it->second << " "; +// for (size_t i = 0; i < error_pages.size(); i++) +// std::cout << error_pages->first << "--" << error_pages->second << " "; std::cout << "\nallow_methods: "; - for (int i = 0; i < allow_methods.size(); i++) + for (size_t i = 0; i < allow_methods.size(); i++) std::cout << allow_methods[i] << " "; std::cout << "\nskiping Locations for now...\n"; std::cout << "also skiping send_timeout and recv\n"; diff --git a/srcs/Webserv.cpp b/srcs/Webserv.cpp index b98c685..b26964d 100644 --- a/srcs/Webserv.cpp +++ b/srcs/Webserv.cpp @@ -28,6 +28,8 @@ Webserv::Webserv() } */ +// we'll come back to this +/* Webserv::Webserv(std::vector* servers) : _servers(servers) { @@ -42,6 +44,7 @@ Webserv::Webserv(std::vector* servers) throw std::runtime_error("Epoll init"); } } +*/ Webserv::~Webserv() { diff --git a/srcs/Webserv.hpp b/srcs/Webserv.hpp index 68345b6..2eebbaf 100644 --- a/srcs/Webserv.hpp +++ b/srcs/Webserv.hpp @@ -25,7 +25,15 @@ # include "Client.hpp" # include "Server.hpp" +# include "ConfigParser.hpp" +# include "ServerConfig.hpp" +# include "LocationConfig.hpp" +# include "MethodType.hpp" # include // signal +# include +# include +# include +# include # define BUFSIZE 8192 # define TIMEOUT 3000 @@ -63,7 +71,7 @@ class Webserv // Webserv(Webserv const &src); // what should it take as arg, *, &, ? - Webserv(std::vector& servers); +// Webserv(std::vector& servers); ~Webserv(); // Webserv &operator=(Webserv const &rhs); diff --git a/srcs/main.cpp b/srcs/main.cpp index 7cf49d9..5495a18 100644 --- a/srcs/main.cpp +++ b/srcs/main.cpp @@ -20,10 +20,10 @@ int main(int ac, char **av) configParser._print_content(); - std::vector servers = configParser.parse(); +// std::vector* servers = configParser.parse(); - for (int i = 0; i < server.size(); i++) - servers[i].print_all(); +// for (size_t i = 0; i < servers->size(); i++) +// servers[i]->print_all(); // Webserv serv(configParser.parse()); // is this better or worse than using From a5fa5462d46fb59aa342ce684de61bf3dacde93d Mon Sep 17 00:00:00 2001 From: Me Date: Sat, 30 Jul 2022 00:30:40 +0200 Subject: [PATCH 7/9] solid progress today, doesn't compile just yet, so don't know what all my errors are, but i'm happy with the overall logic --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0137954..0b972a4 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ Thumbs.db *.lnk *.zip +builds + ubuntu_tester ubuntu_cgi_tester webserv From 665623c7ee65a87bfaba8b850c081bd4a6748e17 Mon Sep 17 00:00:00 2001 From: Me Date: Sat, 30 Jul 2022 21:08:21 +0200 Subject: [PATCH 8/9] well i think i have the Config Parser working and pretty clean, there might be a few tweaks here and there but looks good, now to integrate it with Webserv --- Makefile | 3 +- big.config | 122 ++++++++++++++++++ default.config | 4 +- srcs/ConfigParser.cpp | 289 ++++++++++++++++++++++-------------------- srcs/Webserv.hpp | 1 + srcs/main.cpp | 14 +- srcs/utils.cpp | 19 +++ srcs/utils.hpp | 10 ++ 8 files changed, 318 insertions(+), 144 deletions(-) create mode 100644 big.config create mode 100644 srcs/utils.cpp create mode 100644 srcs/utils.hpp diff --git a/Makefile b/Makefile index 3e4486d..03abd77 100644 --- a/Makefile +++ b/Makefile @@ -20,13 +20,14 @@ HEADERS = Webserv.hpp \ Client.hpp \ Server.hpp \ MethodType.hpp \ + utils.hpp \ DEPENDENCIES = $(HEADERS:%=$(HEADERS_D)/%) SRCS = main.cpp \ Webserv.cpp \ ConfigParser.cpp \ - + utils.cpp \ DIR_OBJS = builds OBJS = $(SRCS:%.cpp=$(DIR_OBJS)/%.o) diff --git a/big.config b/big.config new file mode 100644 index 0000000..5139c18 --- /dev/null +++ b/big.config @@ -0,0 +1,122 @@ +server { + server_name webserv; + listen 0.0.0.0:4242; + + root ./www/html; + + allow_methods GET; + + autoindex on; + index index.html index2.html; + client_body_limit 4096; + + error_page 404 405 ./www/html/error/error.html; + error_page 500 ./www/html/error/error2.html; + + location /board { + allow_methods GET; + root ./www/html; + } + + location /board/content { + allow_methods GET POST DELETE; + root ./www/html/contents; + index board.html; + cgi_info .php php-cgi; + } + + location /cgi { + allow_methods GET POST; + cgi_info php php-fpm; + } +} + +server { + server_name another_webserv; + listen 0.0.0.0:4242; + + root ./www/html; + + allow_methods GET; + + client_body_limit 256; + + location /board { + allow_methods GET; + root ./www/html; + } + + location /board/content { + allow_methods GET POST DELETE; + root ./www/html/contents; + } + + location /cgi { + allow_methods GET POST; + cgi_info php php-fpm; + } +} + +server { + server_name webserv; + listen 0.0.0.0:4243; + + root ./www/html; + index index.html; + + allow_methods GET; + + autoindex off; + client_body_limit 256 ; + recv_timeout 6; + send_timeout 6; + + location /board { + allow_methods GET DELETE; + root ./www/html; + } + + location /board/post { + allow_methods POST; + root ./www/html/contents; + } + + location /cgi { + allow_methods GET; + cgi_info cgi_tester hello world; + } +} +server { + server_name webserv; + listen 0.0.0.0:4243; + + root ./www/html; + index index.html; + + allow_methods GET; + + autoindex off; + client_body_limit 256 ; + recv_timeout 6; + send_timeout 6; + + location /board { + allow_methods GET DELETE; + root ./www/html; + } + + location /board/post { + allow_methods POST; + root ./www/html/contents; + } + + location /cgi { + allow_methods GET; + cgi_info cgi_tester hello world; + } +} + +server { + listen 0.0.0.0:8000; + return 301 https://profile.intra.42.fr/; +} diff --git a/default.config b/default.config index 8c5ff14..3912ba6 100644 --- a/default.config +++ b/default.config @@ -1,11 +1,13 @@ server { +# this is a comment + server_name our_server; listen 0.0.0.0:80; - index index.html; + index index.html; # this is another comment root ./www/; allow_methods GET; diff --git a/srcs/ConfigParser.cpp b/srcs/ConfigParser.cpp index d1144e9..8fa9e70 100644 --- a/srcs/ConfigParser.cpp +++ b/srcs/ConfigParser.cpp @@ -108,7 +108,7 @@ std::vector * ConfigParser::parse() curr = _content.find_first_of(" \t\n", start); std::string key = _content.substr(start, curr - start); if (key != "server") - throw std::invalid_argument("bad config file arguments"); + throw std::invalid_argument("bad config file arguments 1"); // Server server = parse_server(&curr); // ret->push_back(server); // why not this? @@ -124,7 +124,7 @@ ServerConfig ConfigParser::_parse_server(size_t *start) size_t curr = _content.find_first_not_of(" \t\n", *start); if (curr == std::string::npos || _content[curr] != '{') - throw std::invalid_argument("bad config file syntax"); + throw std::invalid_argument("bad config file syntax 1"); curr = _content.find_first_of(" \t\n", curr + 1); // if (curr == std::string::npos) // are there other things to check for? @@ -162,10 +162,17 @@ ServerConfig ConfigParser::_parse_server(size_t *start) LocationConfig ConfigParser::_parse_location(size_t *start) { LocationConfig ret; - size_t curr = _content.find_first_not_of(" \t\n", *start); + size_t curr = *start; + // start is after the 1st word aka "location" + + ret.path = _get_first_word(&curr); + // in theory now curr should be right after the "path" + + curr = _content.find_first_not_of(" \t\n", curr); + if (curr == std::string::npos || _content[curr] != '{') - throw std::invalid_argument("bad config file syntax"); + throw std::invalid_argument("bad config file syntax 2"); curr = _content.find_first_of(" \t\n", curr + 1); // if (curr == std::string::npos) // are there other things to check for? @@ -206,12 +213,15 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ // check values for ; at end and right number of words depending on key if (key.find_first_of(";") != std::string::npos) - throw std::invalid_argument("bad config file arguments"); + throw std::invalid_argument("bad config file arguments 2"); // there shouldn't be any tabs, right? not between values... if (value.find_first_of("\t") != std::string::npos) - throw std::invalid_argument("bad config file arguments"); - + { + std::cout << value << "\n"; + throw std::invalid_argument("bad config file arguments 3"); + } + size_t i = value.find_first_of(";"); // so you can't have no ; // you can't have just ; @@ -219,116 +229,114 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ // in theory value_find_last_of should find the only ; if (i == std::string::npos || (value.find_last_not_of(" \n")) != i \ || value.compare(";") == 0) - throw std::invalid_argument("bad config file arguments"); + throw std::invalid_argument("bad config file arguments 4"); // we Trim value. // is this valid? // would it be better to shove the result directly in tmp_val? // like call substr in split? - value = value.substr(0, i - 1); + //value = value.substr(0, i - 1); + value = value.substr(0, i); std::vector tmp_val = split(value, ' '); + size_t size = tmp_val.size(); - if (tmp_val.size() == 1) + // would if if be more optimized? + if (size < 1) + throw std::invalid_argument("missing value"); + else if (key == "server_name" && size == 1) { - if (key == "server_name") + server->server_name = tmp_val[0]; + } + else if (key == "listen" && size == 1) + { + if (tmp_val[0].find_first_of(":") == std::string::npos) { - server->server_name = tmp_val[0]; - } - else if (key == "listen") - { - if (tmp_val[0].find_first_of(":") == std::string::npos) - { - // why not store as vector [4] ? - server->host = "0.0.0.0"; - server->port = tmp_val[0]; - } - else - { - // maybe do this differently? - std::vector tmp2 = split(tmp_val[0], ':'); - // i might take issue with this, will see - if (server->host != "" && server->host != tmp2[0]) - throw std::invalid_argument("bad listen"); - server->host = tmp2[0]; - server->port = tmp2[1]; - } - } - else if (key == "root") - { - server->root = tmp_val[0]; - } - else if (key == "autoindex") - { - server->autoindex = (tmp_val[0] == "on" ? true : false); - } - else if (key == "client_body_limit") - { - server->client_body_limit = atoi(tmp_val[0].c_str()); - } - else if (key == "recv_timeout") - { - // what is tv_sec and do i need it? - // ok so i don't fully understand this part but ok, keep for now... - server->recv_timeout.tv_sec = atoi(tmp_val[0].c_str()); - } - else if (key == "send_timeout") - { - server->send_timeout.tv_sec = atoi(tmp_val[0].c_str()); + // why not store as vector [4] ? + server->host = "0.0.0.0"; + server->port = tmp_val[0]; } else { - throw std::invalid_argument("should only have 1 value"); - // yea ok but it could also be something else like too many - // args - + // maybe do this differently? + std::vector tmp2 = split(tmp_val[0], ':'); + // i might take issue with this, will see + if (server->host != "" && server->host != tmp2[0]) + throw std::invalid_argument("bad listen"); + server->host = tmp2[0]; + server->port = tmp2[1]; } } - else if (tmp_val.size() > 1) + else if (key == "root" && size == 1) { - if (key == "index") + server->root = tmp_val[0]; + } + else if (key == "autoindex" && size == 1) + { + server->autoindex = (tmp_val[0] == "on" ? true : false); + } + else if (key == "client_body_limit" && size == 1) + { + server->client_body_limit = atoi(tmp_val[0].c_str()); + } + else if (key == "recv_timeout" && size == 1) + { + // what is tv_sec and do i need it? +// ok so i don't fully understand this part but ok, keep for now... + server->recv_timeout.tv_sec = atoi(tmp_val[0].c_str()); + } + else if (key == "send_timeout" && size == 1) + { + server->send_timeout.tv_sec = atoi(tmp_val[0].c_str()); + } +/* else + { + throw std::invalid_argument("should only have 1 value"); + // yea ok but it could also be something else like too many + // args + + } +*/ + else if (key == "index") + { + // could run more tests on value content but meh... + for (unsigned long i = 0; i != tmp_val.size(); i++) + server->index.push_back(tmp_val[i]); + } + else if (key == "allow_methods") + { + // might do something different here + // like change how methods are stored? + for (unsigned long i = 0; i != tmp_val.size(); i++) + server->allow_methods.push_back(_str_to_method_type(tmp_val[i])); + } + else if (key == "return") + { + // could run more checks here too + // like tmp_val.size() must be 2 + // and tmp_val[0] should be a number and tmp_val[1] a string? + server->redirect_status = atoi(tmp_val[0].c_str()); + server->redirect_uri = tmp_val[1]; + } + else if (key == "error_page") + { + // something more complicated? + // like make sure ints then 1 string? + std::string path = tmp_val[tmp_val.size() - 1]; + for (unsigned long i = 0; i != tmp_val.size() - 1; i++) { - // could run more tests on value content but meh... - for (unsigned long i = 0; i != tmp_val.size(); i++) - server->index.push_back(tmp_val[i]); - } - else if (key == "allow_methods") - { - // might do something different here - // like change how methods are stored? - for (unsigned long i = 0; i != tmp_val.size(); i++) - server->allow_methods.push_back(_str_to_method_type(tmp_val[i])); - } - else if (key == "return") - { - // could run more checks here too - // like tmp_val.size() must be 2 - // and tmp_val[0] should be a number and tmp_val[1] a string? - server->redirect_status = atoi(tmp_val[0].c_str()); - server->redirect_uri = tmp_val[1]; - } - else if (key == "error_page") - { - // something more complicated? - // like make sure ints then 1 string? - std::string path = tmp_val[tmp_val.size() - 1]; - for (unsigned long i = 0; i != tmp_val.size() - 1; i++) - { - int status_code = atoi(tmp_val[i].c_str()); - // yea IDK i might not want to store this like that... - if (server->error_pages.find(status_code) != server->error_pages.end()) - continue ; - server->error_pages[status_code] = path; - } - } - else - { - throw std::invalid_argument("wrong number of values"); + int status_code = atoi(tmp_val[i].c_str()); + // yea IDK i might not want to store this like that... + if (server->error_pages.find(status_code) != server->error_pages.end()) + continue ; + server->error_pages[status_code] = path; } } else - throw std::invalid_argument("missing value"); + { + throw std::invalid_argument("wrong number of values"); + } } // again not sure i want an int ret @@ -339,11 +347,11 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ // check values for ; at end and right number of words depending on key if (key.find_first_of(";") != std::string::npos) - throw std::invalid_argument("bad config file arguments"); + throw std::invalid_argument("bad config file arguments 5"); // there shouldn't be any tabs, right? not between values... if (value.find_first_of("\t") != std::string::npos) - throw std::invalid_argument("bad config file arguments"); + throw std::invalid_argument("bad config file arguments 6"); size_t i = value.find_first_of(";"); // so you can't have no ; @@ -352,61 +360,56 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ // in theory value_find_last_of should find the only ; if (i == std::string::npos || (value.find_last_not_of(" \n")) != i \ || value.compare(";") == 0) - throw std::invalid_argument("bad config file arguments"); + throw std::invalid_argument("bad config file arguments 7"); // we Trim value. // is this valid? // could do like above? - value = value.substr(0, i - 1); + value = value.substr(0, i); std::vector tmp_val = ::split(value, ' '); + size_t size = tmp_val.size(); - if (tmp_val.size() == 1) + if (size < 1) + throw std::invalid_argument("missing value"); + else if (key == "root" && size == 1) { - if (key == "root") - { - location->root = tmp_val[0]; - } - else if (key == "client_body_limit") - { - location->client_body_limit = atoi(tmp_val[0].c_str()); - } - else - { - throw std::invalid_argument("should only have 1 argument"); - } + location->root = tmp_val[0]; } - else if (tmp_val.size() > 1) + else if (key == "client_body_limit" && size == 1) + { + location->client_body_limit = atoi(tmp_val[0].c_str()); + } +/* else + { + throw std::invalid_argument("should only have 1 argument"); + } +*/ + else if (key == "index") + { + for (unsigned long i = 0; i != tmp_val.size(); i++) + location->index.push_back(tmp_val[i]); + } + else if (key == "allow_methods") + { + for (unsigned long i = 0; i != tmp_val.size(); i++) + location->allow_methods.push_back(_str_to_method_type(tmp_val[i])); + } + else if (key == "cgi_info") { - if (key == "index") - { - for (unsigned long i = 0; i != tmp_val.size(); i++) - location->index.push_back(tmp_val[i]); - } - else if (key == "allow_methods") - { - for (unsigned long i = 0; i != tmp_val.size(); i++) - location->allow_methods.push_back(_str_to_method_type(tmp_val[i])); - } - else if (key == "cgi_info") - { // ok wtf is all this even doing, figure that out - unsigned long i = value.find_first_of(" "); - if (i == std::string::npos) - throw std::invalid_argument("bad config file arguments"); + unsigned long i = value.find_first_of(" "); + if (i == std::string::npos) + throw std::invalid_argument("bad config file arguments 8"); // ok why an int now, we gotta be more consistent! - int j = value.find_first_not_of(" ", i); - location->cgi_info[value.substr(0, i)] = value.substr(j, value.length()); - } - else - { - throw std::invalid_argument("bad config file arguments"); - } + int j = value.find_first_not_of(" ", i); + location->cgi_info[value.substr(0, i)] = value.substr(j, value.length()); } else - throw std::invalid_argument("missing a value"); - + { + throw std::invalid_argument("bad config file arguments 9"); + } } // assumes curr is on a space or \t or \n @@ -433,10 +436,18 @@ std::string ConfigParser::_get_rest_of_line(size_t *curr) if ((start = _content.find_first_not_of(" \t\n", *curr)) == std::string::npos) throw std::invalid_argument("bad config file arguments"); + +// std::cout << "start + 4 = " << _content.substr(start, 4) << "\n"; +// std::cout << "curr + 4 = " << _content.substr(*curr, 4) << "\n"; + + if ((*curr = _content.find_first_of("\n", start)) == std::string::npos) throw std::invalid_argument("bad config file arguments"); - std::string values = _content.substr(start, *curr); + std::string values = _content.substr(start, *curr - start); + +// std::cout << "curr + 4 = " << _content.substr(*curr, 4) << "\n"; + std::cout << "rest of Line values: " << values << "\n"; return (values); } diff --git a/srcs/Webserv.hpp b/srcs/Webserv.hpp index 2eebbaf..4d5b039 100644 --- a/srcs/Webserv.hpp +++ b/srcs/Webserv.hpp @@ -29,6 +29,7 @@ # include "ServerConfig.hpp" # include "LocationConfig.hpp" # include "MethodType.hpp" +# include "utils.hpp" # include // signal # include # include diff --git a/srcs/main.cpp b/srcs/main.cpp index 5495a18..c0d1d71 100644 --- a/srcs/main.cpp +++ b/srcs/main.cpp @@ -20,20 +20,28 @@ int main(int ac, char **av) configParser._print_content(); -// std::vector* servers = configParser.parse(); + // i don't love that servers has to be a pointer... + std::vector* servers = configParser.parse(); -// for (size_t i = 0; i < servers->size(); i++) -// servers[i]->print_all(); + // use an iterator you moron + for (std::vector::iterator it = servers->begin(); it < servers->end(); it++) + { + // std::cout << it->server_name << " "; + it->print_all(); + } + // Webserv serv(configParser.parse()); // is this better or worse than using // serv.init_virtual_servers(); // serv.start(); + delete servers; } catch (std::exception& e) { std::cout << e.what() << '\n'; } + return (0); } diff --git a/srcs/utils.cpp b/srcs/utils.cpp new file mode 100644 index 0000000..b66cd62 --- /dev/null +++ b/srcs/utils.cpp @@ -0,0 +1,19 @@ + + +#include "Webserv.hpp" + + + +std::vector split(std::string input, char delimiter) +{ + std::vector answer; + std::stringstream ss(input); + std::string temp; + + while (getline(ss, temp, delimiter)) + answer.push_back(temp); + + return answer; +} + + diff --git a/srcs/utils.hpp b/srcs/utils.hpp new file mode 100644 index 0000000..3f3b48c --- /dev/null +++ b/srcs/utils.hpp @@ -0,0 +1,10 @@ + + + +#ifndef UTILS_HPP +# define UTILS_HPP + + +std::vector split(std::string input, char delimiter); + +#endif From e5c286917228ab90bf2dcf9b71bc24d4e4efe6c6 Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Sun, 31 Jul 2022 00:27:48 +0200 Subject: [PATCH 9/9] Review parsing Eric and Luke. Combined the config parser with Webserv class. --- Makefile | 5 +- default.config | 21 ++- srcs/ConfigParser.cpp | 6 +- srcs/Server.hpp | 32 ---- srcs/Webserv.cpp | 324 -------------------------------------- srcs/Webserv.hpp | 18 ++- srcs/main.cpp | 7 +- srcs/webserv/base.cpp | 3 +- srcs/webserv/init.cpp | 47 ++++-- srcs/webserv/run_loop.cpp | 4 +- 10 files changed, 76 insertions(+), 391 deletions(-) delete mode 100644 srcs/Server.hpp delete mode 100644 srcs/Webserv.cpp diff --git a/Makefile b/Makefile index e454828..912ee6b 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ NAME = webserv CXX = c++ CXXFLAGS = -Wall -Wextra #-Werror -CXXFLAGS += $(HEADERS) +CXXFLAGS += -I$(HEADERS_D) CXXFLAGS += -std=c++98 CXXFLAGS += -g CXXFLAGS += -MMD -MP #header dependencie @@ -12,14 +12,13 @@ CXXFLAGS += -MMD -MP #header dependencie #SHELL = /bin/zsh VPATH = $(SRCS_D) -HEADERS = $(HEADERS_D:%=-I%) +# HEADERS = $(HEADERS_D:%=-I%) HEADERS_D = ./srcs HEADERS = Webserv.hpp \ ConfigParser.hpp \ ServerConfig.hpp \ LocationConfig.hpp \ Client.hpp \ - Server.hpp \ MethodType.hpp \ utils.hpp \ diff --git a/default.config b/default.config index 3912ba6..395acfc 100644 --- a/default.config +++ b/default.config @@ -4,15 +4,26 @@ server { server_name our_server; - listen 0.0.0.0:80; + listen 0.0.0.0:4040; + + + index index.html; # this is another comment + root ./www/; + + allow_methods GET; +} + +server { + +# this is a comment + + server_name our_server; + + listen 0.0.0.0:4047; index index.html; # this is another comment root ./www/; allow_methods GET; - - - - } diff --git a/srcs/ConfigParser.cpp b/srcs/ConfigParser.cpp index 8fa9e70..d7a24a3 100644 --- a/srcs/ConfigParser.cpp +++ b/srcs/ConfigParser.cpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* ConfigParser.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: me +#+ +:+ +#+ */ +/* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/07/13 22:11:17 by me #+# #+# */ -/* Updated: 2022/07/27 19:27:55 by me ### ########.fr */ +/* Updated: 2022/07/30 23:07:42 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ @@ -447,7 +447,7 @@ std::string ConfigParser::_get_rest_of_line(size_t *curr) std::string values = _content.substr(start, *curr - start); // std::cout << "curr + 4 = " << _content.substr(*curr, 4) << "\n"; - std::cout << "rest of Line values: " << values << "\n"; +// std::cout << "rest of Line values: " << values << "\n"; return (values); } diff --git a/srcs/Server.hpp b/srcs/Server.hpp deleted file mode 100644 index a9063d1..0000000 --- a/srcs/Server.hpp +++ /dev/null @@ -1,32 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* Server.hpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: lperrey +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2022/07/24 12:11:07 by lperrey #+# #+# */ -/* Updated: 2022/07/24 12:11:13 by lperrey ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#ifndef SERVER_HPP -# define SERVER_HPP - -# include -# include - -class Server -{ - public: - // Server(Placeholder); - // Server(); - // Server(Server const &src); - // ~Server(); - // Server &operator=(Server const &rhs); - - private: - -}; - -#endif \ No newline at end of file diff --git a/srcs/Webserv.cpp b/srcs/Webserv.cpp deleted file mode 100644 index b26964d..0000000 --- a/srcs/Webserv.cpp +++ /dev/null @@ -1,324 +0,0 @@ - -#include "Webserv.hpp" - -int g_last_signal; -bool g_run; -void signal_handler(int signum) -{ - g_last_signal = signum; -} - -Webserv::Webserv() -{ - std::cerr << "Server init\n"; - - _epfd = ::epoll_create1(0); // (EPOLL_CLOEXEC) for CGI fork ? - if (_epfd == -1) - { - std::perror("err epoll_create1(): "); - throw std::runtime_error("Epoll init"); - } - - std::signal(SIGPIPE, signal_handler); - std::signal(SIGINT, signal_handler); -} - -/* Webserv::Webserv(Webserv const &src) -{ - -} */ - -// we'll come back to this -/* -Webserv::Webserv(std::vector* servers) -: _servers(servers) -{ - // talk to luke about what all this does - // the Param Constructor might need to do dif stuff - std::cout << "Server init\n"; - - _epfd = ::epoll_create1(0); // (EPOLL_CLOEXEC) for CGI fork ? - if (_epfd == -1) - { - std::perror("err epoll_create1(): "); - throw std::runtime_error("Epoll init"); - } -} -*/ - -Webserv::~Webserv() -{ - close(_socket_fd); - close(_epfd); - _close_all_clients(); - std::cerr << "Server destroyed\n"; -} - -/* Webserv & Webserv::operator=(Webserv const &rhs) -{ - -} */ - - /////////////// - // Functions // - -void Webserv::init_virtual_servers() // ADD config param -{ - _socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); // (SOCK_CLOEXEC) for CGI fork ? - if (_socket_fd == -1) - { - std::perror("err socket(): "); - throw std::runtime_error("Socket init"); - } - - _bind(_socket_fd, 80); - _listen(_socket_fd, 512); // 512 arbitrary - - if (_epoll_update(_socket_fd, EPOLLIN, EPOLL_CTL_ADD) == -1) - throw std::runtime_error("Socket init"); -} - -void Webserv::start() -{ - std::cerr << "Server started\n"; - struct epoll_event events[MAX_EVENTS]; - int nfds; - int i; - int count_loop = 0; - - g_run = true; - while (g_run) - { - std::cerr << ++count_loop << "----loop epoll()\n"; - nfds = ::epoll_wait(_epfd, events, MAX_EVENTS, TIMEOUT); - if (nfds == -1) - { - std::perror("err epoll_wait(): "); - throw std::runtime_error("Epoll wait"); - } - else if (nfds == 0) - { - if (!_clients.empty()) - { - std::cerr << "Timeout " << TIMEOUT << "ms\n"; - _close_all_clients(); - } - } - i = 0; - while (i < nfds) - { - // if ((events[i].data.u32 == SERVER_FD) && (events[i].events & EPOLLIN)) // Dont work, see "SERVER_FD" define - if ((events[i].data.fd == _socket_fd) && (events[i].events & EPOLLIN)) - _accept_connection(events[i].data.fd); - else if (events[i].events & EPOLLIN) - _read_request(static_cast(events[i].data.ptr)); - else if (events[i].events & EPOLLOUT) - _send_response(static_cast(events[i].data.ptr)); - ++i; - _actual_client = NULL; - } - } - -} - - - /////////////////////// - // Private Functions // - -void Webserv::_accept_connection(int fd) -{ - struct sockaddr_in addr; - socklen_t addr_len; - int accepted_fd; - - std::cerr << "accept()\n"; - addr_len = sizeof addr; - accepted_fd = ::accept(fd, (sockaddr*)&addr, &addr_len); - if (accepted_fd == -1) - { - std::perror("err accept(): "); - return ; - } - ::fcntl(accepted_fd, F_SETFL, O_NONBLOCK); - - _clients.push_back(Client()); - _clients.back().fd = accepted_fd; - - _epoll_update(accepted_fd, EPOLLIN, EPOLL_CTL_ADD, &_clients.back()); -} - - ////////// - // READ // -void Webserv::_read_request(Client *client) -{ - char buf[BUFSIZE+1]; - ssize_t ret; - _actual_client = client; - - std::cerr << "recv()\n"; - ret = ::recv(client->fd, buf, BUFSIZE, 0); - if (ret == -1) - { - std::perror("err recv(): "); - // if (g_last_signal) - // _handle_last_signal(); - // else - // _close_client(client->fd); - - std::cerr << "client ptr =" << client << "\n"; // DEBUG - std::cerr << "client.fd =" << client->fd << "\n"; // DEBUG - return ; - } - /* - if (ret == BUFSIZE) - // send error like "request too long" to client - */ - - buf[ret] = '\0'; - client->raw_request.append(buf); - - _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD, client); -} - - /////////// - // WRITE // -void Webserv::_send_response(Client *client) -{ - ssize_t ret; - _actual_client = client; - - std::cerr << "send()\n"; - std::cerr << "RAW_REQUEST\n|\n" << client->raw_request << "|\n"; - - ret = ::send(client->fd, MSG_TEST, sizeof MSG_TEST - 1, 0); - if (ret == -1) - { - std::perror("err send(): "); - if (g_last_signal) - _handle_last_signal(); - // else - // _close_client(client->fd); - return ; - } - - _close_client(client->fd); - // if (client->raw_request.find("Connection: keep-alive") == std::string::npos) - // _close_client(client->fd); - // else - // _epoll_update(client->fd, EPOLLIN, EPOLL_CTL_MOD, client); - - client->raw_request.clear(); -} - - - //////////////////// - // Misc functions // - -int Webserv::_epoll_update(int fd, uint32_t events, int op) -{ - struct epoll_event ev; - std::memset(&ev, 0, sizeof ev); - ev.events = events; - ev.data.fd = fd; - if (::epoll_ctl(_epfd, op, fd, &ev) == -1) - { - std::perror("err _epoll_update(): "); - return (-1); - } - return (0); -} - -int Webserv::_epoll_update(int fd, uint32_t events, int op, void *ptr) -{ - struct epoll_event ev; - std::memset(&ev, 0, sizeof ev); - ev.events = events; - ev.data.ptr = ptr; - if (::epoll_ctl(_epfd, op, fd, &ev) == -1) - { - std::perror("err _epoll_update(): "); - return (-1); - } - return (0); -} - -void Webserv::_handle_last_signal() -{ - if (g_last_signal == SIGPIPE) - { - std::cerr << "SIGPIPE\n"; - if (_actual_client) - { - _close_client(_actual_client->fd); - _actual_client = NULL; - } - } - else if (g_last_signal == SIGINT) - { - g_run = false; - } - g_last_signal = 0; -} - -void Webserv::_close_client(int fd) -{ - std::vector::iterator it = _clients.begin(); - while (it != _clients.end()) - { - if (it->fd == fd) - { - // _epoll_update(fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG - if (::close(fd) == -1) - std::perror("err close(): "); - else - std::cerr << "close fd " << fd << "\n"; - _clients.erase(it); - break; - } - ++it; - } -} - -void Webserv::_close_all_clients() -{ - while (!_clients.empty()) - { - // _epoll_update(_clients.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG - if (::close(_clients.back().fd) == -1) - std::perror("err close(): "); - else - std::cerr << "close fd " << _clients.back().fd << "\n"; - _clients.pop_back(); - } -} - - - //////////////////// - // Init functions // - -void Webserv::_bind(int socket_fd, in_port_t port) -{ - // cast invalid ? how to ? - // const struct sockaddr* cast_test = static_cast(addr); - - struct sockaddr_in addr; - std::memset(&addr, 0, sizeof addr); - addr.sin_family = AF_INET; - addr.sin_port = ::htons(port); - addr.sin_addr.s_addr = ::htonl(INADDR_ANY); // htonl useless with 0 value (INADDR_ANY) ? - - if (::bind(socket_fd, (const sockaddr*)&addr, sizeof addr) == -1) - { - std::perror("err bind(): "); - throw std::runtime_error("Socket bind"); - } -} - -void Webserv::_listen(int socket_fd, unsigned int max_connections) -{ - if (::listen(socket_fd, max_connections) == -1) - { - std::perror("err listen(): "); - throw std::runtime_error("Socket listen"); - } -} diff --git a/srcs/Webserv.hpp b/srcs/Webserv.hpp index 015669b..6ba2970 100644 --- a/srcs/Webserv.hpp +++ b/srcs/Webserv.hpp @@ -24,21 +24,25 @@ # include // fcntl # include "Client.hpp" -# include "Server.hpp" -# include "ConfigParser.hpp" # include "ServerConfig.hpp" + +// TODO: A virer +# include "ConfigParser.hpp" # include "LocationConfig.hpp" # include "MethodType.hpp" # include "utils.hpp" +// TODO: A virer + # include // signal # include # include # include # include -# include // itoa +# include // atoi, itoa # include // ifstream char *ft_itoa(int n); # include // access +# include // find extern bool g_run; extern int g_last_signal; @@ -75,14 +79,14 @@ class Webserv // Webserv &operator=(Webserv const &rhs); // init.cpp - void init_virtual_servers(); // ADD config param + void init_virtual_servers(std::vector* servers); // run_loop.cpp void run(); private: int _epfd; - int _socket_fd; // temp, to replace with std::vector - // std::vector _servers; + std::vector _listen_sockets; + std::vector _servers; std::vector _clients; // accept.cpp @@ -105,7 +109,7 @@ class Webserv void _close_client(int fd); void _close_all_clients(); // init.cpp - void _bind(int socket_fd, in_port_t port); + void _bind(int socket_fd, in_port_t port, std::string host); void _listen(int socket_fd, unsigned int max_connections); }; diff --git a/srcs/main.cpp b/srcs/main.cpp index c0d1d71..4c580f3 100644 --- a/srcs/main.cpp +++ b/srcs/main.cpp @@ -34,9 +34,12 @@ int main(int ac, char **av) // Webserv serv(configParser.parse()); // is this better or worse than using -// serv.init_virtual_servers(); -// serv.start(); + Webserv serv; + + // serv.init_virtual_servers(); + serv.init_virtual_servers(servers); delete servers; + serv.run(); } catch (std::exception& e) { diff --git a/srcs/webserv/base.cpp b/srcs/webserv/base.cpp index f4d4e0d..6267ec9 100644 --- a/srcs/webserv/base.cpp +++ b/srcs/webserv/base.cpp @@ -42,7 +42,8 @@ Webserv::Webserv(std::vector* servers) Webserv::~Webserv() { - close(_socket_fd); + //close(_socket_fd); + // TODO : CLOSE ALL _listen_sockets close(_epfd); _close_all_clients(); std::cerr << "Server destroyed\n"; diff --git a/srcs/webserv/init.cpp b/srcs/webserv/init.cpp index 97a3b90..b773964 100644 --- a/srcs/webserv/init.cpp +++ b/srcs/webserv/init.cpp @@ -1,23 +1,43 @@ #include "Webserv.hpp" -void Webserv::init_virtual_servers() // ADD config param +void Webserv::init_virtual_servers(std::vector* servers) { - _socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); // (SOCK_CLOEXEC) for CGI fork ? - if (_socket_fd == -1) + int ret; + std::vector _open_ports; + + _servers = *servers; + _listen_sockets.clear(); + std::vector::iterator it = _servers.begin(); + + while (it != _servers.end()) { - std::perror("err socket()"); - throw std::runtime_error("Socket init"); + if ( std::find(_open_ports.begin(), _open_ports.end(), std::atoi(it->port.data()) ) != _open_ports.end() ) + { + ++it; + continue; + } + + ret = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); // (SOCK_CLOEXEC) for CGI fork ? + if (ret == -1) + { + std::perror("err socket()"); + throw std::runtime_error("Socket init"); + } + _listen_sockets.push_back(ret); + + _bind(_listen_sockets.back(), std::atoi(it->port.data()), it->host); + _listen(_listen_sockets.back(), 512); // 512 arbitrary + + if (_epoll_update(_listen_sockets.back(), EPOLLIN, EPOLL_CTL_ADD) == -1) + throw std::runtime_error("Socket init"); + + _open_ports.push_back(std::atoi(it->port.data())); + ++it; } - - _bind(_socket_fd, 4040); - _listen(_socket_fd, 512); // 512 arbitrary - - if (_epoll_update(_socket_fd, EPOLLIN, EPOLL_CTL_ADD) == -1) - throw std::runtime_error("Socket init"); } -void Webserv::_bind(int socket_fd, in_port_t port) +void Webserv::_bind(int socket_fd, in_port_t port, std::string host) { // cast invalid ? how to ? // const struct sockaddr* cast_test = static_cast(addr); @@ -26,7 +46,8 @@ void Webserv::_bind(int socket_fd, in_port_t port) std::memset(&addr, 0, sizeof addr); addr.sin_family = AF_INET; addr.sin_port = ::htons(port); - addr.sin_addr.s_addr = ::htonl(INADDR_ANY); // htonl useless with 0 value (INADDR_ANY) ? + addr.sin_addr.s_addr = ::htonl(::inet_addr(host.c_str())); + // addr.sin_addr.s_addr = ::htonl(INADDR_ANY); // htonl useless with 0 value (INADDR_ANY) ? if (::bind(socket_fd, (const sockaddr*)&addr, sizeof addr) == -1) { diff --git a/srcs/webserv/run_loop.cpp b/srcs/webserv/run_loop.cpp index 9b466b5..f8ce7cb 100644 --- a/srcs/webserv/run_loop.cpp +++ b/srcs/webserv/run_loop.cpp @@ -34,7 +34,9 @@ void Webserv::run() while (i < nfds) { // if ((events[i].data.u32 == SERVER_FD) && (events[i].events & EPOLLIN)) // Dont work, see "SERVER_FD" define - if ((events[i].data.fd == _socket_fd) && (events[i].events & EPOLLIN)) + // if ((events[i].data.fd == _socket_fd) && (events[i].events & EPOLLIN)) + if ((std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd) != _listen_sockets.end()) + && (events[i].events & EPOLLIN)) _accept_connection(events[i].data.fd); else if (events[i].events & EPOLLIN) _request(static_cast(events[i].data.ptr));