From fef26aee5b99a3260955a6f63053498908e5831a Mon Sep 17 00:00:00 2001 From: Me Date: Wed, 3 Aug 2022 18:56:34 +0200 Subject: [PATCH 01/21] getting ready to pull --- default.config | 10 +++++++++- srcs/{ => config}/ConfigParser.cpp | 0 srcs/{ => config}/ConfigParser.hpp | 0 srcs/{ => config}/ConfigParserPost.cpp | 0 srcs/{ => config}/ConfigParserUtils.cpp | 0 srcs/{ => config}/LocationConfig.hpp | 0 srcs/{ => config}/ServerConfig.hpp | 0 7 files changed, 9 insertions(+), 1 deletion(-) rename srcs/{ => config}/ConfigParser.cpp (100%) rename srcs/{ => config}/ConfigParser.hpp (100%) rename srcs/{ => config}/ConfigParserPost.cpp (100%) rename srcs/{ => config}/ConfigParserUtils.cpp (100%) rename srcs/{ => config}/LocationConfig.hpp (100%) rename srcs/{ => config}/ServerConfig.hpp (100%) diff --git a/default.config b/default.config index a3de0b3..f0d3a68 100644 --- a/default.config +++ b/default.config @@ -10,8 +10,16 @@ server { # client_body_limit 400; index index.html; # this is another comment - root ./www/; + root /website; allow_methods GET; + + +# 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; + } + } diff --git a/srcs/ConfigParser.cpp b/srcs/config/ConfigParser.cpp similarity index 100% rename from srcs/ConfigParser.cpp rename to srcs/config/ConfigParser.cpp diff --git a/srcs/ConfigParser.hpp b/srcs/config/ConfigParser.hpp similarity index 100% rename from srcs/ConfigParser.hpp rename to srcs/config/ConfigParser.hpp diff --git a/srcs/ConfigParserPost.cpp b/srcs/config/ConfigParserPost.cpp similarity index 100% rename from srcs/ConfigParserPost.cpp rename to srcs/config/ConfigParserPost.cpp diff --git a/srcs/ConfigParserUtils.cpp b/srcs/config/ConfigParserUtils.cpp similarity index 100% rename from srcs/ConfigParserUtils.cpp rename to srcs/config/ConfigParserUtils.cpp diff --git a/srcs/LocationConfig.hpp b/srcs/config/LocationConfig.hpp similarity index 100% rename from srcs/LocationConfig.hpp rename to srcs/config/LocationConfig.hpp diff --git a/srcs/ServerConfig.hpp b/srcs/config/ServerConfig.hpp similarity index 100% rename from srcs/ServerConfig.hpp rename to srcs/config/ServerConfig.hpp From 3d46505411f744baea78056603824fbc3619e264 Mon Sep 17 00:00:00 2001 From: Me Date: Thu, 4 Aug 2022 01:09:40 +0200 Subject: [PATCH 02/21] well, restructured things a bit, but mostly started trying to sort LocationConfigs, it is sort of going well, good ideas, implementations is still a bit lacking... --- Makefile | 6 +- default.config | 32 +++- srcs/config/ConfigParser.hpp | 21 ++- srcs/config/ConfigParserPost.cpp | 85 --------- srcs/config/LocationConfig.hpp | 57 ++++++- srcs/config/ServerConfig.hpp | 16 +- srcs/config/compareLocationConfigs.cpp | 27 +++ ...{ConfigParserUtils.cpp => extraConfig.cpp} | 0 srcs/config/{ConfigParser.cpp => parser.cpp} | 65 +++++-- srcs/config/postProcessing.cpp | 161 ++++++++++++++++++ srcs/utils.cpp | 2 + srcs/utils.hpp | 2 + www/test/index.html | 11 ++ 13 files changed, 363 insertions(+), 122 deletions(-) delete mode 100644 srcs/config/ConfigParserPost.cpp create mode 100644 srcs/config/compareLocationConfigs.cpp rename srcs/config/{ConfigParserUtils.cpp => extraConfig.cpp} (100%) rename srcs/config/{ConfigParser.cpp => parser.cpp} (87%) create mode 100644 srcs/config/postProcessing.cpp create mode 100644 www/test/index.html 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 From ca8427262d9cb6d6efdac23fdd642073929bafdc Mon Sep 17 00:00:00 2001 From: Me Date: Thu, 4 Aug 2022 01:41:19 +0200 Subject: [PATCH 03/21] wrote a tiny thing to improve the operator< overlaod, will test tomorrow --- srcs/config/LocationConfig.hpp | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/srcs/config/LocationConfig.hpp b/srcs/config/LocationConfig.hpp index 7be88fe..ad1465d 100644 --- a/srcs/config/LocationConfig.hpp +++ b/srcs/config/LocationConfig.hpp @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/07/23 16:08:00 by me #+# #+# */ -/* Updated: 2022/08/02 14:06:07 by lperrey ### ########.fr */ +/* Updated: 2022/08/04 01:40:40 by me ### ########.fr */ /* */ /* ************************************************************************** */ @@ -67,6 +67,8 @@ public: } // works a lot better than using a compare function... +// but it still doesn't work... +// problem is the logic bool operator<(const LocationConfig& rhs) const { size_t len_lhs = 0; @@ -75,6 +77,15 @@ public: // consider adding 1 to path that ends in a file not folder. + // What are the rules... + // / is smaller than /test + // and /test/test1 is bigger than test + // so we want to count / + + len_lhs = _count_chars(this->path); + len_rhs = _count_chars(rhs.path); + +/* while ((tmp = this->path.find_first_of("/", tmp)) != std::string::npos) { std::cout << "tmp_lhs: " << tmp << "\n"; @@ -88,11 +99,30 @@ public: ++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 <= ? }; + size_t _count_chars(std::string str) + { + const char *tmp = str.c_str(); + size_t i = 0; + size_t count = 0; + + while (i < str.lenght()) + { + if (tmp[i] == '/') + ++count; + ++i; + } + + return (count); + } + + + }; // ok it needs to go somewhere else From fce1bcbecea24691544ffe1afa6cd2ee6e75c8f0 Mon Sep 17 00:00:00 2001 From: Me Date: Thu, 4 Aug 2022 16:45:12 +0200 Subject: [PATCH 04/21] well, the location sorter is better, but i don't understand why, kinda by accident, will try to figure it out --- default.config | 2 -- srcs/config/LocationConfig.hpp | 44 +++++++++++++++++++++++++------ srcs/config/postProcessing.cpp | 47 +++++++++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 11 deletions(-) diff --git a/default.config b/default.config index beade3c..096b35f 100644 --- a/default.config +++ b/default.config @@ -34,11 +34,9 @@ server { location /something/long/here { - } location /something/long/here/but/more { - } diff --git a/srcs/config/LocationConfig.hpp b/srcs/config/LocationConfig.hpp index ad1465d..07ce034 100644 --- a/srcs/config/LocationConfig.hpp +++ b/srcs/config/LocationConfig.hpp @@ -71,9 +71,11 @@ public: // problem is the logic bool operator<(const LocationConfig& rhs) const { - size_t len_lhs = 0; - size_t len_rhs = 0; - size_t tmp = 0; +// size_t len_lhs = 0; +// size_t len_rhs = 0; + int len_lhs = 0; + int len_rhs = 0; +// size_t tmp = 0; // consider adding 1 to path that ends in a file not folder. @@ -82,8 +84,28 @@ public: // and /test/test1 is bigger than test // so we want to count / - len_lhs = _count_chars(this->path); - len_rhs = _count_chars(rhs.path); +// len_lhs = _count_chars(this->path); +// len_rhs = _count_chars(rhs.path); + + const char *tmp1 = this->path.c_str(); + size_t i = 0; + + while (tmp1[i]) + { + if (tmp1[i] == '/') + ++len_lhs; + ++i; + } + + const char *tmp2 = rhs.path.c_str(); + i = 0; + + while (tmp2[i]) + { + if (tmp2[i] == '/') + ++len_rhs; + ++i; + } /* while ((tmp = this->path.find_first_of("/", tmp)) != std::string::npos) @@ -100,11 +122,17 @@ public: ++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 <= ? + std::cout << "len_lhs: " << len_lhs << " len_rhs: " << len_rhs \ + << " bool res: " << (len_lhs > len_rhs) << "\n"; + // i honestly can't tell you how or why but using > rather than < + // fixed all my problems + // the fact that the bool was always 0 before, and the correct order + // i want... super weird... + return (len_lhs > len_rhs); // right comparison ? not <= ? }; +/* size_t _count_chars(std::string str) { const char *tmp = str.c_str(); @@ -120,7 +148,7 @@ public: return (count); } - +*/ }; diff --git a/srcs/config/postProcessing.cpp b/srcs/config/postProcessing.cpp index e9971db..0b0cfcf 100644 --- a/srcs/config/postProcessing.cpp +++ b/srcs/config/postProcessing.cpp @@ -24,8 +24,25 @@ bool compareLocationConfigs(const LocationConfig &a, const LocationConfig &b) } */ +/* +class spec_int +{ +public: + spec_int() {} + spec_int(int i): i(i){} + ~spec_int() {} +// spec_int(int start, int num) +// { + +// } - + int i; + bool operator<(const spec_int &a, const spec_int &b) + { + return (a.i < b.i); + } +} +*/ void ConfigParser::_post_processing(std::vector *servers) { @@ -135,6 +152,34 @@ void ConfigParser::_post_processing(std::vector *servers) // std::reverse(it->locations.begin(), it->locations.end()); + +/* +// let's test sort + int myints[] = {32,71,12,45,26,80,53,33}; +// std::vector myvector (myints, myints+8); +// std::vector myvector(10, 5); + std::vector myvector; + + myvector.resize(6); + + myvector[0].i = 32; + myvector[1].i = 71; + myvector[2].i = 12; + myvector[3].i = 45; + myvector[4].i = 26; + myvector[5].i = 80; + + + std::sort(myvector.begin(), myvector.end()); + + std::cout << "myvector contains:"; +// for (std::vector::iterator it=myvector.begin(); it!=myvector.end(); ++it) + for (std::vector::iterator it=myvector.begin(); it!=myvector.end(); ++it) + std::cout << ' ' << *it; + std::cout << '\n'; +*/ + + ++it; } From f7e6b618115d69ba61fb781a9b7edc4a44ce487f Mon Sep 17 00:00:00 2001 From: Eric LAZO Date: Thu, 4 Aug 2022 19:33:38 +0200 Subject: [PATCH 05/21] LocationConfig sorter works as intended, tho should prolly check things thoroughly later --- srcs/config/LocationConfig.hpp | 70 ++++++++-------------------------- srcs/config/postProcessing.cpp | 32 +--------------- 2 files changed, 16 insertions(+), 86 deletions(-) diff --git a/srcs/config/LocationConfig.hpp b/srcs/config/LocationConfig.hpp index 07ce034..6d1478d 100644 --- a/srcs/config/LocationConfig.hpp +++ b/srcs/config/LocationConfig.hpp @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/07/23 16:08:00 by me #+# #+# */ -/* Updated: 2022/08/04 01:40:40 by me ### ########.fr */ +/* Updated: 2022/08/04 19:32:40 by erlazo ### ########.fr */ /* */ /* ************************************************************************** */ @@ -71,11 +71,9 @@ public: // problem is the logic bool operator<(const LocationConfig& rhs) const { -// size_t len_lhs = 0; -// size_t len_rhs = 0; - int len_lhs = 0; - int len_rhs = 0; -// size_t tmp = 0; + int comp_lhs = 0; + int comp_rhs = 0; + size_t tmp = 0; // consider adding 1 to path that ends in a file not folder. @@ -84,72 +82,34 @@ public: // and /test/test1 is bigger than test // so we want to count / -// len_lhs = _count_chars(this->path); -// len_rhs = _count_chars(rhs.path); - const char *tmp1 = this->path.c_str(); - size_t i = 0; - - while (tmp1[i]) - { - if (tmp1[i] == '/') - ++len_lhs; - ++i; - } - - const char *tmp2 = rhs.path.c_str(); - i = 0; - - while (tmp2[i]) - { - if (tmp2[i] == '/') - ++len_rhs; - ++i; - } - -/* while ((tmp = this->path.find_first_of("/", tmp)) != std::string::npos) { - std::cout << "tmp_lhs: " << tmp << "\n"; ++tmp; - ++len_lhs; + ++comp_lhs; } + if (path[path.find_last_of("/") + 1] != '\0') + ++comp_lhs; tmp = 0; while ((tmp = rhs.path.find_first_of("/", tmp)) != std::string::npos) { - std::cout << "tmp_rhs: " << tmp << "\n"; ++tmp; - ++len_rhs; + ++comp_rhs; } -*/ - std::cout << "len_lhs: " << len_lhs << " len_rhs: " << len_rhs \ - << " bool res: " << (len_lhs > len_rhs) << "\n"; + if (rhs.path[rhs.path.find_last_of("/") + 1] != '\0') + ++comp_rhs; + + std::cout << "comp_lhs: " << comp_lhs << " comp_rhs: " << comp_rhs \ + << " bool res: " << (comp_lhs > comp_rhs) << "\n"; // i honestly can't tell you how or why but using > rather than < // fixed all my problems // the fact that the bool was always 0 before, and the correct order // i want... super weird... - return (len_lhs > len_rhs); // right comparison ? not <= ? + // return (comp_lhs > comp_rhs); // right comparison ? not <= ? + return (comp_lhs < comp_rhs); // right comparison ? not <= ? }; -/* - size_t _count_chars(std::string str) - { - const char *tmp = str.c_str(); - size_t i = 0; - size_t count = 0; - - while (i < str.lenght()) - { - if (tmp[i] == '/') - ++count; - ++i; - } - - return (count); - } -*/ - }; diff --git a/srcs/config/postProcessing.cpp b/srcs/config/postProcessing.cpp index 0b0cfcf..8fbeb98 100644 --- a/srcs/config/postProcessing.cpp +++ b/srcs/config/postProcessing.cpp @@ -139,8 +139,6 @@ void ConfigParser::_post_processing(std::vector *servers) ++it_l; } -// Then put locations in order... -// may change how the order is set later // ok we can sort in order and reverse... @@ -148,38 +146,10 @@ void ConfigParser::_post_processing(std::vector *servers) // 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()); + std::reverse(it->locations.begin(), it->locations.end()); -/* -// let's test sort - int myints[] = {32,71,12,45,26,80,53,33}; -// std::vector myvector (myints, myints+8); -// std::vector myvector(10, 5); - std::vector myvector; - - myvector.resize(6); - - myvector[0].i = 32; - myvector[1].i = 71; - myvector[2].i = 12; - myvector[3].i = 45; - myvector[4].i = 26; - myvector[5].i = 80; - - - std::sort(myvector.begin(), myvector.end()); - - std::cout << "myvector contains:"; -// for (std::vector::iterator it=myvector.begin(); it!=myvector.end(); ++it) - for (std::vector::iterator it=myvector.begin(); it!=myvector.end(); ++it) - std::cout << ' ' << *it; - std::cout << '\n'; -*/ - - ++it; } From 9ac14aa1aa1e07a3ab44b7cc9e22248fbd2abfce Mon Sep 17 00:00:00 2001 From: Me Date: Fri, 5 Aug 2022 03:42:42 +0200 Subject: [PATCH 06/21] Well we learned a lot from Nginx, starting to incorporate some, but hoping for feedback before i do most of that, instead worked on improving the location sorter and checking that locations paths are valid, close but not quite done --- default.config | 15 +++++++--- srcs/config/LocationConfig.hpp | 36 ++++++++++++++++++++++++ srcs/config/parser.cpp | 30 +++++++++++++++++--- srcs/config/postProcessing.cpp | 51 ++++------------------------------ www/test/something.html | 11 ++++++++ 5 files changed, 90 insertions(+), 53 deletions(-) create mode 100644 www/test/something.html diff --git a/default.config b/default.config index 096b35f..3a20f6b 100644 --- a/default.config +++ b/default.config @@ -10,8 +10,9 @@ server { # client_body_limit 400; index index.html; # this is another comment +# i think root requires leading / # root goop; - root www; + 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 @@ -19,21 +20,27 @@ server { # root /home/me/Programming/42/group_webserv; # but this is fine location /test { - root www/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 POST; + location /test/something.html { + allow_methods GET POST DELETE; + } - location /something/long/here { +# location /something/long/here { +# } + + location /something/long { } location /something/long/here/but/more { diff --git a/srcs/config/LocationConfig.hpp b/srcs/config/LocationConfig.hpp index 6d1478d..69f6780 100644 --- a/srcs/config/LocationConfig.hpp +++ b/srcs/config/LocationConfig.hpp @@ -17,6 +17,10 @@ # include # include # include +# include // stat() + +# include // printf(), gotta go + # include "utils.hpp" @@ -99,6 +103,38 @@ public: if (rhs.path[rhs.path.find_last_of("/") + 1] != '\0') ++comp_rhs; + // ok now we need to add a thing where we check for files vs folders + if (comp_lhs == comp_rhs) + { + std::cout << "locations are equal\n"; + std::string tmp_path_lhs = root + path; + std::cout << "root + path: " << tmp_path_lhs << '\n'; + + // const char *c_path_lhs = (root + path).substr(1).c_str(); +// could the problem be that i'm in the .hpp ? + const char *c_path_lhs = tmp_path_lhs.substr(1).c_str(); + const char *c_path_rhs = (rhs.root + rhs.path).substr(1).c_str(); + + printf("lhs path: %s\n", c_path_lhs); + printf("rhs path: %s\n", c_path_rhs); + + struct stat sl; + struct stat sr; + + if (stat(c_path_lhs, &sl) == 0 && S_ISREG(sl.st_mode)) + { + std::cout << "lhs is a file\n"; + --comp_lhs; + } + if (stat(c_path_rhs, &sr) == 0 && S_ISREG(sr.st_mode)) + { + std::cout << "rhs is a file\n"; + --comp_rhs; + } + // do i need to free c_path's ??? + } + + std::cout << "comp_lhs: " << comp_lhs << " comp_rhs: " << comp_rhs \ << " bool res: " << (comp_lhs > comp_rhs) << "\n"; // i honestly can't tell you how or why but using > rather than < diff --git a/srcs/config/parser.cpp b/srcs/config/parser.cpp index 896f89d..2e4e28a 100644 --- a/srcs/config/parser.cpp +++ b/srcs/config/parser.cpp @@ -146,7 +146,12 @@ LocationConfig ConfigParser::_parse_location(size_t *start) ret.client_body_limit = 0; ret.redirect_status = 0; ret.allow_methods = 0; + +// path must have a leading / else move on to next location + // i guess we'll be strict cuz can't return (NULL); or NUL... ret.path = _get_first_word(&curr); + if (ret.path[0] != '/') + throw std::invalid_argument("Location path require a leading /"); // in theory now curr should be right after the "path" curr = _content.find_first_not_of(" \t\n", curr); @@ -178,6 +183,9 @@ LocationConfig ConfigParser::_parse_location(size_t *start) } +#include + + void ConfigParser::_set_server_values(ServerConfig *server, \ const std::string key, std::string value) { @@ -232,22 +240,33 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ } else if (key == "root" && size == 1 && server->root == "") { - // consider using lstat if you don't? want symlinks included? + if (tmp_val[0][0] != '/') + throw std::invalid_argument("Root requires leading /"); + + // unclear if this is always true? might only be true in Server + // but not in Locations? idk... + //i think it does, i must have read wrong somewhere... + + + // don't bother using lstat // 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(); + const char* folder = tmp_val[0].substr(1).c_str(); struct stat sb; + printf("folder:%s\n", folder); + 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"); + throw std::invalid_argument("root dir could not be opened 1"); + // do i need to free folder? /* DIR* dir = opendir(tmp_val[0].c_str()); if (dir) closedir(dir); @@ -350,7 +369,10 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ throw std::invalid_argument("missing value"); else if (key == "root" && size == 1 && location->root == "") { - const char* folder = tmp_val[0].c_str(); + if (tmp_val[0][0] != '/') + throw std::invalid_argument("Root requires leading /"); + + const char* folder = tmp_val[0].substr(1).c_str(); struct stat sb; if (stat(folder, &sb) == 0 && S_ISDIR(sb.st_mode)) diff --git a/srcs/config/postProcessing.cpp b/srcs/config/postProcessing.cpp index 8fbeb98..c17e876 100644 --- a/srcs/config/postProcessing.cpp +++ b/srcs/config/postProcessing.cpp @@ -3,47 +3,6 @@ #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 <= ? -} -*/ - -/* -class spec_int -{ -public: - spec_int() {} - spec_int(int i): i(i){} - ~spec_int() {} -// spec_int(int start, int num) -// { - -// } - - int i; - bool operator<(const spec_int &a, const spec_int &b) - { - return (a.i < b.i); - } -} -*/ - void ConfigParser::_post_processing(std::vector *servers) { @@ -83,7 +42,7 @@ void ConfigParser::_post_processing(std::vector *servers) // actually do this at the end, once we know if there aren't any locations // with path / -/* if (!_find_root_path_location(it->locations)) + if (!_find_root_path_location(it->locations)) { LocationConfig tmp; @@ -95,7 +54,7 @@ void ConfigParser::_post_processing(std::vector *servers) tmp.redirect_status = 0; it->locations.push_back(tmp); } -*/ + std::vector::iterator it_l = it->locations.begin(); // first check locations we have @@ -103,9 +62,11 @@ void ConfigParser::_post_processing(std::vector *servers) { // 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(); + const char* folder = it_l->path.substr(1).c_str(); struct stat sb; +// wait also have to add checks in for files! +// also need to add the root to the path!!!!!!!! see LocationConfig and parser if (stat(folder, &sb) == 0 && S_ISDIR(sb.st_mode)) { // std::cout << "is a Dir\n"; @@ -114,7 +75,7 @@ void ConfigParser::_post_processing(std::vector *servers) } else throw std::invalid_argument("location dir could not be opened"); -*/ + diff --git a/www/test/something.html b/www/test/something.html new file mode 100644 index 0000000..3501b3a --- /dev/null +++ b/www/test/something.html @@ -0,0 +1,11 @@ + + + + Le Webserv in test and is Something + + +

Le index (˘ ͜ʖ˘)

+
+

(˚3˚)

+ + From f7dc5ccde41e483abd82729e22b545d4e0c5c3fc Mon Sep 17 00:00:00 2001 From: Me Date: Fri, 5 Aug 2022 21:46:46 +0200 Subject: [PATCH 07/21] ok Location sorting and processing is finally working as expected, still a few things to add like error_pages but will get there soon --- default.config | 20 ++++--- srcs/config/LocationConfig.hpp | 8 +++ srcs/config/extraConfig.cpp | 3 + srcs/config/parser.cpp | 90 ++++++----------------------- srcs/config/postProcessing.cpp | 36 +++--------- srcs/utils.cpp | 40 +++++++++++++ srcs/utils.hpp | 6 +- www/index.html | 2 +- www/test/index.html | 4 +- www/test/something.html | 2 +- www/test/test_deeper/index.html | 11 ++++ www/test/test_deeper/something.html | 11 ++++ 12 files changed, 119 insertions(+), 114 deletions(-) create mode 100644 www/test/test_deeper/index.html create mode 100644 www/test/test_deeper/something.html diff --git a/default.config b/default.config index 3a20f6b..fc18753 100644 --- a/default.config +++ b/default.config @@ -20,30 +20,32 @@ server { # root /home/me/Programming/42/group_webserv; # but this is fine location /test { - root /www/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; - index index.html; - allow_methods DELETE; - } +# location / { +# root /www; +# index index.html; +# allow_methods DELETE; +# } allow_methods GET POST; +# location /test/something.html { location /test/something.html { - allow_methods GET POST DELETE; + allow_methods DELETE; } # location /something/long/here { # } - location /something/long { + location /test/test_deeper { } - location /something/long/here/but/more { + location /test/test_deeper/something.html { + allow_methods DELETE; } diff --git a/srcs/config/LocationConfig.hpp b/srcs/config/LocationConfig.hpp index 69f6780..ceba538 100644 --- a/srcs/config/LocationConfig.hpp +++ b/srcs/config/LocationConfig.hpp @@ -106,6 +106,13 @@ public: // ok now we need to add a thing where we check for files vs folders if (comp_lhs == comp_rhs) { + + if (path_is_valid(root + path) == 2) + --comp_lhs; + if (path_is_valid(rhs.root + rhs.path) == 2) + --comp_rhs; + +/* std::cout << "locations are equal\n"; std::string tmp_path_lhs = root + path; std::cout << "root + path: " << tmp_path_lhs << '\n'; @@ -132,6 +139,7 @@ public: --comp_rhs; } // do i need to free c_path's ??? +*/ } diff --git a/srcs/config/extraConfig.cpp b/srcs/config/extraConfig.cpp index ee5ef4e..dfd770b 100644 --- a/srcs/config/extraConfig.cpp +++ b/srcs/config/extraConfig.cpp @@ -82,6 +82,9 @@ std::string ConfigParser::_get_rest_of_line(size_t *curr) return (values); } + + + void ConfigParser::_print_content() const { std::cout << _content; diff --git a/srcs/config/parser.cpp b/srcs/config/parser.cpp index 2e4e28a..dd043f2 100644 --- a/srcs/config/parser.cpp +++ b/srcs/config/parser.cpp @@ -85,10 +85,11 @@ std::vector * ConfigParser::parse() throw std::invalid_argument("empty config file"); while (curr != std::string::npos) { -// 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); + if ((start = _content.find_first_not_of(" \t\n", curr)) == std::string::npos) + throw std::invalid_argument("empty config file"); + + if ((curr = _content.find_first_of(" \t\n", start)) == std::string::npos) + throw std::invalid_argument("empty config file"); std::string key = _content.substr(start, curr - start); if (key != "server") throw std::invalid_argument("bad config file arguments 1"); @@ -109,9 +110,9 @@ ServerConfig ConfigParser::_parse_server(size_t *start) if (curr == std::string::npos || _content[curr] != '{') 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? -// throw std::invalid_argument("bad config file syntax"); + if ((curr = _content.find_first_of(" \t\n", curr + 1)) == std::string::npos) + throw std::invalid_argument("bad config file syntax"); + // are there other things to check for? while (curr != std::string::npos) // here curr == { + 1 { // so this moves curr to past the word... @@ -147,8 +148,6 @@ LocationConfig ConfigParser::_parse_location(size_t *start) ret.redirect_status = 0; ret.allow_methods = 0; -// path must have a leading / else move on to next location - // i guess we'll be strict cuz can't return (NULL); or NUL... ret.path = _get_first_word(&curr); if (ret.path[0] != '/') throw std::invalid_argument("Location path require a leading /"); @@ -159,9 +158,9 @@ LocationConfig ConfigParser::_parse_location(size_t *start) if (curr == std::string::npos || _content[curr] != '{') 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? -// throw std::invalid_argument("bad config file syntax"); + if ((curr = _content.find_first_of(" \t\n", curr + 1)) == std::string::npos) + throw std::invalid_argument("bad config file syntax"); + // are there other things to check for? while (curr != std::string::npos) { // so this moves curr to past the word... @@ -183,8 +182,6 @@ LocationConfig ConfigParser::_parse_location(size_t *start) } -#include - void ConfigParser::_set_server_values(ServerConfig *server, \ const std::string key, std::string value) @@ -198,12 +195,9 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ throw std::invalid_argument("missing value"); else if (key == "server_name" && server->server_name.empty()) { - // 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 (it->compare(tmp_val[0]) == 0) throw std::invalid_argument("server_name already exists"); } @@ -243,44 +237,11 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ if (tmp_val[0][0] != '/') throw std::invalid_argument("Root requires leading /"); - // unclear if this is always true? might only be true in Server - // but not in Locations? idk... - //i think it does, i must have read wrong somewhere... - - - // don't bother using lstat - // 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].substr(1).c_str(); - struct stat sb; - - printf("folder:%s\n", folder); - - if (stat(folder, &sb) == 0 && S_ISDIR(sb.st_mode)) - { -// std::cout << "is a Dir\n"; + // std::cout << "root: " << tmp_val[0] << '\n'; + if (path_is_valid(tmp_val[0]) == 1) server->root = tmp_val[0]; - } else - throw std::invalid_argument("root dir could not be opened 1"); - - // do i need to free folder? -/* DIR* dir = opendir(tmp_val[0].c_str()); - if (dir) - closedir(dir); - else - { - 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"); - } - } -*/ + throw std::invalid_argument("Root dir invalid 1"); } else if (key == "autoindex" && size == 1) { @@ -338,17 +299,7 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ server->error_pages[status_code] = path; } } -/* else if (key == "recv_timeout" && size == 1 && server->server_name == "") - { - // 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->server_name == "") - { - server->send_timeout.tv_sec = atoi(tmp_val[0].c_str()); - } -*/ else + else { // means either you didn't write the right key, or the value is // missing, or the value has already been filled. @@ -369,19 +320,14 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ throw std::invalid_argument("missing value"); else if (key == "root" && size == 1 && location->root == "") { +// std::cout << "location root: " << tmp_val[0] << '\n'; if (tmp_val[0][0] != '/') throw std::invalid_argument("Root requires leading /"); - const char* folder = tmp_val[0].substr(1).c_str(); - struct stat sb; - - if (stat(folder, &sb) == 0 && S_ISDIR(sb.st_mode)) - { -// std::cout << "is a Dir\n"; + if (path_is_valid(tmp_val[0]) == 1) location->root = tmp_val[0]; - } else - throw std::invalid_argument("root dir could not be opened"); + throw std::invalid_argument("Root dir invalid"); } else if (key == "client_body_limit" && size == 1 \ && location->client_body_limit == 0) diff --git a/srcs/config/postProcessing.cpp b/srcs/config/postProcessing.cpp index c17e876..70d549a 100644 --- a/srcs/config/postProcessing.cpp +++ b/srcs/config/postProcessing.cpp @@ -57,27 +57,8 @@ void ConfigParser::_post_processing(std::vector *servers) 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.substr(1).c_str(); - struct stat sb; - -// wait also have to add checks in for files! -// also need to add the root to the path!!!!!!!! see LocationConfig and parser - 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? @@ -97,26 +78,25 @@ void ConfigParser::_post_processing(std::vector *servers) // maybe do something for Cgi_info? +// std::cout << "In Post, Root + Path: " << it_l->root + it_l->path << '\n'; + if (path_is_valid(it_l->root + it_l->path) == 0) + { + //either we throw or we erase + throw std::invalid_argument("location path is invalid"); + } + ++it_l; } -// ok we can sort in order and reverse... - std::cout << "made it to sorting...\n"; +// std::cout << "made it to sorting...\n"; // std::sort(it->locations.begin(), it->locations.end(), compareLocationConfigs); std::sort(it->locations.begin(), it->locations.end()); - std::reverse(it->locations.begin(), it->locations.end()); - - ++it; } - - // do the defaults at the end? - - } bool ConfigParser::_find_root_path_location(std::vector locations) diff --git a/srcs/utils.cpp b/srcs/utils.cpp index fc22095..642c875 100644 --- a/srcs/utils.cpp +++ b/srcs/utils.cpp @@ -86,3 +86,43 @@ std::string http_methods_to_str(unsigned int methods) return (str); } + +int path_is_valid(std::string path) +{ + std::string i_path = path.substr(1); + const char *tmp_path = i_path.c_str(); + struct stat s; + + if (stat(tmp_path, &s) == 0) + { + if (S_ISREG(s.st_mode)) + { +// std::cout << "is a file\n"; + return (2); + } + else if (S_ISDIR(s.st_mode)) + { +// std::cout << "is a Dir\n"; + return (1); + } + } + +/* + if (stat(tmp_path, &s) == 0 && S_ISREG(s.st_mode)) // a File + { + std::cout << "is a file\n"; + return (2); + } + else if (stat(tmp_path, &s) == 0 && S_ISDIR(s.st_mode)) // A Folder + { + std::cout << "is a Dir\n"; + return (1); + } +*/ +// std::cout << "path is neither dir nor file\n"; + return (0); +} + + + + diff --git a/srcs/utils.hpp b/srcs/utils.hpp index a0215fc..35ca453 100644 --- a/srcs/utils.hpp +++ b/srcs/utils.hpp @@ -6,6 +6,10 @@ # include # include # include // atoi +# include // stat() + +# include // tmp + // enum http_method @@ -33,6 +37,6 @@ std::string itos(int n); 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); - +int path_is_valid(std::string path); #endif diff --git a/www/index.html b/www/index.html index bc65643..9e2c22a 100644 --- a/www/index.html +++ b/www/index.html @@ -8,4 +8,4 @@

(˚3˚)

- \ No newline at end of file + diff --git a/www/test/index.html b/www/test/index.html index bc65643..ba02623 100644 --- a/www/test/index.html +++ b/www/test/index.html @@ -1,11 +1,11 @@ - Le Webserv + Webserv test index

Le index (˘ ͜ʖ˘)


(˚3˚)

- \ No newline at end of file + diff --git a/www/test/something.html b/www/test/something.html index 3501b3a..3e8a32f 100644 --- a/www/test/something.html +++ b/www/test/something.html @@ -1,7 +1,7 @@ - Le Webserv in test and is Something + Webserv test Something

Le index (˘ ͜ʖ˘)

diff --git a/www/test/test_deeper/index.html b/www/test/test_deeper/index.html new file mode 100644 index 0000000..2992159 --- /dev/null +++ b/www/test/test_deeper/index.html @@ -0,0 +1,11 @@ + + + + Webserv Test Deeper Index + + +

Le index (˘ ͜ʖ˘)

+
+

(˚3˚)

+ + diff --git a/www/test/test_deeper/something.html b/www/test/test_deeper/something.html new file mode 100644 index 0000000..44f17ac --- /dev/null +++ b/www/test/test_deeper/something.html @@ -0,0 +1,11 @@ + + + + Webserv test deeper Something + + +

Le index (˘ ͜ʖ˘)

+
+

(˚3˚)

+ + From 8ec1353723b61d0b3197434344e61ac207c848ed Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Sun, 7 Aug 2022 01:38:33 +0200 Subject: [PATCH 08/21] fixed response.append(body) problem. + File I/O working but maybe not perfect (it seems complicated to do it with std::filebuf) + fixed Content-Type for unknown file extension --- srcs/Client.cpp | 5 +- srcs/Client.hpp | 3 -- srcs/webserv/Webserv.hpp | 7 ++- srcs/webserv/init.cpp | 5 +- srcs/webserv/response.cpp | 96 ++++++++++++++++++--------------------- 5 files changed, 54 insertions(+), 62 deletions(-) diff --git a/srcs/Client.cpp b/srcs/Client.cpp index f994d57..c63cc91 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -1,13 +1,11 @@ #include "Client.hpp" -char Client::buf[MAX_FILESIZE+1]; - /********************************************* * COPLIENS *********************************************/ -Client::Client() : fd(0), body_size(0), status(0) { +Client::Client() : fd(0), status(0) { return; } @@ -56,7 +54,6 @@ void Client::clear() clear_request(); raw_request.clear(); response.clear(); - body_size = 0; status = 0; } diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 5a67601..eee05aa 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -17,7 +17,6 @@ struct Request std::string body; }; -# define MAX_FILESIZE 1000000 // (1Mo) class Client { public: @@ -29,8 +28,6 @@ class Client int fd; std::string raw_request; std::string response; - static char buf[MAX_FILESIZE+1]; - size_t body_size; unsigned int status; listen_socket *lsocket; diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index c5d6409..d2de04f 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -38,6 +38,8 @@ void signal_handler(int signum); # define FAILURE -1 # define SUCCESS 1 +# define MIME_TYPE_DEFAULT "application/octet-stream" + class Webserv { public: @@ -78,7 +80,7 @@ class Webserv void _process_method(Client *client, ServerConfig &server, LocationConfig &location); void _insert_status_line(Client *client); void _error_html_response(Client *client, ServerConfig &server); - void _append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension = ""); + void _append_body(Client *client, const std::string &body, const std::string &file_extension = ""); void _get(Client *client, ServerConfig &server, LocationConfig &location); void _get_file(Client *client, const std::string &path); @@ -90,7 +92,8 @@ class Webserv void _delete_file(Client *client, const std::string &path); ServerConfig &_determine_process_server(Client *client); - LocationConfig &_determine_location(ServerConfig &server, std::string &path); + LocationConfig &_determine_location(ServerConfig &server, const std::string &path); + std::string _determine_file_extension(const std::string &path) const; // cgi_script.cpp bool _is_cgi(Client *client); void _exec_cgi(Client *client); diff --git a/srcs/webserv/init.cpp b/srcs/webserv/init.cpp index 3a33ed1..f86d5ee 100644 --- a/srcs/webserv/init.cpp +++ b/srcs/webserv/init.cpp @@ -105,7 +105,10 @@ void Webserv::_init_http_status_map() void Webserv::_init_mime_types_map() { - _mime_types[""] = "application/octet-stream"; +/* +** From : http://nginx.org/en/docs/http/ngx_http_core_module.html#types +*/ + _mime_types[""] = MIME_TYPE_DEFAULT; _mime_types["html"] = "text/html"; _mime_types["htm"] = "text/html"; diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 134dcff..927d103 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -23,6 +23,7 @@ void Webserv::_send_response(Client *client, ServerConfig &server) if (client->status >= 400) _error_html_response(client, server); + std::cerr << "client->response.size() = " << client->response.size() << "\n"; // DEBUG ret = ::send(client->fd, client->response.c_str(), client->response.size(), 0); if (ret == -1) { @@ -31,19 +32,7 @@ void Webserv::_send_response(Client *client, ServerConfig &server) _close_client(client->fd); return ; } - - // Body send (WIP for working binary files) - if (client->body_size) - { - ret = ::send(client->fd, client->buf, client->body_size, 0); - if (ret == -1) - { - std::perror("err send()"); - std::cerr << "client.fd =" << client->fd << "\n"; // DEBUG - _close_client(client->fd); - return ; - } - } + std::cerr << "ret send() = " << ret << "\n"; // DEBUG if (client->get_headers("Connection") == "close") _close_client(client->fd); @@ -125,7 +114,7 @@ void Webserv::_error_html_response(Client *client, ServerConfig &server) { std::string html_page = HTML_ERROR; ::replace_all_substr(html_page, STATUS_PLACEHOLDER, _http_status[client->status]); - _append_body(client, html_page.c_str(), html_page.size(), "html"); + _append_body(client, html_page, "html"); } else _get_file(client, server.error_pages[client->status]); @@ -156,10 +145,16 @@ void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &locatio _get_file(client, path); } +# define MAX_FILESIZE 1000000 // (1Mo) void Webserv::_get_file(Client *client, const std::string &path) { - std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ? - // char buf[MAX_FILESIZE+1]; +/* + std::ios::binary + https://gcc.gnu.org/onlinedocs/libstdc++/manual/fstreams.html#std.io.filestreams.binary + tldr : its seems to not be so simple to do read/write of binary file in a portable way. +*/ + std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ? + std::stringstream buf; if (access(path.c_str(), F_OK) == -1) { @@ -175,7 +170,7 @@ void Webserv::_get_file(Client *client, const std::string &path) return ; } - ifd.open(path.c_str(), std::ios::binary | std::ios::ate); // std::ios::binary (binary for files like images ?) + ifd.open(path.c_str(), std::ios::ate); if (!ifd) { std::cerr << path << ": ifd.open fail" << '\n'; @@ -196,8 +191,8 @@ void Webserv::_get_file(Client *client, const std::string &path) } ifd.seekg(0, std::ios::beg); - ifd.read(client->buf, size); - if (!ifd) + buf << ifd.rdbuf(); + if (!ifd || !buf) { std::cerr << path << ": ifd.read fail" << '\n'; client->status = 500; @@ -205,47 +200,36 @@ void Webserv::_get_file(Client *client, const std::string &path) else { client->status = 200; - client->buf[ifd.gcount()] = '\0'; - - std::string file_ext = ""; - size_t dot_pos = path.rfind("."); - std::cerr << "dot_pos = " << dot_pos << "\n"; - if (dot_pos != std::string::npos && dot_pos + 1 < path.size()) - file_ext = path.substr(dot_pos + 1); - std::cerr << "file_ext = " << file_ext << "\n"; - - client->body_size = ifd.gcount(); - // WIP, pass empty body argument because append to string mess up binary file - _append_body(client, "", client->body_size, file_ext); + std::string file_ext = _determine_file_extension(path); + _append_body(client, buf.str(), file_ext); } ifd.close(); } } -void Webserv::_append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension) +void Webserv::_append_body(Client *client, const std::string &body, const std::string &file_extension) { -/* - TODO : determine Content-Type - how ? read the body ? - or before in other way (like based and file extension) and pass here as argument ? - http://nginx.org/en/docs/http/ngx_http_core_module.html#types - Need to look "conf/mime.types" of nginx. Maybe make a map<> based on that. -*/ - const std::string &mime_type = _mime_types[file_extension]; - client->response.append("Content-Type: "); + const std::string &mime_type = _mime_types[file_extension]; + + client->response.append("Content-Type: "); + if (mime_type.empty()) + client->response.append(MIME_TYPE_DEFAULT); + else + { client->response.append(mime_type); if (mime_type.find("text/") != std::string::npos) client->response.append("; charset=UTF-8"); - client->response.append(CRLF); + } + client->response.append(CRLF); - client->response.append("Content-Length: "); - std::string tmp = ::itos(body_size); - client->response.append(tmp); - client->response.append(CRLF); + client->response.append("Content-Length: "); + std::string tmp = ::itos(body.size()); + client->response.append(tmp); + client->response.append(CRLF); - client->response.append(CRLF); - client->response.append(body); + client->response.append(CRLF); + client->response.append(body); } void Webserv::_post(Client *client, ServerConfig &server, LocationConfig &location) @@ -281,7 +265,7 @@ void Webserv::_post_file(Client *client, const std::string &path) return ; } - ofd.open(path.c_str(), std::ios::binary | std::ios::trunc); + ofd.open(path.c_str(), std::ios::trunc); if (!ofd) { std::cerr << path << ": ofd.open fail" << '\n'; @@ -289,11 +273,11 @@ void Webserv::_post_file(Client *client, const std::string &path) } else { - // Used body.size() so Content-Length useless at this point ? + // Content-Length useless at this point ? // Maybe usefull in _read_request() for rejecting too big content. // Need to _determine_process_server() as soon as possible, // like in _read_request() for stopping read if body is too big ? - ofd.write(client->get_body().c_str(), client->get_body().size()); + ofd << client->get_body(); if (!ofd) { std::cerr << path << ": ofd.write fail" << '\n'; @@ -383,7 +367,7 @@ ServerConfig &Webserv::_determine_process_server(Client *client) return (*default_server); } -LocationConfig &Webserv::_determine_location(ServerConfig &server, std::string &path) +LocationConfig &Webserv::_determine_location(ServerConfig &server, const std::string &path) { /* Assume there is at least one location in vector for path "/" @@ -404,3 +388,11 @@ LocationConfig &Webserv::_determine_location(ServerConfig &server, std::string & else return (server.locations.front()); } + +std::string Webserv::_determine_file_extension(const std::string &path) const +{ + size_t dot_pos = path.rfind("."); + if (dot_pos != std::string::npos && dot_pos + 1 < path.size()) + return ( path.substr(dot_pos + 1) ); + return (std::string("")); +} From 4870b2c05dcd414e47cb995f6b684dcebdd81c0b Mon Sep 17 00:00:00 2001 From: Me Date: Sun, 7 Aug 2022 03:24:49 +0200 Subject: [PATCH 09/21] Location sorter works, fixed the compilation error i was having on this branch, now working on autoindex --- srcs/config/LocationConfig.hpp | 46 +++------------------------------- srcs/config/postProcessing.cpp | 3 ++- srcs/utils.cpp | 4 ++- srcs/utils.hpp | 4 ++- srcs/webserv/Webserv.hpp | 5 ++++ srcs/webserv/response.cpp | 36 ++++++++++++++++++++------ 6 files changed, 45 insertions(+), 53 deletions(-) diff --git a/srcs/config/LocationConfig.hpp b/srcs/config/LocationConfig.hpp index ceba538..22be5e5 100644 --- a/srcs/config/LocationConfig.hpp +++ b/srcs/config/LocationConfig.hpp @@ -71,16 +71,12 @@ public: } // works a lot better than using a compare function... -// but it still doesn't work... -// problem is the logic bool operator<(const LocationConfig& rhs) const { int comp_lhs = 0; int comp_rhs = 0; size_t tmp = 0; - // consider adding 1 to path that ends in a file not folder. - // What are the rules... // / is smaller than /test // and /test/test1 is bigger than test @@ -106,61 +102,25 @@ public: // ok now we need to add a thing where we check for files vs folders if (comp_lhs == comp_rhs) { - if (path_is_valid(root + path) == 2) --comp_lhs; if (path_is_valid(rhs.root + rhs.path) == 2) --comp_rhs; - -/* - std::cout << "locations are equal\n"; - std::string tmp_path_lhs = root + path; - std::cout << "root + path: " << tmp_path_lhs << '\n'; - - // const char *c_path_lhs = (root + path).substr(1).c_str(); -// could the problem be that i'm in the .hpp ? - const char *c_path_lhs = tmp_path_lhs.substr(1).c_str(); - const char *c_path_rhs = (rhs.root + rhs.path).substr(1).c_str(); - - printf("lhs path: %s\n", c_path_lhs); - printf("rhs path: %s\n", c_path_rhs); - - struct stat sl; - struct stat sr; - - if (stat(c_path_lhs, &sl) == 0 && S_ISREG(sl.st_mode)) - { - std::cout << "lhs is a file\n"; - --comp_lhs; - } - if (stat(c_path_rhs, &sr) == 0 && S_ISREG(sr.st_mode)) - { - std::cout << "rhs is a file\n"; - --comp_rhs; - } - // do i need to free c_path's ??? -*/ } - - std::cout << "comp_lhs: " << comp_lhs << " comp_rhs: " << comp_rhs \ - << " bool res: " << (comp_lhs > comp_rhs) << "\n"; +// std::cout << "comp_lhs: " << comp_lhs << " comp_rhs: " << comp_rhs +// << " bool res: " << (comp_lhs > comp_rhs) << "\n"; // i honestly can't tell you how or why but using > rather than < // fixed all my problems // the fact that the bool was always 0 before, and the correct order // i want... super weird... - // return (comp_lhs > comp_rhs); // right comparison ? not <= ? + // return (comp_lhs > comp_rhs); return (comp_lhs < comp_rhs); // right comparison ? not <= ? }; - }; -// ok it needs to go somewhere else - - - #endif diff --git a/srcs/config/postProcessing.cpp b/srcs/config/postProcessing.cpp index 70d549a..412ea08 100644 --- a/srcs/config/postProcessing.cpp +++ b/srcs/config/postProcessing.cpp @@ -29,7 +29,8 @@ void ConfigParser::_post_processing(std::vector *servers) // 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; + it->allow_methods = ANY_METHODS; + // would prefer ALL_METHODS if (it->index.empty()) throw std::invalid_argument("Config file needs an Index"); diff --git a/srcs/utils.cpp b/srcs/utils.cpp index 4d8c472..2c3c15a 100644 --- a/srcs/utils.cpp +++ b/srcs/utils.cpp @@ -61,7 +61,8 @@ http_method str_to_http_method(std::string &str) else if (str == "DELETE") return DELETE; else if (str == "ALL_METHODS") - return ALL_METHODS; + return ANY_METHODS; + // would prefere ALL_METHODS return UNKNOWN; } @@ -87,6 +88,7 @@ std::string http_methods_to_str(unsigned int methods) return (str); } +// you could make this &path... int path_is_valid(std::string path) { std::string i_path = path.substr(1); diff --git a/srcs/utils.hpp b/srcs/utils.hpp index b981bd5..ad08e95 100644 --- a/srcs/utils.hpp +++ b/srcs/utils.hpp @@ -28,6 +28,8 @@ enum http_method POST = 1 << 1, DELETE = 1 << 2, ANY_METHODS = 0b11111111, +// ALL_METHODS = 0b11111111, + // i would prefer this... }; struct listen_socket @@ -47,6 +49,6 @@ 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); int path_is_valid(std::string path); -void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr) +void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr); #endif diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index c5d6409..f2323b8 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -81,6 +81,11 @@ class Webserv void _append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension = ""); void _get(Client *client, ServerConfig &server, LocationConfig &location); + +// in progress + void _autoindex(Client *client, std::string &path); + + void _get_file(Client *client, const std::string &path); void _post(Client *client, ServerConfig &server, LocationConfig &location); diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 134dcff..001743c 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -143,6 +143,10 @@ void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &locatio std::cerr << "path = " << path << "\n"; + std::cout << "ERIC path: " << path << '\n'; + +// if (path_is_valid( + // TMP HUGO // if (_is_cgi(client)) @@ -156,6 +160,30 @@ void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &locatio _get_file(client, path); } +// i might need some sort of _generate_autoindex() + +void Webserv::_autoindex(Client *client, std::string &path) +{ + // i think the plan is to generate an html file and return it + // it should be filled with the stuff that is found in that repo + + // either i create a tmp file and put the html in it an call + // the _get_file on it with a new path... + // or i make the html and do what _get_file does if it found + // a valid file... + + // Let's try the 2nd one first. + + + + + + // if successful we call _append_body + +} + + + void Webserv::_get_file(Client *client, const std::string &path) { std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ? @@ -223,6 +251,7 @@ void Webserv::_get_file(Client *client, const std::string &path) } } + void Webserv::_append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension) { /* @@ -385,13 +414,6 @@ ServerConfig &Webserv::_determine_process_server(Client *client) LocationConfig &Webserv::_determine_location(ServerConfig &server, std::string &path) { -/* - Assume there is at least one location in vector for path "/" - TODO in ConfigParser : - If no location block in config file, one need to be generated - for path "/", and filled with fields "root" and "index" based on parent server block -*/ - std::vector::iterator it = server.locations.begin(); while (it != server.locations.end()) { From 4ab099ee4d406fe51e30c04278a0ffe678b440e2 Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Sun, 7 Aug 2022 05:41:01 +0200 Subject: [PATCH 10/21] redone _read_request(). Should work with any BUFSIZE. + WIP in some aspects. Need to adjust parse_request() among others things. + update memo.txt --- memo.txt | 14 ++++++++-- srcs/Client.cpp | 11 +++++++- srcs/Client.hpp | 3 ++ srcs/webserv/request.cpp | 60 +++++++++++++++++++++++++++++++++------- 4 files changed, 75 insertions(+), 13 deletions(-) diff --git a/memo.txt b/memo.txt index dd03cec..03ec750 100644 --- a/memo.txt +++ b/memo.txt @@ -1,6 +1,16 @@ - -- do correct handling of special character in url (/rfc2119_files/errata.js.t%C3%A9l%C3%A9chargement -> /rfc2119_files/errata.js.téléchargement) +IN 42 SUBJECT, PRIORITY : +- 505 HTTP Version Not Supported +- CGI - handle redirection +- index and autoindex +- gestion memoire en cas de bad_alloc +- Ecrire des tests ! +----------------------------- +- replace atoi() with a better function +- 408 Request Timeout +- gerer le champ "Accept" du client +- gerer les ".." dans un URL (verifier que l'on ne sort pas du dossier "root") +- do correct handling of special character in url (/rfc2119_files/errata.js.t%C3%A9l%C3%A9chargement -> /rfc2119_files/errata.js.téléchargement) - maybe add a "last_action_time" in Client for timeout handling little global timeout on epoll, like 100ms, then find client that actualy need to timeout if (actual_time - client.last_action_time > 10000ms){timeout(client)} diff --git a/srcs/Client.cpp b/srcs/Client.cpp index c63cc91..0d7b7d7 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -5,7 +5,12 @@ * COPLIENS *********************************************/ -Client::Client() : fd(0), status(0) { +Client::Client() + : fd(0), + status(0), + header_complete(false), + read_body_size(0) +{ return; } @@ -52,6 +57,8 @@ void Client::parse_request() void Client::clear() { clear_request(); + header_complete = false; + read_body_size = 0; raw_request.clear(); response.clear(); status = 0; @@ -125,6 +132,8 @@ void Client::_parse_request_headers( std::vector list ) void Client::_parse_request_body( size_t pos ) { + // TODO : a revoir avec une std::string, + // pour ne pas avoir le probleme d'un '0' qui marque la fin des données std::string body = &raw_request[pos]; _request.body = body; diff --git a/srcs/Client.hpp b/srcs/Client.hpp index eee05aa..84eb82d 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -31,6 +31,9 @@ class Client unsigned int status; listen_socket *lsocket; + bool header_complete; + size_t read_body_size; + // const functions ? http_method get_method(); std::string &get_path(); diff --git a/srcs/webserv/request.cpp b/srcs/webserv/request.cpp index 34338fb..4f5c39f 100644 --- a/srcs/webserv/request.cpp +++ b/srcs/webserv/request.cpp @@ -2,6 +2,8 @@ #include "Webserv.hpp" #define BUFSIZE 8192 +#define MAX_HEADER_SIZE 42000 +#define MAX_BODY_SIZE 500000 // test macro, replace with server config void Webserv::_request(Client *client) { @@ -12,9 +14,10 @@ void Webserv::_request(Client *client) void Webserv::_read_request(Client *client) { - char buf[BUFSIZE+1]; + char buf[BUFSIZE]; ssize_t ret; + std::cerr << "call recv()" << "\n" ; ret = ::recv(client->fd, buf, BUFSIZE, 0); std::cerr << "recv() on fd(" << client->fd << ") returned = " << ret << "\n" ; if (ret == -1) @@ -25,20 +28,57 @@ void Webserv::_read_request(Client *client) _close_client(client->fd); return ; } - if (ret == 0) // Not sure what to do in case of 0. Just close ? + if (ret == 0) { _close_client(client->fd); return ; } - /* - if (ret == BUFSIZE) - // send error like "request too long" to client - */ - buf[ret] = '\0'; - client->raw_request.append(buf); - client->parse_request(); + client->raw_request.append(buf, ret); + if (!client->header_complete) + { + if (client->raw_request.find(CRLF CRLF) != std::string::npos) + { + client->header_complete = true; + client->parse_request(); // TODO : split function to avoid useless parsing ? + // TODO : determine server here for body size limit + if (!client->get_headers("Content-Length").empty() + && ::atoi(client->get_headers("Content-Length").c_str()) > MAX_BODY_SIZE) + { + client->status = 413; + _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); + return; + } + } + else if (client->raw_request.size() > MAX_HEADER_SIZE) + { + client->status = 400; + _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); + return; + } + } + else if (client->header_complete) + { + client->read_body_size += ret; + if (client->read_body_size > MAX_BODY_SIZE) + { + client->status = 413; + _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); + return; + } + if ((int)client->read_body_size > ::atoi(client->get_headers("Content-Length").c_str())) + { + client->parse_request(); // reparse for the body + _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); + return; + } + } - _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); + + if (client->header_complete && client->get_headers("Content-Type").empty() && client->get_headers("Content-Length").empty() ) + { + _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); + return; + } } From 1ccf61bc6836076061791d911897ad0750e551e0 Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Sun, 7 Aug 2022 17:37:24 +0200 Subject: [PATCH 11/21] assign server and location to client in _read_request() --- srcs/Client.cpp | 7 ++++- srcs/Client.hpp | 6 +++- srcs/webserv/Webserv.hpp | 18 ++++++------ srcs/webserv/request.cpp | 10 +++---- srcs/webserv/response.cpp | 61 +++++++++++++++++---------------------- 5 files changed, 52 insertions(+), 50 deletions(-) diff --git a/srcs/Client.cpp b/srcs/Client.cpp index 0d7b7d7..33e8a8d 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -7,9 +7,12 @@ Client::Client() : fd(0), + lsocket(NULL), status(0), header_complete(false), - read_body_size(0) + read_body_size(0), + assigned_server(NULL), + assigned_location(NULL) { return; } @@ -59,6 +62,8 @@ void Client::clear() clear_request(); header_complete = false; read_body_size = 0; + assigned_server = NULL; + assigned_location = NULL; raw_request.clear(); response.clear(); status = 0; diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 84eb82d..9a255e1 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -7,6 +7,7 @@ # include # include # include "utils.hpp" +# include "ServerConfig.hpp" struct Request { @@ -26,13 +27,16 @@ class Client //Client &operator=(Client const &rhs); int fd; + const listen_socket *lsocket; + std::string raw_request; std::string response; unsigned int status; - listen_socket *lsocket; bool header_complete; size_t read_body_size; + ServerConfig *assigned_server; // cant be const cause of error_pages.operator[] + const LocationConfig *assigned_location; // const functions ? http_method get_method(); diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index d2de04f..9184726 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -73,26 +73,26 @@ class Webserv void _read_request(Client *client); // response.cpp void _response(Client *client); - void _send_response(Client *client, ServerConfig &server); + void _send_response(Client *client); void _append_base_headers(Client *client); - void _construct_response(Client *client, ServerConfig &server); - void _process_method(Client *client, ServerConfig &server, LocationConfig &location); + void _construct_response(Client *client); + void _process_method(Client *client); void _insert_status_line(Client *client); - void _error_html_response(Client *client, ServerConfig &server); + void _error_html_response(Client *client); void _append_body(Client *client, const std::string &body, const std::string &file_extension = ""); - void _get(Client *client, ServerConfig &server, LocationConfig &location); + void _get(Client *client); void _get_file(Client *client, const std::string &path); - void _post(Client *client, ServerConfig &server, LocationConfig &location); + void _post(Client *client); void _post_file(Client *client, const std::string &path); - void _delete(Client *client, ServerConfig &server, LocationConfig &location); + void _delete(Client *client); void _delete_file(Client *client, const std::string &path); - ServerConfig &_determine_process_server(Client *client); - LocationConfig &_determine_location(ServerConfig &server, const std::string &path); + ServerConfig *_determine_process_server(Client *client); // cant be const cause of error_pages.operator[] + const LocationConfig *_determine_location(const ServerConfig &server, const std::string &path) const; std::string _determine_file_extension(const std::string &path) const; // cgi_script.cpp bool _is_cgi(Client *client); diff --git a/srcs/webserv/request.cpp b/srcs/webserv/request.cpp index 4f5c39f..8a96573 100644 --- a/srcs/webserv/request.cpp +++ b/srcs/webserv/request.cpp @@ -2,8 +2,7 @@ #include "Webserv.hpp" #define BUFSIZE 8192 -#define MAX_HEADER_SIZE 42000 -#define MAX_BODY_SIZE 500000 // test macro, replace with server config +#define MAX_HEADER_SIZE 42000 // arbitrary void Webserv::_request(Client *client) { @@ -41,9 +40,10 @@ void Webserv::_read_request(Client *client) { client->header_complete = true; client->parse_request(); // TODO : split function to avoid useless parsing ? - // TODO : determine server here for body size limit + client->assigned_server = _determine_process_server(client); + client->assigned_location = _determine_location(*client->assigned_server, client->get_path()); if (!client->get_headers("Content-Length").empty() - && ::atoi(client->get_headers("Content-Length").c_str()) > MAX_BODY_SIZE) + && ::atoi(client->get_headers("Content-Length").c_str()) > (int)client->assigned_server->client_body_limit) { client->status = 413; _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); @@ -60,7 +60,7 @@ void Webserv::_read_request(Client *client) else if (client->header_complete) { client->read_body_size += ret; - if (client->read_body_size > MAX_BODY_SIZE) + if (client->read_body_size > client->assigned_server->client_body_limit) { client->status = 413; _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 927d103..08fdf7e 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -3,25 +3,22 @@ void Webserv::_response(Client *client) { - client->status = 200; // default value - - ServerConfig &server = _determine_process_server(client); - _send_response(client, server); + _send_response(client); if (g_last_signal) _handle_last_signal(); } -void Webserv::_send_response(Client *client, ServerConfig &server) +void Webserv::_send_response(Client *client) { ssize_t ret; std::cerr << "send()\n"; _append_base_headers(client); - _construct_response(client, server); + _construct_response(client); _insert_status_line(client); if (client->status >= 400) - _error_html_response(client, server); + _error_html_response(client); std::cerr << "client->response.size() = " << client->response.size() << "\n"; // DEBUG ret = ::send(client->fd, client->response.c_str(), client->response.size(), 0); @@ -53,19 +50,18 @@ void Webserv::_append_base_headers(Client *client) client->response.append("Connection: keep-alive" CRLF); } -void Webserv::_construct_response(Client *client, ServerConfig &server) +void Webserv::_construct_response(Client *client) { // TODO : Move this in read(), stop read if content too large - if (client->get_body().size() > server.client_body_limit) + if (client->get_body().size() > client->assigned_server->client_body_limit) { client->status = 413; return; } - LocationConfig &location = _determine_location(server, client->get_path()); - _process_method(client, server, location); + _process_method(client); } -void Webserv::_process_method(Client *client, ServerConfig &server, LocationConfig &location) +void Webserv::_process_method(Client *client) { unsigned int allow_methods = ANY_METHODS; // TEMP VARIABLE // after update in ConfigParser, use the "allow_methods" of location. @@ -80,11 +76,11 @@ void Webserv::_process_method(Client *client, ServerConfig &server, LocationConf switch (client->get_method()) { case (GET): - _get(client, server, location); break; + _get(client); break; case (POST): - _post(client, server, location); break; + _post(client); break; case (DELETE): - _delete(client, server, location); break; + _delete(client); break; default: break; } @@ -108,27 +104,26 @@ void Webserv::_insert_status_line(Client *client) client->response.insert(0, status_line); } -void Webserv::_error_html_response(Client *client, ServerConfig &server) +void Webserv::_error_html_response(Client *client) { - if (server.error_pages[client->status].empty()) + if (client->assigned_server->error_pages[client->status].empty()) { std::string html_page = HTML_ERROR; ::replace_all_substr(html_page, STATUS_PLACEHOLDER, _http_status[client->status]); _append_body(client, html_page, "html"); } else - _get_file(client, server.error_pages[client->status]); + _get_file(client, client->assigned_server->error_pages[client->status]); } #define INDEX "index.html" // temp wip -void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &location) +void Webserv::_get(Client *client) { - (void)server; // To remove from arg if we determine its useless std::string path = client->get_path(); if (path == "/") // TODO : index and autoindex path.append(INDEX); - path.insert(0, location.root); + path.insert(0, client->assigned_location->root); std::cerr << "path = " << path << "\n"; @@ -232,15 +227,14 @@ void Webserv::_append_body(Client *client, const std::string &body, const std::s client->response.append(body); } -void Webserv::_post(Client *client, ServerConfig &server, LocationConfig &location) +void Webserv::_post(Client *client) { - (void)server; // To remove from arg if we determine its useless /* WIP https://www.rfc-editor.org/rfc/rfc9110.html#name-post */ std::string path = client->get_path(); - path.insert(0, location.root); + path.insert(0, client->assigned_location->root); /* CGI Here ? */ @@ -298,15 +292,14 @@ void Webserv::_post_file(Client *client, const std::string &path) } } -void Webserv::_delete(Client *client, ServerConfig &server, LocationConfig &location) +void Webserv::_delete(Client *client) { - (void)server; // To remove from arg if we determine its useless /* WIP https://www.rfc-editor.org/rfc/rfc9110.html#name-delete */ std::string path = client->get_path(); - path.insert(0, location.root); + path.insert(0, client->assigned_location->root); /* CGI Here ? */ @@ -337,7 +330,7 @@ void Webserv::_delete_file(Client *client, const std::string &path) } } -ServerConfig &Webserv::_determine_process_server(Client *client) +ServerConfig *Webserv::_determine_process_server(Client *client) { /* http://nginx.org/en/docs/http/request_processing.html @@ -362,12 +355,12 @@ ServerConfig &Webserv::_determine_process_server(Client *client) ++it; } if (it != _servers.end()) - return (*it); + return (&(*it)); else - return (*default_server); + return (&(*default_server)); } -LocationConfig &Webserv::_determine_location(ServerConfig &server, const std::string &path) +const LocationConfig *Webserv::_determine_location(const ServerConfig &server, const std::string &path) const { /* Assume there is at least one location in vector for path "/" @@ -376,7 +369,7 @@ LocationConfig &Webserv::_determine_location(ServerConfig &server, const std::st for path "/", and filled with fields "root" and "index" based on parent server block */ - std::vector::iterator it = server.locations.begin(); + std::vector::const_iterator it = server.locations.begin(); while (it != server.locations.end()) { if (it->path.compare(0, path.size(), path)) @@ -384,9 +377,9 @@ LocationConfig &Webserv::_determine_location(ServerConfig &server, const std::st ++it; } if (it != server.locations.end()) - return (*it); + return (&(*it)); else - return (server.locations.front()); + return (&(server.locations.front())); } std::string Webserv::_determine_file_extension(const std::string &path) const From f777441edf61204970f2452fe0b01d4c1fcd3054 Mon Sep 17 00:00:00 2001 From: Me Date: Sun, 7 Aug 2022 20:37:53 +0200 Subject: [PATCH 12/21] autoindex in progress but need to check stuff on master branch --- default.config | 1 - srcs/config/LocationConfig.hpp | 10 ++++--- srcs/config/ServerConfig.hpp | 7 ----- srcs/config/parser.cpp | 45 +++++++--------------------- srcs/config/postProcessing.cpp | 25 ++++------------ srcs/webserv/Webserv.hpp | 3 +- srcs/webserv/autoindex.hpp | 25 ++++++++++++++++ srcs/webserv/response.cpp | 43 ++++++++++++++++++++++++-- www/test/{index.html => index1.html} | 0 9 files changed, 90 insertions(+), 69 deletions(-) create mode 100644 srcs/webserv/autoindex.hpp rename www/test/{index.html => index1.html} (100%) diff --git a/default.config b/default.config index fc18753..5bcea6c 100644 --- a/default.config +++ b/default.config @@ -31,7 +31,6 @@ server { # allow_methods DELETE; # } - allow_methods GET POST; # location /test/something.html { location /test/something.html { diff --git a/srcs/config/LocationConfig.hpp b/srcs/config/LocationConfig.hpp index 22be5e5..09ea756 100644 --- a/srcs/config/LocationConfig.hpp +++ b/srcs/config/LocationConfig.hpp @@ -38,12 +38,14 @@ public: std::string path; - int client_body_limit; std::string root; std::vector index; unsigned int allow_methods; - std::map cgi_info; + std::vector cgi_ext; // php not .php + bool autoindex; + + std::vector upload_repo; // wait if i can call several times, shouldn't it be a map? // wait no there can only be 1 and i think it might have to be in // location only... @@ -57,7 +59,6 @@ public: 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"; @@ -100,13 +101,14 @@ public: ++comp_rhs; // ok now we need to add a thing where we check for files vs folders - if (comp_lhs == comp_rhs) +/* if (comp_lhs == comp_rhs) { if (path_is_valid(root + path) == 2) --comp_lhs; if (path_is_valid(rhs.root + rhs.path) == 2) --comp_rhs; } +*/ // std::cout << "comp_lhs: " << comp_lhs << " comp_rhs: " << comp_rhs // << " bool res: " << (comp_lhs > comp_rhs) << "\n"; diff --git a/srcs/config/ServerConfig.hpp b/srcs/config/ServerConfig.hpp index 90e61b9..ceee50a 100644 --- a/srcs/config/ServerConfig.hpp +++ b/srcs/config/ServerConfig.hpp @@ -33,14 +33,12 @@ public: unsigned int client_body_limit; // set to default max if none set // 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; // fuck it, you can only call allow_methods once in Server - unsigned int allow_methods; std::vector locations; @@ -71,17 +69,12 @@ public: 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: "; - 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'; - // std::cout << "redirect_uri: " << redirect_uri << '\n'; std::cout << "host: " << host << '\n'; std::cout << "port: " << port << '\n'; diff --git a/srcs/config/parser.cpp b/srcs/config/parser.cpp index dd043f2..601f471 100644 --- a/srcs/config/parser.cpp +++ b/srcs/config/parser.cpp @@ -105,8 +105,6 @@ ServerConfig ConfigParser::_parse_server(size_t *start) size_t curr = _content.find_first_not_of(" \t\n", *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,7 +142,7 @@ LocationConfig ConfigParser::_parse_location(size_t *start) size_t curr = *start; // start is after the 1st word aka "location" - ret.client_body_limit = 0; + ret.autoindex = false; ret.redirect_status = 0; ret.allow_methods = 0; @@ -243,12 +241,6 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ else throw std::invalid_argument("Root dir invalid 1"); } - else if (key == "autoindex" && size == 1) - { - // autoindex is a bool, there's no good way for me to see if it has - // bet set already - server->autoindex = (tmp_val[0] == "on" ? true : false); - } else if (key == "client_body_limit" && size == 1 \ && server->client_body_limit == 0) { @@ -265,16 +257,6 @@ 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 == 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 |= m; - } - } else if (key == "error_page") { @@ -329,12 +311,9 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ else throw std::invalid_argument("Root dir invalid"); } - else if (key == "client_body_limit" && size == 1 \ - && location->client_body_limit == 0) + else if (key == "autoindex" && size == 1) { - if (!::isNumeric(tmp_val[0])) - throw std::invalid_argument("client_body_limit not a number"); - location->client_body_limit = atoi(tmp_val[0].c_str()); + location->autoindex = (tmp_val[0] == "on" ? true : false); } else if (key == "index") { @@ -352,18 +331,16 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ location->allow_methods |= m; } } - else if (key == "cgi_info") + else if (key == "cgi_ext") { - // you can call cgi_info several times i think. -// 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 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()); + for (size_t i = 0; i < tmp_val.size(); i++) + { + if (tmp_val[i][0] == '.') + throw std::invalid_argument("cgi_ext should not have a leading '.'"); + location->cgi_ext.push_back(tmp_val[i]); + } } - else if (key == "return" && location->redirect_status == 0 \ + else if (key == "redirect" && location->redirect_status == 0 \ && location->redirect_uri == "") { // actually i think there can only be one per location... diff --git a/srcs/config/postProcessing.cpp b/srcs/config/postProcessing.cpp index 412ea08..0ca5e5e 100644 --- a/srcs/config/postProcessing.cpp +++ b/srcs/config/postProcessing.cpp @@ -5,11 +5,6 @@ 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()) @@ -25,12 +20,6 @@ void ConfigParser::_post_processing(std::vector *servers) 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 = ANY_METHODS; - // would prefer ALL_METHODS if (it->index.empty()) throw std::invalid_argument("Config file needs an Index"); @@ -48,10 +37,10 @@ void ConfigParser::_post_processing(std::vector *servers) 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.allow_methods = ANY_METHODS; + tmp.autoindex = false; tmp.redirect_status = 0; it->locations.push_back(tmp); } @@ -60,15 +49,11 @@ void ConfigParser::_post_processing(std::vector *servers) while (it_l != it->locations.end()) { - - 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; + if (it_l->allow_methods == UNKNOWN) + it_l->allow_methods = ANY_METHODS; // fill out index from Server? // or do a bunch of checks on what is in there... @@ -108,7 +93,7 @@ bool ConfigParser::_find_root_path_location(std::vector location { if (it->path.compare("/") == 0) { - std::cout << "in compare: " << it->path << " -- "; + // std::cout << "in compare: " << it->path << " -- "; return true; } ++it; diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index f2323b8..e5fe312 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -29,6 +29,7 @@ # include "ServerConfig.hpp" # include "utils.hpp" # include "http_status.hpp" +# include "autoindex.hpp" extern bool g_run; extern int g_last_signal; @@ -83,7 +84,7 @@ class Webserv void _get(Client *client, ServerConfig &server, LocationConfig &location); // in progress - void _autoindex(Client *client, std::string &path); + void _autoindex(Client *client, LocationConfig &location, std::string &path); void _get_file(Client *client, const std::string &path); diff --git a/srcs/webserv/autoindex.hpp b/srcs/webserv/autoindex.hpp new file mode 100644 index 0000000..32d9d11 --- /dev/null +++ b/srcs/webserv/autoindex.hpp @@ -0,0 +1,25 @@ + +#ifndef AUTOINDEX_HPP +# define AUTOINDEX_HPP + +// # define HTML_ERROR(STATUS) "\r\n"STATUS"

"STATUS"


Le Webserv/0.1

" + +# define AUTOINDEX_START \ +""\ +""\ +""\ + " Index of " + +# define AUTOINDEX_MID \ +""\ +""\ +"" + + +# define AUTOINDEX_END \ +""\ +"" + + + +#endif diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 001743c..c658461 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -145,7 +145,11 @@ void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &locatio std::cout << "ERIC path: " << path << '\n'; -// if (path_is_valid( +/* if (path_is_valid(path) == 1 && location.autoindex == true) + { + _autoindex(client, location, path); + } +*/ // TMP HUGO // @@ -162,7 +166,10 @@ void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &locatio // i might need some sort of _generate_autoindex() -void Webserv::_autoindex(Client *client, std::string &path) +#include +#include + +void Webserv::_autoindex(Client *client, LocationConfig &location, std::string &path) { // i think the plan is to generate an html file and return it // it should be filled with the stuff that is found in that repo @@ -174,7 +181,39 @@ void Webserv::_autoindex(Client *client, std::string &path) // Let's try the 2nd one first. + std::cout << "made it to _autoindex\n"; + DIR *dir; + struct dirent *ent; + + if ((dir = opendir ((location.root + location.path).c_str())) != NULL) { + /* print all the files and directories within directory */ + while ((ent = readdir (dir)) != NULL) { + printf ("%s\n", ent->d_name); + } + closedir (dir); + } else { + /* could not open directory */ +// perror (""); + std::cout << "could not open dir\n"; + return ; + } + + + + std::string dir_list; + + dir_list.append(AUTOINDEX_START); + dir_list.append(location.path); + dir_list.append(AUTOINDEX_MID); + // loop something + dir_list.append(location.path); + + + + dir_list.append(AUTOINDEX_END); + + _append_body(client, dir_list.c_str(), dir_list.size(), "html"); diff --git a/www/test/index.html b/www/test/index1.html similarity index 100% rename from www/test/index.html rename to www/test/index1.html From 94852babc6f9a444258d4b3cfde5024af955e254 Mon Sep 17 00:00:00 2001 From: Me Date: Sun, 7 Aug 2022 22:25:24 +0200 Subject: [PATCH 13/21] autoindex is working, a few things to iron out be we well on our way --- default.config | 5 ++- srcs/config/LocationConfig.hpp | 1 + srcs/config/parser.cpp | 26 +++++++------ srcs/config/postProcessing.cpp | 3 +- srcs/utils.cpp | 7 +++- srcs/webserv/autoindex.hpp | 11 +++++- srcs/webserv/response.cpp | 71 ++++++++++++++++++++++++---------- 7 files changed, 85 insertions(+), 39 deletions(-) diff --git a/default.config b/default.config index 5bcea6c..ed483e0 100644 --- a/default.config +++ b/default.config @@ -12,7 +12,8 @@ server { index index.html; # this is another comment # i think root requires leading / # root goop; - root /www; +# root ./www/; + 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 @@ -21,7 +22,7 @@ server { location /test { # root /www/test; - index index.html; + autoindex on; } # If not explicitly set, ConfigParser need to genererate a location block # like this for path "/" (based on field "root" and "index" of the server) diff --git a/srcs/config/LocationConfig.hpp b/srcs/config/LocationConfig.hpp index 09ea756..cc09353 100644 --- a/srcs/config/LocationConfig.hpp +++ b/srcs/config/LocationConfig.hpp @@ -60,6 +60,7 @@ public: std::cout << "Path: " << path << '\n'; std::cout << "root: " << root << '\n'; + std::cout << "autoindex: " << autoindex << '\n'; std::cout << "Skipping index...\n"; diff --git a/srcs/config/parser.cpp b/srcs/config/parser.cpp index 601f471..38a5c4b 100644 --- a/srcs/config/parser.cpp +++ b/srcs/config/parser.cpp @@ -147,8 +147,8 @@ LocationConfig ConfigParser::_parse_location(size_t *start) ret.allow_methods = 0; ret.path = _get_first_word(&curr); - if (ret.path[0] != '/') - throw std::invalid_argument("Location path require a leading /"); +// if (ret.path[0] != '/') +// throw std::invalid_argument("Location path require a leading /"); // in theory now curr should be right after the "path" curr = _content.find_first_not_of(" \t\n", curr); @@ -232,14 +232,15 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ } else if (key == "root" && size == 1 && server->root == "") { - if (tmp_val[0][0] != '/') - throw std::invalid_argument("Root requires leading /"); +// if (tmp_val[0][0] != '/') +// throw std::invalid_argument("Root requires leading /"); // std::cout << "root: " << tmp_val[0] << '\n'; - if (path_is_valid(tmp_val[0]) == 1) +//might not even do these checks here... +// if (path_is_valid(tmp_val[0]) == 1) server->root = tmp_val[0]; - else - throw std::invalid_argument("Root dir invalid 1"); +// else +// throw std::invalid_argument("Root dir invalid 1"); } else if (key == "client_body_limit" && size == 1 \ && server->client_body_limit == 0) @@ -303,17 +304,18 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ else if (key == "root" && size == 1 && location->root == "") { // std::cout << "location root: " << tmp_val[0] << '\n'; - if (tmp_val[0][0] != '/') - throw std::invalid_argument("Root requires leading /"); +// if (tmp_val[0][0] != '/') +// throw std::invalid_argument("Root requires leading /"); - if (path_is_valid(tmp_val[0]) == 1) +// if (path_is_valid(tmp_val[0]) == 1) location->root = tmp_val[0]; - else - throw std::invalid_argument("Root dir invalid"); +// else +// throw std::invalid_argument("Root dir invalid"); } else if (key == "autoindex" && size == 1) { location->autoindex = (tmp_val[0] == "on" ? true : false); + std::cout << "in parser " << location->path << " autoindex: " << location->autoindex << '\n'; } else if (key == "index") { diff --git a/srcs/config/postProcessing.cpp b/srcs/config/postProcessing.cpp index 0ca5e5e..62c63b5 100644 --- a/srcs/config/postProcessing.cpp +++ b/srcs/config/postProcessing.cpp @@ -65,11 +65,12 @@ void ConfigParser::_post_processing(std::vector *servers) // maybe do something for Cgi_info? // std::cout << "In Post, Root + Path: " << it_l->root + it_l->path << '\n'; - if (path_is_valid(it_l->root + it_l->path) == 0) +/* if (path_is_valid(it_l->root + it_l->path) == 0) { //either we throw or we erase throw std::invalid_argument("location path is invalid"); } +*/ ++it_l; } diff --git a/srcs/utils.cpp b/srcs/utils.cpp index 2c3c15a..f8c498d 100644 --- a/srcs/utils.cpp +++ b/srcs/utils.cpp @@ -88,11 +88,14 @@ std::string http_methods_to_str(unsigned int methods) return (str); } +# include + // you could make this &path... int path_is_valid(std::string path) { - std::string i_path = path.substr(1); - const char *tmp_path = i_path.c_str(); +// std::string i_path = path.substr(1); +// const char *tmp_path = i_path.c_str(); + const char *tmp_path = path.c_str(); struct stat s; if (stat(tmp_path, &s) == 0) diff --git a/srcs/webserv/autoindex.hpp b/srcs/webserv/autoindex.hpp index 32d9d11..88911e3 100644 --- a/srcs/webserv/autoindex.hpp +++ b/srcs/webserv/autoindex.hpp @@ -10,13 +10,20 @@ ""\ " Index of " -# define AUTOINDEX_MID \ +# define AUTOINDEX_MID1 \ ""\ ""\ -"" +"" \ + "

Index of " +# define AUTOINDEX_MID2 \ +"

"\ +"
"\ +"
"
 
 # define AUTOINDEX_END \
+"
"\ +"
"\ ""\ "" diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index c658461..5a4b0eb 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -145,11 +145,22 @@ void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &locatio std::cout << "ERIC path: " << path << '\n'; -/* if (path_is_valid(path) == 1 && location.autoindex == true) +/* RULES ** + +if path is a valid dir check if index is specified and serve that +if no index and autoindex, server that +if file, server that! + +*/ + + +// std::cout << "location: " << location.path << " autoindex: " << location.autoindex << '\n'; + if (path_is_valid(path) == 1 && location.autoindex == true) { + std::cout << "about to call autoindex\n"; _autoindex(client, location, path); } -*/ + // TMP HUGO // @@ -182,17 +193,45 @@ void Webserv::_autoindex(Client *client, LocationConfig &location, std::string & // Let's try the 2nd one first. std::cout << "made it to _autoindex\n"; + std::string dir_list; DIR *dir; struct dirent *ent; - if ((dir = opendir ((location.root + location.path).c_str())) != NULL) { + if ((dir = opendir ((location.root + location.path).c_str())) != NULL) + { /* print all the files and directories within directory */ - while ((ent = readdir (dir)) != NULL) { - printf ("%s\n", ent->d_name); - } + dir_list.append(AUTOINDEX_START); + dir_list.append(location.path); + dir_list.append(AUTOINDEX_MID1); + dir_list.append(location.path); + dir_list.append(AUTOINDEX_MID2); + while ((ent = readdir (dir)) != NULL) + { +// printf ("%s\n", ent->d_name); + if (strcmp(".", ent->d_name) == 0) + continue ; + dir_list.append("d_name); + dir_list.append("\">"); + dir_list.append(ent->d_name); + dir_list.append(""); + dir_list.append("\r\n"); + } + +// nginx.org.
+ + dir_list.append(AUTOINDEX_END); + _append_body(client, dir_list.c_str(), dir_list.size(), "html"); + closedir (dir); - } else { + } + else + { /* could not open directory */ // perror (""); std::cout << "could not open dir\n"; @@ -201,19 +240,7 @@ void Webserv::_autoindex(Client *client, LocationConfig &location, std::string & - std::string dir_list; - dir_list.append(AUTOINDEX_START); - dir_list.append(location.path); - dir_list.append(AUTOINDEX_MID); - // loop something - dir_list.append(location.path); - - - - dir_list.append(AUTOINDEX_END); - - _append_body(client, dir_list.c_str(), dir_list.size(), "html"); @@ -453,10 +480,14 @@ ServerConfig &Webserv::_determine_process_server(Client *client) LocationConfig &Webserv::_determine_location(ServerConfig &server, std::string &path) { +// std::cout << "determin location path sent: " << path << '\n'; + std::vector::iterator it = server.locations.begin(); while (it != server.locations.end()) { - if (it->path.compare(0, path.size(), path)) +// std::cout << it->path << " -- "; + // if (it->path.compare(0, path.size(), path) == 0) + if (it->path.compare(0, it->path.size(), path) == 0) break; ++it; } From cf69168a8456cc6146d216c0f9f6debaa6df86f8 Mon Sep 17 00:00:00 2001 From: Me Date: Sun, 7 Aug 2022 22:54:58 +0200 Subject: [PATCH 14/21] some cleanup of config stuff --- srcs/config/parser.cpp | 18 +++++++++++++----- srcs/config/postProcessing.cpp | 20 +++++--------------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/srcs/config/parser.cpp b/srcs/config/parser.cpp index 38a5c4b..982b160 100644 --- a/srcs/config/parser.cpp +++ b/srcs/config/parser.cpp @@ -31,8 +31,6 @@ ConfigParser::ConfigParser(const char* path) 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()) { getline(file, buf); @@ -45,7 +43,7 @@ ConfigParser::ConfigParser(const char* path) } else if (comment > 0 && (buf.find_first_not_of(" \t")) < comment) { - // is there a comment at the end of the line + // check for comment at the end of the line std::string tmp = buf.substr(0, comment - 1); _content.append(tmp + '\n'); } @@ -53,7 +51,7 @@ ConfigParser::ConfigParser(const char* path) file.close(); } else - throw std::invalid_argument("open config"); + throw std::invalid_argument("failed to open config"); } ConfigParser::~ConfigParser() @@ -147,8 +145,11 @@ LocationConfig ConfigParser::_parse_location(size_t *start) ret.allow_methods = 0; ret.path = _get_first_word(&curr); -// if (ret.path[0] != '/') + if (ret.path[0] != '/') + ret.path.insert(0, "/"); // throw std::invalid_argument("Location path require a leading /"); + if (ret.path.back() != '/') + ret.path.push_back('/'); // in theory now curr should be right after the "path" curr = _content.find_first_not_of(" \t\n", curr); @@ -235,6 +236,10 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ // if (tmp_val[0][0] != '/') // throw std::invalid_argument("Root requires leading /"); + // remove trailing / + if (tmp_val[0].back() == '/') + tmp_val[0].erase(tmp_val[0].size(), 1); + // std::cout << "root: " << tmp_val[0] << '\n'; //might not even do these checks here... // if (path_is_valid(tmp_val[0]) == 1) @@ -307,6 +312,9 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ // if (tmp_val[0][0] != '/') // throw std::invalid_argument("Root requires leading /"); + // remove trailing / + if (tmp_val[0].back() == '/') + tmp_val[0].erase(tmp_val[0].size(), 1); // if (path_is_valid(tmp_val[0]) == 1) location->root = tmp_val[0]; // else diff --git a/srcs/config/postProcessing.cpp b/srcs/config/postProcessing.cpp index 62c63b5..c35968f 100644 --- a/srcs/config/postProcessing.cpp +++ b/srcs/config/postProcessing.cpp @@ -17,21 +17,18 @@ void ConfigParser::_post_processing(std::vector *servers) 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? - - + // index is mandatory in Server if (it->index.empty()) throw std::invalid_argument("Config file needs an Index"); - + if (it->client_body_limit == 0) + it->client_body_limit = 5000; // what is the recomended size? + // 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; @@ -55,10 +52,8 @@ void ConfigParser::_post_processing(std::vector *servers) if (it_l->allow_methods == UNKNOWN) it_l->allow_methods = ANY_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? + it_l->index = it->index; // same for redirect status i think @@ -74,11 +69,6 @@ void ConfigParser::_post_processing(std::vector *servers) ++it_l; } - - - -// std::cout << "made it to sorting...\n"; -// std::sort(it->locations.begin(), it->locations.end(), compareLocationConfigs); std::sort(it->locations.begin(), it->locations.end()); std::reverse(it->locations.begin(), it->locations.end()); From 9ee7205b95e6de1304e431c1a54af36a3905f696 Mon Sep 17 00:00:00 2001 From: Me Date: Mon, 8 Aug 2022 02:50:37 +0200 Subject: [PATCH 15/21] Index and Autoindex work nicely, standarized way paths for root and location path are stored in config, still needs a little polishing prolly --- default.config | 26 +--- srcs/config/LocationConfig.hpp | 39 +----- srcs/config/ServerConfig.hpp | 24 +--- srcs/config/parser.cpp | 33 +---- srcs/config/postProcessing.cpp | 6 +- srcs/utils.cpp | 15 --- srcs/webserv/Webserv.hpp | 1 + srcs/webserv/autoindex.hpp | 2 +- srcs/webserv/response.cpp | 118 +++++++++++------- www/test/index1.html | 2 +- www/test/something.html | 2 +- .../test_deeper/{index.html => index1.html} | 2 +- www/test/test_deeper/something.html | 2 +- 13 files changed, 99 insertions(+), 173 deletions(-) rename www/test/test_deeper/{index.html => index1.html} (70%) diff --git a/default.config b/default.config index ed483e0..7277066 100644 --- a/default.config +++ b/default.config @@ -10,30 +10,13 @@ server { # client_body_limit 400; index index.html; # this is another comment -# i think root requires leading / -# root goop; -# root ./www/; - 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 + + root ./www/; location /test { -# root /www/test; - autoindex on; + index something.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; -# index index.html; -# allow_methods DELETE; -# } - -# location /test/something.html { location /test/something.html { allow_methods DELETE; } @@ -41,7 +24,8 @@ server { # location /something/long/here { # } - location /test/test_deeper { + location /test/test_deeper/ { + autoindex on; } location /test/test_deeper/something.html { diff --git a/srcs/config/LocationConfig.hpp b/srcs/config/LocationConfig.hpp index cc09353..72a4886 100644 --- a/srcs/config/LocationConfig.hpp +++ b/srcs/config/LocationConfig.hpp @@ -30,22 +30,16 @@ 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; - - std::string root; + std::string path; // /path and /path/ are fine + // i add trailing / if a dir + std::string root; std::vector index; unsigned int allow_methods; std::vector cgi_ext; // php not .php - - bool autoindex; + bool autoindex; std::vector upload_repo; + // wait if i can call several times, shouldn't it be a map? // wait no there can only be 1 and i think it might have to be in // location only... @@ -79,12 +73,6 @@ public: int comp_rhs = 0; size_t tmp = 0; - // What are the rules... - // / is smaller than /test - // and /test/test1 is bigger than test - // so we want to count / - - while ((tmp = this->path.find_first_of("/", tmp)) != std::string::npos) { ++tmp; @@ -101,23 +89,6 @@ public: if (rhs.path[rhs.path.find_last_of("/") + 1] != '\0') ++comp_rhs; - // ok now we need to add a thing where we check for files vs folders -/* if (comp_lhs == comp_rhs) - { - if (path_is_valid(root + path) == 2) - --comp_lhs; - if (path_is_valid(rhs.root + rhs.path) == 2) - --comp_rhs; - } -*/ - -// std::cout << "comp_lhs: " << comp_lhs << " comp_rhs: " << comp_rhs -// << " bool res: " << (comp_lhs > comp_rhs) << "\n"; - // i honestly can't tell you how or why but using > rather than < - // fixed all my problems - // the fact that the bool was always 0 before, and the correct order - // i want... super weird... - // return (comp_lhs > comp_rhs); return (comp_lhs < comp_rhs); // right comparison ? not <= ? }; diff --git a/srcs/config/ServerConfig.hpp b/srcs/config/ServerConfig.hpp index ceee50a..c0feecf 100644 --- a/srcs/config/ServerConfig.hpp +++ b/srcs/config/ServerConfig.hpp @@ -14,44 +14,24 @@ class ServerConfig { public: - // do i need some canonic stuff? - - // there can be several std::vector server_name; // we could shove default in here if we wanted to... - // there can only be 1 per server... std::string host; std::string port; // port needs to be something else... not quite an int - // should a Server be able to handle several? - // there can only be one. - std::string root; + std::string root; // ./www/ or www work www/ and www work + // i do remove trailing / tho unsigned int client_body_limit; // set to default max if none set - // might be the only one we let slide if bad input... It remains false... - - // we will check the index in the post processing with access() ? std::vector index; std::map error_pages; - // fuck it, you can only call allow_methods once in Server - std::vector locations; - // not convinced we need these... -// struct timeval send_timeout; -// struct timeval recv_timeout; - - -// fuck maybe i do need return here... - // wait if i can call several times, shouldn't it be a map? -// i think actually there can only be 1 and it can only be in a location? -// int redirect_status; -// std::string redirect_uri; void print_all() { diff --git a/srcs/config/parser.cpp b/srcs/config/parser.cpp index 982b160..36a0ae2 100644 --- a/srcs/config/parser.cpp +++ b/srcs/config/parser.cpp @@ -148,8 +148,6 @@ LocationConfig ConfigParser::_parse_location(size_t *start) if (ret.path[0] != '/') ret.path.insert(0, "/"); // throw std::invalid_argument("Location path require a leading /"); - if (ret.path.back() != '/') - ret.path.push_back('/'); // in theory now curr should be right after the "path" curr = _content.find_first_not_of(" \t\n", curr); @@ -233,19 +231,10 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ } else if (key == "root" && size == 1 && server->root == "") { -// if (tmp_val[0][0] != '/') -// throw std::invalid_argument("Root requires leading /"); - // remove trailing / - if (tmp_val[0].back() == '/') - tmp_val[0].erase(tmp_val[0].size(), 1); - - // std::cout << "root: " << tmp_val[0] << '\n'; -//might not even do these checks here... -// if (path_is_valid(tmp_val[0]) == 1) - server->root = tmp_val[0]; -// else -// throw std::invalid_argument("Root dir invalid 1"); + if (tmp_val[0][tmp_val[0].size() - 1] == '/') + tmp_val[0].erase(tmp_val[0].size() - 1, 1); + server->root = tmp_val[0]; } else if (key == "client_body_limit" && size == 1 \ && server->client_body_limit == 0) @@ -257,9 +246,6 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ else if (key == "index") { // i think you can call index several times... - // should i be doing an access? - // since index is at the root, but root might not yet be defined - // will check index later in post for (unsigned long i = 0; i != tmp_val.size(); i++) server->index.push_back(tmp_val[i]); } @@ -288,11 +274,7 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ } } else - { - // means either you didn't write the right key, or the value is - // missing, or the value has already been filled. throw std::invalid_argument("bad key value pair"); - } } @@ -313,8 +295,9 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ // throw std::invalid_argument("Root requires leading /"); // remove trailing / - if (tmp_val[0].back() == '/') - tmp_val[0].erase(tmp_val[0].size(), 1); + // if (tmp_val[0].back() == '/') + if (tmp_val[0][tmp_val[0].size() - 1] == '/') + tmp_val[0].erase(tmp_val[0].size() - 1, 1); // if (path_is_valid(tmp_val[0]) == 1) location->root = tmp_val[0]; // else @@ -367,11 +350,7 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ location->redirect_uri = tmp_val[1]; } else - { - // means either you didn't write the right key, or the value is - // missing, or the value has already been filled. throw std::invalid_argument("bad key value pair"); - } } diff --git a/srcs/config/postProcessing.cpp b/srcs/config/postProcessing.cpp index c35968f..61f338a 100644 --- a/srcs/config/postProcessing.cpp +++ b/srcs/config/postProcessing.cpp @@ -57,7 +57,7 @@ void ConfigParser::_post_processing(std::vector *servers) // same for redirect status i think - // maybe do something for Cgi_info? + // maybe do something for Cgi_ext? // std::cout << "In Post, Root + Path: " << it_l->root + it_l->path << '\n'; /* if (path_is_valid(it_l->root + it_l->path) == 0) @@ -66,6 +66,10 @@ void ConfigParser::_post_processing(std::vector *servers) throw std::invalid_argument("location path is invalid"); } */ + if (path_is_valid(it_l->root + it_l->path) == 1 \ + && it_l->path[it_l->path.size() - 1] != '/') + it_l->path.push_back('/'); + ++it_l; } diff --git a/srcs/utils.cpp b/srcs/utils.cpp index f8c498d..b53f4a7 100644 --- a/srcs/utils.cpp +++ b/srcs/utils.cpp @@ -93,8 +93,6 @@ std::string http_methods_to_str(unsigned int methods) // you could make this &path... int path_is_valid(std::string path) { -// std::string i_path = path.substr(1); -// const char *tmp_path = i_path.c_str(); const char *tmp_path = path.c_str(); struct stat s; @@ -111,19 +109,6 @@ int path_is_valid(std::string path) return (1); } } - -/* - if (stat(tmp_path, &s) == 0 && S_ISREG(s.st_mode)) // a File - { - std::cout << "is a file\n"; - return (2); - } - else if (stat(tmp_path, &s) == 0 && S_ISDIR(s.st_mode)) // A Folder - { - std::cout << "is a Dir\n"; - return (1); - } -*/ // std::cout << "path is neither dir nor file\n"; return (0); } diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index e5fe312..246a818 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -24,6 +24,7 @@ # include // string # include // perror, remove # include // atoi (athough it's already cover by ) +# include // opendir() # include "Client.hpp" # include "ServerConfig.hpp" diff --git a/srcs/webserv/autoindex.hpp b/srcs/webserv/autoindex.hpp index 88911e3..1fc9f9e 100644 --- a/srcs/webserv/autoindex.hpp +++ b/srcs/webserv/autoindex.hpp @@ -8,7 +8,7 @@ ""\ ""\ ""\ - " Index of " + "<title>Index of " # define AUTOINDEX_MID1 \ ""\ diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 5a4b0eb..70d0aaa 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -134,32 +134,64 @@ void Webserv::_error_html_response(Client *client, ServerConfig &server) #define INDEX "index.html" // temp wip void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &location) { - (void)server; // To remove from arg if we determine its useless - std::string path = client->get_path(); - - if (path == "/") // TODO : index and autoindex - path.append(INDEX); - path.insert(0, location.root); - - std::cerr << "path = " << path << "\n"; - - std::cout << "ERIC path: " << path << '\n'; - /* RULES ** if path is a valid dir check if index is specified and serve that if no index and autoindex, server that if file, server that! +WHere does cgi fit in in all this ??? + +THIS NEEDS WORK... + +*/ + (void)server; // To remove from arg if we determine its useless + std::string path = client->get_path(); + +/* if (path == "/") // TODO : index and autoindex + path.append(INDEX); + path.insert(0, location.root); */ + // that was actually a horrible idea... + path.insert(0, location.root); + std::cerr << "path = " << path << "\n"; -// std::cout << "location: " << location.path << " autoindex: " << location.autoindex << '\n'; - if (path_is_valid(path) == 1 && location.autoindex == true) + // path = root + location.path + // we will tack on an index if there is a valid one + // or autoindex if allowed + // or let _get_file sort out the error otherwise. + + if (path_is_valid(path) == 1) { - std::cout << "about to call autoindex\n"; - _autoindex(client, location, path); + std::cout << "path is valid\n"; + if (path[path.size() - 1] != '/') + path.push_back('/'); + for (size_t i = 0; i < location.index.size(); i++) + { + std::cout << "location path: " << location.path << '\n'; + std::cout << "location index: " << location.index[i] << '\n'; +// std::cout << "path with index: " << path + location.index[i] << '\n'; + if (path_is_valid(path + location.index[i]) == 2) + { + std::cout << "found a valid index\n"; + path.append(location.index[i]); + break ; // what if index and autoindex in a single location? + // does this completely fail? + // do this instead of break? + //_get_file(client, path); + } + } + if (location.autoindex == true) + { + _autoindex(client, location, path); + return ; + } } +// else +// _get_file(client, path); + // what about cgi ??? + // TMP HUGO @@ -175,29 +207,21 @@ if file, server that! _get_file(client, path); } -// i might need some sort of _generate_autoindex() - -#include -#include +// i only sort of need &path... +// def can improve but works for now... void Webserv::_autoindex(Client *client, LocationConfig &location, std::string &path) { - // i think the plan is to generate an html file and return it - // it should be filled with the stuff that is found in that repo - - // either i create a tmp file and put the html in it an call - // the _get_file on it with a new path... - // or i make the html and do what _get_file does if it found - // a valid file... - - // Let's try the 2nd one first. - std::cout << "made it to _autoindex\n"; - std::string dir_list; - DIR *dir; - struct dirent *ent; + std::string dir_list; + DIR *dir; + struct dirent *ent; + std::cout << "location root: " << location.root << " location path: " \ + << location.path << '\n'; + +// if ((dir = opendir (path.c_str())) != NULL) if ((dir = opendir ((location.root + location.path).c_str())) != NULL) { /* print all the files and directories within directory */ @@ -208,44 +232,36 @@ void Webserv::_autoindex(Client *client, LocationConfig &location, std::string & dir_list.append(AUTOINDEX_MID2); while ((ent = readdir (dir)) != NULL) { -// printf ("%s\n", ent->d_name); if (strcmp(".", ent->d_name) == 0) continue ; dir_list.append("d_name); dir_list.append("\">"); dir_list.append(ent->d_name); dir_list.append(""); - dir_list.append("\r\n"); + dir_list.append("\r\n"); // is this right? } // nginx.org.
+// index1.html + +// apparently this is more than good enough! +// .. dir_list.append(AUTOINDEX_END); - _append_body(client, dir_list.c_str(), dir_list.size(), "html"); - + std::cout << "\n\n" << dir_list << '\n'; closedir (dir); + _append_body(client, dir_list.c_str(), dir_list.size(), "html"); } else { + // in theory not possible cuz we already checked... /* could not open directory */ // perror (""); std::cout << "could not open dir\n"; return ; } - - - - - - - - // if successful we call _append_body - } @@ -255,6 +271,8 @@ void Webserv::_get_file(Client *client, const std::string &path) std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ? // char buf[MAX_FILESIZE+1]; + std::cout << "made it to get_file\n"; + if (access(path.c_str(), F_OK) == -1) { std::perror("err access()"); @@ -489,6 +507,10 @@ LocationConfig &Webserv::_determine_location(ServerConfig &server, std::string & // if (it->path.compare(0, path.size(), path) == 0) if (it->path.compare(0, it->path.size(), path) == 0) break; +// kinda gross i know but... have to deal with when there's a / at the end + if (it->path[it->path.size() - 1] == '/' \ + && it->path.compare(0, it->path.size() - 1, path) == 0) + break; ++it; } if (it != server.locations.end()) diff --git a/www/test/index1.html b/www/test/index1.html index ba02623..1db5ee9 100644 --- a/www/test/index1.html +++ b/www/test/index1.html @@ -4,7 +4,7 @@ Webserv test index -

Le index (˘ ͜ʖ˘)

+

Webserv Test Index


(˚3˚)

diff --git a/www/test/something.html b/www/test/something.html index 3e8a32f..5eb0f8b 100644 --- a/www/test/something.html +++ b/www/test/something.html @@ -4,7 +4,7 @@ Webserv test Something -

Le index (˘ ͜ʖ˘)

+

Webserv Test Something


(˚3˚)

diff --git a/www/test/test_deeper/index.html b/www/test/test_deeper/index1.html similarity index 70% rename from www/test/test_deeper/index.html rename to www/test/test_deeper/index1.html index 2992159..c5c0b87 100644 --- a/www/test/test_deeper/index.html +++ b/www/test/test_deeper/index1.html @@ -4,7 +4,7 @@ Webserv Test Deeper Index -

Le index (˘ ͜ʖ˘)

+

Webserv Test Deeper Index


(˚3˚)

diff --git a/www/test/test_deeper/something.html b/www/test/test_deeper/something.html index 44f17ac..c864180 100644 --- a/www/test/test_deeper/something.html +++ b/www/test/test_deeper/something.html @@ -4,7 +4,7 @@ Webserv test deeper Something -

Le index (˘ ͜ʖ˘)

+

Webserv Test Deeper Something


(˚3˚)

From f87024c32f969e9532f8276c033eed24e9013958 Mon Sep 17 00:00:00 2001 From: Me Date: Mon, 8 Aug 2022 04:02:53 +0200 Subject: [PATCH 16/21] further tested autoindex, and i got a .css stylesheet to load from a folder outside of /www, pretty neat :) --- default.config | 12 +++++++++++- stylesheet/style.css | 4 ++++ www/test/index1.html | 5 ++++- www/test/test_deeper/super_deep/something.html | 11 +++++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 stylesheet/style.css create mode 100644 www/test/test_deeper/super_deep/something.html diff --git a/default.config b/default.config index 7277066..ab88bfd 100644 --- a/default.config +++ b/default.config @@ -14,7 +14,13 @@ server { root ./www/; location /test { - index something.html; + index index1.html; + } + + # /stylesheet/ alone doesn't work, i mean we don't have wildcards... + location /stylesheet/style.css { +# root ./www/../; + root ./; } location /test/something.html { @@ -28,6 +34,10 @@ server { autoindex on; } + location /test/test_deeper/super_deep { + autoindex on; + } + location /test/test_deeper/something.html { allow_methods DELETE; } diff --git a/stylesheet/style.css b/stylesheet/style.css new file mode 100644 index 0000000..2035bb4 --- /dev/null +++ b/stylesheet/style.css @@ -0,0 +1,4 @@ +h1 { + color: red; + text-align: center; +} diff --git a/www/test/index1.html b/www/test/index1.html index 1db5ee9..f976302 100644 --- a/www/test/index1.html +++ b/www/test/index1.html @@ -2,9 +2,12 @@ Webserv test index + + + -

Webserv Test Index

+

Webserv Test Index


(˚3˚)

diff --git a/www/test/test_deeper/super_deep/something.html b/www/test/test_deeper/super_deep/something.html new file mode 100644 index 0000000..94fb38c --- /dev/null +++ b/www/test/test_deeper/super_deep/something.html @@ -0,0 +1,11 @@ + + + + Webserv test deeper Something + + +

Webserv Test Super Deep Something

+
+

(˚3˚)

+ + From 02cfdf43bc3e32b79e604bbd94cb454d4d808f0d Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Mon, 8 Aug 2022 04:24:03 +0200 Subject: [PATCH 17/21] bad_alloc handling + map.insert() replace map.operator[] for init, more efficient --- memo.txt | 4 +- srcs/main.cpp | 2 +- srcs/utils.cpp | 8 ++ srcs/utils.hpp | 1 + srcs/webserv/init.cpp | 241 ++++++++++++++++++++------------------ srcs/webserv/request.cpp | 2 +- srcs/webserv/response.cpp | 8 +- srcs/webserv/run_loop.cpp | 32 +++-- 8 files changed, 162 insertions(+), 136 deletions(-) diff --git a/memo.txt b/memo.txt index 03ec750..5b32a3e 100644 --- a/memo.txt +++ b/memo.txt @@ -1,9 +1,10 @@ IN 42 SUBJECT, PRIORITY : +- chunked request (response not mandatory it seems) +- upload files with confif "upload_dir" - 505 HTTP Version Not Supported - CGI - handle redirection - index and autoindex -- gestion memoire en cas de bad_alloc - Ecrire des tests ! ----------------------------- - replace atoi() with a better function @@ -17,7 +18,6 @@ IN 42 SUBJECT, PRIORITY : - add headers "Date" and "Last-Modified" to response - change "std::string" to reference "std::string &" in most functions and add "const" if apropriate. -- http_method en mode binary flags. "std::vector allow_methods" -> "unsigned int allow_methods;" - Dans le parsing, trier les "locations" par ordre de precision. Compter les "/" dans le chemin, les locations avec le plus de "/" seront en premier dans le vector. - Il faut vérifier le path de la requête, voir si le serveur est bien censé délivrer cette ressource et si le client y a accès, avant d'appeler le CGI. diff --git a/srcs/main.cpp b/srcs/main.cpp index fbe96e3..94b1fc4 100644 --- a/srcs/main.cpp +++ b/srcs/main.cpp @@ -44,7 +44,7 @@ int main(int ac, char **av) } catch (std::exception& e) { - std::cout << e.what() << '\n'; + std::cerr << e.what() << '\n'; } return (0); diff --git a/srcs/utils.cpp b/srcs/utils.cpp index 2144a51..a03a33b 100644 --- a/srcs/utils.cpp +++ b/srcs/utils.cpp @@ -1,6 +1,14 @@ #include "utils.hpp" +void throw_test() +{ + static int i = 0; + ++i; + if (i % 8 == 0) + throw std::bad_alloc(); +} + std::vector split(std::string input, char delimiter) { std::vector answer; diff --git a/srcs/utils.hpp b/srcs/utils.hpp index 6ea657c..7d81a94 100644 --- a/srcs/utils.hpp +++ b/srcs/utils.hpp @@ -46,5 +46,6 @@ 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); void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr); +void throw_test(); #endif diff --git a/srcs/webserv/init.cpp b/srcs/webserv/init.cpp index f86d5ee..cfe877b 100644 --- a/srcs/webserv/init.cpp +++ b/srcs/webserv/init.cpp @@ -89,135 +89,144 @@ void Webserv::_listen(int socket_fd, unsigned int max_connections) void Webserv::_init_http_status_map() { - _http_status[200] = S200; - _http_status[201] = S201; - _http_status[204] = S204; +/* "map.insert()" over "map.operator[]" : +** http://www.uml.org.cn/c%2B%2B/pdf/EffectiveSTL.pdf#page=93 +*/ + typedef std::map::value_type status_pair; - _http_status[400] = S400; - _http_status[403] = S403; - _http_status[404] = S404; - _http_status[405] = S405; - _http_status[413] = S413; + // _http_status.insert(std::make_pair(200, S200)); // equivalent + _http_status.insert(status_pair(200, S200)); + _http_status.insert(status_pair(201, S201)); + _http_status.insert(status_pair(204, S204)); - _http_status[500] = S500; - _http_status[501] = S501; + _http_status.insert(status_pair(400, S400)); + _http_status.insert(status_pair(403, S403)); + _http_status.insert(status_pair(404, S404)); + _http_status.insert(status_pair(405, S405)); + _http_status.insert(status_pair(413, S413)); + + _http_status.insert(status_pair(500, S500)); + _http_status.insert(status_pair(501, S501)); } void Webserv::_init_mime_types_map() { -/* -** From : http://nginx.org/en/docs/http/ngx_http_core_module.html#types +/* From : +** http://nginx.org/en/docs/http/ngx_http_core_module.html#types */ - _mime_types[""] = MIME_TYPE_DEFAULT; + typedef std::map::value_type mime_pair; - _mime_types["html"] = "text/html"; - _mime_types["htm"] = "text/html"; - _mime_types["shtml"] = "text/html"; - _mime_types["css"] = "text/css"; - _mime_types["xml"] = "text/xml"; - _mime_types["gif"] = "image/gif"; - _mime_types["jpeg"] = "image/jpeg"; - _mime_types["jpg"] = "image/jpeg"; - _mime_types["js"] = "application/javascript"; - _mime_types["atom"] = "application/atom+xml"; - _mime_types["rss"] = "application/rss+xml"; + _mime_types.insert(mime_pair("", MIME_TYPE_DEFAULT)); - _mime_types["mml"] = "text/mathml"; - _mime_types["txt"] = "text/plain"; - _mime_types["jad"] = "text/vnd.sun.j2me.app-descriptor"; - _mime_types["wml"] = "text/vnd.wap.wml"; - _mime_types["htc"] = "text/x-component"; + _mime_types.insert(mime_pair("html", "text/html")); + _mime_types.insert(mime_pair("html", "text/html")); + _mime_types.insert(mime_pair("htm", "text/html")); + _mime_types.insert(mime_pair("shtml", "text/html")); + _mime_types.insert(mime_pair("css", "text/css")); + _mime_types.insert(mime_pair("xml", "text/xml")); + _mime_types.insert(mime_pair("gif", "image/gif")); + _mime_types.insert(mime_pair("jpeg", "image/jpeg")); + _mime_types.insert(mime_pair("jpg", "image/jpeg")); + _mime_types.insert(mime_pair("js", "application/javascript")); + _mime_types.insert(mime_pair("atom", "application/atom+xml")); + _mime_types.insert(mime_pair("rss", "application/rss+xml")); - _mime_types["png"] = "image/png"; - _mime_types["tif"] = "image/tiff"; - _mime_types["tiff"] = "image/tiff"; - _mime_types["wbmp"] = "image/vnd.wap.wbmp"; - _mime_types["ico"] = "image/x-icon"; - _mime_types["jng"] = "image/x-jng"; - _mime_types["bmp"] = "image/x-ms-bmp"; - _mime_types["svg"] = "image/svg+xml"; - _mime_types["svgz"] = "image/svg+xml"; - _mime_types["webp"] = "image/webp"; + _mime_types.insert(mime_pair("mml", "text/mathml")); + _mime_types.insert(mime_pair("txt", "text/plain")); + _mime_types.insert(mime_pair("jad", "text/vnd.sun.j2me.app-descriptor")); + _mime_types.insert(mime_pair("wml", "text/vnd.wap.wml")); + _mime_types.insert(mime_pair("htc", "text/x-component")); - _mime_types["woff"] = "application/font-woff"; - _mime_types["jar"] = "application/java-archive"; - _mime_types["war"] = "application/java-archive"; - _mime_types["ear"] = "application/java-archive"; - _mime_types["json"] = "application/json"; - _mime_types["hqx"] = "application/mac-binhex40"; - _mime_types["doc"] = "application/msword"; - _mime_types["pdf"] = "application/pdf"; - _mime_types["ps"] = "application/postscript"; - _mime_types["eps"] = "application/postscript"; - _mime_types["ai"] = "application/postscript"; - _mime_types["rtf"] = "application/rtf"; - _mime_types["m3u8"] = "application/vnd.apple.mpegurl"; - _mime_types["xls"] = "application/vnd.ms-excel"; - _mime_types["eot"] = "application/vnd.ms-fontobject"; - _mime_types["ppt"] = "application/vnd.ms-powerpoint"; - _mime_types["wmlc"] = "application/vnd.wap.wmlc"; - _mime_types["kml"] = "application/vnd.google-earth.kml+xml"; - _mime_types["kmz"] = "application/vnd.google-earth.kmz"; - _mime_types["7z"] = "application/x-7z-compressed"; - _mime_types["cco"] = "application/x-cocoa"; - _mime_types["jardiff"] = "application/x-java-archive-diff"; - _mime_types["jnlp"] = "application/x-java-jnlp-file"; - _mime_types["run"] = "application/x-makeself"; - _mime_types["pl"] = "application/x-perl"; - _mime_types["pm"] = "application/x-perl"; - _mime_types["prc"] = "application/x-pilot"; - _mime_types["pdb"] = "application/x-pilot"; - _mime_types["rar"] = "application/x-rar-compressed"; - _mime_types["rpm"] = "application/x-redhat-package-manager"; - _mime_types["sea"] = "application/x-sea"; - _mime_types["swf"] = "application/x-shockwave-flash"; - _mime_types["sit"] = "application/x-stuffit"; - _mime_types["tcl"] = "application/x-tcl"; - _mime_types["tk"] = "application/x-tcl"; - _mime_types["der"] = "application/x-x509-ca-cert"; - _mime_types["pem"] = "application/x-x509-ca-cert"; - _mime_types["crt"] = "application/x-x509-ca-cert"; - _mime_types["xpi"] = "application/x-xpinstall"; - _mime_types["xhtml"] = "application/xhtml+xml"; - _mime_types["xspf"] = "application/xspf+xml"; - _mime_types["zip"] = "application/zip"; + _mime_types.insert(mime_pair("png", "image/png")); + _mime_types.insert(mime_pair("tif", "image/tiff")); + _mime_types.insert(mime_pair("tiff", "image/tiff")); + _mime_types.insert(mime_pair("wbmp", "image/vnd.wap.wbmp")); + _mime_types.insert(mime_pair("ico", "image/x-icon")); + _mime_types.insert(mime_pair("jng", "image/x-jng")); + _mime_types.insert(mime_pair("bmp", "image/x-ms-bmp")); + _mime_types.insert(mime_pair("svg", "image/svg+xml")); + _mime_types.insert(mime_pair("svgz", "image/svg+xml")); + _mime_types.insert(mime_pair("webp", "image/webp")); - _mime_types["bin"] = "application/octet-stream"; - _mime_types["exe"] = "application/octet-stream"; - _mime_types["dll"] = "application/octet-stream"; - _mime_types["deb"] = "application/octet-stream"; - _mime_types["dmg"] = "application/octet-stream"; - _mime_types["iso"] = "application/octet-stream"; - _mime_types["img"] = "application/octet-stream"; - _mime_types["msi"] = "application/octet-stream"; - _mime_types["msp"] = "application/octet-stream"; - _mime_types["msm"] = "application/octet-stream"; + _mime_types.insert(mime_pair("woff", "application/font-woff")); + _mime_types.insert(mime_pair("jar", "application/java-archive")); + _mime_types.insert(mime_pair("war", "application/java-archive")); + _mime_types.insert(mime_pair("ear", "application/java-archive")); + _mime_types.insert(mime_pair("json", "application/json")); + _mime_types.insert(mime_pair("hqx", "application/mac-binhex40")); + _mime_types.insert(mime_pair("doc", "application/msword")); + _mime_types.insert(mime_pair("pdf", "application/pdf")); + _mime_types.insert(mime_pair("ps", "application/postscript")); + _mime_types.insert(mime_pair("eps", "application/postscript")); + _mime_types.insert(mime_pair("ai", "application/postscript")); + _mime_types.insert(mime_pair("rtf", "application/rtf")); + _mime_types.insert(mime_pair("m3u8", "application/vnd.apple.mpegurl")); + _mime_types.insert(mime_pair("xls", "application/vnd.ms-excel")); + _mime_types.insert(mime_pair("eot", "application/vnd.ms-fontobject")); + _mime_types.insert(mime_pair("ppt", "application/vnd.ms-powerpoint")); + _mime_types.insert(mime_pair("wmlc", "application/vnd.wap.wmlc")); + _mime_types.insert(mime_pair("kml", "application/vnd.google-earth.kml+xml")); + _mime_types.insert(mime_pair("kmz", "application/vnd.google-earth.kmz")); + _mime_types.insert(mime_pair("7z", "application/x-7z-compressed")); + _mime_types.insert(mime_pair("cco", "application/x-cocoa")); + _mime_types.insert(mime_pair("jardiff", "application/x-java-archive-diff")); + _mime_types.insert(mime_pair("jnlp", "application/x-java-jnlp-file")); + _mime_types.insert(mime_pair("run", "application/x-makeself")); + _mime_types.insert(mime_pair("pl", "application/x-perl")); + _mime_types.insert(mime_pair("pm", "application/x-perl")); + _mime_types.insert(mime_pair("prc", "application/x-pilot")); + _mime_types.insert(mime_pair("pdb", "application/x-pilot")); + _mime_types.insert(mime_pair("rar", "application/x-rar-compressed")); + _mime_types.insert(mime_pair("rpm", "application/x-redhat-package-manager")); + _mime_types.insert(mime_pair("sea", "application/x-sea")); + _mime_types.insert(mime_pair("swf", "application/x-shockwave-flash")); + _mime_types.insert(mime_pair("sit", "application/x-stuffit")); + _mime_types.insert(mime_pair("tcl", "application/x-tcl")); + _mime_types.insert(mime_pair("tk", "application/x-tcl")); + _mime_types.insert(mime_pair("der", "application/x-x509-ca-cert")); + _mime_types.insert(mime_pair("pem", "application/x-x509-ca-cert")); + _mime_types.insert(mime_pair("crt", "application/x-x509-ca-cert")); + _mime_types.insert(mime_pair("xpi", "application/x-xpinstall")); + _mime_types.insert(mime_pair("xhtml", "application/xhtml+xml")); + _mime_types.insert(mime_pair("xspf", "application/xspf+xml")); + _mime_types.insert(mime_pair("zip", "application/zip")); - _mime_types["docx"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; - _mime_types["xlsx"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; - _mime_types["pptx"] = "application/vnd.openxmlformats-officedocument.presentationml.presentation"; + _mime_types.insert(mime_pair("bin", "application/octet-stream")); + _mime_types.insert(mime_pair("exe", "application/octet-stream")); + _mime_types.insert(mime_pair("dll", "application/octet-stream")); + _mime_types.insert(mime_pair("deb", "application/octet-stream")); + _mime_types.insert(mime_pair("dmg", "application/octet-stream")); + _mime_types.insert(mime_pair("iso", "application/octet-stream")); + _mime_types.insert(mime_pair("img", "application/octet-stream")); + _mime_types.insert(mime_pair("msi", "application/octet-stream")); + _mime_types.insert(mime_pair("msp", "application/octet-stream")); + _mime_types.insert(mime_pair("msm", "application/octet-stream")); - _mime_types["mid"] = "audio/midi"; - _mime_types["midi"] = "audio/midi"; - _mime_types["kar"] = "audio/midi"; - _mime_types["mp3"] = "audio/mpeg"; - _mime_types["ogg"] = "audio/ogg"; - _mime_types["m4a"] = "audio/x-m4a"; - _mime_types["ra"] = "audio/x-realaudio"; + _mime_types.insert(mime_pair("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document")); + _mime_types.insert(mime_pair("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")); + _mime_types.insert(mime_pair("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation")); - _mime_types["3gpp"] = "video/3gpp"; - _mime_types["3gp"] = "video/3gpp"; - _mime_types["ts"] = "video/mp2t"; - _mime_types["mp4"] = "video/mp4"; - _mime_types["mpeg"] = "video/mpeg"; - _mime_types["mpg"] = "video/mpeg"; - _mime_types["mov"] = "video/quicktime"; - _mime_types["webm"] = "video/webm"; - _mime_types["flv"] = "video/x-flv"; - _mime_types["m4v"] = "video/x-m4v"; - _mime_types["mng"] = "video/x-mng"; - _mime_types["asx"] = "video/x-ms-asf"; - _mime_types["asf"] = "video/x-ms-asf"; - _mime_types["wmv"] = "video/x-ms-wmv"; - _mime_types["avi"] = "video/x-msvideo"; + _mime_types.insert(mime_pair("mid", "audio/midi")); + _mime_types.insert(mime_pair("midi", "audio/midi")); + _mime_types.insert(mime_pair("kar", "audio/midi")); + _mime_types.insert(mime_pair("mp3", "audio/mpeg")); + _mime_types.insert(mime_pair("ogg", "audio/ogg")); + _mime_types.insert(mime_pair("m4a", "audio/x-m4a")); + _mime_types.insert(mime_pair("ra", "audio/x-realaudio")); + + _mime_types.insert(mime_pair("3gpp", "video/3gpp")); + _mime_types.insert(mime_pair("3gp", "video/3gpp")); + _mime_types.insert(mime_pair("ts", "video/mp2t")); + _mime_types.insert(mime_pair("mp4", "video/mp4")); + _mime_types.insert(mime_pair("mpeg", "video/mpeg")); + _mime_types.insert(mime_pair("mpg", "video/mpeg")); + _mime_types.insert(mime_pair("mov", "video/quicktime")); + _mime_types.insert(mime_pair("webm", "video/webm")); + _mime_types.insert(mime_pair("flv", "video/x-flv")); + _mime_types.insert(mime_pair("m4v", "video/x-m4v")); + _mime_types.insert(mime_pair("mng", "video/x-mng")); + _mime_types.insert(mime_pair("asx", "video/x-ms-asf")); + _mime_types.insert(mime_pair("asf", "video/x-ms-asf")); + _mime_types.insert(mime_pair("wmv", "video/x-ms-wmv")); + _mime_types.insert(mime_pair("avi", "video/x-msvideo")); } diff --git a/srcs/webserv/request.cpp b/srcs/webserv/request.cpp index 8a96573..b492a63 100644 --- a/srcs/webserv/request.cpp +++ b/srcs/webserv/request.cpp @@ -11,7 +11,7 @@ void Webserv::_request(Client *client) _handle_last_signal(); } -void Webserv::_read_request(Client *client) +void Webserv::_read_request(Client *client) // Messy, Need refactoring { char buf[BUFSIZE]; ssize_t ret; diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 08fdf7e..825055e 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -15,7 +15,8 @@ void Webserv::_send_response(Client *client) std::cerr << "send()\n"; _append_base_headers(client); - _construct_response(client); + if (!client->status) + _construct_response(client); _insert_status_line(client); if (client->status >= 400) _error_html_response(client); @@ -181,7 +182,6 @@ void Webserv::_get_file(Client *client, const std::string &path) // Then chunk client->status = 500; // WIP temp std::cerr << "File too large for non chunk body\n"; - ifd.close(); return ; } @@ -198,8 +198,6 @@ void Webserv::_get_file(Client *client, const std::string &path) std::string file_ext = _determine_file_extension(path); _append_body(client, buf.str(), file_ext); } - - ifd.close(); } } @@ -287,8 +285,6 @@ void Webserv::_post_file(Client *client, const std::string &path) client->status = 201; // WIP https://www.rfc-editor.org/rfc/rfc9110.html#section-9.3.3-4 } - - ofd.close(); } } diff --git a/srcs/webserv/run_loop.cpp b/srcs/webserv/run_loop.cpp index ec9165d..04c1e03 100644 --- a/srcs/webserv/run_loop.cpp +++ b/srcs/webserv/run_loop.cpp @@ -34,17 +34,29 @@ void Webserv::run() i = 0; while (i < nfds) { - // TODO : handle EPOLLERR and EPOLLHUP - it_socket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd); - if (it_socket != _listen_sockets.end() && events[i].events & EPOLLIN) - _accept_connection(*it_socket); - else if (events[i].events & EPOLLIN) - _request( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) ); - else if (events[i].events & EPOLLOUT) - _response( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) ); - ++i; - if (!g_run) + try + { + // TODO : handle EPOLLERR and EPOLLHUP + it_socket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd); + if (it_socket != _listen_sockets.end() && events[i].events & EPOLLIN) + _accept_connection(*it_socket); + else if (events[i].events & EPOLLIN) + _request( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) ); + else if (events[i].events & EPOLLOUT) + _response( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) ); + ++i; + if (!g_run) + break; + } + catch (const std::bad_alloc& e) + { + std::cerr << e.what() << '\n'; + _close_all_clients(); + /* Swap to free the memory + From : http://www.uml.org.cn/c%2B%2B/pdf/EffectiveSTL.pdf#page=66 */ + std::vector().swap(_clients); break; + } } } } From 7fdc81f5f45659c2155bdfc99ed539d55d4603ba Mon Sep 17 00:00:00 2001 From: Me Date: Mon, 8 Aug 2022 17:13:55 +0200 Subject: [PATCH 18/21] a bit messy but merged index and autoindex work --- srcs/webserv/Webserv.hpp | 2 +- srcs/webserv/response.cpp | 53 ++++++++++++++++++--------------------- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index fd7abbf..5084386 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -88,7 +88,7 @@ class Webserv // void _get(Client *client, ServerConfig &server, LocationConfig &location); // in progress - void _autoindex(Client *client, LocationConfig &location, std::string &path); + void _autoindex(Client *client, std::string &path); void _get_file(Client *client, const std::string &path); diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 7083008..2fbeea9 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -128,21 +128,13 @@ if file, server that! WHere does cgi fit in in all this ??? -THIS NEEDS WORK... */ - (void)server; // To remove from arg if we determine its useless std::string path = client->get_path(); -/* if (path == "/") // TODO : index and autoindex - path.append(INDEX); -<<<<<<< HEAD - path.insert(0, location.root); -*/ + // this might not be the best thing, a voir path.insert(0, client->assigned_location->root); - // that was actually a horrible idea... -// path.insert(0, location.root); std::cerr << "path = " << path << "\n"; // path = root + location.path @@ -152,27 +144,28 @@ THIS NEEDS WORK... if (path_is_valid(path) == 1) { - std::cout << "path is valid\n"; + // std::cout << "path is valid\n"; if (path[path.size() - 1] != '/') path.push_back('/'); - for (size_t i = 0; i < location.index.size(); i++) + for (size_t i = 0; i < client->assigned_location->index.size(); i++) { - std::cout << "location path: " << location.path << '\n'; - std::cout << "location index: " << location.index[i] << '\n'; -// std::cout << "path with index: " << path + location.index[i] << '\n'; - if (path_is_valid(path + location.index[i]) == 2) +// std::cout << "location path: " << client->assigned_location->path << '\n'; +// std::cout << "location index: " << client->assigned_location->index[i] << '\n'; +// std::cout << "path with index: " << path + assigned_location->index[i] << '\n'; + if (path_is_valid(path + client->assigned_location->index[i]) == 2) { - std::cout << "found a valid index\n"; - path.append(location.index[i]); + // std::cout << "found a valid index\n"; + path.append(client->assigned_location->index[i]); break ; // what if index and autoindex in a single location? // does this completely fail? // do this instead of break? //_get_file(client, path); } } - if (location.autoindex == true) + if (client->assigned_location->autoindex == true) { - _autoindex(client, location, path); + // _autoindex(client, client->assigned_location, path); + _autoindex(client, path); return ; } } @@ -198,32 +191,34 @@ THIS NEEDS WORK... // i only sort of need &path... // def can improve but works for now... -void Webserv::_autoindex(Client *client, LocationConfig &location, std::string &path) +//void Webserv::_autoindex(Client *client, LocationConfig &location, std::string &path) +void Webserv::_autoindex(Client *client, std::string &path) { - std::cout << "made it to _autoindex\n"; +// std::cout << "made it to _autoindex\n"; + (void)path; std::string dir_list; DIR *dir; struct dirent *ent; - std::cout << "location root: " << location.root << " location path: " \ - << location.path << '\n'; +// std::cout << "location root: " << client->assigned_location->root << " location path: " +// << client->assigned_location->path << '\n'; // if ((dir = opendir (path.c_str())) != NULL) - if ((dir = opendir ((location.root + location.path).c_str())) != NULL) + if ((dir = opendir ((client->assigned_location->root + client->assigned_location->path).c_str())) != NULL) { /* print all the files and directories within directory */ dir_list.append(AUTOINDEX_START); - dir_list.append(location.path); + dir_list.append(client->assigned_location->path); dir_list.append(AUTOINDEX_MID1); - dir_list.append(location.path); + dir_list.append(client->assigned_location->path); dir_list.append(AUTOINDEX_MID2); while ((ent = readdir (dir)) != NULL) { if (strcmp(".", ent->d_name) == 0) continue ; dir_list.append("assigned_location->path.c_str()); dir_list.append(ent->d_name); dir_list.append("\">"); dir_list.append(ent->d_name); @@ -238,9 +233,9 @@ void Webserv::_autoindex(Client *client, LocationConfig &location, std::string & // .. dir_list.append(AUTOINDEX_END); - std::cout << "\n\n" << dir_list << '\n'; +// std::cout << "\n\n" << dir_list << '\n'; closedir (dir); - _append_body(client, dir_list.c_str(), dir_list.size(), "html"); + _append_body(client, dir_list, "html"); } else { From a44b9b493ab82deb3833dc4c292ba7873571b457 Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Mon, 8 Aug 2022 20:36:01 +0200 Subject: [PATCH 19/21] split respone.cpp file --- Makefile | 1 + memo.txt | 9 +- srcs/utils.cpp | 2 +- srcs/webserv/method_delete.cpp | 40 +++++ srcs/webserv/method_get.cpp | 192 ++++++++++++++++++++ srcs/webserv/method_post.cpp | 66 +++++++ srcs/webserv/response.cpp | 309 +-------------------------------- 7 files changed, 311 insertions(+), 308 deletions(-) create mode 100644 srcs/webserv/method_delete.cpp create mode 100644 srcs/webserv/method_get.cpp create mode 100644 srcs/webserv/method_post.cpp diff --git a/Makefile b/Makefile index 0c35a34..1761476 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,7 @@ SRCS_D = srcs \ SRCS = main.cpp \ base.cpp init.cpp close.cpp epoll_update.cpp signal.cpp \ accept.cpp request.cpp response.cpp \ + method_get.cpp method_post.cpp method_delete.cpp \ run_loop.cpp \ parser.cpp \ extraConfig.cpp \ diff --git a/memo.txt b/memo.txt index 5b32a3e..eb86386 100644 --- a/memo.txt +++ b/memo.txt @@ -1,12 +1,15 @@ IN 42 SUBJECT, PRIORITY : - chunked request (response not mandatory it seems) -- upload files with confif "upload_dir" - 505 HTTP Version Not Supported - CGI -- handle redirection -- index and autoindex +- index (default file directory) - Ecrire des tests ! + +- handle redirection +- upload files with config "upload_repo" ----------------------------- +- autoindex (done, need test) +-------------- - replace atoi() with a better function - 408 Request Timeout - gerer le champ "Accept" du client diff --git a/srcs/utils.cpp b/srcs/utils.cpp index 47ab461..4df5eab 100644 --- a/srcs/utils.cpp +++ b/srcs/utils.cpp @@ -68,7 +68,7 @@ http_method str_to_http_method(std::string &str) return POST; else if (str == "DELETE") return DELETE; - else if (str == "ALL_METHODS") + else if (str == "ALL_METHODS") // for Eric: why this test ? can we delete it? return ANY_METHODS; // would prefere ALL_METHODS return UNKNOWN; diff --git a/srcs/webserv/method_delete.cpp b/srcs/webserv/method_delete.cpp new file mode 100644 index 0000000..f707e3a --- /dev/null +++ b/srcs/webserv/method_delete.cpp @@ -0,0 +1,40 @@ + +#include "Webserv.hpp" + +void Webserv::_delete(Client *client) +{ +/* + WIP + https://www.rfc-editor.org/rfc/rfc9110.html#name-delete +*/ + std::string path = client->get_path(); + path.insert(0, client->assigned_location->root); + + /* CGI Here ? */ + + _delete_file(client, path); +} + +void Webserv::_delete_file(Client *client, const std::string &path) +{ + if (access(path.c_str(), F_OK) == -1) + { + std::perror("err access()"); + client->status = 404; + return ; + } + + if (access(path.c_str(), W_OK) == -1) + { + std::perror("err access()"); + client->status = 403; + return ; + } + + if (remove(path.c_str()) == -1) + { + std::perror("err remove()"); + client->status = 500; + return ; + } +} diff --git a/srcs/webserv/method_get.cpp b/srcs/webserv/method_get.cpp new file mode 100644 index 0000000..e5bca7e --- /dev/null +++ b/srcs/webserv/method_get.cpp @@ -0,0 +1,192 @@ + +#include "Webserv.hpp" + +void Webserv::_get(Client *client) +{ +/* RULES ** + +if path is a valid dir check if index is specified and serve that +if no index and autoindex, server that +if file, server that! + +WHere does cgi fit in in all this ??? + + +*/ + std::string path = client->get_path(); + + // this might not be the best thing, a voir + path.insert(0, client->assigned_location->root); + + std::cerr << "path = " << path << "\n"; + + // path = root + location.path + // we will tack on an index if there is a valid one + // or autoindex if allowed + // or let _get_file sort out the error otherwise. + + if (path_is_valid(path) == 1) + { + // std::cout << "path is valid\n"; + if (path[path.size() - 1] != '/') + path.push_back('/'); + for (size_t i = 0; i < client->assigned_location->index.size(); i++) + { +// std::cout << "location path: " << client->assigned_location->path << '\n'; +// std::cout << "location index: " << client->assigned_location->index[i] << '\n'; +// std::cout << "path with index: " << path + assigned_location->index[i] << '\n'; + if (path_is_valid(path + client->assigned_location->index[i]) == 2) + { + // std::cout << "found a valid index\n"; + path.append(client->assigned_location->index[i]); + break ; // what if index and autoindex in a single location? + // does this completely fail? + // do this instead of break? + //_get_file(client, path); + } + } + if (client->assigned_location->autoindex == true) + { + // _autoindex(client, client->assigned_location, path); + _autoindex(client, path); + return ; + } + } +// else +// _get_file(client, path); + // what about cgi ??? + + + + // TMP HUGO + // + if (_is_cgi(client)) + { + _exec_cgi(client); + return; + } + // + // END TMP HUGO + + _get_file(client, path); +} + +# define MAX_FILESIZE 1000000 // (1Mo) +void Webserv::_get_file(Client *client, const std::string &path) +{ +/* + std::ios::binary + https://gcc.gnu.org/onlinedocs/libstdc++/manual/fstreams.html#std.io.filestreams.binary + tldr : its seems to not be so simple to do read/write of binary file in a portable way. +*/ + std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ? + std::stringstream buf; + + std::cout << "made it to get_file\n"; + + if (access(path.c_str(), F_OK) == -1) + { + std::perror("err access()"); + client->status = 404; + return ; + } + + if (access(path.c_str(), R_OK) == -1) + { + std::perror("err access()"); + client->status = 403; + return ; + } + + ifd.open(path.c_str(), std::ios::ate); + if (!ifd) + { + std::cerr << path << ": ifd.open fail" << '\n'; + client->status = 500; + } + else + { + std::streampos size = ifd.tellg(); + + // WIP : Chunk or not chunk (if filesize too big) + if (size > MAX_FILESIZE) + { + // Then chunk + client->status = 500; // WIP temp + std::cerr << "File too large for non chunk body\n"; + return ; + } + + ifd.seekg(0, std::ios::beg); + buf << ifd.rdbuf(); + if (!ifd || !buf) + { + std::cerr << path << ": ifd.read fail" << '\n'; + client->status = 500; + } + else + { + client->status = 200; + std::string file_ext = _determine_file_extension(path); + _append_body(client, buf.str(), file_ext); + } + } +} + +// i only sort of need &path... +// def can improve but works for now... +//void Webserv::_autoindex(Client *client, LocationConfig &location, std::string &path) +void Webserv::_autoindex(Client *client, std::string &path) +{ +// std::cout << "made it to _autoindex\n"; + + (void)path; + std::string dir_list; + DIR *dir; + struct dirent *ent; + +// std::cout << "location root: " << client->assigned_location->root << " location path: " +// << client->assigned_location->path << '\n'; + +// if ((dir = opendir (path.c_str())) != NULL) + if ((dir = opendir ((client->assigned_location->root + client->assigned_location->path).c_str())) != NULL) + { + /* print all the files and directories within directory */ + dir_list.append(AUTOINDEX_START); + dir_list.append(client->assigned_location->path); + dir_list.append(AUTOINDEX_MID1); + dir_list.append(client->assigned_location->path); + dir_list.append(AUTOINDEX_MID2); + while ((ent = readdir (dir)) != NULL) + { + if (strcmp(".", ent->d_name) == 0) + continue ; + dir_list.append("assigned_location->path.c_str()); + dir_list.append(ent->d_name); + dir_list.append("\">"); + dir_list.append(ent->d_name); + dir_list.append(""); + dir_list.append("\r\n"); // is this right? + } + +// nginx.org.
+// index1.html + +// apparently this is more than good enough! +// .. + + dir_list.append(AUTOINDEX_END); +// std::cout << "\n\n" << dir_list << '\n'; + closedir (dir); + _append_body(client, dir_list, "html"); + } + else + { + // in theory not possible cuz we already checked... + /* could not open directory */ +// perror (""); + std::cout << "could not open dir\n"; + return ; + } +} \ No newline at end of file diff --git a/srcs/webserv/method_post.cpp b/srcs/webserv/method_post.cpp new file mode 100644 index 0000000..2c011b4 --- /dev/null +++ b/srcs/webserv/method_post.cpp @@ -0,0 +1,66 @@ + +#include "Webserv.hpp" + + +void Webserv::_post(Client *client) +{ +/* + WIP + https://www.rfc-editor.org/rfc/rfc9110.html#name-post +*/ + std::string path = client->get_path(); + path.insert(0, client->assigned_location->root); + + /* CGI Here ? */ + + _post_file(client, path); +} + +void Webserv::_post_file(Client *client, const std::string &path) +{ + std::ofstream ofd; + + bool file_existed; + if (access(path.c_str(), F_OK) == -1) + file_existed = false; + else + file_existed = true; + + // How to determine status 403 for file that dont already exist ? + if (file_existed && access(path.c_str(), W_OK) == -1) + { + std::perror("err access()"); + client->status = 403; + return ; + } + + ofd.open(path.c_str(), std::ios::trunc); + if (!ofd) + { + std::cerr << path << ": ofd.open fail" << '\n'; + client->status = 500; + } + else + { + // Content-Length useless at this point ? + // Maybe usefull in _read_request() for rejecting too big content. + // Need to _determine_process_server() as soon as possible, + // like in _read_request() for stopping read if body is too big ? + ofd << client->get_body(); + if (!ofd) + { + std::cerr << path << ": ofd.write fail" << '\n'; + client->status = 500; + } + else if (file_existed) + { + client->status = 200; + // WIP https://www.rfc-editor.org/rfc/rfc9110.html#name-200-ok + } + else + { + client->status = 201; + // WIP https://www.rfc-editor.org/rfc/rfc9110.html#section-9.3.3-4 + } + } +} diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 2fbeea9..c288388 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -64,15 +64,13 @@ void Webserv::_construct_response(Client *client) void Webserv::_process_method(Client *client) { - unsigned int allow_methods = ANY_METHODS; // TEMP VARIABLE - // after update in ConfigParser, use the "allow_methods" of location. - // TODO in ConfigParser : by default if no field in config file, "allow_methods" must be set to ANY_METHODS - + std::cerr << "assigned_location->path = " << client->assigned_location->path << "\n"; // debug + std::cerr << "allow_methods = " << client->assigned_location->allow_methods << "\n"; // debug if (client->get_method() == UNKNOWN) { client->status = 501; } - else if (allow_methods & client->get_method()) + else if (client->assigned_location->allow_methods & client->get_method()) { switch (client->get_method()) { @@ -90,7 +88,7 @@ void Webserv::_process_method(Client *client) { client->status = 405; client->response.append("Allow: "); - client->response.append(::http_methods_to_str(allow_methods)); + client->response.append(::http_methods_to_str(client->assigned_location->allow_methods)); client->response.append(CRLF); } } @@ -117,202 +115,6 @@ void Webserv::_error_html_response(Client *client) _get_file(client, client->assigned_server->error_pages[client->status]); } -//#define INDEX "index.html" // temp wip -void Webserv::_get(Client *client) -{ -/* RULES ** - -if path is a valid dir check if index is specified and serve that -if no index and autoindex, server that -if file, server that! - -WHere does cgi fit in in all this ??? - - -*/ - std::string path = client->get_path(); - - // this might not be the best thing, a voir - path.insert(0, client->assigned_location->root); - - std::cerr << "path = " << path << "\n"; - - // path = root + location.path - // we will tack on an index if there is a valid one - // or autoindex if allowed - // or let _get_file sort out the error otherwise. - - if (path_is_valid(path) == 1) - { - // std::cout << "path is valid\n"; - if (path[path.size() - 1] != '/') - path.push_back('/'); - for (size_t i = 0; i < client->assigned_location->index.size(); i++) - { -// std::cout << "location path: " << client->assigned_location->path << '\n'; -// std::cout << "location index: " << client->assigned_location->index[i] << '\n'; -// std::cout << "path with index: " << path + assigned_location->index[i] << '\n'; - if (path_is_valid(path + client->assigned_location->index[i]) == 2) - { - // std::cout << "found a valid index\n"; - path.append(client->assigned_location->index[i]); - break ; // what if index and autoindex in a single location? - // does this completely fail? - // do this instead of break? - //_get_file(client, path); - } - } - if (client->assigned_location->autoindex == true) - { - // _autoindex(client, client->assigned_location, path); - _autoindex(client, path); - return ; - } - } -// else -// _get_file(client, path); - // what about cgi ??? - - - - // TMP HUGO - // - if (_is_cgi(client)) - { - _exec_cgi(client); - return; - } - // - // END TMP HUGO - - _get_file(client, path); -} - - -// i only sort of need &path... -// def can improve but works for now... -//void Webserv::_autoindex(Client *client, LocationConfig &location, std::string &path) -void Webserv::_autoindex(Client *client, std::string &path) -{ -// std::cout << "made it to _autoindex\n"; - - (void)path; - std::string dir_list; - DIR *dir; - struct dirent *ent; - -// std::cout << "location root: " << client->assigned_location->root << " location path: " -// << client->assigned_location->path << '\n'; - -// if ((dir = opendir (path.c_str())) != NULL) - if ((dir = opendir ((client->assigned_location->root + client->assigned_location->path).c_str())) != NULL) - { - /* print all the files and directories within directory */ - dir_list.append(AUTOINDEX_START); - dir_list.append(client->assigned_location->path); - dir_list.append(AUTOINDEX_MID1); - dir_list.append(client->assigned_location->path); - dir_list.append(AUTOINDEX_MID2); - while ((ent = readdir (dir)) != NULL) - { - if (strcmp(".", ent->d_name) == 0) - continue ; - dir_list.append("assigned_location->path.c_str()); - dir_list.append(ent->d_name); - dir_list.append("\">"); - dir_list.append(ent->d_name); - dir_list.append(""); - dir_list.append("\r\n"); // is this right? - } - -// nginx.org.
-// index1.html - -// apparently this is more than good enough! -// .. - - dir_list.append(AUTOINDEX_END); -// std::cout << "\n\n" << dir_list << '\n'; - closedir (dir); - _append_body(client, dir_list, "html"); - } - else - { - // in theory not possible cuz we already checked... - /* could not open directory */ -// perror (""); - std::cout << "could not open dir\n"; - return ; - } -} - - - -# define MAX_FILESIZE 1000000 // (1Mo) -void Webserv::_get_file(Client *client, const std::string &path) -{ -/* - std::ios::binary - https://gcc.gnu.org/onlinedocs/libstdc++/manual/fstreams.html#std.io.filestreams.binary - tldr : its seems to not be so simple to do read/write of binary file in a portable way. -*/ - std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ? - std::stringstream buf; - - std::cout << "made it to get_file\n"; - - if (access(path.c_str(), F_OK) == -1) - { - std::perror("err access()"); - client->status = 404; - return ; - } - - if (access(path.c_str(), R_OK) == -1) - { - std::perror("err access()"); - client->status = 403; - return ; - } - - ifd.open(path.c_str(), std::ios::ate); - if (!ifd) - { - std::cerr << path << ": ifd.open fail" << '\n'; - client->status = 500; - } - else - { - std::streampos size = ifd.tellg(); - - // WIP : Chunk or not chunk (if filesize too big) - if (size > MAX_FILESIZE) - { - // Then chunk - client->status = 500; // WIP temp - std::cerr << "File too large for non chunk body\n"; - return ; - } - - ifd.seekg(0, std::ios::beg); - buf << ifd.rdbuf(); - if (!ifd || !buf) - { - std::cerr << path << ": ifd.read fail" << '\n'; - client->status = 500; - } - else - { - client->status = 200; - std::string file_ext = _determine_file_extension(path); - _append_body(client, buf.str(), file_ext); - } - } -} - - -//void Webserv::_append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension) void Webserv::_append_body(Client *client, const std::string &body, const std::string &file_extension) { const std::string &mime_type = _mime_types[file_extension]; @@ -337,107 +139,6 @@ void Webserv::_append_body(Client *client, const std::string &body, const std::s client->response.append(body); } -void Webserv::_post(Client *client) -{ -/* - WIP - https://www.rfc-editor.org/rfc/rfc9110.html#name-post -*/ - std::string path = client->get_path(); - path.insert(0, client->assigned_location->root); - - /* CGI Here ? */ - - _post_file(client, path); -} - -void Webserv::_post_file(Client *client, const std::string &path) -{ - std::ofstream ofd; - - bool file_existed; - if (access(path.c_str(), F_OK) == -1) - file_existed = false; - else - file_existed = true; - - // How to determine status 403 for file that dont already exist ? - if (file_existed && access(path.c_str(), W_OK) == -1) - { - std::perror("err access()"); - client->status = 403; - return ; - } - - ofd.open(path.c_str(), std::ios::trunc); - if (!ofd) - { - std::cerr << path << ": ofd.open fail" << '\n'; - client->status = 500; - } - else - { - // Content-Length useless at this point ? - // Maybe usefull in _read_request() for rejecting too big content. - // Need to _determine_process_server() as soon as possible, - // like in _read_request() for stopping read if body is too big ? - ofd << client->get_body(); - if (!ofd) - { - std::cerr << path << ": ofd.write fail" << '\n'; - client->status = 500; - } - else if (file_existed) - { - client->status = 200; - // WIP https://www.rfc-editor.org/rfc/rfc9110.html#name-200-ok - } - else - { - client->status = 201; - // WIP https://www.rfc-editor.org/rfc/rfc9110.html#section-9.3.3-4 - } - } -} - -void Webserv::_delete(Client *client) -{ -/* - WIP - https://www.rfc-editor.org/rfc/rfc9110.html#name-delete -*/ - std::string path = client->get_path(); - path.insert(0, client->assigned_location->root); - - /* CGI Here ? */ - - _delete_file(client, path); -} - -void Webserv::_delete_file(Client *client, const std::string &path) -{ - if (access(path.c_str(), F_OK) == -1) - { - std::perror("err access()"); - client->status = 404; - return ; - } - - if (access(path.c_str(), W_OK) == -1) - { - std::perror("err access()"); - client->status = 403; - return ; - } - - if (remove(path.c_str()) == -1) - { - std::perror("err remove()"); - client->status = 500; - return ; - } -} - ServerConfig *Webserv::_determine_process_server(Client *client) { /* @@ -488,7 +189,7 @@ const LocationConfig *Webserv::_determine_location(const ServerConfig &server, c if (it != server.locations.end()) return (&(*it)); else - return (&(server.locations.front())); + return (&(server.locations.back())); } std::string Webserv::_determine_file_extension(const std::string &path) const From 643b09c4f7044a8b88ad7a87999b290db3fe298a Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Tue, 9 Aug 2022 01:46:59 +0200 Subject: [PATCH 20/21] _request() and _response() refactoring + Wip redirection (weird behavior) + 505 HTTP Version Not Supported --- memo.txt | 3 +- srcs/utils.hpp | 9 ------ srcs/webserv/Webserv.hpp | 31 ++++++++----------- srcs/webserv/http_status.hpp | 8 +++++ srcs/webserv/init.cpp | 7 +++++ srcs/webserv/request.cpp | 57 ++++++++++++++++++++++++----------- srcs/webserv/response.cpp | 58 ++++++++++++++++++++++++++++-------- srcs/webserv/run_loop.cpp | 5 ++++ 8 files changed, 118 insertions(+), 60 deletions(-) diff --git a/memo.txt b/memo.txt index eb86386..c076cb7 100644 --- a/memo.txt +++ b/memo.txt @@ -1,11 +1,10 @@ IN 42 SUBJECT, PRIORITY : - chunked request (response not mandatory it seems) -- 505 HTTP Version Not Supported - CGI - index (default file directory) - Ecrire des tests ! -- handle redirection +- handle redirection (weird behavior, to fix) - upload files with config "upload_repo" ----------------------------- - autoindex (done, need test) diff --git a/srcs/utils.hpp b/srcs/utils.hpp index bd48de3..faa73c8 100644 --- a/srcs/utils.hpp +++ b/srcs/utils.hpp @@ -12,15 +12,6 @@ # define LF "\n" # define CRLF CR LF -// enum http_method -// { -// UNKNOWN = 0b00000000, -// GET = 0b00000001, -// POST = 0b00000010, -// DELETE = 0b00000100, -// ANY_METHODS = 0b11111111, -// }; - enum http_method { UNKNOWN = 0b0, diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index 5084386..518cd24 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -72,36 +72,29 @@ class Webserv void _accept_connection(listen_socket &lsocket); // request.cpp void _request(Client *client); - void _read_request(Client *client); + int _read_request(Client *client); // response.cpp void _response(Client *client); - void _send_response(Client *client); - + int _send_response(Client *client); void _append_base_headers(Client *client); void _construct_response(Client *client); void _process_method(Client *client); void _insert_status_line(Client *client); void _error_html_response(Client *client); void _append_body(Client *client, const std::string &body, const std::string &file_extension = ""); - - void _get(Client *client); - // void _get(Client *client, ServerConfig &server, LocationConfig &location); - -// in progress - void _autoindex(Client *client, std::string &path); - - - void _get_file(Client *client, const std::string &path); - - void _post(Client *client); - void _post_file(Client *client, const std::string &path); - - void _delete(Client *client); - void _delete_file(Client *client, const std::string &path); - ServerConfig *_determine_process_server(Client *client); // cant be const cause of error_pages.operator[] const LocationConfig *_determine_location(const ServerConfig &server, const std::string &path) const; std::string _determine_file_extension(const std::string &path) const; + // method_get.cpp + void _get(Client *client); + void _get_file(Client *client, const std::string &path); + void _autoindex(Client *client, std::string &path); + // method_post.cpp + void _post(Client *client); + void _post_file(Client *client, const std::string &path); + // method_delete.cpp + void _delete(Client *client); + void _delete_file(Client *client, const std::string &path); // cgi_script.cpp bool _is_cgi(Client *client); void _exec_cgi(Client *client); diff --git a/srcs/webserv/http_status.hpp b/srcs/webserv/http_status.hpp index d6017f0..beba594 100644 --- a/srcs/webserv/http_status.hpp +++ b/srcs/webserv/http_status.hpp @@ -30,6 +30,13 @@ # define S201 "201 Created" # define S204 "204 No Content" +# define S301 "301 Moved Permanently" +# define S302 "302 Found" +# define S303 "303 See Other" +# define S304 "304 Not Modified" // unused +# define S307 "307 Temporary Redirect" +# define S308 "308 Permanent Redirect" + # define S400 "400 Bad Request" # define S403 "403 Forbidden" # define S404 "404 Not Found" @@ -38,5 +45,6 @@ # define S500 "500 Internal Server Error" # define S501 "501 Not Implemented" +# define S505 "505 HTTP Version Not Supported" #endif diff --git a/srcs/webserv/init.cpp b/srcs/webserv/init.cpp index cfe877b..4b034ce 100644 --- a/srcs/webserv/init.cpp +++ b/srcs/webserv/init.cpp @@ -99,6 +99,13 @@ void Webserv::_init_http_status_map() _http_status.insert(status_pair(201, S201)); _http_status.insert(status_pair(204, S204)); + _http_status.insert(status_pair(301, S301)); + _http_status.insert(status_pair(302, S302)); + _http_status.insert(status_pair(303, S303)); + _http_status.insert(status_pair(304, S304)); + _http_status.insert(status_pair(307, S307)); + _http_status.insert(status_pair(308, S308)); + _http_status.insert(status_pair(400, S400)); _http_status.insert(status_pair(403, S403)); _http_status.insert(status_pair(404, S404)); diff --git a/srcs/webserv/request.cpp b/srcs/webserv/request.cpp index b492a63..707e24a 100644 --- a/srcs/webserv/request.cpp +++ b/srcs/webserv/request.cpp @@ -4,14 +4,31 @@ #define BUFSIZE 8192 #define MAX_HEADER_SIZE 42000 // arbitrary +enum read_return +{ + READ_IN_PROGRESS, + READ_COMPLETE, + READ_CLOSE, +}; + void Webserv::_request(Client *client) { - _read_request(client); + int ret = _read_request(client); + if (g_last_signal) - _handle_last_signal(); + _handle_last_signal(); + + if (ret == READ_CLOSE) + { + _close_client(client->fd); + } + else if (ret == READ_COMPLETE) + { + _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); + } } -void Webserv::_read_request(Client *client) // Messy, Need refactoring +int Webserv::_read_request(Client *client) // Messy, Need refactoring { char buf[BUFSIZE]; ssize_t ret; @@ -24,13 +41,12 @@ void Webserv::_read_request(Client *client) // Messy, Need refactoring std::perror("err recv()"); std::cerr << "client ptr =" << client << "\n"; // DEBUG std::cerr << "client.fd =" << client->fd << "\n"; // DEBUG - _close_client(client->fd); - return ; + return READ_CLOSE; } if (ret == 0) { - _close_client(client->fd); - return ; + std::cerr << "recv() read 0, then close client" << "\n"; // DEBUG + return READ_CLOSE; } client->raw_request.append(buf, ret); @@ -38,23 +54,29 @@ void Webserv::_read_request(Client *client) // Messy, Need refactoring { if (client->raw_request.find(CRLF CRLF) != std::string::npos) { + // std::cerr << "Raw_request :\n|||||||||||||||||||||||||||||\n " << client->raw_request << "\n|||||||||||||||||||||||||||||\n"; // DEBUG client->header_complete = true; client->parse_request(); // TODO : split function to avoid useless parsing ? + if (client->status) // WIP, need to change client->parse_request() for status update + return READ_COMPLETE; client->assigned_server = _determine_process_server(client); client->assigned_location = _determine_location(*client->assigned_server, client->get_path()); + if (client->get_version().compare(0, sizeof("HTTP/1") - 1, "HTTP/1") != 0) + { // TODO : move in Client parsing ? + client->status = 505; + return READ_COMPLETE; + } if (!client->get_headers("Content-Length").empty() && ::atoi(client->get_headers("Content-Length").c_str()) > (int)client->assigned_server->client_body_limit) { client->status = 413; - _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); - return; + return READ_COMPLETE; } } else if (client->raw_request.size() > MAX_HEADER_SIZE) { client->status = 400; - _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); - return; + return READ_COMPLETE; } } else if (client->header_complete) @@ -63,22 +85,21 @@ void Webserv::_read_request(Client *client) // Messy, Need refactoring if (client->read_body_size > client->assigned_server->client_body_limit) { client->status = 413; - _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); - return; + return READ_COMPLETE; } - if ((int)client->read_body_size > ::atoi(client->get_headers("Content-Length").c_str())) + if ((int)client->read_body_size >= ::atoi(client->get_headers("Content-Length").c_str())) { client->parse_request(); // reparse for the body - _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); - return; + return READ_COMPLETE; } } if (client->header_complete && client->get_headers("Content-Type").empty() && client->get_headers("Content-Length").empty() ) { - _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); - return; + return READ_COMPLETE; } + + return READ_IN_PROGRESS; } diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index c288388..67c5754 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -1,14 +1,37 @@ #include "Webserv.hpp" +enum send_return +{ + SEND_IN_PROGRESS, // unused + SEND_COMPLETE, + SEND_CLOSE, +}; + void Webserv::_response(Client *client) { - _send_response(client); + int ret = _send_response(client); + if (g_last_signal) _handle_last_signal(); + + if (ret == SEND_CLOSE) + { + _close_client(client->fd); + } + else if (ret == SEND_COMPLETE) + { + if (client->get_headers("Connection") == "close") + _close_client(client->fd); + else + { + _epoll_update(client->fd, EPOLLIN, EPOLL_CTL_MOD); + client->clear(); + } + } } -void Webserv::_send_response(Client *client) +int Webserv::_send_response(Client *client) { ssize_t ret; @@ -27,18 +50,11 @@ void Webserv::_send_response(Client *client) { std::perror("err send()"); std::cerr << "client.fd =" << client->fd << "\n"; // DEBUG - _close_client(client->fd); - return ; + return SEND_CLOSE; } std::cerr << "ret send() = " << ret << "\n"; // DEBUG - if (client->get_headers("Connection") == "close") - _close_client(client->fd); - else - { - _epoll_update(client->fd, EPOLLIN, EPOLL_CTL_MOD); - client->clear(); - } + return SEND_COMPLETE; } void Webserv::_append_base_headers(Client *client) @@ -59,6 +75,24 @@ void Webserv::_construct_response(Client *client) client->status = 413; return; } +/* if (client->assigned_location->redirect_status) + { + // (for codes 301, 302, 303, 307, and 308) + client->status = client->assigned_location->redirect_status; + client->response.append("Location: "); + client->response.append(client->assigned_location->redirect_uri); + client->response.append(CRLF); + } */ + if (client->get_path().find("redirect_test") != std::string::npos) // Test block + { // Weird behavior. The web browser seems to wait for a complete response until timeout. + // (for codes 301, 302, 303, 307, and 308) + client->status = 307; + client->response.append("Location: "); + client->response.append("https://www.rfc-editor.org/rfc/rfc3875#section-3.3"); + client->response.append(CRLF); + client->response.append(CRLF); + return ; + } _process_method(client); } @@ -105,7 +139,7 @@ void Webserv::_insert_status_line(Client *client) void Webserv::_error_html_response(Client *client) { - if (client->assigned_server->error_pages[client->status].empty()) + if (!client->assigned_server || client->assigned_server->error_pages[client->status].empty()) { std::string html_page = HTML_ERROR; ::replace_all_substr(html_page, STATUS_PLACEHOLDER, _http_status[client->status]); diff --git a/srcs/webserv/run_loop.cpp b/srcs/webserv/run_loop.cpp index 04c1e03..cb91672 100644 --- a/srcs/webserv/run_loop.cpp +++ b/srcs/webserv/run_loop.cpp @@ -57,6 +57,11 @@ void Webserv::run() std::vector().swap(_clients); break; } + catch (const std::exception& e) + { + std::cerr << e.what() << '\n'; + ++i; + } } } } From 97c90236b999006c91d4c49dcc52e84f20bc1654 Mon Sep 17 00:00:00 2001 From: Me Date: Tue, 9 Aug 2022 02:37:28 +0200 Subject: [PATCH 21/21] cgi_ext, redirect and upload_repo now functional in config, fixed location picker, some cleanup --- default.config | 9 ++--- srcs/config/LocationConfig.hpp | 9 ++--- srcs/config/parser.cpp | 30 +++++++++------- srcs/config/postProcessing.cpp | 2 +- srcs/webserv/method_get.cpp | 11 +++--- srcs/webserv/response.cpp | 63 ++++++++++++++++++++++++++-------- www/test/index1.html | 2 +- 7 files changed, 79 insertions(+), 47 deletions(-) diff --git a/default.config b/default.config index ab88bfd..17399b2 100644 --- a/default.config +++ b/default.config @@ -24,13 +24,14 @@ server { } location /test/something.html { - allow_methods DELETE; + # allow_methods DELETE; } # location /something/long/here { # } location /test/test_deeper/ { +# allow_methods autoindex on; } @@ -38,9 +39,9 @@ server { autoindex on; } - location /test/test_deeper/something.html { - allow_methods DELETE; - } +# location /test/test_deeper/something.html { +# allow_methods DELETE; +# } # ok in theory if one were to go to /test they would get the index in www diff --git a/srcs/config/LocationConfig.hpp b/srcs/config/LocationConfig.hpp index 72a4886..66de1c5 100644 --- a/srcs/config/LocationConfig.hpp +++ b/srcs/config/LocationConfig.hpp @@ -38,13 +38,10 @@ public: std::vector cgi_ext; // php not .php bool autoindex; - std::vector upload_repo; + std::string upload_repo; // might change name... - // wait if i can call several times, shouldn't it be a map? - // wait no there can only be 1 and i think it might have to be in - // location only... - int redirect_status; - std::string redirect_uri; + int redirect_status; + std::string redirect_uri; // au pire you do location / { return 301 http://location; } // and that's how you get the redirect from the root. diff --git a/srcs/config/parser.cpp b/srcs/config/parser.cpp index 36a0ae2..c804b86 100644 --- a/srcs/config/parser.cpp +++ b/srcs/config/parser.cpp @@ -145,6 +145,7 @@ LocationConfig ConfigParser::_parse_location(size_t *start) ret.allow_methods = 0; ret.path = _get_first_word(&curr); +// are you sure about this? if (ret.path[0] != '/') ret.path.insert(0, "/"); // throw std::invalid_argument("Location path require a leading /"); @@ -290,18 +291,10 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ throw std::invalid_argument("missing value"); else if (key == "root" && size == 1 && location->root == "") { -// std::cout << "location root: " << tmp_val[0] << '\n'; -// if (tmp_val[0][0] != '/') -// throw std::invalid_argument("Root requires leading /"); - // remove trailing / - // if (tmp_val[0].back() == '/') if (tmp_val[0][tmp_val[0].size() - 1] == '/') tmp_val[0].erase(tmp_val[0].size() - 1, 1); -// if (path_is_valid(tmp_val[0]) == 1) - location->root = tmp_val[0]; -// else -// throw std::invalid_argument("Root dir invalid"); + location->root = tmp_val[0]; } else if (key == "autoindex" && size == 1) { @@ -310,6 +303,7 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ } else if (key == "index") { + // what about index /index.html; aka at the root? not handle? // you can definitely call Index several times, i think for (unsigned long i = 0; i != tmp_val.size(); i++) location->index.push_back(tmp_val[i]); @@ -341,14 +335,24 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ if (tmp_val.size() != 2) throw std::invalid_argument("wrong number of values"); // and tmp_val[0] should be a number and tmp_val[1] a string? - if (!(::isNumeric(tmp_val[0]))) - throw std::invalid_argument("value not a number"); + if (tmp_val[0] != "301" && tmp_val[0] != "302" + && tmp_val[0] != "303" && tmp_val[0] != "307" + && tmp_val[0] != "308") + throw std::invalid_argument("bad redirect status"); +// double check this + // it means we aren't allowing internal redirects. + if (tmp_val[1].compare(0, 7, "http://") + || tmp_val[1].compare(0, 8, "https://")) + throw std::invalid_argument("bad redirect uri"); - // somehow check that tmp_val[1] is a string? or valid? how? - // something about using access() to see if location->redirect_status = atoi(tmp_val[0].c_str()); location->redirect_uri = tmp_val[1]; } + else if (key == "upload_repo" && size == 1 && location->upload_repo == "") + { + // what checks to do? + location->upload_repo = tmp_val[0]; + } else throw std::invalid_argument("bad key value pair"); } diff --git a/srcs/config/postProcessing.cpp b/srcs/config/postProcessing.cpp index 61f338a..e193549 100644 --- a/srcs/config/postProcessing.cpp +++ b/srcs/config/postProcessing.cpp @@ -74,7 +74,7 @@ void ConfigParser::_post_processing(std::vector *servers) ++it_l; } std::sort(it->locations.begin(), it->locations.end()); - std::reverse(it->locations.begin(), it->locations.end()); +// std::reverse(it->locations.begin(), it->locations.end()); ++it; } diff --git a/srcs/webserv/method_get.cpp b/srcs/webserv/method_get.cpp index e5bca7e..c8f0506 100644 --- a/srcs/webserv/method_get.cpp +++ b/srcs/webserv/method_get.cpp @@ -9,7 +9,7 @@ if path is a valid dir check if index is specified and serve that if no index and autoindex, server that if file, server that! -WHere does cgi fit in in all this ??? +Where does cgi fit in in all this ??? */ @@ -39,15 +39,12 @@ WHere does cgi fit in in all this ??? { // std::cout << "found a valid index\n"; path.append(client->assigned_location->index[i]); - break ; // what if index and autoindex in a single location? - // does this completely fail? - // do this instead of break? - //_get_file(client, path); + _get_file(client, path); + return ; } } if (client->assigned_location->autoindex == true) { - // _autoindex(client, client->assigned_location, path); _autoindex(client, path); return ; } @@ -189,4 +186,4 @@ void Webserv::_autoindex(Client *client, std::string &path) std::cout << "could not open dir\n"; return ; } -} \ No newline at end of file +} diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index c288388..53861c0 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -171,25 +171,58 @@ ServerConfig *Webserv::_determine_process_server(Client *client) const LocationConfig *Webserv::_determine_location(const ServerConfig &server, const std::string &path) const { -// std::cout << "determin location path sent: " << path << '\n'; + std::cout << "determin location path sent: " << path << '\n'; - std::vector::const_iterator it = server.locations.begin(); - while (it != server.locations.end()) + +/// NO FUCKING IDEA WHY BUT... +// basically if 2 strings are identical to a point, compare from +// longer one or it'll freak out cuz of \0 or something idk +//// Basically: str.compare() from the larger string... + +/* RULES *** + +If a path coresponds exactly to a location, use that one +if no path coresponds then use the most correct one + most correct means the most precise branch that is still above + the point we are aiming for + +*/ + + std::vector::const_iterator best; + std::cout << "\nMade it to weird location picker case.\n"; + + for (std::vector::const_iterator it = server.locations.begin(); it != server.locations.end(); it++) { -// std::cout << it->path << " -- "; - // if (it->path.compare(0, path.size(), path) == 0) - if (it->path.compare(0, it->path.size(), path) == 0) - break; -// kinda gross i know but... have to deal with when there's a / at the end - if (it->path[it->path.size() - 1] == '/' \ + std::cout << it->path << " -- "; + // if (rit->path.size() > path.size()) +/* if ((rit->path[rit->path.size() - 1] == '/' ? rit->path.size() : rit->path.size() - 1) > path.size()) + { + std::cout << "skipping this one\n"; + continue ; + } +*/ +// OK I REALLY DON"T LOVE THIS PART, BUT IT DOES WORK FOR NOW... + // if (it->path[it->path.size() - 1] == '/' + // && it->path.compare(0, it->path.size(), path + "/") == 0) +// HOLD ON THIS MIGHT BE GOOD, BUT I COULD USE SOME HELP... + if (it->path[it->path.size() - 1] == '/' && it->path.compare(0, it->path.size() - 1, path) == 0) - break; - ++it; + { + best = it; + std::cout << "Picked a best! 1\n"; + } +// int comp = path.compare(0, rit->path.size(), rit->path); + //int comp = rit->path.compare(0, rit->path.size() - 1, path); +// std::cout << "rit path size: " << rit->path.size() << " comp: " << comp << '\n'; + // if (rit->path.compare(0, rit->path.size(), path) == 0) + // if (comp == 0) + if (path.compare(0, it->path.size(), it->path) == 0) + { + best = it; + std::cout << "Picked a best! 2\n"; + } } - if (it != server.locations.end()) - return (&(*it)); - else - return (&(server.locations.back())); + return (&(*best)); } std::string Webserv::_determine_file_extension(const std::string &path) const diff --git a/www/test/index1.html b/www/test/index1.html index f976302..cf2702d 100644 --- a/www/test/index1.html +++ b/www/test/index1.html @@ -3,7 +3,7 @@ Webserv test index - +