From bb0d32815864e1ee0bba3458d050ee8c1f880490 Mon Sep 17 00:00:00 2001 From: minakim Date: Thu, 11 Jul 2024 20:46:14 +0200 Subject: [PATCH 1/6] add: requestHandler, staticFileHandler, todo: test method --- include/HttpRequest.hpp | 20 ++--- include/HttpResponse.hpp | 4 +- include/StaticFileHandler.hpp | 8 +- src/main.cpp | 4 +- src/main_back.cpp | 4 +- src/server/HttpRequest.cpp | 141 ++++++++++++++++++++----------- src/server/HttpResponse.cpp | 37 +++++--- src/server/RequestHandler.cpp | 18 +++- src/server/Server.cpp | 4 +- src/server/StaticFileHandler.cpp | 54 ++++++++++-- 10 files changed, 205 insertions(+), 89 deletions(-) diff --git a/include/HttpRequest.hpp b/include/HttpRequest.hpp index 1b3081e..af6edb5 100644 --- a/include/HttpRequest.hpp +++ b/include/HttpRequest.hpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/08 22:47:33 by minakim ### ########.fr */ +/* Updated: 2024/07/11 20:02:56 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -16,35 +16,35 @@ # include # include +# define WHITESPACE " \t\r\n" + class HttpRequest { public: HttpRequest(); ~HttpRequest(); - bool parse(const std::string requestData); + bool parse(const std::string& requestData); std::string getMethod() const; - std::string getPath() const; + std::string getUri() const; std::string getVersion() const; std::map getHeaders() const; std::string getBody() const; bool isConnectionClose() const; - + static std::string trim(const std::string& str); private: std::string _method; - std::string _path; + std::string _uri; std::string _version; std::map _headers; std::string _body; - void _parseRequestLine(const std::string requestLine); - void _parseHeaders(const std::string headerLines); - void _parseBody(const std::string bodylines); - - static std::string _trim(const std::string& str); + bool _parseRequestLine(const std::string requestLine); + bool _parseHeaders(const std::string headerLines); + bool _parseBody(const std::string bodylines); }; #endif \ No newline at end of file diff --git a/include/HttpResponse.hpp b/include/HttpResponse.hpp index 3271fa0..2426bde 100644 --- a/include/HttpResponse.hpp +++ b/include/HttpResponse.hpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/08 22:27:34 by minakim ### ########.fr */ +/* Updated: 2024/07/11 19:49:27 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -55,6 +55,8 @@ class HttpResponse static HttpResponse requestEntityTooLarge_413(); static HttpResponse imaTeapot_418(); static HttpResponse internalServerError_500(); + static HttpResponse success_200(); + static HttpResponse notImplemented_501(); private: int _statusCode; diff --git a/include/StaticFileHandler.hpp b/include/StaticFileHandler.hpp index 673a5d5..67bb550 100644 --- a/include/StaticFileHandler.hpp +++ b/include/StaticFileHandler.hpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* StaticFileHandler.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: sanghupa +#+ +:+ +#+ */ +/* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/04 15:59:03 by sanghupa ### ########.fr */ +/* Updated: 2024/07/11 20:44:09 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -14,6 +14,7 @@ # define STATICFILEHANDLER_HPP # include +# include # include "HttpRequest.hpp" # include "HttpResponse.hpp" @@ -26,8 +27,11 @@ class StaticFileHandler HttpResponse handleRequest(const HttpRequest request); private: + static std::map _mimeTypes; + std::string getMimeType(const std::string path) const; bool fileExists(const std::string path) const; + static void initializeMimeTypes(); }; #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 2013e3d..50deca0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* main.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: sanghupa +#+ +:+ +#+ */ +/* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/22 21:05:14 by sanghupa #+# #+# */ -/* Updated: 2024/07/08 22:49:29 by sanghupa ### ########.fr */ +/* Updated: 2024/07/11 20:31:46 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ diff --git a/src/main_back.cpp b/src/main_back.cpp index e602850..b34c749 100644 --- a/src/main_back.cpp +++ b/src/main_back.cpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* main_back.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: sanghupa +#+ +:+ +#+ */ +/* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/22 21:05:14 by sanghupa #+# #+# */ -/* Updated: 2024/07/04 15:59:03 by sanghupa ### ########.fr */ +/* Updated: 2024/07/11 20:18:19 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ diff --git a/src/server/HttpRequest.cpp b/src/server/HttpRequest.cpp index 56d732b..b63611b 100644 --- a/src/server/HttpRequest.cpp +++ b/src/server/HttpRequest.cpp @@ -6,52 +6,33 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/10 10:21:47 by minakim ### ########.fr */ +/* Updated: 2024/07/11 20:42:00 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ #include "webserv.hpp" #include "HttpRequest.hpp" -/// @todo check for necessary initialization +/// TODO check for necessary initialization HttpRequest::HttpRequest() {} HttpRequest::~HttpRequest() {} - -/// @todo check the `requestData` formats -bool HttpRequest::parse(const std::string requestData) -{ - std::istringstream iss(requestData); - std::string requestLine; - std::string headerLines; - std::string bodylines; - - iss >> requestLine; - _parseRequestLine(requestLine); - iss >> headerLines; - _parseHeaders(headerLines); - iss >> bodylines; - _parseBody(bodylines); - return (true); -} - - ///////////////////////////////////////////////////////////////////////////////////// -std::string HttpRequest::getMethod() const +std::string HttpRequest::getMethod() const { return (_method); } -std::string HttpRequest::getPath() const +std::string HttpRequest::getUri() const { - return (_path); + return (_uri); } -std::string HttpRequest::getVersion() const +std::string HttpRequest::getVersion() const { return (_version); } @@ -61,14 +42,14 @@ std::map HttpRequest::getHeaders() const return (_headers); } -std::string HttpRequest::getBody() const +std::string HttpRequest::getBody() const { if (_body.empty()) return (""); return (_body); } -bool HttpRequest::isConnectionClose() const +bool HttpRequest::isConnectionClose() const { std::map::const_iterator it = _headers.find("Connection"); if (it != _headers.end() && it->second == "close") @@ -76,34 +57,98 @@ bool HttpRequest::isConnectionClose() const return (false); } - - ///////////////////////////////////////////////////////////////////////////////////// -/// @todo Update all parseXXX functions to include new line parsing logic. -/// - Verify the trim logic used in this function. -/// - Ensure future param values (parse memberfunction == key) are handled. -void HttpRequest::_parseRequestLine(const std::string requestLine) +/// @brief This function parses the request data and extracts +/// the method, path, version, headers, and body. +/// @param requestData The request data to be parsed. +/// @return bool +bool HttpRequest::parse(const std::string& requestData) { - std::string trimmedLine = _trim(requestLine); - std::istringstream iss(trimmedLine); - iss >> _method >> _path >> _version; + std::istringstream iss(requestData); + std::string requestLine; + std::string headerLines; + std::string bodylines; + + if (requestData.empty()) + return (false); + iss >> requestLine; + iss >> headerLines; + iss >> bodylines; + if (!_parseRequestLine(requestLine)) + return (false); + if (!_parseHeaders(headerLines)) + return (false); + if (!_parseBody(bodylines)) + return (false); + return (true); } -void HttpRequest::_parseHeaders(const std::string headerLines) -{} -void HttpRequest::_parseBody(const std::string bodylines) -{} +/// @brief Parses the request line and extracts the method, path, and version. +/// @param requestLine _method _uri _version, example: GET /path/resource HTTP/1.1 +/// @return bool +bool HttpRequest::_parseRequestLine(const std::string requestLine) +{ + std::string trimmedLine = trim(requestLine); + std::istringstream iss(trimmedLine); + + if (requestLine.empty() || trimmedLine.empty()) + return (false); + iss >> _method >> _uri >> _version; + if (_method.empty() || _uri.empty() || _version.empty()) + return (false); + return (true); +} +/// @brief Parses the header lines and extracts the headers. +/// @param headerLines key:value pairs separated by \r\n +/// @return bool +bool HttpRequest::_parseHeaders(const std::string headerLines) +{ + if (headerLines.empty()) + return (false); + std::istringstream iss(headerLines); + std::string line; + + while (std::getline(iss, line)) + { + if (line.empty()) + continue; + std::string key = trim(line.substr(0, line.find(":"))); + if (key.empty()) + return (false); + std::string value = trim(line.substr(line.find(":") + 1)); + if (value.empty()) + return (false); + _headers.insert(std::make_pair(key, value)); + line.clear(); + } + return (true); +} -# define WHITESPACE " \t" // [?] add /r/n -/// @todo check the trim logic in this function -std::string HttpRequest::_trim(const std::string& str) +/// @brief Parses the body and extracts the body. +/// @param bodylines exameple key1=value1&key2=value2 +/// @return bool +bool HttpRequest::_parseBody(const std::string bodylines) { - size_t first = str.find_first_not_of(WHITESPACE); - if (first == std::string::npos) - return ""; - size_t last = str.find_last_not_of(WHITESPACE); - return (str.substr(first, last - first + 1)); + if (bodylines.empty()) + return (false); + _body = bodylines; + return (true); +} + +/// @brief Trims the string by removing leading and trailing whitespace. +/// @details Whitespace includes: space, tab, carriage return, and newline. +/// @param str The string to be trimmed. +/// @return The trimmed string. +std::string HttpRequest::trim(const std::string& str) +{ + std::string::size_type first = str.find_first_not_of(WHITESPACE); + if (first == std::string::npos) + return (""); + std::string::size_type last = str.find_last_not_of(WHITESPACE); + if (last == std::string::npos) + return (""); + return (str.substr(first, last - first + 1)); } \ No newline at end of file diff --git a/src/server/HttpResponse.cpp b/src/server/HttpResponse.cpp index e451b15..5ecaaba 100644 --- a/src/server/HttpResponse.cpp +++ b/src/server/HttpResponse.cpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/10 10:21:32 by minakim ### ########.fr */ +/* Updated: 2024/07/11 20:23:07 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -38,14 +38,14 @@ void HttpResponse::setBody(const std::string bodyContent) _body = bodyContent; } -/// @todo how return valuse used in other functions? +/// @todo How will the return value be used in other functions? /// - check Server.cpp std::string HttpResponse::toString() const { return (_getHeadersString() + "\r\n\r\n" + _body); } - +/// TODO test this function /// @brief Creates an HttpResponse object by reading the contents of a file. /// /// @param filePath The path to the file to be read. @@ -53,22 +53,22 @@ std::string HttpResponse::toString() const HttpResponse HttpResponse::fromFile(const std::string filePath) { HttpResponse resp; - std::ifstream file(filePath, std::ios::binary | std::ios::ate); + std::ifstream file(filePath.c_str(), std::ios::binary | std::ios::ate); if (!file.is_open()) return (notFound_404()); - std::streamsize fileSize = file.tellg(); + std::streamsize fileSize = file.tellg(); file.seekg(0, std::ios::beg); std::vector buffer(fileSize); - if (file.read(buffer.data(), fileSize)) - resp.setBody(std::string(buffer.data(), fileSize)); - else - resp = internalServerError_500(); + if (!file.read(buffer.data(), fileSize)) + return (file.close(), internalServerError_500()); + resp.setBody(std::string(buffer.data(), fileSize)); file.close(); return (resp); } ///////////////////////////////////////////////////////////////////////////////////// + /// std::string HttpResponse::_getHeadersString() const /// std::string HttpResponse::_getStatusLine() const /// @todo log design @@ -87,10 +87,13 @@ std::string HttpResponse::_getHeadersString() const std::string HttpResponse::_getStatusLine() const { - return ("HTTP/1.1 " + std::to_string(_statusCode) + " " + _statusMessage + "\r\n"); + std::stringstream statusLine; + statusLine << "HTTP/1.1 " << _statusCode << " " << _statusMessage << "\r\n"; + return (statusLine.str()); } ///////////////////////////////////////////////////////////////////////////////////// + /// @brief static functions to create HttpResponse objects with specific status codes. /// @return HttpResponse The created HttpResponse object. /// @@ -150,4 +153,18 @@ HttpResponse HttpResponse::internalServerError_500() HttpResponse resp; resp.setStatusCode(500, "Internal Server Error"); return (resp); +} + +HttpResponse HttpResponse::success_200() +{ + HttpResponse resp; + resp.setStatusCode(200, "OK"); + return (resp); +} + +HttpResponse HttpResponse::notImplemented_501() +{ + HttpResponse resp; + resp.setStatusCode(501, "Not Implemented"); + return (resp); } \ No newline at end of file diff --git a/src/server/RequestHandler.cpp b/src/server/RequestHandler.cpp index 9d84078..7d4eaaf 100644 --- a/src/server/RequestHandler.cpp +++ b/src/server/RequestHandler.cpp @@ -3,15 +3,17 @@ /* ::: :::::::: */ /* RequestHandler.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: sanghupa +#+ +:+ +#+ */ +/* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/04 15:59:03 by sanghupa ### ########.fr */ +/* Updated: 2024/07/11 19:53:06 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ #include "webserv.hpp" #include "RequestHandler.hpp" +#include "StaticFileHandler.hpp" +#include "HttpResponse.hpp" RequestHandler::RequestHandler() {} @@ -19,5 +21,15 @@ RequestHandler::RequestHandler() RequestHandler::~RequestHandler() {} + HttpResponse RequestHandler::handleRequest(const HttpRequest request) -{} +{ + if (request.getMethod() == "GET") + return (_staticFileHandler.handleRequest(request)); + else if (request.getMethod() == "POST") + return (HttpResponse::notImplemented_501()); + else if (request.getMethod() == "DELETE") + return (HttpResponse::notImplemented_501()); + else + return (HttpResponse::notImplemented_501()); +} diff --git a/src/server/Server.cpp b/src/server/Server.cpp index 50cd2f0..616889b 100644 --- a/src/server/Server.cpp +++ b/src/server/Server.cpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* Server.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: sanghupa +#+ +:+ +#+ */ +/* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:46 by sanghupa #+# #+# */ -/* Updated: 2024/07/08 22:48:41 by sanghupa ### ########.fr */ +/* Updated: 2024/07/10 22:11:51 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ diff --git a/src/server/StaticFileHandler.cpp b/src/server/StaticFileHandler.cpp index 531eab9..a677309 100644 --- a/src/server/StaticFileHandler.cpp +++ b/src/server/StaticFileHandler.cpp @@ -3,27 +3,63 @@ /* ::: :::::::: */ /* StaticFileHandler.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: sanghupa +#+ +:+ +#+ */ +/* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/04 15:59:03 by sanghupa ### ########.fr */ +/* Updated: 2024/07/11 20:43:38 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ #include "webserv.hpp" #include "StaticFileHandler.hpp" + StaticFileHandler::StaticFileHandler() -{} +{ + if (_mimeTypes.empty()) + initializeMimeTypes(); +} StaticFileHandler::~StaticFileHandler() {} -HttpResponse StaticFileHandler::handleRequest(const HttpRequest request) -{} +HttpResponse StaticFileHandler::handleRequest(const HttpRequest request) +{ + if (!fileExists(request.getUri())) + return (HttpResponse::notFound_404()); + +} -std::string StaticFileHandler::getMimeType(const std::string path) const -{} +void testPrint(std::string target) +{ + std::cout << target << std::endl; +} -bool StaticFileHandler::fileExists(const std::string path) const -{} +std::string StaticFileHandler::getMimeType(const std::string path) const +{ + std::string::size_type dotPosition = path.find_last_of("."); + if (dotPosition == std::string::npos) + return ("text/plain"); + std::string ext = path.substr(dotPosition); + std::map::const_iterator it = _mimeTypes.find(ext); + if (it != _mimeTypes.end()) + return (it->second); + return ("text/plain"); +} + +bool StaticFileHandler::fileExists(const std::string path) const +{ + struct stat buffer; + return (stat(path.c_str(), &buffer) == 0); +} + +void StaticFileHandler::initializeMimeTypes() +{ + _mimeTypes.insert(std::make_pair(".html", "text/html")); + _mimeTypes.insert(std::make_pair(".css", "text/css")); + _mimeTypes.insert(std::make_pair(".js", "application/javascript")); + _mimeTypes.insert(std::make_pair(".png", "image/png")); + _mimeTypes.insert(std::make_pair(".jpg", "image/jpeg")); + _mimeTypes.insert(std::make_pair(".gif", "image/gif")); + _mimeTypes.insert(std::make_pair(".txt", "text/plain")); +} \ No newline at end of file From 704d0297c08e7c3906dd59e4e5fafe37aea505c9 Mon Sep 17 00:00:00 2001 From: minakim Date: Fri, 12 Jul 2024 14:54:15 +0200 Subject: [PATCH 2/6] update --- include/RequestHandler.hpp | 4 ++-- src/server/HttpRequest.cpp | 15 ++++++++------- src/server/HttpResponse.cpp | 16 +++++++++------- src/server/RequestHandler.cpp | 9 +++++++-- src/server/StaticFileHandler.cpp | 25 +++++++++++++++++++------ 5 files changed, 45 insertions(+), 24 deletions(-) diff --git a/include/RequestHandler.hpp b/include/RequestHandler.hpp index fdc3372..8a30ad8 100644 --- a/include/RequestHandler.hpp +++ b/include/RequestHandler.hpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* RequestHandler.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: sanghupa +#+ +:+ +#+ */ +/* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/04 15:59:03 by sanghupa ### ########.fr */ +/* Updated: 2024/07/12 11:12:44 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ diff --git a/src/server/HttpRequest.cpp b/src/server/HttpRequest.cpp index b63611b..cf32696 100644 --- a/src/server/HttpRequest.cpp +++ b/src/server/HttpRequest.cpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/11 20:42:00 by minakim ### ########.fr */ +/* Updated: 2024/07/12 14:44:09 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -20,7 +20,7 @@ HttpRequest::HttpRequest() HttpRequest::~HttpRequest() {} -///////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// std::string HttpRequest::getMethod() const { @@ -57,7 +57,8 @@ bool HttpRequest::isConnectionClose() const return (false); } -///////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + /// @brief This function parses the request data and extracts /// the method, path, version, headers, and body. @@ -86,7 +87,7 @@ bool HttpRequest::parse(const std::string& requestData) /// @brief Parses the request line and extracts the method, path, and version. -/// @param requestLine _method _uri _version, example: GET /path/resource HTTP/1.1 +/// @param requestLine `_method` `_uri` `_version`, example: GET /path/resource HTTP/1.1 /// @return bool bool HttpRequest::_parseRequestLine(const std::string requestLine) { @@ -102,7 +103,7 @@ bool HttpRequest::_parseRequestLine(const std::string requestLine) } /// @brief Parses the header lines and extracts the headers. -/// @param headerLines key:value pairs separated by \r\n +/// @param headerLines key:value pairs separated by `\r\n` /// @return bool bool HttpRequest::_parseHeaders(const std::string headerLines) { @@ -139,8 +140,8 @@ bool HttpRequest::_parseBody(const std::string bodylines) } /// @brief Trims the string by removing leading and trailing whitespace. -/// @details Whitespace includes: space, tab, carriage return, and newline. -/// @param str The string to be trimmed. +/// @details `WHITESPACE`: Whitespace includes: space, tab, carriage return, and newline. +/// @param str `const std::string&`, The string to be trimmed. /// @return The trimmed string. std::string HttpRequest::trim(const std::string& str) { diff --git a/src/server/HttpResponse.cpp b/src/server/HttpResponse.cpp index 5ecaaba..3bc6479 100644 --- a/src/server/HttpResponse.cpp +++ b/src/server/HttpResponse.cpp @@ -6,13 +6,15 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/11 20:23:07 by minakim ### ########.fr */ +/* Updated: 2024/07/12 14:49:20 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ #include "webserv.hpp" #include "HttpResponse.hpp" +// TODO add doc + HttpResponse::HttpResponse() : _statusCode(200), _statusMessage("OK") { @@ -38,8 +40,8 @@ void HttpResponse::setBody(const std::string bodyContent) _body = bodyContent; } -/// @todo How will the return value be used in other functions? -/// - check Server.cpp +// TODO How will the return value be used in other functions? +// - check Server.cpp std::string HttpResponse::toString() const { return (_getHeadersString() + "\r\n\r\n" + _body); @@ -67,11 +69,11 @@ HttpResponse HttpResponse::fromFile(const std::string filePath) return (resp); } -///////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// /// std::string HttpResponse::_getHeadersString() const /// std::string HttpResponse::_getStatusLine() const -/// @todo log design +// TODO log design, doc std::string HttpResponse::_getHeadersString() const { @@ -92,12 +94,12 @@ std::string HttpResponse::_getStatusLine() const return (statusLine.str()); } -///////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// /// @brief static functions to create HttpResponse objects with specific status codes. /// @return HttpResponse The created HttpResponse object. /// -/// @todo think about seperate functions to another class. +// TODO think about seperate functions to another class. HttpResponse HttpResponse::badRequest_400() { diff --git a/src/server/RequestHandler.cpp b/src/server/RequestHandler.cpp index 7d4eaaf..13caa47 100644 --- a/src/server/RequestHandler.cpp +++ b/src/server/RequestHandler.cpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/11 19:53:06 by minakim ### ########.fr */ +/* Updated: 2024/07/12 14:30:32 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -21,7 +21,12 @@ RequestHandler::RequestHandler() RequestHandler::~RequestHandler() {} - +/// @brief +/// @param request HttpRequest object +/// @return 1. if request is `GET`, 2. if request is `POST`, +/// 3. if request is `DELETE`, 4. if request is `not implemented`. +/// @note `501 Not Implemented`: temp response, the server does not support +/// the functionality required to fulfill the request. HttpResponse RequestHandler::handleRequest(const HttpRequest request) { if (request.getMethod() == "GET") diff --git a/src/server/StaticFileHandler.cpp b/src/server/StaticFileHandler.cpp index a677309..ac804a9 100644 --- a/src/server/StaticFileHandler.cpp +++ b/src/server/StaticFileHandler.cpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/11 20:43:38 by minakim ### ########.fr */ +/* Updated: 2024/07/12 14:52:10 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -23,18 +23,30 @@ StaticFileHandler::StaticFileHandler() StaticFileHandler::~StaticFileHandler() {} +// TODO check the logic, how to work with path/request HttpResponse StaticFileHandler::handleRequest(const HttpRequest request) { - if (!fileExists(request.getUri())) + std::string filePath = /* path + */ request.getUri(); + + // test + std::cout << "[test] file path: " << filePath << std::endl; + + if (!fileExists(filePath)) return (HttpResponse::notFound_404()); -} + + std::string mimeType = getMimeType(filePath); + + // test + std::cout << "[test] mime type: " << mimeType << std::endl; -void testPrint(std::string target) -{ - std::cout << target << std::endl; + HttpResponse resp = HttpResponse::fromFile(filePath); + resp.setHeader(getMimeType(filePath), mimeType); + + return (resp); } +// TODO test result, parse part std::string StaticFileHandler::getMimeType(const std::string path) const { std::string::size_type dotPosition = path.find_last_of("."); @@ -53,6 +65,7 @@ bool StaticFileHandler::fileExists(const std::string path) const return (stat(path.c_str(), &buffer) == 0); } +/// @brief Initializes the mimeTypes map with the default mime types. void StaticFileHandler::initializeMimeTypes() { _mimeTypes.insert(std::make_pair(".html", "text/html")); From 27d59a2f1c1256deca1e3b6ca55173fc5ac75f06 Mon Sep 17 00:00:00 2001 From: minakim Date: Fri, 12 Jul 2024 15:02:25 +0200 Subject: [PATCH 3/6] update: todo --- src/server/HttpResponse.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/HttpResponse.cpp b/src/server/HttpResponse.cpp index 3bc6479..f387d9a 100644 --- a/src/server/HttpResponse.cpp +++ b/src/server/HttpResponse.cpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 14:49:20 by minakim ### ########.fr */ +/* Updated: 2024/07/12 15:02:09 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -47,7 +47,7 @@ std::string HttpResponse::toString() const return (_getHeadersString() + "\r\n\r\n" + _body); } -/// TODO test this function +/// TODO test: function, check if it works (internalServerError_500()) /// @brief Creates an HttpResponse object by reading the contents of a file. /// /// @param filePath The path to the file to be read. From 1eaae9bdb8834d3ddf08975ff6985ddcb3faf470 Mon Sep 17 00:00:00 2001 From: minakim Date: Fri, 12 Jul 2024 17:58:30 +0200 Subject: [PATCH 4/6] fix: after testing using the server, I am modifying the structure and necessary parts of some functions. --- .vscode/launch.json | 25 ++++++++++ .vscode/settings.json | 16 +++++- .vscode/tasks.json | 60 ++++++++++++++++++++++ Makefile | 15 ++++-- include/HttpRequest.hpp | 16 +++++- include/StaticFileHandler.hpp | 2 +- src/server/HttpRequest.cpp | 85 +++++++++++++++++++++++--------- src/server/StaticFileHandler.cpp | 3 +- 8 files changed, 189 insertions(+), 33 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..2853e67 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,25 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/webserv_test", + "args": ["abc"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "build" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 26a7b4f..8646d0e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -70,6 +70,20 @@ "shared_mutex": "cpp", "source_location": "cpp", "thread": "cpp", - "typeindex": "cpp" + "typeindex": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "compare": "cpp", + "concepts": "cpp", + "deque": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "numbers": "cpp" } } diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..e5b2e94 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,60 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "command": "g++", + "args": [ + "-g", + "-std=c++98", + "-Wall", + "-Wextra", + "-Werror", + "-lstdc++", + "-I${workspaceFolder}/include", + "${workspaceFolder}/src/main.cpp", + "${workspaceFolder}/src/network/Poller.cpp", + "${workspaceFolder}/src/network/Socket.cpp", + "${workspaceFolder}/src/server/Server.cpp", + "${workspaceFolder}/src/server/HttpRequest.cpp", + "${workspaceFolder}/src/server/HttpResponse.cpp", + "${workspaceFolder}/src/server/RequestHandler.cpp", + "${workspaceFolder}/src/server/StaticFileHandler.cpp", + "-o", + "${workspaceFolder}/webserv_test" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [ + "$gcc" + ], + "detail": "Generated task by Debugger." + }, + { + "type": "cppbuild", + "label": "C/C++: gcc build active file", + "command": "/usr/bin/gcc", + "args": [ + "-fdiagnostics-color=always", + "-g", + "${file}", + "-o", + "${fileDirname}/${fileBasenameNoExtension}" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "Task generated by Debugger." + } + ] +} \ No newline at end of file diff --git a/Makefile b/Makefile index 3b22784..a1d12bc 100644 --- a/Makefile +++ b/Makefile @@ -6,11 +6,16 @@ CFLAGS = -Wall -Wextra -Werror -std=c++98 RM = rm -f -# SRC_NAME = ./src/main.cpp \ -# ./src/server/Server.cpp \ -# ./src/network/Poller.cpp \ -# ./src/network/Socket.cpp -SRC_NAME = $(shell find ./src -iname "*.cpp") +SRC_NAME = ./src/main.cpp \ + ./src/server/Server.cpp \ + ./src/network/Poller.cpp \ + ./src/network/Socket.cpp \ + ./src/server/RequestHandler.cpp \ + ./src/server/HttpRequest.cpp \ + ./src/server/HttpResponse.cpp \ + ./src/server/StaticFileHandler.cpp + +# SRC_NAME = $(shell find ./src -iname "*.cpp") OBJ_NAME = $(SRC_NAME:.cpp=.o) HEADERS = -I ./include diff --git a/include/HttpRequest.hpp b/include/HttpRequest.hpp index af6edb5..0c9a664 100644 --- a/include/HttpRequest.hpp +++ b/include/HttpRequest.hpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/11 20:02:56 by minakim ### ########.fr */ +/* Updated: 2024/07/12 17:53:13 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -18,6 +18,14 @@ # define WHITESPACE " \t\r\n" +typedef struct s_read_request { + std::string request; + std::vector headers; + std::string body; + bool iscomplete; + +} t_read_request; + class HttpRequest { public: @@ -43,8 +51,12 @@ class HttpRequest std::string _body; bool _parseRequestLine(const std::string requestLine); - bool _parseHeaders(const std::string headerLines); + bool _parseHeaders(const std::vector headerLines); bool _parseBody(const std::string bodylines); + t_read_request _separateRequestData(const std::string& requestData); + std::vector _dataToHeaders(std::istringstream& iss); + std::string _dataToBody(std::istringstream& iss); + }; #endif \ No newline at end of file diff --git a/include/StaticFileHandler.hpp b/include/StaticFileHandler.hpp index 67bb550..a3014f0 100644 --- a/include/StaticFileHandler.hpp +++ b/include/StaticFileHandler.hpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/11 20:44:09 by minakim ### ########.fr */ +/* Updated: 2024/07/12 15:13:53 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ diff --git a/src/server/HttpRequest.cpp b/src/server/HttpRequest.cpp index cf32696..aebfea1 100644 --- a/src/server/HttpRequest.cpp +++ b/src/server/HttpRequest.cpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 14:44:09 by minakim ### ########.fr */ +/* Updated: 2024/07/12 17:57:01 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -45,7 +45,7 @@ std::map HttpRequest::getHeaders() const std::string HttpRequest::getBody() const { if (_body.empty()) - return (""); + return (""); return (_body); } @@ -59,6 +59,49 @@ bool HttpRequest::isConnectionClose() const //////////////////////////////////////////////////////////////////////////////// +std::vector HttpRequest::_dataToHeaders(std::istringstream& iss) +{ + std::string readline; + std::vector res; + + while (std::getline(iss, readline) && readline != "\r") + res.push_back(readline); + return (res); +} + +std::string HttpRequest::_dataToBody(std::istringstream& iss) +{ + std::string readline; + std::string drafts; + + while (std::getline(iss, readline)) + drafts += readline; + if (drafts.empty()) + return (""); + return (drafts); +} + +t_read_request HttpRequest::_separateRequestData(const std::string& requestData) +{ + t_read_request data; + std::istringstream iss(requestData); + std::string readline; + std::string drafts; + + data.iscomplete = false; + + if (requestData.empty()) + return (data); + if (!std::getline(iss, readline)) + return (data); + data.request = readline; + data.headers = _dataToHeaders(iss); + if (data.headers.empty()) + return (data); + data.body = _dataToBody(iss); + data.iscomplete = true; + return (data); +} /// @brief This function parses the request data and extracts /// the method, path, version, headers, and body. @@ -66,22 +109,16 @@ bool HttpRequest::isConnectionClose() const /// @return bool bool HttpRequest::parse(const std::string& requestData) { - std::istringstream iss(requestData); - std::string requestLine; - std::string headerLines; - std::string bodylines; - - if (requestData.empty()) + t_read_request separatedData = _separateRequestData(requestData); + if (!separatedData.iscomplete) return (false); - iss >> requestLine; - iss >> headerLines; - iss >> bodylines; - if (!_parseRequestLine(requestLine)) + if (!_parseRequestLine(separatedData.request)) return (false); - if (!_parseHeaders(headerLines)) + if (!_parseHeaders(separatedData.headers)) return (false); - if (!_parseBody(bodylines)) + if (_method == "POST" && !_parseBody(separatedData.body)) return (false); + return (true); } @@ -105,25 +142,27 @@ bool HttpRequest::_parseRequestLine(const std::string requestLine) /// @brief Parses the header lines and extracts the headers. /// @param headerLines key:value pairs separated by `\r\n` /// @return bool -bool HttpRequest::_parseHeaders(const std::string headerLines) +bool HttpRequest::_parseHeaders(const std::vector headerLines) { if (headerLines.empty()) - return (false); - std::istringstream iss(headerLines); - std::string line; - - while (std::getline(iss, line)) + return false; + for (std::vector::const_iterator it = headerLines.begin(); + it != headerLines.end(); + ++it) { + const std::string& line = *it; if (line.empty()) continue; - std::string key = trim(line.substr(0, line.find(":"))); + size_t colonPos = line.find(':'); + if (colonPos == std::string::npos) + return (false); + std::string key = trim(line.substr(0, colonPos)); if (key.empty()) return (false); - std::string value = trim(line.substr(line.find(":") + 1)); + std::string value = trim(line.substr(colonPos + 1)); if (value.empty()) return (false); _headers.insert(std::make_pair(key, value)); - line.clear(); } return (true); } diff --git a/src/server/StaticFileHandler.cpp b/src/server/StaticFileHandler.cpp index ac804a9..2cb1f0b 100644 --- a/src/server/StaticFileHandler.cpp +++ b/src/server/StaticFileHandler.cpp @@ -6,13 +6,14 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 14:52:10 by minakim ### ########.fr */ +/* Updated: 2024/07/12 15:13:24 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ #include "webserv.hpp" #include "StaticFileHandler.hpp" +std::map StaticFileHandler::_mimeTypes; StaticFileHandler::StaticFileHandler() { From 5e10e4c4d0ce8bbf92b9c65ffbe84ec46b153882 Mon Sep 17 00:00:00 2001 From: minakim Date: Fri, 12 Jul 2024 21:33:17 +0200 Subject: [PATCH 5/6] feat: featured request, response to a simple, usable level, update: doc, todo: Check for sustainable connectivity, especially fromFile, which is only tested on .html files yet. --- include/HttpRequest.hpp | 2 +- include/HttpResponse.hpp | 23 +------- include/Server.hpp | 6 +- include/StaticFileHandler.hpp | 3 +- src/server/HttpRequest.cpp | 8 +-- src/server/HttpResponse.cpp | 95 +++++++++++++++++++++++++------- src/server/RequestHandler.cpp | 4 +- src/server/Server.cpp | 20 ++++++- src/server/StaticFileHandler.cpp | 25 ++++----- 9 files changed, 118 insertions(+), 68 deletions(-) diff --git a/include/HttpRequest.hpp b/include/HttpRequest.hpp index 0c9a664..3d6c6ee 100644 --- a/include/HttpRequest.hpp +++ b/include/HttpRequest.hpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 17:53:13 by minakim ### ########.fr */ +/* Updated: 2024/07/12 19:17:46 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ diff --git a/include/HttpResponse.hpp b/include/HttpResponse.hpp index 2426bde..8d0f505 100644 --- a/include/HttpResponse.hpp +++ b/include/HttpResponse.hpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/11 19:49:27 by minakim ### ########.fr */ +/* Updated: 2024/07/12 21:22:52 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -16,24 +16,6 @@ # include # include -enum e_status_code -{ - STATUS_SUCCESS = 200, - STATUS_CREATED = 201, - STATUS_NO_CONTENT = 204, - STATUS_MOVED = 301, - STATUS_BAD_REQUEST = 400, - STATUS_FORBIDDEN = 403, - STATUS_NOT_FOUND = 404, - STATUS_NOT_ALLOWED = 405, - STATUS_CONFLICT = 409, - STATUS_LENGTH_REQUIRED = 411, - STATUS_TOO_LARGE = 413, - STATUS_URI_TOO_LONG = 414, - STATUS_INTERNAL_ERR = 500, - STATUS_NOT_IMPLEMENTED = 501 -}; - class HttpResponse { public: @@ -44,6 +26,7 @@ class HttpResponse void setHeader(const std::string key, const std::string value); void setBody(const std::string bodyContent); + std::string getBody(); std::string toString() const; static HttpResponse fromFile(const std::string filePath); @@ -62,11 +45,11 @@ class HttpResponse int _statusCode; std::string _statusMessage; std::string _body; - std::map _headers; std::string _getStatusLine() const; std::string _getHeadersString() const; + std::string _getResponseLine() const; }; #endif \ No newline at end of file diff --git a/include/Server.hpp b/include/Server.hpp index 966c68d..c08faf5 100644 --- a/include/Server.hpp +++ b/include/Server.hpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* Server.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: sanghupa +#+ +:+ +#+ */ +/* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:46 by sanghupa #+# #+# */ -/* Updated: 2024/07/10 21:23:36 by sanghupa ### ########.fr */ +/* Updated: 2024/07/12 15:16:05 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -73,7 +73,7 @@ class Server Socket _listenSocket; Poller _poller; std::vector _pollfds; - // RequestHandler _requestHandler; + RequestHandler _requestHandler; void _handleNewConnection(); void _handleClientData(Poller::t_event event); diff --git a/include/StaticFileHandler.hpp b/include/StaticFileHandler.hpp index a3014f0..e1ededf 100644 --- a/include/StaticFileHandler.hpp +++ b/include/StaticFileHandler.hpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 15:13:53 by minakim ### ########.fr */ +/* Updated: 2024/07/12 19:24:36 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -18,6 +18,7 @@ # include "HttpRequest.hpp" # include "HttpResponse.hpp" +# define FOLDER_PATH "./www/static" class StaticFileHandler { public: diff --git a/src/server/HttpRequest.cpp b/src/server/HttpRequest.cpp index aebfea1..eb4702e 100644 --- a/src/server/HttpRequest.cpp +++ b/src/server/HttpRequest.cpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 17:57:01 by minakim ### ########.fr */ +/* Updated: 2024/07/12 19:20:58 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -80,7 +80,9 @@ std::string HttpRequest::_dataToBody(std::istringstream& iss) return (""); return (drafts); } - +/// @brief Separate the request data into request line, headers, and body. +/// @param requestData The request data to be separated. +/// @return A struct containing the separated request data. t_read_request HttpRequest::_separateRequestData(const std::string& requestData) { t_read_request data; @@ -118,11 +120,9 @@ bool HttpRequest::parse(const std::string& requestData) return (false); if (_method == "POST" && !_parseBody(separatedData.body)) return (false); - return (true); } - /// @brief Parses the request line and extracts the method, path, and version. /// @param requestLine `_method` `_uri` `_version`, example: GET /path/resource HTTP/1.1 /// @return bool diff --git a/src/server/HttpResponse.cpp b/src/server/HttpResponse.cpp index f387d9a..2ce42af 100644 --- a/src/server/HttpResponse.cpp +++ b/src/server/HttpResponse.cpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 15:02:09 by minakim ### ########.fr */ +/* Updated: 2024/07/12 21:29:54 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -40,41 +40,63 @@ void HttpResponse::setBody(const std::string bodyContent) _body = bodyContent; } -// TODO How will the return value be used in other functions? -// - check Server.cpp +std::string HttpResponse::getBody() +{ + return (_body); +} +std::string HttpResponse::_getResponseLine() const +{ + std::ostringstream oss; + oss << "HTTP/1.1 " << _statusCode << " " << _statusMessage << "\r\n"; + return (oss.str()); +} + std::string HttpResponse::toString() const { - return (_getHeadersString() + "\r\n\r\n" + _body); + std::cout << "TEST | HttpResponse::toString" << std::endl; + std::cout << _getResponseLine() + _getHeadersString() + "\r\n\r\n" + _body << std::endl; + return (_getResponseLine() + _getHeadersString() + "\r\n\r\n" + _body); +} + +std::string getDefualtPagePath(int page_code) +{ + std::ostringstream oss; + oss << "./www/error_pages/" << page_code << ".html"; + return (oss.str()); } -/// TODO test: function, check if it works (internalServerError_500()) /// @brief Creates an HttpResponse object by reading the contents of a file. /// -/// @param filePath The path to the file to be read. +/// @param file_path The path to the file to be read. /// @return HttpResponse The created HttpResponse object. -HttpResponse HttpResponse::fromFile(const std::string filePath) +HttpResponse HttpResponse::fromFile(const std::string file_path) { HttpResponse resp; - std::ifstream file(filePath.c_str(), std::ios::binary | std::ios::ate); + std::ifstream file(file_path.data()); if (!file.is_open()) return (notFound_404()); - std::streamsize fileSize = file.tellg(); - file.seekg(0, std::ios::beg); - std::vector buffer(fileSize); - if (!file.read(buffer.data(), fileSize)) - return (file.close(), internalServerError_500()); - resp.setBody(std::string(buffer.data(), fileSize)); - file.close(); + file.seekg(0, std::ios::end); + std::streamsize fileSize = file.tellg(); + file.seekg(0, std::ios::beg); + if (fileSize <= 0) + return internalServerError_500(); + std::string fileContents(fileSize, '\0'); + if (!file.read(&fileContents[0], fileSize)) + return (file.close(), internalServerError_500()); + file.close(); + std::stringstream ss; + ss << fileSize; + resp.setBody(fileContents); + resp.setHeader("Content-Length", ss.str()); + resp.setHeader("Connection", "close"); return (resp); } //////////////////////////////////////////////////////////////////////////////// -/// std::string HttpResponse::_getHeadersString() const -/// std::string HttpResponse::_getStatusLine() const -// TODO log design, doc - +/// @brief Returns the headers as a string. +/// @return std::string, The headers as a string. std::string HttpResponse::_getHeadersString() const { std::string headers; @@ -87,6 +109,8 @@ std::string HttpResponse::_getHeadersString() const return (headers); } +/// @brief returns the status line as a string. +/// @return std::string, The status line as a string. std::string HttpResponse::_getStatusLine() const { std::stringstream statusLine; @@ -94,17 +118,24 @@ std::string HttpResponse::_getStatusLine() const return (statusLine.str()); } -//////////////////////////////////////////////////////////////////////////////// -/// @brief static functions to create HttpResponse objects with specific status codes. + +//////////////////////////////////////////////////////////////////////////////// +/// @brief static functions to create HttpResponse objects +/// with specific status codes. /// @return HttpResponse The created HttpResponse object. /// // TODO think about seperate functions to another class. +//////////////////////////////////////////////////////////////////////////////// + + + HttpResponse HttpResponse::badRequest_400() { HttpResponse resp; resp.setStatusCode(400, "Bad Request"); + resp.fromFile(getDefualtPagePath(400)); return (resp); } @@ -112,13 +143,28 @@ HttpResponse HttpResponse::forbidden_403() { HttpResponse resp; resp.setStatusCode(403, "Forbidden"); + resp.fromFile(getDefualtPagePath(403)); return (resp); } +/// @brief Creates an HttpResponse object for a 404 Not Found error. +/// +/// This function attempts to read a default 404 error page from the +/// filesystem. If the page is not found or cannot be read, it falls +/// back to a simple HTML message indicating a 404 error. +/// +/// @return HttpResponse The generated HttpResponse object for the 404 error. HttpResponse HttpResponse::notFound_404() { HttpResponse resp; resp.setStatusCode(404, "Not Found"); + std::string defaultPagePath = getDefualtPagePath(404); + + HttpResponse fileResponse = fromFile(defaultPagePath); + if (fileResponse.getBody().empty()) + resp.setBody("

