diff --git a/memo.txt b/memo.txt index 5482d1f..28280f6 100644 --- a/memo.txt +++ b/memo.txt @@ -1,5 +1,11 @@ - +- handle redirection +- 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)} +- 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. diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index f859ea3..585feac 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -77,13 +77,16 @@ 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); void _get(Client *client, ServerConfig &server, LocationConfig &location); void _get_file(Client *client, const std::string &path); - void _append_body(Client *client, const char *body, size_t body_size); void _post(Client *client, ServerConfig &server, LocationConfig &location); + void _post_file(Client *client, const std::string &path); + void _delete(Client *client, ServerConfig &server, LocationConfig &location); + void _delete_file(Client *client, const std::string &path); ServerConfig &_determine_process_server(Client *client); LocationConfig &_determine_location(ServerConfig &server, std::string &path); diff --git a/srcs/webserv/http_status.hpp b/srcs/webserv/http_status.hpp index efc64b4..c53170d 100644 --- a/srcs/webserv/http_status.hpp +++ b/srcs/webserv/http_status.hpp @@ -16,8 +16,11 @@ // When new status added, need to update _init_http_status_map() # define S200 "200 OK" +# define S201 "201 Created" +# define S204 "204 No Content" # define S400 "400 Bad Request" +# define S403 "403 Forbidden" # define S404 "404 Not Found" # define S405 "405 Method Not Allowed" # define S413 "413 Content Too Large" diff --git a/srcs/webserv/init.cpp b/srcs/webserv/init.cpp index 4445ca8..db0c4be 100644 --- a/srcs/webserv/init.cpp +++ b/srcs/webserv/init.cpp @@ -80,8 +80,11 @@ 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; _http_status[400] = S400; + _http_status[403] = S403; _http_status[404] = S404; _http_status[405] = S405; _http_status[413] = S413; diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 0a09f28..705f77d 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -123,6 +123,7 @@ 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 @@ -150,23 +151,31 @@ 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]; - if (access(path.c_str(), R_OK) == -1) + 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::binary | std::ios::ate); // std::ios::binary (binary for files like images ?) if (!ifd) { - std::cerr << path << ": open fail" << '\n'; + std::cerr << path << ": ifd.open fail" << '\n'; client->status = 500; } else { - // WIP : Chunk or not chunk (if filesize too big) std::streampos size = ifd.tellg(); + + // WIP : Chunk or not chunk (if filesize too big) if (size > MAX_FILESIZE) { // Then chunk @@ -178,9 +187,17 @@ void Webserv::_get_file(Client *client, const std::string &path) ifd.seekg(0, std::ios::beg); ifd.read(buf, size); - buf[ifd.gcount()] = '\0'; - - _append_body(client, buf, ifd.gcount()); + if (!ifd) + { + std::cerr << path << ": ifd.read fail" << '\n'; + client->status = 500; + } + else + { + client->status = 200; + buf[ifd.gcount()] = '\0'; + _append_body(client, buf, ifd.gcount()); + } ifd.close(); } @@ -208,18 +225,107 @@ void Webserv::_append_body(Client *client, const char *body, size_t body_size) void Webserv::_post(Client *client, ServerConfig &server, LocationConfig &location) { + (void)server; // To remove from arg if we determine its useless /* - TODO + WIP + https://www.rfc-editor.org/rfc/rfc9110.html#name-post */ - (void)0; + std::string path = client->get_path(); + path.insert(0, 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::binary | std::ios::trunc); + if (!ofd) + { + std::cerr << path << ": ofd.open fail" << '\n'; + client->status = 500; + } + else + { + // Used body.size() so 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()); + 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 + } + + ofd.close(); + } } void Webserv::_delete(Client *client, ServerConfig &server, LocationConfig &location) { + (void)server; // To remove from arg if we determine its useless /* - TODO + WIP + https://www.rfc-editor.org/rfc/rfc9110.html#name-delete */ - (void)0; + std::string path = client->get_path(); + path.insert(0, 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)