From a44b9b493ab82deb3833dc4c292ba7873571b457 Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Mon, 8 Aug 2022 20:36:01 +0200 Subject: [PATCH] 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