404 Not Found

"); + else + resp.setBody(fileResponse.getBody()); return (resp); } @@ -126,6 +172,7 @@ HttpResponse HttpResponse::methodNotAllowed_405() { HttpResponse resp; resp.setStatusCode(405, "Method Not Allowed"); + resp.fromFile(getDefualtPagePath(405)); return (resp); } @@ -133,6 +180,7 @@ HttpResponse HttpResponse::requestTimeout_408() { HttpResponse resp; resp.setStatusCode(408, "Request Timeout"); + resp.fromFile(getDefualtPagePath(408)); return (resp); } @@ -140,6 +188,7 @@ HttpResponse HttpResponse::requestEntityTooLarge_413() { HttpResponse resp; resp.setStatusCode(413, "Request Entity Too Large"); + resp.fromFile(getDefualtPagePath(413)); return (resp); } @@ -147,6 +196,7 @@ HttpResponse HttpResponse::imaTeapot_418() { HttpResponse resp; resp.setStatusCode(418, "I'm a Teapot"); + resp.fromFile(getDefualtPagePath(418)); return (resp); } @@ -154,6 +204,8 @@ HttpResponse HttpResponse::internalServerError_500() { HttpResponse resp; resp.setStatusCode(500, "Internal Server Error"); + resp.fromFile(getDefualtPagePath(500)); + return (resp); } @@ -168,5 +220,6 @@ HttpResponse HttpResponse::notImplemented_501() { HttpResponse resp; resp.setStatusCode(501, "Not Implemented"); + resp.setBody("

