diff --git a/memo.txt b/memo.txt index 5482d1f..dd03cec 100644 --- a/memo.txt +++ b/memo.txt @@ -1,5 +1,12 @@ - +- do correct handling of special character in url (/rfc2119_files/errata.js.t%C3%A9l%C3%A9chargement -> /rfc2119_files/errata.js.téléchargement) +- 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/Client.cpp b/srcs/Client.cpp index 8641916..471da4e 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -1,6 +1,8 @@ #include "Client.hpp" +char Client::buf[MAX_FILESIZE+1]; + /********************************************* * COPLIENS *********************************************/ @@ -35,7 +37,7 @@ void Client::parse_request() std::vector list; size_t pos; - pos = (raw_request).find("\r\n\r\n"); + pos = (raw_request).find(CRLF CRLF); sub = (raw_request).substr(0, pos); list = split(sub, '\n'); // request_line @@ -45,9 +47,27 @@ void Client::parse_request() _parse_request_headers(list); //body- message _parse_request_body(pos + 4); + + // add "raw_request.clear()" after parsing ? for little less memory usage ? } +void Client::clear() +{ + clear_request(); + raw_request.clear(); + response.clear(); + body_size = 0; + status = 0; +} +void Client::clear_request() +{ + _request.method = UNKNOWN; + _request.path.clear(); + _request.version.clear(); + _request.headers.clear(); + _request.body.clear(); +} http_method Client::get_method() { return _request.method; } std::string &Client::get_path() { return _request.path; } diff --git a/srcs/Client.hpp b/srcs/Client.hpp index eef125a..c23a7de 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -10,13 +10,14 @@ struct Request { - std::map headers; http_method method; std::string path; std::string version; + std::map headers; std::string body; }; +# define MAX_FILESIZE 1000000 // (1Mo) class Client { public: @@ -28,6 +29,8 @@ class Client int fd; std::string raw_request; std::string response; + static char buf[MAX_FILESIZE+1]; + size_t body_size; unsigned int status; // const functions ? @@ -38,6 +41,8 @@ class Client std::string &get_headers(const std::string &key); void parse_request(); + void clear(); + void clear_request(); private: struct Request _request; diff --git a/srcs/config/ServerConfig.hpp b/srcs/config/ServerConfig.hpp index bda69ff..90e61b9 100644 --- a/srcs/config/ServerConfig.hpp +++ b/srcs/config/ServerConfig.hpp @@ -30,7 +30,7 @@ public: // there can only be one. std::string root; - int client_body_limit; // set to default max if none set + 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; diff --git a/srcs/utils.cpp b/srcs/utils.cpp index 642c875..063cc98 100644 --- a/srcs/utils.cpp +++ b/srcs/utils.cpp @@ -124,5 +124,18 @@ int path_is_valid(std::string path) } - +void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr) +{ + if (ori_substr.empty()) + return; + size_t pos = 0; + while (1) + { + pos = str.find(ori_substr, pos); + if (pos == std::string::npos) + break; + str.replace(pos, ori_substr.size(), new_substr); + pos += new_substr.size(); + } +} diff --git a/srcs/utils.hpp b/srcs/utils.hpp index 35ca453..1411f46 100644 --- a/srcs/utils.hpp +++ b/srcs/utils.hpp @@ -8,9 +8,9 @@ # include // atoi # include // stat() -# include // tmp - - +# define CR "\r" +# define LF "\n" +# define CRLF CR LF // enum http_method // { @@ -38,5 +38,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) #endif diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index a9d69fe..67e2c13 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -28,6 +28,7 @@ # include "Client.hpp" # include "ServerConfig.hpp" # include "utils.hpp" +# include "http_status.hpp" extern bool g_run; extern int g_last_signal; @@ -60,6 +61,8 @@ class Webserv std::vector _listen_sockets; std::vector _servers; std::vector _clients; + std::map _http_status; + std::map _mime_types; // accept.cpp void _accept_connection(int fd); @@ -69,11 +72,23 @@ class Webserv // response.cpp void _response(Client *client); void _send_response(Client *client, ServerConfig &server); + + void _append_base_headers(Client *client); void _construct_response(Client *client, ServerConfig &server); - void _insert_status_line(Client *client, ServerConfig &server); - void _get_ressource(Client *client, ServerConfig &server, LocationConfig &location); + 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 _get(Client *client, ServerConfig &server, LocationConfig &location); + void _get_file(Client *client, const std::string &path); + 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); // cgi_script.cpp @@ -94,6 +109,8 @@ class Webserv // init.cpp void _bind(int socket_fd, in_port_t port, std::string host); void _listen(int socket_fd, unsigned int max_connections); + void _init_http_status_map(); + void _init_mime_types_map(); }; #endif diff --git a/srcs/webserv/base.cpp b/srcs/webserv/base.cpp index 6267ec9..3392619 100644 --- a/srcs/webserv/base.cpp +++ b/srcs/webserv/base.cpp @@ -12,6 +12,9 @@ Webserv::Webserv() throw std::runtime_error("Epoll init"); } + _init_http_status_map(); + _init_mime_types_map(); + std::signal(SIGPIPE, signal_handler); std::signal(SIGINT, signal_handler); } diff --git a/srcs/webserv/http_status.hpp b/srcs/webserv/http_status.hpp new file mode 100644 index 0000000..8aa513a --- /dev/null +++ b/srcs/webserv/http_status.hpp @@ -0,0 +1,41 @@ + +#ifndef HTTP_STATUS_HPP +# define HTTP_STATUS_HPP + +// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml + +/* + First version of macro HTML_ERROR(STATUS) dont work with call like this : + client->response.append( HTML_ERROR( _http_status[client->status].c_str() ) ); + so I made the other version with dynamic replacement of STATUS . +*/ +// # define HTML_ERROR(STATUS) "\r\n"STATUS"

