From cf509f09b7b41b75195ed7b40d3f51d88d2794cc Mon Sep 17 00:00:00 2001 From: y-syo Date: Wed, 19 Mar 2025 03:15:20 +0100 Subject: [PATCH] =?UTF-8?q?=E3=80=8C=E2=9C=A8=E3=80=8D=20feat(http/GET):?= =?UTF-8?q?=20file=20listing=20page=20if=20opening=20a=20directory?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- includes/requests/Errors.hpp | 90 +------------------------- includes/requests/HttpResponse.hpp | 3 +- src/main.cpp | 7 +- src/requests_handling/Errors.cpp | 2 +- src/requests_handling/HttpRequests.cpp | 87 ++++++++++++++++++++----- src/requests_handling/HttpResponse.cpp | 9 +-- 6 files changed, 84 insertions(+), 114 deletions(-) diff --git a/includes/requests/Errors.hpp b/includes/requests/Errors.hpp index 225293d..2eb958c 100644 --- a/includes/requests/Errors.hpp +++ b/includes/requests/Errors.hpp @@ -6,7 +6,7 @@ /* By: mmoussou message; private: static std::map populateMessages(); - static std::map message; static std::map set_error_pages; }; -/*std::map Errors::populateMessages() -{ - std::map m; - - m[100] = "Continue"; - m[101] = "Switching Protocols"; - m[102] = "Processing"; - m[103] = "Early Hints"; - m[200] = "OK"; - m[201] = "Created"; - m[202] = "Accepted"; - m[203] = "Non-Authoritative Information"; - m[204] = "No Content"; - m[205] = "Reset Content"; - m[206] = "Partial Content"; - m[207] = "Multi-Status"; - m[208] = "Already Reported"; - m[226] = "IM Used"; - m[300] = "Multiple Choices"; - m[301] = "Moved Permanently"; - m[302] = "Found"; - m[303] = "See Other"; - m[304] = "Not Modified"; - m[305] = "Use Proxy"; - m[306] = "Switch Proxy"; - m[307] = "Temporary Redirect"; - m[308] = "Permanent Redirect"; - m[400] = "Bad Request"; - m[401] = "Unauthorized"; - m[402] = "Payment Required"; - m[403] = "Forbidden"; - m[404] = "Not Found"; - m[405] = "Method Not Allowed"; - m[406] = "Not Acceptable"; - m[407] = "Proxy Authentication Required"; - m[408] = "Request Timeout"; - m[409] = "Conflict"; - m[410] = "Gone"; - m[411] = "Length Required"; - m[412] = "Precondition Failed"; - m[413] = "Payload Too Large"; - m[414] = "URI Too Long"; - m[415] = "Unsupported Media Type"; - m[416] = "Range Not Satisfiable"; - m[417] = "Expectation Failed"; - m[418] = "I'm a teapot"; - m[420] = "Method Failure"; - m[421] = "Misdirected Request"; - m[422] = "Unprocessable Entity"; - m[423] = "Locked"; - m[424] = "Failed Dependency"; - m[426] = "Upgrade Required"; - m[428] = "Precondition Required"; - m[429] = "Too Many Requests"; - m[431] = "Request Header Fields Too Large"; - m[451] = "Unavailable For Legal Reasons"; - m[500] = "Internal Server error"; - m[501] = "Not Implemented"; - m[502] = "Bad Gateway"; - m[503] = "Service Unavailable"; - m[504] = "gateway Timeout"; - m[505] = "Http version not supported"; - m[506] = "Varient Also negotiate"; - m[507] = "Insufficient Storage"; - m[508] = "Loop Detected"; - m[510] = "Not Extended"; - m[511] = "Network Authentication Required"; - - return m; -} - -std::map Errors::message = Errors::populateMessages(); - -std::map Errors::set_error_pages; - -http::Response &Errors::getRequest(int error_code) -{ - http::Response *result = new http::Response; - - if (Errors::set_error_pages.find(error_code) != Errors::set_error_pages.end()) - result->setBody(Errors::set_error_pages[error_code]); - else - result->setBody("

" + Errors::message[error_code] + "

"); - return (*result); -}*/ - } // -namespace http } // -namespace webserv diff --git a/includes/requests/HttpResponse.hpp b/includes/requests/HttpResponse.hpp index c9c7304..db5a7d7 100644 --- a/includes/requests/HttpResponse.hpp +++ b/includes/requests/HttpResponse.hpp @@ -6,7 +6,7 @@ /* By: mmoussou +#include + #include +#include +#include using namespace webserv; @@ -116,32 +121,86 @@ void http::Get::parse(std::string const &data) //*/ } +char isDirectory(const std::string& path) { + struct stat fileStat; + if (stat(path.c_str(), &fileStat) != 0) + throw; + return S_ISDIR(fileStat.st_mode); +} + http::Response http::Get::execute(void) { http::Response response; try { - std::ifstream file(this->_target.c_str(), std::ios::binary); - response.setProtocol(this->_protocol); - response.setStatusCode(200); - response.setStatusText("OK"); - 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 + if (isDirectory(this->_target)) + { + DIR *dir; + struct dirent *entry; + struct stat file_stat; + std::vector files; + + if ((dir = opendir(this->_target.c_str())) == NULL) + throw; + while ((entry = readdir(dir)) != NULL) + { + std::string file_name = entry->d_name; + if (file_name == ".") + continue; + std::string file_path = this->_target + "/" + file_name; + if (stat(file_path.c_str(), &file_stat) == 0) + { + if (S_ISDIR(file_stat.st_mode)) + files.push_back(file_name + "/"); + else + files.push_back(file_name); + } + } + closedir(dir); - 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(); - response.addHeader("Content-Length", length.str()); + std::sort(files.begin(), files.end()); - response.setBody(std::string((std::istreambuf_iterator(file)), std::istreambuf_iterator())); + std::string body = "
    \n"; + for (size_t i = 0; i < files.size(); i++) + body += "
  • " + files[i] + "
  • \n"; + body += "