501 Not Implemented

"); return (resp); } \ No newline at end of file diff --git a/src/server/RequestHandler.cpp b/src/server/RequestHandler.cpp index 13caa47..60075c8 100644 --- a/src/server/RequestHandler.cpp +++ b/src/server/RequestHandler.cpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 14:30:32 by minakim ### ########.fr */ +/* Updated: 2024/07/12 20:48:17 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -29,6 +29,8 @@ RequestHandler::~RequestHandler() /// the functionality required to fulfill the request. HttpResponse RequestHandler::handleRequest(const HttpRequest request) { + std::cout << "\r" << request.getMethod() << " | " << request.getUri() << " | " << + request.getVersion() << std::endl; if (request.getMethod() == "GET") return (_staticFileHandler.handleRequest(request)); else if (request.getMethod() == "POST") diff --git a/src/server/Server.cpp b/src/server/Server.cpp index db152a9..fbfa892 100644 --- a/src/server/Server.cpp +++ b/src/server/Server.cpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:46 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 15:06:24 by minakim ### ########.fr */ +/* Updated: 2024/07/12 21:11:29 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -222,10 +222,26 @@ void Server::_handleClientData_2(int clientSocket, size_t idx) { close(clientSocket); _pollfds.erase(_pollfds.begin() + idx); + return ; } std::string requestData(buffer, count); - std::string responseData = handle_request(requestData); + + HttpRequest request; + + + if (!request.parse(requestData)) + return ; // throw? + + HttpResponse response = _requestHandler.handleRequest(request); + std::string responseData = response.toString(); + // std::string responseData = handle_request(requestData); + + + std::cout << "TEST | start: handleClientData_2" << std::endl; + std::cout << "TEST | " << requestData << std::endl; + + // Send the response write(clientSocket, responseData.c_str(), responseData.size()); close(clientSocket); _pollfds.erase(_pollfds.begin() + idx); diff --git a/src/server/StaticFileHandler.cpp b/src/server/StaticFileHandler.cpp index 2cb1f0b..7cabaf8 100644 --- a/src/server/StaticFileHandler.cpp +++ b/src/server/StaticFileHandler.cpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 15:13:24 by minakim ### ########.fr */ +/* Updated: 2024/07/12 20:18:24 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -24,22 +24,14 @@ StaticFileHandler::StaticFileHandler() StaticFileHandler::~StaticFileHandler() {} -// TODO check the logic, how to work with path/request HttpResponse StaticFileHandler::handleRequest(const HttpRequest request) { - std::string filePath = /* path + */ request.getUri(); - - // test - std::cout << "[test] file path: " << filePath << std::endl; - + std::string filePath = FOLDER_PATH + request.getUri(); + // std::cout << "filePath: " << filePath << std::endl; + if (!fileExists(filePath)) return (HttpResponse::notFound_404()); - - std::string mimeType = getMimeType(filePath); - - // test - std::cout << "[test] mime type: " << mimeType << std::endl; HttpResponse resp = HttpResponse::fromFile(filePath); resp.setHeader(getMimeType(filePath), mimeType); @@ -47,7 +39,6 @@ HttpResponse StaticFileHandler::handleRequest(const HttpRequest request) return (resp); } -// TODO test result, parse part std::string StaticFileHandler::getMimeType(const std::string path) const { std::string::size_type dotPosition = path.find_last_of("."); @@ -57,13 +48,17 @@ std::string StaticFileHandler::getMimeType(const std::string path) const std::map::const_iterator it = _mimeTypes.find(ext); if (it != _mimeTypes.end()) return (it->second); - return ("text/plain"); + return ("application/octet-stream"); } bool StaticFileHandler::fileExists(const std::string path) const { struct stat buffer; - return (stat(path.c_str(), &buffer) == 0); + if (stat(path.c_str(), &buffer) != 0) + return (false); + if (S_ISREG(buffer.st_mode)) + return (true); + return (false); } /// @brief Initializes the mimeTypes map with the default mime types. From 742baf70ca806d5412fb8b5fd46b19a010035408 Mon Sep 17 00:00:00 2001 From: minakim Date: Sun, 14 Jul 2024 17:43:42 +0200 Subject: [PATCH 6/6] update: feedback from PR --- include/HttpRequest.hpp | 11 +- include/HttpResponse.hpp | 13 ++- include/StaticFileHandler.hpp | 20 ++-- src/server/HttpRequest.cpp | 54 +++++---- src/server/HttpResponse.cpp | 186 +++++++++++++++++++++---------- src/server/StaticFileHandler.cpp | 74 +++++++----- 6 files changed, 235 insertions(+), 123 deletions(-) diff --git a/include/HttpRequest.hpp b/include/HttpRequest.hpp index 3d6c6ee..83224f6 100644 --- a/include/HttpRequest.hpp +++ b/include/HttpRequest.hpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 19:17:46 by minakim ### ########.fr */ +/* Updated: 2024/07/14 14:49:37 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -18,13 +18,14 @@ # define WHITESPACE " \t\r\n" -typedef struct s_read_request { + +struct t_read_request { std::string request; std::vector headers; std::string body; bool iscomplete; - -} t_read_request; + t_read_request() : iscomplete(false) {} +}; class HttpRequest { @@ -50,10 +51,10 @@ class HttpRequest std::map _headers; std::string _body; + t_read_request _splitRequestData(const std::string& requestData); bool _parseRequestLine(const std::string requestLine); bool _parseHeaders(const std::vector headerLines); bool _parseBody(const std::string bodylines); - t_read_request _separateRequestData(const std::string& requestData); std::vector _dataToHeaders(std::istringstream& iss); std::string _dataToBody(std::istringstream& iss); diff --git a/include/HttpResponse.hpp b/include/HttpResponse.hpp index 8d0f505..3962551 100644 --- a/include/HttpResponse.hpp +++ b/include/HttpResponse.hpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 21:22:52 by minakim ### ########.fr */ +/* Updated: 2024/07/14 17:27:02 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -16,12 +16,18 @@ # include # include +std::string getErrorPagePath(int pageCode); + class HttpResponse { public: HttpResponse(); + HttpResponse(const std::string filePath); + HttpResponse(const HttpResponse& other); + HttpResponse& operator=(const HttpResponse& other); ~HttpResponse(); - + + void setStatusCode(int code); void setStatusCode(int code, const std::string statusMessage); void setHeader(const std::string key, const std::string value); void setBody(const std::string bodyContent); @@ -50,6 +56,9 @@ class HttpResponse std::string _getStatusLine() const; std::string _getHeadersString() const; std::string _getResponseLine() const; + + static const std::map& _getStatusMessages(); + static HttpResponse _errorResponse(int code); }; #endif \ No newline at end of file diff --git a/include/StaticFileHandler.hpp b/include/StaticFileHandler.hpp index e1ededf..be9e587 100644 --- a/include/StaticFileHandler.hpp +++ b/include/StaticFileHandler.hpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 19:24:36 by minakim ### ########.fr */ +/* Updated: 2024/07/14 16:44:21 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -18,7 +18,10 @@ # include "HttpRequest.hpp" # include "HttpResponse.hpp" -# define FOLDER_PATH "./www/static" +// FIXME: Delete when correct logic is applied in the future +# define LOCATION_FIXME "./www/static" +# define LOOT_DIR "./www/static" + class StaticFileHandler { public: @@ -28,11 +31,14 @@ class StaticFileHandler HttpResponse handleRequest(const HttpRequest request); private: - static std::map _mimeTypes; + static std::map _staticMimeTypes; - std::string getMimeType(const std::string path) const; - bool fileExists(const std::string path) const; - static void initializeMimeTypes(); + std::string _getMimeType(const std::string path) const; + bool _fileExists(const std::string path) const; + static void _staticInitializeMimeTypes(); + HttpResponse _handleRoot(); + std::string _getFilePath(const std::string& uri) const; + HttpResponse _handleFileNotFound(); }; -#endif \ No newline at end of file +#endif diff --git a/src/server/HttpRequest.cpp b/src/server/HttpRequest.cpp index eb4702e..d58e991 100644 --- a/src/server/HttpRequest.cpp +++ b/src/server/HttpRequest.cpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 19:20:58 by minakim ### ########.fr */ +/* Updated: 2024/07/14 15:39:21 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -49,6 +49,7 @@ std::string HttpRequest::getBody() const return (_body); } +// TODO: check for necessary initialization bool HttpRequest::isConnectionClose() const { std::map::const_iterator it = _headers.find("Connection"); @@ -80,30 +81,12 @@ std::string HttpRequest::_dataToBody(std::istringstream& iss) return (""); return (drafts); } -/// @brief Separate the request data into request line, headers, and body. -/// @param requestData The request data to be separated. -/// @return A struct containing the separated request data. -t_read_request HttpRequest::_separateRequestData(const std::string& requestData) -{ - t_read_request data; - std::istringstream iss(requestData); - std::string readline; - std::string drafts; - data.iscomplete = false; +//////////////////////////////////////////////////////////////////////////////// +/// The current parse logic for my request is to first split the syntax into +/// request, header, and body lines, and then parse the split syntax separately. +/// I've separated the 'split' and 'parse' parts so that one function does one job. - if (requestData.empty()) - return (data); - if (!std::getline(iss, readline)) - return (data); - data.request = readline; - data.headers = _dataToHeaders(iss); - if (data.headers.empty()) - return (data); - data.body = _dataToBody(iss); - data.iscomplete = true; - return (data); -} /// @brief This function parses the request data and extracts /// the method, path, version, headers, and body. @@ -111,7 +94,7 @@ t_read_request HttpRequest::_separateRequestData(const std::string& requestData) /// @return bool bool HttpRequest::parse(const std::string& requestData) { - t_read_request separatedData = _separateRequestData(requestData); + t_read_request separatedData = _splitRequestData(requestData); if (!separatedData.iscomplete) return (false); if (!_parseRequestLine(separatedData.request)) @@ -123,6 +106,29 @@ bool HttpRequest::parse(const std::string& requestData) return (true); } + +/// @brief Separate the request data into request line, headers, and body. +/// @param requestData The request data to be separated. +/// @return A struct containing the separated request data. +t_read_request HttpRequest::_splitRequestData(const std::string& requestData) +{ + t_read_request data; + std::istringstream iss(requestData); + std::string readline; + std::string drafts; + if (requestData.empty()) + return (data); + if (!std::getline(iss, readline)) + return (data); + data.request = readline; + data.headers = _dataToHeaders(iss); + if (data.headers.empty()) + return (data); + data.body = _dataToBody(iss); + data.iscomplete = true; + return (data); +} + /// @brief Parses the request line and extracts the method, path, and version. /// @param requestLine `_method` `_uri` `_version`, example: GET /path/resource HTTP/1.1 /// @return bool diff --git a/src/server/HttpResponse.cpp b/src/server/HttpResponse.cpp index 2ce42af..e54526e 100644 --- a/src/server/HttpResponse.cpp +++ b/src/server/HttpResponse.cpp @@ -6,7 +6,7 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 21:29:54 by minakim ### ########.fr */ +/* Updated: 2024/07/14 17:35:57 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ @@ -20,10 +20,39 @@ HttpResponse::HttpResponse() { } +HttpResponse::HttpResponse(const std::string filePath) + :_statusCode(200), _statusMessage("OK") +{ + fromFile(filePath); +} + +HttpResponse::HttpResponse(const HttpResponse& other) +{ + _statusCode = other._statusCode; + _statusMessage = other._statusMessage; + _headers = other._headers; + _body = other._body; + +} + +HttpResponse& HttpResponse::operator=(const HttpResponse& other) +{ + if (this != &other) + { + _statusCode = other._statusCode; + _statusMessage = other._statusMessage; + _headers = other._headers; + _body = other._body; + } + return (*this); +} + HttpResponse::~HttpResponse() { } +//////////////////////////////////////////////////////////////////////////////// + void HttpResponse::setStatusCode(int code, const std::string statusMessage) { _statusCode = code; @@ -44,6 +73,7 @@ std::string HttpResponse::getBody() { return (_body); } + std::string HttpResponse::_getResponseLine() const { std::ostringstream oss; @@ -53,42 +83,34 @@ std::string HttpResponse::_getResponseLine() const std::string HttpResponse::toString() const { - std::cout << "TEST | HttpResponse::toString" << std::endl; - std::cout << _getResponseLine() + _getHeadersString() + "\r\n\r\n" + _body << std::endl; return (_getResponseLine() + _getHeadersString() + "\r\n\r\n" + _body); } -std::string getDefualtPagePath(int page_code) -{ - std::ostringstream oss; - oss << "./www/error_pages/" << page_code << ".html"; - return (oss.str()); -} +//////////////////////////////////////////////////////////////////////////////// -/// @brief Creates an HttpResponse object by reading the contents of a file. -/// -/// @param file_path The path to the file to be read. +/// @brief Creates an Static HttpResponse object by reading the contents of a file. +/// @param filePath The path to the file to be read. /// @return HttpResponse The created HttpResponse object. -HttpResponse HttpResponse::fromFile(const std::string file_path) +HttpResponse HttpResponse::fromFile(const std::string filePath) { HttpResponse resp; - std::ifstream file(file_path.data()); + std::ifstream file(filePath.data()); if (!file.is_open()) return (notFound_404()); file.seekg(0, std::ios::end); - std::streamsize fileSize = file.tellg(); - file.seekg(0, std::ios::beg); + std::streamsize fileSize = file.tellg(); + file.seekg(0, std::ios::beg); if (fileSize <= 0) - return internalServerError_500(); + return internalServerError_500(); std::string fileContents(fileSize, '\0'); - if (!file.read(&fileContents[0], fileSize)) + if (!file.read(&fileContents[0], fileSize)) return (file.close(), internalServerError_500()); - file.close(); + file.close(); std::stringstream ss; - ss << fileSize; + ss << fileSize; resp.setBody(fileContents); - resp.setHeader("Content-Length", ss.str()); + resp.setHeader("Content-Length", ss.str()); resp.setHeader("Connection", "close"); return (resp); } @@ -118,8 +140,53 @@ std::string HttpResponse::_getStatusLine() const return (statusLine.str()); } +//////////////////////////////////////////////////////////////////////////////// + + +std::string getErrorPagePath(int pageCode) +{ + std::ostringstream oss; + oss << "./www/error_pages/" << pageCode << ".html"; + return (oss.str()); +} + +const std::map& HttpResponse::_getStatusMessages() +{ + static std::map statusMessages; + + if (statusMessages.empty()) + { + statusMessages[200] = "OK"; + // statusMessages[201] = "Created"; + // statusMessages[204] = "No Content"; + // statusMessages[301] = "Moved Permanently"; + // statusMessages[302] = "Found"; + statusMessages[400] = "Bad Request"; + // statusMessages[401] = "Unauthorized"; + statusMessages[403] = "Forbidden"; + statusMessages[404] = "Not Found"; + statusMessages[405] = "Method Not Allowed"; + statusMessages[408] = "Request Timeout"; + statusMessages[413] = "Request Entity Too Large"; + statusMessages[418] = "I'm a Teapot"; + statusMessages[500] = "Internal Server Error"; + statusMessages[501] = "Not Implemented"; + } + return (statusMessages); +} +void HttpResponse::setStatusCode(int code) +{ + _statusCode = code; + const std::map& statusMessages = _getStatusMessages(); + std::map::const_iterator it = statusMessages.find(code); + if (it != statusMessages.end()) + _statusMessage = it->second; + else + throw std::runtime_error("Unknown status code"); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief static functions to create HttpResponse objects /// with specific status codes. @@ -128,23 +195,24 @@ std::string HttpResponse::_getStatusLine() const // TODO think about seperate functions to another class. //////////////////////////////////////////////////////////////////////////////// - - +/// @brief Handle error responses. +/// @param code +/// @return HttpResponse +HttpResponse HttpResponse::_errorResponse(int code) +{ + HttpResponse resp(fromFile(getErrorPagePath(code))); + resp.setStatusCode(code); + return (resp); +} HttpResponse HttpResponse::badRequest_400() { - HttpResponse resp; - resp.setStatusCode(400, "Bad Request"); - resp.fromFile(getDefualtPagePath(400)); - return (resp); + return (_errorResponse(400)); } HttpResponse HttpResponse::forbidden_403() { - HttpResponse resp; - resp.setStatusCode(403, "Forbidden"); - resp.fromFile(getDefualtPagePath(403)); - return (resp); + return (_errorResponse(403)); } /// @brief Creates an HttpResponse object for a 404 Not Found error. @@ -157,62 +225,54 @@ HttpResponse HttpResponse::forbidden_403() HttpResponse HttpResponse::notFound_404() { HttpResponse resp; - resp.setStatusCode(404, "Not Found"); - std::string defaultPagePath = getDefualtPagePath(404); - - HttpResponse fileResponse = fromFile(defaultPagePath); - if (fileResponse.getBody().empty()) + HttpResponse from404File(_errorResponse(404)); + + if (from404File.getBody().empty()) resp.setBody("

