From 665623c7ee65a87bfaba8b850c081bd4a6748e17 Mon Sep 17 00:00:00 2001 From: Me Date: Sat, 30 Jul 2022 21:08:21 +0200 Subject: [PATCH] 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