diff --git a/exemples/test.toml b/exemples/test.toml index 60416b7..a1c15d2 100644 --- a/exemples/test.toml +++ b/exemples/test.toml @@ -25,15 +25,15 @@ cgi.go = "/bin/go" [server.location./redir] redirect = "https://kanel.ovh" -[server1] +[serverr] server_names = { "ptnnnn.local"} -host = "0.0.0.0" -port = 90 +host = "127.0.0.2" +port = 9090 -[server1.error_pages] +[serverr.error_pages] 404 = "existepasfd***.html" -[server1.location./] +[serverr.location./] methods = { "GET", "DELETE" } root = "/var/lib/docker/volumes/test_data/_data" dirlist = false diff --git a/includes/requests/Errors.hpp b/includes/requests/Errors.hpp index e2b2e46..83b6fe5 100644 --- a/includes/requests/Errors.hpp +++ b/includes/requests/Errors.hpp @@ -6,7 +6,7 @@ /* By: mmoussou ); static std::map message; + private: static std::map populateMessages(); diff --git a/includes/requests/HttpRequest.hpp b/includes/requests/HttpRequest.hpp index f1d8b7e..16f3851 100644 --- a/includes/requests/HttpRequest.hpp +++ b/includes/requests/HttpRequest.hpp @@ -6,7 +6,7 @@ /* By: mmoussou #include +#include #include diff --git a/includes/requests/Mime.hpp b/includes/requests/Mime.hpp new file mode 100644 index 0000000..7b8f705 --- /dev/null +++ b/includes/requests/Mime.hpp @@ -0,0 +1,32 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Mime.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: mmoussou +#include + +namespace webserv { +namespace http { + +class Mime { +public: + static std::string getType(const std::string &filename); + +private: + static std::map initMimeTypes(); + + static std::map mimeTypes; +}; + +} // -namespace http +} // -namespace webserv diff --git a/includes/server/Client.hpp b/includes/server/Client.hpp index 4d1ca6f..9b01183 100644 --- a/includes/server/Client.hpp +++ b/includes/server/Client.hpp @@ -6,7 +6,7 @@ /* By: adjoly +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/14 14:14:39 by adjoly #+# #+# */ -/* Updated: 2025/04/23 14:39:16 by mmoussou ### ########.fr */ +/* Updated: 2025/04/25 12:43:54 by mmoussou ### ########.fr */ /* */ /* ************************************************************************** */ @@ -23,7 +23,9 @@ namespace server { class Client { public: - Client(int, sockaddr_in, config::Config *); + Client(); + Client(struct pollfd, sockaddr_in, config::Config *); + void parse(struct pollfd, sockaddr_in, config::Config *); virtual ~Client(void); void answer(void); @@ -31,7 +33,7 @@ class Client { private: void _getRequest(std::string); - int _fd; + struct pollfd _fd; struct sockaddr_in _client_addr; http::IRequest *_request; //http::Response *_response; diff --git a/src/config/Config.cpp b/src/config/Config.cpp index 02513d1..eb34fda 100644 --- a/src/config/Config.cpp +++ b/src/config/Config.cpp @@ -6,7 +6,7 @@ /* By: adjoly +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/14 12:53:54 by adjoly #+# #+# */ -/* Updated: 2025/04/22 15:35:52 by adjoly ### ########.fr */ +/* Updated: 2025/04/23 17:42:07 by adjoly ### ########.fr */ /* */ /* ************************************************************************** */ @@ -15,13 +15,19 @@ #include "cppeleven.hpp" #include "node/ANode.hpp" #include +#include using namespace webserv::config; Config::Config(std::string &filename) { toml::Toml *file = new toml::Toml(filename); - file->parse(); + try { + file->parse(); + } catch (std::runtime_error &e) { + delete file; + throw e; + } toml::ANode *table = file->getParsedFile(); bool found = false; @@ -36,8 +42,13 @@ Config::Config(std::string &filename) { for (auto it = prange(node)) { if (it->second->type() == toml::TABLE) { _log->info("taking server from table : " + it->first); - Server *srv = new Server(it->second); - _servers.push_back(srv); + try { + Server *srv = new Server(it->second); + _servers.push_back(srv); + } catch (std::runtime_error &e) { + _log->error(e.what()); + break; + } } } delete table; diff --git a/src/requests_handling/HttpRequests.cpp b/src/requests_handling/HttpRequests.cpp index ba7e50f..b3a4c9e 100644 --- a/src/requests_handling/HttpRequests.cpp +++ b/src/requests_handling/HttpRequests.cpp @@ -6,7 +6,7 @@ /* By: mmoussou #include +#include + using namespace webserv; http::IRequest::~IRequest(void) { @@ -174,7 +176,30 @@ http::Response http::Get::execute(void) std::sort(files.begin(), files.end()); - std::string body = "
    \n"; + std::string body = ""; + + body += ""; + + body += "
      \n"; for (size_t i = 0; i < files.size(); i++) body += "
    • " + files[i] + "
    • \n"; body += "
    "; @@ -199,13 +224,9 @@ http::Response http::Get::execute(void) response.setProtocol(this->_protocol); response.setStatusCode(200); - response.addHeader("Content-Type", "text/html"); // TODO: change it to check the file extension and set it to the corresponding MIME or text/plain if unkown. we will only implement the important MIME types in the Mozilla documentation because https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types + response.addHeader("Content-Type", http::Mime::getType(this->_target)); - //std::ifstream file_end(this->_target.c_str(), std::ios::binary | std::ios::ate); - //std::stringstream length; - //length << (file_end.tellg() - file.tellg()); - //std::cout << length.str() << std::endl; - //response.addHeader("Content-Length", length.str()); + _log->debug(response.str().c_str()); } } catch (...) diff --git a/src/requests_handling/Mime.cpp b/src/requests_handling/Mime.cpp new file mode 100644 index 0000000..eae298a --- /dev/null +++ b/src/requests_handling/Mime.cpp @@ -0,0 +1,113 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Mime.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: mmoussou + +using namespace webserv; + +std::map http::Mime::initMimeTypes() { + std::map types; + + types["aac"] = "audio/aac"; + types["abw"] = "application/x-abiword"; + types["apng"] = "image/apng"; + types["arc"] = "application/x-freearc"; + types["avif"] = "image/avif"; + types["avi"] = "video/x-msvideo"; + types["azw"] = "application/vnd.amazon.ebook"; + types["bin"] = "application/octet-stream"; + types["bmp"] = "image/bmp"; + types["bz"] = "application/x-bzip"; + types["bz2"] = "application/x-bzip2"; + types["cda"] = "application/x-cdf"; + types["csh"] = "application/x-csh"; + types["css"] = "text/css"; + types["csv"] = "text/csv"; + types["doc"] = "application/msword"; + types["docx"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; + types["eot"] = "application/vnd.ms-fontobject"; + types["epub"] = "application/epub+zip"; + types["gz"] = "application/gzip"; + types["gif"] = "image/gif"; + types["htm"] = "text/html"; + types["html"] = "text/html"; + types["ico"] = "image/vnd.microsoft.icon"; + types["ics"] = "text/calendar"; + types["jar"] = "application/java-archive"; + types["jpeg,"] = "image/jpeg"; + types["js"] = "text/javascript"; + types["json"] = "application/json"; + types["jsonld"] = "application/ld+json"; + types["md"] = "text/plain"; + types["mid"] = "audio/midi"; + types["midi"] = "audio/midi"; + types["mjs"] = "text/javascript"; + types["mp3"] = "audio/mpeg"; + types["mp4"] = "video/mp4"; + types["mpeg"] = "video/mpeg"; + types["mpkg"] = "application/vnd.apple.installer+xml"; + types["odp"] = "application/vnd.oasis.opendocument.presentation"; + types["ods"] = "application/vnd.oasis.opendocument.spreadsheet"; + types["odt"] = "application/vnd.oasis.opendocument.text"; + types["oga"] = "audio/ogg"; + types["ogv"] = "video/ogg"; + types["ogx"] = "application/ogg"; + types["opus"] = "audio/ogg"; + types["otf"] = "font/otf"; + types["png"] = "image/png"; + types["pdf"] = "application/pdf"; + types["php"] = "application/x-httpd-php"; + types["ppt"] = "application/vnd.ms-powerpoint"; + types["pptx"] = "application/vnd.openxmlformats-officedocument.presentationml.presentation"; + types["rar"] = "application/vnd.rar"; + types["rtf"] = "application/rtf"; + types["sh"] = "application/x-sh"; + types["svg"] = "image/svg+xml"; + types["tar"] = "application/x-tar"; + types["tif,"] = "image/tiff"; + types["ts"] = "video/mp2t"; + types["ttf"] = "font/ttf"; + types["txt"] = "text/plain"; + types["vsd"] = "application/vnd.visio"; + types["wav"] = "audio/wav"; + types["weba"] = "audio/webm"; + types["webm"] = "video/webm"; + types["webp"] = "image/webp"; + types["woff"] = "font/woff"; + types["woff2"] = "font/woff2"; + types["xhtml"] = "application/xhtml+xml"; + types["xls"] = "application/vnd.ms-excel"; + types["xlsx"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + types["xml"] = "application/xml"; + types["xul"] = "application/vnd.mozilla.xul+xml"; + types["zip"] = "application/zip"; + types["3gp"] = "video/3gpp"; + types["3g2"] = "video/3gpp2"; + types["7z"] = "application/x-7z-compressed"; + types["nix"] = "text/plain"; + + return types; +} + +std::map http::Mime::mimeTypes = Mime::initMimeTypes(); + +std::string http::Mime::getType(const std::string &filename) { + size_t dot_pos = filename.find_last_of('.'); + if (dot_pos == std::string::npos) + return "text/plain"; //default + + std::string ext = filename.substr(dot_pos + 1); + std::map::const_iterator it = mimeTypes.find(ext); + if (it != mimeTypes.end()) + return it->second; + return "application/octet-stream"; //unknown extension so default +} diff --git a/src/server/Client.cpp b/src/server/Client.cpp index cf1b71b..60290aa 100644 --- a/src/server/Client.cpp +++ b/src/server/Client.cpp @@ -6,7 +6,7 @@ /* By: mmoussou _fd.fd, buffer, BUFFER_SIZE - 1, 0); if (bytes_received == -1) { _log->error("failed to receive request"); throw std::runtime_error("failed to receive request"); @@ -34,6 +37,33 @@ Client::Client(int fd, sockaddr_in socket, config::Config *conf) this->_conf = conf->getServer(this->_request->getHeaders()["Host"]); + + // if (received_data.length > (get max_body_size from Route corresponding) ) + // throw error +} + +void Client::parse(struct pollfd fd, sockaddr_in socket, config::Config *conf) +{ + this->_fd = fd; + this->_client_addr = socket; + std::string received_data; + char buffer[BUFFER_SIZE]; + ssize_t bytes_received; + do { + std::memset(buffer, 0, BUFFER_SIZE); + bytes_received = recv(this->_fd.fd, buffer, BUFFER_SIZE - 1, 0); + if (bytes_received == -1) { + _log->error("failed to receive request"); + throw std::runtime_error("failed to receive request"); + } + received_data += std::string(buffer, bytes_received); + } while (buffer[bytes_received]); + + this->_getRequest(received_data); + + this->_conf = conf->getServer(this->_request->getHeaders()["Host"]); + + // if (received_data.length > (get max_body_size from Route corresponding) ) // throw error } @@ -42,20 +72,28 @@ void Client::_getRequest(std::string request_str) { std::string method = request_str.substr( 0, request_str.substr(0, 4).find_last_not_of(" ") + 1); - if (method == "GET") { - _log->info("get request received"); + if (method == "GET") + { this->_request = new http::Get(request_str); - } else if (method == "DELETE") { - _log->info("delete request received"); + _log->info("get request received"); + } + else if (method == "DELETE") + { this->_request = new http::Delete(request_str); - } else if (method == "POST") { - _log->info("post request received"); + _log->info("delete request received"); + } + else if (method == "POST") + { this->_request = new http::Post(request_str); - } else { - _log->info("unsupported request received"); + _log->info("post request received"); + } + else + { this->_request = new http::Get(); this->_request->setMethod("501"); + _log->info("unsupported request received"); } + // set target to correct target with the conf } void Client::answer(void) { @@ -68,7 +106,7 @@ void Client::answer(void) { response = this->_request->execute().str(); else response = "HTTP/1.1 501 Not Implemented\r\nContent-Type: text/html\r\n\r\n

    501 Not Implemented

    "; - send(this->_fd, response.c_str(), response.length(), 0); + send(this->_fd.fd, response.c_str(), response.length(), 0); } Client::~Client(void) {