"; + + response.setProtocol(this->_protocol); + response.setStatusCode(200); + std::stringstream length; + length << body.length(); + response.addHeader("Content-Length", length.str()); + response.addHeader("Content-Type", "text/html"); + response.setBody(body); + + } + else + { + std::ifstream file(this->_target.c_str(), std::ios::binary); + std::streampos file_start = file.tellg(); + response.setBody(std::string((std::istreambuf_iterator(file)), std::istreambuf_iterator())); + std::stringstream length; + length << (file.tellg() - file_start); + std::cout << length.str() << std::endl; + response.addHeader("Content-Length", length.str()); + + 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 + + //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()); + } } catch (...) { // TODO: replace with a predefined array of error pages response.setProtocol(this->_protocol); response.setStatusCode(404); - response.setStatusText("Not Found"); response.addHeader("Content-Type", "text/html"); response.setBody("nuh uh, get 404'd >:D"); } @@ -212,7 +271,6 @@ http::Response http::Delete::execute(void) throw; response.setProtocol(this->_protocol); response.setStatusCode(204); // this cool dude on the internet said i should not do that so i'll change it https://blog.ploeh.dk/2013/04/30/rest-lesson-learned-avoid-204-responses/ - response.setStatusText("No Content"); time_t now = std::time(NULL); response.addHeader("Date", std::string(std::ctime(&now))); } @@ -222,7 +280,6 @@ http::Response http::Delete::execute(void) response.setProtocol(this->_protocol); response.setStatusCode(404); - response.setStatusText("Not Found"); response.addHeader("Content-Type", "text/html"); response.setBody("nuh uh, get 404'd >:D"); } diff --git a/src/requests_handling/HttpResponse.cpp b/src/requests_handling/HttpResponse.cpp index a5dbb24..0626827 100644 --- a/src/requests_handling/HttpResponse.cpp +++ b/src/requests_handling/HttpResponse.cpp @@ -6,11 +6,12 @@ /* By: mmoussou +#include /* - do a map of all the status_text and get it from here, not storing them @@ -66,9 +67,5 @@ void http::Response::setProtocol(std::string const protocol) void http::Response::setStatusCode(size_t const status_code) { this->_status_code = status_code; -} - -void http::Response::setStatusText(std::string const status_text) -{ - this->_status_text = status_text; + this->_status_text = Errors::message[status_code]; }