"STATUS"


Le Webserv/0.1

" + +# define STATUS_PLACEHOLDER "$STATUS" +# define HTML_ERROR \ +""\ +""\ +""\ + "" STATUS_PLACEHOLDER ""\ +""\ +""\ + "

" STATUS_PLACEHOLDER "

"\ + "
"\ + "

Le Webserv/0.1

"\ +""\ +"" + +// 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" + +# define S500 "500 Internal Server Error" + +#endif diff --git a/srcs/webserv/init.cpp b/srcs/webserv/init.cpp index 4c5956e..ddd0edc 100644 --- a/srcs/webserv/init.cpp +++ b/srcs/webserv/init.cpp @@ -76,3 +76,134 @@ void Webserv::_listen(int socket_fd, unsigned int max_connections) throw std::runtime_error("Socket listen"); } } + +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; + + _http_status[500] = S500; +} + +void Webserv::_init_mime_types_map() +{ + _mime_types[""] = "application/octet-stream"; + + _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["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["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["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["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["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["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["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"; +} diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index e751ac0..0b6f3fa 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -3,6 +3,8 @@ void Webserv::_response(Client *client) { + client->status = 200; // default value + ServerConfig &server = _determine_process_server(client); _send_response(client, server); if (g_last_signal) @@ -14,9 +16,12 @@ void Webserv::_send_response(Client *client, ServerConfig &server) ssize_t ret; std::cerr << "send()\n"; - // std::cerr << "RAW_REQUEST\n|\n" << client->raw_request << "|\n"; // DEBUG + _append_base_headers(client); _construct_response(client, server); + _insert_status_line(client); + if (client->status >= 400) + _error_html_response(client, server); ret = ::send(client->fd, client->response.c_str(), client->response.size(), 0); if (ret == -1) @@ -27,30 +32,51 @@ void Webserv::_send_response(Client *client, ServerConfig &server) return ; } - if (client->raw_request.find("Connection: close") != std::string::npos) + // 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 ; + } + } + + if (client->get_headers("Connection") == "close") _close_client(client->fd); else { _epoll_update(client->fd, EPOLLIN, EPOLL_CTL_MOD); - client->raw_request.clear(); - client->response.clear(); + client->clear(); } } +void Webserv::_append_base_headers(Client *client) +{ + client->response.append("Server: Webserv/0.1" CRLF); + + if (client->get_headers("Connection") == "close") + client->response.append("Connection: close" CRLF); + else + client->response.append("Connection: keep-alive" CRLF); +} + void Webserv::_construct_response(Client *client, ServerConfig &server) { + if (client->get_body().size() > server.client_body_limit) + { + client->status = 413; + return; + } LocationConfig &location = _determine_location(server, client->get_path()); + _process_method(client, server, location); +} - client->status = 200; // default value - - client->response.append("Server: Webserv/0.1\r\n"); - - if (client->get_headers("Connection") == "close") - client->response.append("Connection: close\r\n"); - else - client->response.append("Connection: keep-alive\r\n"); - - +void Webserv::_process_method(Client *client, ServerConfig &server, LocationConfig &location) +{ 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 @@ -61,72 +87,61 @@ void Webserv::_construct_response(Client *client, ServerConfig &server) } 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); + switch (client->get_method()) + { + case (GET): + _get(client, server, location); + break; + case (POST): + _post(client, server, location); + break; + case (DELETE): + _delete(client, server, location); + break; + default: + break; + } } else { client->status = 405; client->response.append("Allow: "); client->response.append(::http_methods_to_str(allow_methods)); - client->response.append("\r\n"); + client->response.append(CRLF); } - - _insert_status_line(client, server); } -// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml -#define HTML_ERROR(STATUS) "\r\n"STATUS"