404 Not Found

"); else - resp.setBody(fileResponse.getBody()); + resp.setBody(from404File.getBody()); return (resp); } HttpResponse HttpResponse::methodNotAllowed_405() { - HttpResponse resp; - resp.setStatusCode(405, "Method Not Allowed"); - resp.fromFile(getDefualtPagePath(405)); - return (resp); + return (_errorResponse(405)); + } HttpResponse HttpResponse::requestTimeout_408() { - HttpResponse resp; - resp.setStatusCode(408, "Request Timeout"); - resp.fromFile(getDefualtPagePath(408)); - return (resp); + return (_errorResponse(408)); } HttpResponse HttpResponse::requestEntityTooLarge_413() { - HttpResponse resp; - resp.setStatusCode(413, "Request Entity Too Large"); - resp.fromFile(getDefualtPagePath(413)); - return (resp); + return (_errorResponse(413)); } HttpResponse HttpResponse::imaTeapot_418() { - HttpResponse resp; - resp.setStatusCode(418, "I'm a Teapot"); - resp.fromFile(getDefualtPagePath(418)); - return (resp); + return (_errorResponse(418)); } HttpResponse HttpResponse::internalServerError_500() { - HttpResponse resp; - resp.setStatusCode(500, "Internal Server Error"); - resp.fromFile(getDefualtPagePath(500)); - - return (resp); + return (_errorResponse(500)); } +// TODO add doc, make new mtethid to set header & body HttpResponse HttpResponse::success_200() { HttpResponse resp; resp.setStatusCode(200, "OK"); + std::string body = "

