From 6f5b28dd9326efae905dc2b1a064a350d9f13fb7 Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Wed, 3 Aug 2022 18:39:22 +0200 Subject: [PATCH] wip, need somes changes in ConfigParser. + _determine_location() + http_method changes + http_method switch in _construct_response() + ConfigParser::_str_to_method_type() moved to global utils.cpp --- default.config | 8 +- srcs/Client.cpp | 4 +- srcs/Client.hpp | 4 +- srcs/config/ConfigParser.cpp | 10 +-- srcs/config/ConfigParser.hpp | 4 +- srcs/config/ConfigParserUtils.cpp | 14 ---- srcs/utils.cpp | 32 ++++++++ srcs/utils.hpp | 22 +++--- srcs/webserv/Webserv.hpp | 7 +- srcs/webserv/cgi_script.cpp | 2 +- srcs/webserv/response.cpp | 120 ++++++++++++++++++++++-------- 11 files changed, 159 insertions(+), 68 deletions(-) diff --git a/default.config b/default.config index a3de0b3..024d45c 100644 --- a/default.config +++ b/default.config @@ -12,6 +12,12 @@ server { index index.html; # this is another comment root ./www/; +# 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 GET; } - diff --git a/srcs/Client.cpp b/srcs/Client.cpp index 5551a1f..8641916 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -49,7 +49,7 @@ void Client::parse_request() -std::string &Client::get_method() { return _request.method; } +http_method Client::get_method() { return _request.method; } std::string &Client::get_path() { return _request.path; } std::string &Client::get_version() { return _request.version; } std::string &Client::get_body() { return _request.body; } @@ -73,7 +73,7 @@ void Client::_parse_request_line( std::string rline ) // method tmp = ::trim(sline[0], ' '); tmp = ::trim(tmp, '\r'); - _request.method = tmp; + _request.method = str_to_http_method(tmp); // TODO uri in request_line // https://www.rfc-editor.org/rfc/rfc7230#section-5.3 // https://stackoverflow.com/questions/40311306/when-is-absoluteuri-used-from-the-http-request-specs diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 24a6c9c..eef125a 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -11,7 +11,7 @@ struct Request { std::map headers; - std::string method; + http_method method; std::string path; std::string version; std::string body; @@ -31,7 +31,7 @@ class Client unsigned int status; // const functions ? - std::string &get_method(); + http_method get_method(); std::string &get_path(); std::string &get_version(); std::string &get_body(); diff --git a/srcs/config/ConfigParser.cpp b/srcs/config/ConfigParser.cpp index 69ab9d0..d754ec6 100644 --- a/srcs/config/ConfigParser.cpp +++ b/srcs/config/ConfigParser.cpp @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/07/13 22:11:17 by me #+# #+# */ -/* Updated: 2022/08/02 19:21:49 by lperrey ### ########.fr */ +/* Updated: 2022/08/03 17:51:35 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ @@ -262,8 +262,8 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ { for (unsigned long i = 0; i != tmp_val.size(); i++) { - http_method m = _str_to_method_type(tmp_val[i]); - if (m == INVALID) + 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); } @@ -347,8 +347,8 @@ void ConfigParser::_set_location_values(LocationConfig *location, \ { for (unsigned long i = 0; i != tmp_val.size(); i++) { - http_method m = _str_to_method_type(tmp_val[i]); - if (m == INVALID) + 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); } diff --git a/srcs/config/ConfigParser.hpp b/srcs/config/ConfigParser.hpp index 119e043..c5e29f3 100644 --- a/srcs/config/ConfigParser.hpp +++ b/srcs/config/ConfigParser.hpp @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/07/11 23:01:41 by me #+# #+# */ -/* Updated: 2022/08/02 14:05:30 by lperrey ### ########.fr */ +/* Updated: 2022/08/03 17:32:33 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ @@ -75,8 +75,6 @@ private: std::string _get_rest_of_line(size_t *curr); // const? - // why static? it's an enum... - static http_method _str_to_method_type(std::string str); diff --git a/srcs/config/ConfigParserUtils.cpp b/srcs/config/ConfigParserUtils.cpp index c9e483c..ee5ef4e 100644 --- a/srcs/config/ConfigParserUtils.cpp +++ b/srcs/config/ConfigParserUtils.cpp @@ -82,20 +82,6 @@ std::string ConfigParser::_get_rest_of_line(size_t *curr) return (values); } - -http_method ConfigParser::_str_to_method_type(std::string str) -{ - if (str == "GET") - return GET; - else if (str == "POST") - return POST; - else if (str == "DELETE") - return DELETE; - return INVALID; -} - - - void ConfigParser::_print_content() const { std::cout << _content; diff --git a/srcs/utils.cpp b/srcs/utils.cpp index 48af746..73c1606 100644 --- a/srcs/utils.cpp +++ b/srcs/utils.cpp @@ -52,3 +52,35 @@ bool isNumeric_btw(int low, int high, std::string str) return true; } +http_method str_to_http_method(std::string &str) +{ + if (str == "GET") + return GET; + else if (str == "POST") + return POST; + else if (str == "DELETE") + return DELETE; + return UNKNOWN; +} + +std::string http_methods_to_str(unsigned int methods) +{ + std::string str; + + if (methods & GET) + str.append("GET"); + if (methods & POST) + { + if (!str.empty()) + str.append(", "); + str.append("POST"); + } + if (methods & DELETE) + { + if (!str.empty()) + str.append(", "); + str.append("DELETE"); + } + + return (str); +} diff --git a/srcs/utils.hpp b/srcs/utils.hpp index 6df52cb..c035cfb 100644 --- a/srcs/utils.hpp +++ b/srcs/utils.hpp @@ -9,24 +9,28 @@ // enum http_method // { -// GET = 0b000001, -// POST = 0b000010, -// DELETE = 0b000100, -// INVALID = 0b001000, +// UNKNOWN = 0b00000000, +// GET = 0b00000001, +// POST = 0b00000010, +// DELETE = 0b00000100, +// ALL_METHODS = 0b11111111, // }; enum http_method { - GET = 1, + UNKNOWN = 0b0, + GET = 1 << 0, POST = 1 << 1, DELETE = 1 << 2, - INVALID = 1 << 3, + ALL_METHODS = 0b11111111, }; -std::vector split(std::string input, char delimiter); -bool isNumeric(std::string str); -bool isNumeric_btw(int low, int high, std::string str); +std::vector split(std::string input, char delimiter); +bool isNumeric(std::string str); +bool isNumeric_btw(int low, int high, std::string str); 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); #endif diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index 7a1715c..a9d69fe 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -68,11 +68,14 @@ class Webserv void _read_request(Client *client); // response.cpp void _response(Client *client); - ServerConfig &_determine_process_server(Client *client); void _send_response(Client *client, ServerConfig &server); void _construct_response(Client *client, ServerConfig &server); void _insert_status_line(Client *client, ServerConfig &server); - void _get_ressource(Client *client, ServerConfig &server); + void _get_ressource(Client *client, ServerConfig &server, LocationConfig &location); + void _post(Client *client, ServerConfig &server, LocationConfig &location); + void _delete(Client *client, ServerConfig &server, LocationConfig &location); + ServerConfig &_determine_process_server(Client *client); + LocationConfig &_determine_location(ServerConfig &server, std::string &path); // cgi_script.cpp bool _is_cgi(Client *client); void _exec_cgi(Client *client); diff --git a/srcs/webserv/cgi_script.cpp b/srcs/webserv/cgi_script.cpp index ee1319e..636303d 100644 --- a/srcs/webserv/cgi_script.cpp +++ b/srcs/webserv/cgi_script.cpp @@ -40,7 +40,7 @@ char** Webserv::_set_env(Client *client) env[8] = _dup_env("REMOTE_HOST", client->get_headers("Host")); // just test env[9] = _dup_env("REMOTE_IDENT"); env[10] = _dup_env("REMOTE_USER"); - env[11] = _dup_env("REQUEST_METHOD", client->get_method()); + env[11] = _dup_env("REQUEST_METHOD", ::http_methods_to_str(client->get_method())); env[12] = _dup_env("SCRIPT_NAME"); env[13] = _dup_env("SERVER_NAME"); env[14] = _dup_env("SERVER_PORT"); diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 0f4373f..e751ac0 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -9,29 +9,6 @@ void Webserv::_response(Client *client) _handle_last_signal(); } -ServerConfig &Webserv::_determine_process_server(Client *client) -{ -/* - TODO : determine virtual server based on ip_address::port and server_name - Ior now its just based on server_name. - (maybe with a map< string, std::vector > where the string is "ip_adress::port") - http://nginx.org/en/docs/http/request_processing.html -*/ - - std::string &server_name = client->get_headers("Host"); - std::vector::iterator it = _servers.begin(); - while (it != _servers.end()) - { - if ( std::find(it->server_name.begin(), it->server_name.end(), server_name) != it->server_name.end() ) - break; - ++it; - } - if (it != _servers.end()) - return (*it); - else - return (_servers.front()); -} - void Webserv::_send_response(Client *client, ServerConfig &server) { ssize_t ret; @@ -62,7 +39,10 @@ void Webserv::_send_response(Client *client, ServerConfig &server) void Webserv::_construct_response(Client *client, ServerConfig &server) { - client->status = 200; + LocationConfig &location = _determine_location(server, client->get_path()); + + client->status = 200; // default value + client->response.append("Server: Webserv/0.1\r\n"); if (client->get_headers("Connection") == "close") @@ -70,8 +50,31 @@ void Webserv::_construct_response(Client *client, ServerConfig &server) else client->response.append("Connection: keep-alive\r\n"); - // TODO : Method switch (GET, POST, DELETE) - _get_ressource(client, server); + + unsigned int allow_methods = ALL_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 ALL_METHODS + + if (client->get_method() == UNKNOWN) + { + client->status = 400; + } + else if (allow_methods & client->get_method()) + { + if (client->get_method() & GET) + _get_ressource(client, server, location); + else if (client->get_method() & POST) + _post(client, server, location); + else if (client->get_method() & DELETE) + _delete(client, server, location); + } + else + { + client->status = 405; + client->response.append("Allow: "); + client->response.append(::http_methods_to_str(allow_methods)); + client->response.append("\r\n"); + } _insert_status_line(client, server); } @@ -114,7 +117,7 @@ void Webserv::_insert_status_line(Client *client, ServerConfig &server) #define ROOT "www" #define INDEX "index.html" #define MAX_FILESIZE 1000000 // (1Mo) -void Webserv::_get_ressource(Client *client, ServerConfig &server) +void Webserv::_get_ressource(Client *client, ServerConfig &server, LocationConfig &location) { std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ? char buf[MAX_FILESIZE+1]; @@ -171,9 +174,8 @@ void Webserv::_get_ressource(Client *client, ServerConfig &server) client->response.append("Content-Type: text/html; charset=UTF-8\r\n"); // TODO : determine Content-Type client->response.append("Content-Length: "); - tmp = ::itos(ifd.gcount()); - client->response.append(tmp.c_str()); + client->response.append(tmp); client->response.append("\r\n"); // Body @@ -184,3 +186,63 @@ void Webserv::_get_ressource(Client *client, ServerConfig &server) } } +void Webserv::_post(Client *client, ServerConfig &server, LocationConfig &location) +{ +/* + TODO +*/ + (void)0; +} + +void Webserv::_delete(Client *client, ServerConfig &server, LocationConfig &location) +{ +/* + TODO +*/ + (void)0; +} + +ServerConfig &Webserv::_determine_process_server(Client *client) +{ +/* + TODO : determine virtual server based on ip_address::port and server_name + Ior now its just based on server_name. + (maybe with a map< string, std::vector > where the string is "ip_adress::port") + http://nginx.org/en/docs/http/request_processing.html +*/ + + std::string &server_name = client->get_headers("Host"); + std::vector::iterator it = _servers.begin(); + while (it != _servers.end()) + { + if ( std::find(it->server_name.begin(), it->server_name.end(), server_name) != it->server_name.end() ) + break; + ++it; + } + if (it != _servers.end()) + return (*it); + else + return (_servers.front()); +} + +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()) + { + if (it->path.compare(0, path.size(), path)) + break; + ++it; + } + if (it != server.locations.end()) + return (*it); + else + return (server.locations.front()); +}