"STATUS"


Le Webserv/0.1

" -#define S200 "200 OK" -#define S400 "400 Bad Request" -#define S404 "404 Not Found" -#define S500 "500 Internal Server Error" -void Webserv::_insert_status_line(Client *client, ServerConfig &server) +void Webserv::_insert_status_line(Client *client) { std::string status_line; status_line.append("HTTP/1.1 "); - // WIP, maybe make a map for status response - switch (client->status) - { - case (200): - status_line.append(S200); - break; - case (400): - status_line.append(S400); - client->response.append(HTML_ERROR(S400)); - break; - case (404): - status_line.append(S404); - client->response.append(HTML_ERROR(S404)); - break; - case (500): - status_line.append(S500); - client->response.append(HTML_ERROR(S500)); - break; - } - status_line.append("\r\n"); - + status_line.append(_http_status[client->status]); + status_line.append(CRLF); client->response.insert(0, status_line); } -#define ROOT "www" -#define INDEX "index.html" -#define MAX_FILESIZE 1000000 // (1Mo) -void Webserv::_get_ressource(Client *client, ServerConfig &server, LocationConfig &location) +void Webserv::_error_html_response(Client *client, ServerConfig &server) { - std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ? - char buf[MAX_FILESIZE+1]; - std::string tmp; + if (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.c_str(), html_page.size(), "html"); + } + else + _get_file(client, server.error_pages[client->status]); +} + +#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 ; With server config + if (path == "/") // TODO : index and autoindex path.append(INDEX); - path.insert(0, ROOT); + path.insert(0, location.root); std::cerr << "path = " << path << "\n"; @@ -140,24 +155,39 @@ void Webserv::_get_ressource(Client *client, ServerConfig &server, LocationConfi // // END TMP HUGO - - if (access(path.c_str(), R_OK) == -1) + _get_file(client, path); +} + +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(), 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 @@ -168,38 +198,161 @@ void Webserv::_get_ressource(Client *client, ServerConfig &server, LocationConfi } ifd.seekg(0, std::ios::beg); - ifd.read(buf, size); - buf[ifd.gcount()] = '\0'; + ifd.read(client->buf, size); + if (!ifd) + { + std::cerr << path << ": ifd.read fail" << '\n'; + client->status = 500; + } + else + { + client->status = 200; + client->buf[ifd.gcount()] = '\0'; - client->response.append("Content-Type: text/html; charset=UTF-8\r\n"); // TODO : determine Content-Type + 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->response.append("Content-Length: "); - tmp = ::itos(ifd.gcount()); - client->response.append(tmp); - client->response.append("\r\n"); - - // Body - client->response.append("\r\n"); - client->response.append(buf); + 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); + } ifd.close(); } } -void Webserv::_post(Client *client, ServerConfig &server, LocationConfig &location) +void Webserv::_append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension) { /* - TODO + 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. */ - (void)0; + const std::string &mime_type = _mime_types[file_extension]; + client->response.append("Content-Type: "); + 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("Content-Length: "); + std::string tmp = ::itos(body_size); + client->response.append(tmp); + client->response.append(CRLF); + + client->response.append(CRLF); + client->response.append(body); +} + +void Webserv::_post(Client *client, ServerConfig &server, LocationConfig &location) +{ + (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); + + /* 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) diff --git a/www/drill.jpg b/www/drill.jpg new file mode 100644 index 0000000..1812dbd Binary files /dev/null and b/www/drill.jpg differ diff --git a/www/favicon.ico b/www/favicon.ico new file mode 100644 index 0000000..8be776b Binary files /dev/null and b/www/favicon.ico differ diff --git a/www/kermit.ico b/www/kermit.ico new file mode 100644 index 0000000..8be776b Binary files /dev/null and b/www/kermit.ico differ diff --git a/www/rfc2119.html b/www/rfc2119.html index b8b389b..42168fa 100644 --- a/www/rfc2119.html +++ b/www/rfc2119.html @@ -13,7 +13,7 @@ - +
@@ -309,4 +309,4 @@ Full stop should appear outside the parentheses in the last sentence. - + \ No newline at end of file diff --git a/www/rfc2119_files/errata-base.css b/www/rfc2119_files/errata-base.css new file mode 100644 index 0000000..c34a536 --- /dev/null +++ b/www/rfc2119_files/errata-base.css @@ -0,0 +1,139 @@ + diff --git a/www/rfc2119_files/errata-color.css b/www/rfc2119_files/errata-color.css new file mode 100644 index 0000000..74428de --- /dev/null +++ b/www/rfc2119_files/errata-color.css @@ -0,0 +1,43 @@ + diff --git a/www/rfc2119_files/errata-monochrome.css b/www/rfc2119_files/errata-monochrome.css new file mode 100644 index 0000000..be74384 --- /dev/null +++ b/www/rfc2119_files/errata-monochrome.css @@ -0,0 +1,34 @@ + diff --git a/www/rfc2119_files/errata-printer.css b/www/rfc2119_files/errata-printer.css new file mode 100644 index 0000000..4a3dab3 --- /dev/null +++ b/www/rfc2119_files/errata-printer.css @@ -0,0 +1,43 @@ + diff --git a/www/rfc2119_files/errata.js b/www/rfc2119_files/errata.js new file mode 100644 index 0000000..4e29587 --- /dev/null +++ b/www/rfc2119_files/errata.js @@ -0,0 +1,4 @@ +function hideFunction(nodeId) { + var ul = document.getElementById(nodeId) + ul.className = (ul.className=="nodeOpenClass") ? "nodeCloseClass" : "nodeOpenClass" +} diff --git a/www/rfc2119_files/errata.js.téléchargement b/www/rfc2119_files/errata.js.téléchargement new file mode 100644 index 0000000..4e29587 --- /dev/null +++ b/www/rfc2119_files/errata.js.téléchargement @@ -0,0 +1,4 @@ +function hideFunction(nodeId) { + var ul = document.getElementById(nodeId) + ul.className = (ul.className=="nodeOpenClass") ? "nodeCloseClass" : "nodeOpenClass" +} diff --git a/www/rfc2119_no_link.html b/www/rfc2119_no_link.html deleted file mode 100644 index eec8fe5..0000000 --- a/www/rfc2119_no_link.html +++ /dev/null @@ -1,300 +0,0 @@ - - - - rfc2119 - - -
-This is a purely informative rendering of an RFC that includes verified errata. This rendering may not be used as a reference. -
-
-The following 'Verified' errata have been incorporated in this document: - EID 493, EID 494, EID 495, EID 496, EID 498, EID 499, EID 500, EID 5101 -
- -
Network Working Group                                         S. Bradner
-Request for Comments: 2119                            Harvard University
-BCP: 14                                                       March 1997
-Category: Best Current Practice
-
-
-        Key words for use in RFCs to Indicate Requirement Levels
-
-Status of this Memo
-
-   This document specifies an Internet Best Current Practices for the
-   Internet Community, and requests discussion and suggestions for
-   improvements.  Distribution of this memo is unlimited.
-
-Abstract
-
-   In many standards track documents several words are used to signify
-   the requirements in the specification.  These words are often
-   capitalized.  This document defines these words as they should be
-   interpreted in IETF documents.  Authors who follow these guidelines
-   should incorporate this phrase near the beginning of their document:
-
-             The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL 
-       NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT 
-       RECOMMENDED",  "MAY", and "OPTIONAL" in this document are to 
-       be interpreted as described in RFC 2119.
-
-
EID 499 (Verified) is as follows:
-
-Section: Abstract
-
-Original Text:
-
-       The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
-       NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and
-       "OPTIONAL" in this document are to be interpreted as described in
-       RFC 2119.
-
-Corrected Text:
-
-       The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
-       NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT 
-       RECOMMENDED",  "MAY", and "OPTIONAL" in this document are to 
-       be interpreted as described in RFC 2119.
-
-Notes:
-The phrase "NOT RECOMMENDED" is missing from this sentence. -
-
- Note that the force of these words is modified by the requirement - level of the document in which they are used. - -1. MUST This word, or the terms "REQUIRED" or "SHALL", means that the - definition is an absolute requirement of the specification. -
-
EID 493 (Verified) is as follows:
-
-Section: 1
-
-Original Text:
-
-2. MUST NOT   This phrase, or the phrase "SHALL NOT", mean that the
-   definition is an absolute prohibition of the specification.
-
-Corrected Text:
-
-2. MUST NOT   This phrase, or the phrase "SHALL NOT", means that the
-   definition is an absolute prohibition of the specification.
-
-Notes:
- -
-
-
EID 498 (Verified) is as follows:
-
-Section: 1
-
-Original Text:
-
-4. SHOULD NOT   This phrase, or the phrase "NOT RECOMMENDED" mean that
-   there may exist valid reasons in particular circumstances when the
-   particular behavior is acceptable or even useful, but the full
-   implications should be understood and the case carefully weighed
-   before implementing any behavior described with this label.
-
-Corrected Text:
-
-4. SHOULD NOT   This phrase, or the phrase "NOT RECOMMENDED", means that
-   there may exist valid reasons in particular circumstances when the
-   particular behavior is acceptable or even useful, but the full
-   implications should be understood and the case carefully weighed
-   before implementing any behavior described with this label.
-
-Notes:
- -
-
-
EID 500 (Verified) is as follows:
-
-Section: 1
-
-Original Text:
-
-3. SHOULD   This word, or the adjective "RECOMMENDED", mean that there
-   may exist valid reasons in particular circumstances to ignore a
-   particular item, but the full implications must be understood and
-   carefully weighed before choosing a different course.
-
-Corrected Text:
-
-3. SHOULD   This word, or the adjective "RECOMMENDED", means that there
-   may exist valid reasons in particular circumstances to ignore a
-   particular item, but the full implications must be understood and
-   carefully weighed before choosing a different course.
-
-Notes:
- -
-
-
-
EID 495 (Verified) is as follows:
-
-Section: 1
-
-Original Text:
-
-1. MUST   This word, or the terms "REQUIRED" or "SHALL", mean that the
-   definition is an absolute requirement of the specification.
-
-
-Corrected Text:
-
-1. MUST   This word, or the terms "REQUIRED" or "SHALL", means that the
-   definition is an absolute requirement of the specification.
-
-Notes:
- -
-
-2. MUST NOT This phrase, or the phrase "SHALL NOT", mean that the - definition is an absolute prohibition of the specification. - -3. SHOULD This word, or the adjective "RECOMMENDED", mean that there - may exist valid reasons in particular circumstances to ignore a - particular item, but the full implications must be understood and - carefully weighed before choosing a different course. - -4. SHOULD NOT This phrase, or the phrase "NOT RECOMMENDED" mean that - there may exist valid reasons in particular circumstances when the - particular behavior is acceptable or even useful, but the full - implications should be understood and the case carefully weighed - before implementing any behavior described with this label. - -5. MAY This word, or the adjective "OPTIONAL", mean that an item is - truly optional. One vendor may choose to include the item because a - particular marketplace requires it or because the vendor feels that - it enhances the product while another vendor may omit the same item. - An implementation which does not include a particular option MUST be - prepared to interoperate with another implementation which does - include the option, though perhaps with reduced functionality. In the - same vein an implementation which does include a particular option - MUST be prepared to interoperate with another implementation which - does not include the option (except, of course, for the feature the - option provides). -
-
EID 5101 (Verified) is as follows:
-
-Section: 5
-
-Original Text:
-
-5. MAY   This word, or the adjective "OPTIONAL", mean that an item is
-   truly optional.  One vendor may choose to include the item because a
-   particular marketplace requires it or because the vendor feels that
-   it enhances the product while another vendor may omit the same item.
-   An implementation which does not include a particular option MUST be
-   prepared to interoperate with another implementation which does
-   include the option, though perhaps with reduced functionality. In the
-   same vein an implementation which does include a particular option
-   MUST be prepared to interoperate with another implementation which
-   does not include the option (except, of course, for the feature the
-   option provides.)
-
-Corrected Text:
-
-5. MAY   This word, or the adjective "OPTIONAL", mean that an item is
-   truly optional.  One vendor may choose to include the item because a
-   particular marketplace requires it or because the vendor feels that
-   it enhances the product while another vendor may omit the same item.
-   An implementation which does not include a particular option MUST be
-   prepared to interoperate with another implementation which does
-   include the option, though perhaps with reduced functionality. In the
-   same vein an implementation which does include a particular option
-   MUST be prepared to interoperate with another implementation which
-   does not include the option (except, of course, for the feature the
-   option provides).
-
-Notes:
-Full stop should appear outside the parentheses in the last sentence. -
-
-6. Guidance in the use of these Imperatives - - Imperatives of the type defined in this memo must be used with care - and sparingly. In particular, they MUST only be used where it is - actually required for interoperation or to limit behavior which has - potential for causing harm (e.g., limiting retransmissions) For -
-
EID 494 (Verified) is as follows:
-
-Section: 6
-
-Original Text:
-
-(e.g., limiting retransmisssions)
-
-Corrected Text:
-
-(e.g., limiting retransmissions)
-
-Notes:
- -
-
-
EID 496 (Verified) is as follows:
-
-Section: 6
-
-Original Text:
-
-   In particular, they MUST only be used where it is actually required
-   for interoperation or to limit behavior which has potential for
-   causing harm (e.g., limiting retransmisssions)  For example, they
-   must not be used to try to impose a particular method on
-   implementors where the method is not required for interoperability.   
-
-Corrected Text:
-
-   In particular, they MUST only be used where it is actually required
-   for interoperation or to limit behavior which has potential for
-   causing harm (e.g., limiting retransmissions).  For example, they
-   must not be used to try to impose a particular method on
-   implementors where the method is not required for interoperability.
-
-Notes:
- -
-
example, they must not be used to try to impose a particular method - on implementors where the method is not required for - interoperability. - -7. Security Considerations - - These terms are frequently used to specify behavior with security - implications. The effects on security of not implementing a MUST or - SHOULD, or doing something the specification says MUST NOT or SHOULD - NOT be done may be very subtle. Document authors should take the time - to elaborate the security implications of not following - recommendations or requirements as most implementors will not have - had the benefit of the experience and discussion that produced the - specification. - -8. Acknowledgments - - The definitions of these terms are an amalgam of definitions taken - from a number of RFCs. In addition, suggestions have been - incorporated from a number of people including Robert Ullmann, Thomas - Narten, Neal McBurnett, and Robert Elz. - -9. Author's Address - - Scott Bradner - Harvard University - 1350 Mass. Ave. - Cambridge, MA 02138 - - phone - +1 617 495 3864 - - email - sob@harvard.edu - - - - - - -
\ No newline at end of file diff --git a/www/root.png b/www/root.png new file mode 100644 index 0000000..ebd1548 Binary files /dev/null and b/www/root.png differ