Success

"; + resp.setBody(body); + + std::ostringstream oss; + oss << body.size(); + resp.setHeader("Content-Length",oss.str()); + resp.setHeader("Content-Type", "text/html"); + resp.setHeader("Connection", "close"); return (resp); } @@ -220,6 +280,14 @@ HttpResponse HttpResponse::notImplemented_501() { HttpResponse resp; resp.setStatusCode(501, "Not Implemented"); - resp.setBody("

501 Not Implemented

"); + + std::string body = "

501 Not Implemented

"; + resp.setBody(body); + + std::ostringstream oss; + oss << body.size(); + resp.setHeader("Content-Length",oss.str()); + resp.setHeader("Content-Type", "text/html"); + resp.setHeader("Connection", "close"); return (resp); } \ No newline at end of file diff --git a/src/server/StaticFileHandler.cpp b/src/server/StaticFileHandler.cpp index 7cabaf8..5ebd9ea 100644 --- a/src/server/StaticFileHandler.cpp +++ b/src/server/StaticFileHandler.cpp @@ -6,19 +6,19 @@ /* By: minakim +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/30 16:23:00 by sanghupa #+# #+# */ -/* Updated: 2024/07/12 20:18:24 by minakim ### ########.fr */ +/* Updated: 2024/07/14 17:17:45 by minakim ### ########.fr */ /* */ /* ************************************************************************** */ #include "webserv.hpp" #include "StaticFileHandler.hpp" -std::map StaticFileHandler::_mimeTypes; +std::map StaticFileHandler::_staticMimeTypes; StaticFileHandler::StaticFileHandler() { - if (_mimeTypes.empty()) - initializeMimeTypes(); + if (_staticMimeTypes.empty()) + _staticInitializeMimeTypes(); } StaticFileHandler::~StaticFileHandler() @@ -26,49 +26,71 @@ StaticFileHandler::~StaticFileHandler() HttpResponse StaticFileHandler::handleRequest(const HttpRequest request) { - std::string filePath = FOLDER_PATH + request.getUri(); - // std::cout << "filePath: " << filePath << std::endl; - - if (!fileExists(filePath)) - return (HttpResponse::notFound_404()); - std::string mimeType = getMimeType(filePath); + if (request.getUri() == "/") + return (_handleRoot()); + std::string filePath = _getFilePath(request.getUri()); + if (!_fileExists(filePath)) + return (_handleFileNotFound()); + std::string mimeType = _getMimeType(filePath); + // HttpResponse resp(filePath); HttpResponse resp = HttpResponse::fromFile(filePath); - resp.setHeader(getMimeType(filePath), mimeType); + resp.setHeader(_getMimeType(filePath), mimeType); return (resp); } -std::string StaticFileHandler::getMimeType(const std::string path) const +HttpResponse StaticFileHandler::_handleRoot() +{ + return (HttpResponse::success_200()); +} + +std::string StaticFileHandler::_getFilePath(const std::string& uri) const +{ + return( LOCATION_FIXME + uri); +} + +HttpResponse StaticFileHandler::_handleFileNotFound() +{ + return (HttpResponse::notFound_404()); +} + +/// @brief Returns the MIME type of a given file based on its file extension. +/// @param path The path of the file. +/// @return The MIME type of the file. + +std::string StaticFileHandler::_getMimeType(const std::string path) const { std::string::size_type dotPosition = path.find_last_of("."); if (dotPosition == std::string::npos) return ("text/plain"); std::string ext = path.substr(dotPosition); - std::map::const_iterator it = _mimeTypes.find(ext); - if (it != _mimeTypes.end()) + std::map::const_iterator it = _staticMimeTypes.find(ext); + if (it != _staticMimeTypes.end()) return (it->second); return ("application/octet-stream"); } -bool StaticFileHandler::fileExists(const std::string path) const +/// @brief Checks if a file exists. +/// @param path The path of the file. +bool StaticFileHandler::_fileExists(const std::string path) const { struct stat buffer; if (stat(path.c_str(), &buffer) != 0) - return (false); + return (false); if (S_ISREG(buffer.st_mode)) - return (true); + return (true); return (false); } /// @brief Initializes the mimeTypes map with the default mime types. -void StaticFileHandler::initializeMimeTypes() +void StaticFileHandler::_staticInitializeMimeTypes() { - _mimeTypes.insert(std::make_pair(".html", "text/html")); - _mimeTypes.insert(std::make_pair(".css", "text/css")); - _mimeTypes.insert(std::make_pair(".js", "application/javascript")); - _mimeTypes.insert(std::make_pair(".png", "image/png")); - _mimeTypes.insert(std::make_pair(".jpg", "image/jpeg")); - _mimeTypes.insert(std::make_pair(".gif", "image/gif")); - _mimeTypes.insert(std::make_pair(".txt", "text/plain")); -} \ No newline at end of file + _staticMimeTypes.insert(std::make_pair(".html", "text/html")); + _staticMimeTypes.insert(std::make_pair(".css", "text/css")); + _staticMimeTypes.insert(std::make_pair(".js", "application/javascript")); + _staticMimeTypes.insert(std::make_pair(".png", "image/png")); + _staticMimeTypes.insert(std::make_pair(".jpg", "image/jpeg")); + _staticMimeTypes.insert(std::make_pair(".gif", "image/gif")); + _staticMimeTypes.insert(std::make_pair(".txt", "text/plain")); +}