diff --git a/Makefile b/Makefile index ad045bd..0c35a34 100644 --- a/Makefile +++ b/Makefile @@ -23,9 +23,9 @@ SRCS = main.cpp \ base.cpp init.cpp close.cpp epoll_update.cpp signal.cpp \ accept.cpp request.cpp response.cpp \ run_loop.cpp \ - ConfigParser.cpp \ - ConfigParserUtils.cpp \ - ConfigParserPost.cpp \ + parser.cpp \ + extraConfig.cpp \ + postProcessing.cpp \ utils.cpp \ cgi_script.cpp \ Client.cpp \ diff --git a/default.config b/default.config index 7299a13..beade3c 100644 --- a/default.config +++ b/default.config @@ -10,22 +10,42 @@ server { # client_body_limit 400; index index.html; # this is another comment - root /website; +# root goop; + root www; +# root www/test; # also works +# root /www; # stat does not like this kind of definition +# root /usr; # because it's looking at / aka absolute path +# root ~/Programming/42/group_webserv/www; # didn't like thise either +# root /home/me/Programming/42/group_webserv; # but this is fine + location /test { + root www/test; + index index.html; + } # If not explicitly set, ConfigParser need to genererate a location block # like this for path "/" (based on field "root" and "index" of the server) location / { - root ./www/; + root www; index index.html; + allow_methods DELETE; } - allow_methods GET; + allow_methods GET POST; + + + location /something/long/here { + + } + + location /something/long/here/but/more { + + } # ok in theory if one were to go to /test they would get the index in www # as opposed to the one in /website... - location /test { - root /www; - } +# location /test { +# root /www; +# } } diff --git a/srcs/config/ConfigParser.hpp b/srcs/config/ConfigParser.hpp index c5e29f3..32197eb 100644 --- a/srcs/config/ConfigParser.hpp +++ b/srcs/config/ConfigParser.hpp @@ -26,8 +26,9 @@ # include // cout, cin # include // ifstream //# include // access() -# include // opendir() - +# include // opendir(), doesn't work... +# include // stat(), replaces opendir() don't bother with ERRNO ? +# include // sort() in Post class ConfigParser { @@ -51,6 +52,13 @@ public: // private member functions from anywhere... void _print_content() const; + +// I don't love that this is here but... +// doesn't work use the operator overload +// bool compareLocationConfigs(const LocationConfig &a, const LocationConfig &b); + + + private: std::string _content; @@ -82,11 +90,20 @@ private: void _post_processing(std::vector *servers); + bool _find_root_path_location(std::vector locations); // const? }; +// no idea if it should go here... +//bool compareLocationConfigs(const LocationConfig &a, +// const LocationConfig &b); + + + + + // def needs work line a better name an do i even need this? // should it be in Utils instead? class MyException : public std::invalid_argument diff --git a/srcs/config/ConfigParserPost.cpp b/srcs/config/ConfigParserPost.cpp deleted file mode 100644 index 3968214..0000000 --- a/srcs/config/ConfigParserPost.cpp +++ /dev/null @@ -1,85 +0,0 @@ - - - -#include "ConfigParser.hpp" - - - -void ConfigParser::_post_processing(std::vector *servers) -{ - - // make certain servers default - // fill out empty settings - // if special settings are empty throw - - std::vector::iterator it = servers->begin(); - - while (it != servers->end()) - { - // host and port should already be set - if (it->host == "") - throw std::invalid_argument("Config file needs a host and port"); - - // is that a good default? - if (it->root == "") - it->root = "/"; - if (it->client_body_limit == 0) - it->client_body_limit = 5000; // what is the recomended size? - - // autoindex should already be false by default right? - - // what do we do if Allow methods is left empty? - // all ? - if (it->allow_methods.empty()) - throw std::invalid_argument("No methods specified"); - - - // what to do if index is left empty? index.html? - // ok but i still need to check index, no idea how... - - // if error_pages is left empty, we'll use the defaults which - // i believe are set elsewhere... - - std::vector::iterator it_l = it->locations.begin(); - while (it_l != it->locations.end()) - { - // check that path is feasible... - // opendir? - DIR* dir = opendir(it_l->path.c_str()); - if (dir) - closedir(dir); - else - throw std::invalid_argument("location dir could not be opened"); - - if (it_l->client_body_limit == 0) - it_l->client_body_limit = 5000; // what is the recomended size? - if (it_l->root == "") - it_l->root = it->root; - - // fill out allow methods from server? - if (it_l->allow_methods.empty()) - it_l->allow_methods = it->allow_methods; - - // fill out index from Server? - // or do a bunch of checks on what is in there... - - // same for redirect status i think - - // maybe do something for Cgi_info? - - ++it_l; - } - - - ++it; - } - - // do the defaults at the end? - - -} - - - - - diff --git a/srcs/config/LocationConfig.hpp b/srcs/config/LocationConfig.hpp index 6db5d58..7be88fe 100644 --- a/srcs/config/LocationConfig.hpp +++ b/srcs/config/LocationConfig.hpp @@ -16,7 +16,9 @@ # include # include # include +# include +# include "utils.hpp" // again, struct instead? class LocationConfig @@ -24,12 +26,18 @@ class LocationConfig public: // canonic stuff? + // i thought this might fix the "non static member function" + // shit i'm getting with the comparator... + LocationConfig() {} + ~LocationConfig() {} + + std::string path; int client_body_limit; std::string root; std::vector index; - std::vector allow_methods; + unsigned int allow_methods; std::map cgi_info; // wait if i can call several times, shouldn't it be a map? @@ -40,10 +48,57 @@ public: // au pire you do location / { return 301 http://location; } // and that's how you get the redirect from the root. + void print_all() + { + std::cout << "\nPRINTING A LOCATION\n"; + + std::cout << "Path: " << path << '\n'; + std::cout << "client_body_limit: " << client_body_limit << '\n'; + std::cout << "root: " << root << '\n'; + + std::cout << "Skipping index...\n"; + + std::cout << "Location allow_methods: "; + std::cout << ::http_methods_to_str(allow_methods) << "\n"; + + std::cout << "Skipping redirect status etc...\n"; + + std::cout << "------\n"; + } + +// works a lot better than using a compare function... + bool operator<(const LocationConfig& rhs) const + { + size_t len_lhs = 0; + size_t len_rhs = 0; + size_t tmp = 0; + + // consider adding 1 to path that ends in a file not folder. + + while ((tmp = this->path.find_first_of("/", tmp)) != std::string::npos) + { + std::cout << "tmp_lhs: " << tmp << "\n"; + ++tmp; + ++len_lhs; + } + tmp = 0; + while ((tmp = rhs.path.find_first_of("/", tmp)) != std::string::npos) + { + std::cout << "tmp_rhs: " << tmp << "\n"; + ++tmp; + ++len_rhs; + } + std::cout << "len_lhs: " << len_lhs << " len_rhs: " << len_rhs << (len_lhs < len_rhs) << "\n"; + return (len_lhs < len_rhs); // right comparison ? not <= ? + }; }; +// ok it needs to go somewhere else + + + #endif diff --git a/srcs/config/ServerConfig.hpp b/srcs/config/ServerConfig.hpp index dc658da..bda69ff 100644 --- a/srcs/config/ServerConfig.hpp +++ b/srcs/config/ServerConfig.hpp @@ -32,17 +32,15 @@ public: int client_body_limit; // set to default max if none set - // might be the only one we let slide if bad input... + // might be the only one we let slide if bad input... It remains false... bool autoindex; // we will check the index in the post processing with access() ? std::vector index; std::map error_pages; - // i'm tempted to do something diff for storing method types... // fuck it, you can only call allow_methods once in Server - // once more in each location. - std::vector allow_methods; + unsigned int allow_methods; std::vector locations; @@ -74,10 +72,12 @@ public: // for (size_t i = 0; i < error_pages.size(); i++) // std::cout << error_pages->first << "--" << error_pages->second << " "; std::cout << "\nallow_methods: "; - 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"; + std::cout << ::http_methods_to_str(allow_methods) << "\n"; + +// std::cout << "skiping Locations for now...\n"; + for (std::vector::iterator it = locations.begin(); it < locations.end(); it++) + it->print_all(); + std::cout << "autoindex: " << autoindex << '\n'; std::cout << "client_body_limit: " << client_body_limit << '\n'; // std::cout << "redirect_status: " << redirect_status << '\n'; diff --git a/srcs/config/compareLocationConfigs.cpp b/srcs/config/compareLocationConfigs.cpp new file mode 100644 index 0000000..8851968 --- /dev/null +++ b/srcs/config/compareLocationConfigs.cpp @@ -0,0 +1,27 @@ + + +// prolly get rid of this file... + + +#include "LocationConfig.hpp" + +#include +#include + +// Ok so maybe it can't be a member functions? +bool compareLocationConfigs(const LocationConfig &a, const LocationConfig &b) +{ + int len_a; + int len_b; + size_t tmp = 0; + + // consider adding 1 to path that ends in a file not folder. + + + while ((tmp = a.path.find_first_of("/", tmp)) != std::string::npos) + ++len_a; + tmp = 0; + while ((tmp = b.path.find_first_of("/", tmp)) != std::string::npos) + ++len_b; + return (len_a < len_b); // right comparison ? not <= ? +} diff --git a/srcs/config/ConfigParserUtils.cpp b/srcs/config/extraConfig.cpp similarity index 100% rename from srcs/config/ConfigParserUtils.cpp rename to srcs/config/extraConfig.cpp diff --git a/srcs/config/ConfigParser.cpp b/srcs/config/parser.cpp similarity index 87% rename from srcs/config/ConfigParser.cpp rename to srcs/config/parser.cpp index d754ec6..896f89d 100644 --- a/srcs/config/ConfigParser.cpp +++ b/srcs/config/parser.cpp @@ -105,6 +105,7 @@ ServerConfig ConfigParser::_parse_server(size_t *start) ret.client_body_limit = 0; ret.autoindex = false; + ret.allow_methods = 0; if (curr == std::string::npos || _content[curr] != '{') throw std::invalid_argument("bad config file syntax 1"); @@ -144,6 +145,7 @@ LocationConfig ConfigParser::_parse_location(size_t *start) ret.client_body_limit = 0; ret.redirect_status = 0; + ret.allow_methods = 0; ret.path = _get_first_word(&curr); // in theory now curr should be right after the "path" @@ -176,9 +178,6 @@ LocationConfig ConfigParser::_parse_location(size_t *start) } - - - void ConfigParser::_set_server_values(ServerConfig *server, \ const std::string key, std::string value) { @@ -189,11 +188,15 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ if (size < 1) throw std::invalid_argument("missing value"); - else if (key == "server_name" && size == 1) + else if (key == "server_name" && server->server_name.empty()) { - for (size_t i = 0; i < server->server_name.size(); i++) + // fuck should i be using an iterator? + // for (size_t i = 0; i < server->server_name.size(); i++) + for (std::vector::iterator it = server->server_name.begin(); \ + it < server->server_name.end(); it++) { - if (server->server_name[i].compare(tmp_val[0]) == 0) + // if (server->server_name[i].compare(tmp_val[0]) == 0) + if (it->compare(tmp_val[0]) == 0) throw std::invalid_argument("server_name already exists"); } server->server_name.push_back(tmp_val[0]); @@ -229,12 +232,36 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ } else if (key == "root" && size == 1 && server->root == "") { - DIR* dir = opendir(tmp_val[0].c_str()); + // consider using lstat if you don't? want symlinks included? + // don't bother with include for now. +// std::cout << tmp_val[0] << '\n'; + + // should i also check that it's not a file? no i think S_ISDIR does that right? + const char* folder = tmp_val[0].c_str(); + struct stat sb; + + if (stat(folder, &sb) == 0 && S_ISDIR(sb.st_mode)) + { +// std::cout << "is a Dir\n"; + server->root = tmp_val[0]; + } + else + throw std::invalid_argument("root dir could not be opened"); + +/* DIR* dir = opendir(tmp_val[0].c_str()); if (dir) closedir(dir); else - throw std::invalid_argument("root dir could not be opened"); - server->root = tmp_val[0]; + { + switch (errno) { + case EACCES: printf("Permission denied\n"); break; + case ENOENT: printf("Directory does not exist\n"); break; + case ENOTDIR: printf("is not a directory\n"); break; + default: + throw std::invalid_argument("root dir could not be opened 1"); + } + } +*/ } else if (key == "autoindex" && size == 1) { @@ -258,14 +285,14 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ for (unsigned long i = 0; i != tmp_val.size(); i++) server->index.push_back(tmp_val[i]); } - else if (key == "allow_methods" && server->allow_methods.empty()) + else if (key == "allow_methods" && server->allow_methods == 0) { for (unsigned long i = 0; i != tmp_val.size(); i++) { http_method m = ::str_to_http_method(tmp_val[i]); if (m == UNKNOWN) throw std::invalid_argument("not a valid method"); - server->allow_methods.push_back(m); + server->allow_methods |= m; } } else if (key == "error_page") @@ -323,12 +350,16 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ throw std::invalid_argument("missing value"); else if (key == "root" && size == 1 && location->root == "") { - DIR* dir = opendir(tmp_val[0].c_str()); - if (dir) - closedir(dir); + const char* folder = tmp_val[0].c_str(); + struct stat sb; + + if (stat(folder, &sb) == 0 && S_ISDIR(sb.st_mode)) + { +// std::cout << "is a Dir\n"; + location->root = tmp_val[0]; + } else throw std::invalid_argument("root dir could not be opened"); - location->root = tmp_val[0]; } else if (key == "client_body_limit" && size == 1 \ && location->client_body_limit == 0) @@ -343,14 +374,14 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ for (unsigned long i = 0; i != tmp_val.size(); i++) location->index.push_back(tmp_val[i]); } - else if (key == "allow_methods" && location->allow_methods.empty()) + else if (key == "allow_methods" && location->allow_methods == 0) { for (unsigned long i = 0; i != tmp_val.size(); i++) { http_method m = ::str_to_http_method(tmp_val[i]); if (m == UNKNOWN) throw std::invalid_argument("not a valid method"); - location->allow_methods.push_back(m); + location->allow_methods |= m; } } else if (key == "cgi_info") diff --git a/srcs/config/postProcessing.cpp b/srcs/config/postProcessing.cpp new file mode 100644 index 0000000..e9971db --- /dev/null +++ b/srcs/config/postProcessing.cpp @@ -0,0 +1,161 @@ + + + +#include "ConfigParser.hpp" + +// technically doesn't belong to ConfigParser or any other class +// adding static in front doesn't work... +/* +bool compareLocationConfigs(const LocationConfig &a, const LocationConfig &b) +{ + int len_a; + int len_b; + size_t tmp = 0; + + // consider adding 1 to path that ends in a file not folder. + + + while ((tmp = a.path.find_first_of("/", tmp)) != std::string::npos) + ++len_a; + tmp = 0; + while ((tmp = b.path.find_first_of("/", tmp)) != std::string::npos) + ++len_b; + return (len_a < len_b); // right comparison ? not <= ? +} +*/ + + + + +void ConfigParser::_post_processing(std::vector *servers) +{ + + // make certain servers default + // fill out empty settings + // if special settings are empty throw + + std::vector::iterator it = servers->begin(); + + while (it != servers->end()) + { + // host and port are Mandatory + if (it->host == "") + throw std::invalid_argument("Config file needs a host and port"); + + // root is mandatory + if (it->root == "") + throw std::invalid_argument("Config file needs a root"); + + if (it->client_body_limit == 0) + it->client_body_limit = 5000; // what is the recomended size? + + // autoindex is False by Default + + // if Allow methodes not specified we set to ALL + if (it->allow_methods == UNKNOWN) // in this case that means nothing... + it->allow_methods = ALL_METHODS; + + if (it->index.empty()) + throw std::invalid_argument("Config file needs an Index"); + + + + // if error_pages is left empty, we'll use the defaults which + // i believe are set elsewhere... + + +// actually do this at the end, once we know if there aren't any locations + // with path / +/* if (!_find_root_path_location(it->locations)) + { + LocationConfig tmp; + + tmp.path = "/"; + tmp.client_body_limit = 5000; // figur out correct amount + tmp.root = it->root; + tmp.index = it->index; + tmp.allow_methods = it->allow_methods; + tmp.redirect_status = 0; + it->locations.push_back(tmp); + } +*/ + std::vector::iterator it_l = it->locations.begin(); + +// first check locations we have + while (it_l != it->locations.end()) + { + // opendir() doesn't work for some reason... + // this doens't work yet cuz the path needs to be relative and stat doesn't like / before... +/* const char* folder = it_l->path.c_str(); + struct stat sb; + + if (stat(folder, &sb) == 0 && S_ISDIR(sb.st_mode)) + { +// std::cout << "is a Dir\n"; +// it_l->path = it_lpath; + // yea nothing happens, i guess i can change how the if conditions work... + } + else + throw std::invalid_argument("location dir could not be opened"); +*/ + + + + if (it_l->client_body_limit == 0) + it_l->client_body_limit = 5000; // what is the recomended size? + if (it_l->root == "") + it_l->root = it->root; + + // if Allow methodes not specified we set to Server methods + if (it_l->allow_methods == UNKNOWN) // in this case that means nothing... + it_l->allow_methods = it->allow_methods; + + // fill out index from Server? + // or do a bunch of checks on what is in there... + if (it_l->index.empty()) + it_l->index = it->index; // right? + + // same for redirect status i think + + // maybe do something for Cgi_info? + + ++it_l; + } + +// Then put locations in order... +// may change how the order is set later + +// ok we can sort in order and reverse... + + std::cout << "made it to sorting...\n"; +// std::sort(it->locations.begin(), it->locations.end(), compareLocationConfigs); + std::sort(it->locations.begin(), it->locations.end()); + +// for some reason no need to reverse... +// std::reverse(it->locations.begin(), it->locations.end()); + + + ++it; + } + + // do the defaults at the end? + + +} + +bool ConfigParser::_find_root_path_location(std::vector locations) +{ + std::vector::iterator it = locations.begin(); + + while (it != locations.end()) + { + if (it->path.compare("/") == 0) + { + std::cout << "in compare: " << it->path << " -- "; + return true; + } + ++it; + } + return false; +} + diff --git a/srcs/utils.cpp b/srcs/utils.cpp index 73c1606..fc22095 100644 --- a/srcs/utils.cpp +++ b/srcs/utils.cpp @@ -60,6 +60,8 @@ http_method str_to_http_method(std::string &str) return POST; else if (str == "DELETE") return DELETE; + else if (str == "ALL_METHODS") + return ALL_METHODS; return UNKNOWN; } diff --git a/srcs/utils.hpp b/srcs/utils.hpp index c035cfb..a0215fc 100644 --- a/srcs/utils.hpp +++ b/srcs/utils.hpp @@ -7,6 +7,7 @@ # include # include // atoi + // enum http_method // { // UNKNOWN = 0b00000000, @@ -33,4 +34,5 @@ std::string trim(std::string str, char c); http_method str_to_http_method(std::string &str); std::string http_methods_to_str(unsigned int methods); + #endif diff --git a/www/test/index.html b/www/test/index.html new file mode 100644 index 0000000..bc65643 --- /dev/null +++ b/www/test/index.html @@ -0,0 +1,11 @@ + + + + Le Webserv + + +

Le index (˘ ͜ʖ˘)

+
+

(˚3˚)

+ + \ No newline at end of file