From 19bc8730e6c4e96cb7797177f8774faa63261c54 Mon Sep 17 00:00:00 2001 From: adjoly Date: Wed, 30 Apr 2025 10:42:23 +0200 Subject: [PATCH] =?UTF-8?q?=E3=80=8C=F0=9F=8F=97=EF=B8=8F=E3=80=8D=20wip:?= =?UTF-8?q?=20reformated=20a=20lot=20of=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- includes/requests/IMessage.hpp | 4 +- includes/server/Client.hpp | 4 +- src/requests_handling/ARequests.cpp | 56 +++ src/requests_handling/Cgi.cpp | 9 +- src/requests_handling/HttpRequests.cpp | 400 ------------------ .../{HttpIMessage.cpp => IMessage.cpp} | 32 +- .../{HttpResponse.cpp => Response.cpp} | 7 +- .../requestImplementation/Delete.cpp | 89 ++++ .../requestImplementation/Get.cpp | 176 ++++++++ .../requestImplementation/Post.cpp | 127 ++++++ 10 files changed, 469 insertions(+), 435 deletions(-) create mode 100644 src/requests_handling/ARequests.cpp delete mode 100644 src/requests_handling/HttpRequests.cpp rename src/requests_handling/{HttpIMessage.cpp => IMessage.cpp} (56%) rename src/requests_handling/{HttpResponse.cpp => Response.cpp} (91%) create mode 100644 src/requests_handling/requestImplementation/Delete.cpp create mode 100644 src/requests_handling/requestImplementation/Get.cpp create mode 100644 src/requests_handling/requestImplementation/Post.cpp diff --git a/includes/requests/IMessage.hpp b/includes/requests/IMessage.hpp index 60511ee..56689ce 100644 --- a/includes/requests/IMessage.hpp +++ b/includes/requests/IMessage.hpp @@ -1,12 +1,12 @@ /* ************************************************************************** */ /* */ /* ::: :::::::: */ -/* HttpIMessage.hpp :+: :+: :+: */ +/* IMessage.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: mmoussou +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/14 14:14:39 by adjoly #+# #+# */ -/* Updated: 2025/04/29 14:24:45 by adjoly ### ########.fr */ +/* Updated: 2025/04/30 09:37:38 by adjoly ### ########.fr */ /* */ /* ************************************************************************** */ @@ -45,7 +45,7 @@ class Client { struct pollfd *_pfd; struct sockaddr_in _client_addr; - http::IRequest *_request; + http::ARequest *_request; // http::Response *_response; config::Server *_conf; config::Config *_Gconf; diff --git a/src/requests_handling/ARequests.cpp b/src/requests_handling/ARequests.cpp new file mode 100644 index 0000000..d7f3d54 --- /dev/null +++ b/src/requests_handling/ARequests.cpp @@ -0,0 +1,56 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ARequests.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: mmoussou +#include +#include +#include + +#include +#include +#include + +using namespace webserv::http; + +std::string ARequest::str(void) const { + std::ostringstream response; + + response << this->_method << " " << this->_target << " " << this->_protocol; + response << "\r\n"; + + for (std::map::const_iterator it = + this->_headers.begin(); + it != this->_headers.end(); ++it) + response << it->first << ": " << it->second << "\r\n"; + + response << "\r\n"; + response << this->_body; + + return (response.str()); +} + +void parse(std::string const &data) { (void)data; } +Response execute(void) { return (Response()); } + +std::string ARequest::getMethod(void) const { return (this->_method); } + +std::string ARequest::getTarget(void) const { return (this->_target); } + +std::string ARequest::getProtocol(void) const { return (this->_protocol); } + +void ARequest::setMethod(std::string const method) { this->_method = method; } + +void ARequest::setTarget(std::string const target) { this->_target = target; } + +void ARequest::setProtocol(std::string const protocol) { + this->_protocol = protocol; +} diff --git a/src/requests_handling/Cgi.cpp b/src/requests_handling/Cgi.cpp index 1637a82..6ce13f8 100644 --- a/src/requests_handling/Cgi.cpp +++ b/src/requests_handling/Cgi.cpp @@ -6,16 +6,15 @@ /* By: adjoly +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/24 13:46:34 by adjoly #+# #+# */ -/* Updated: 2025/04/25 13:22:00 by adjoly ### ########.fr */ +/* Updated: 2025/04/30 09:49:32 by adjoly ### ########.fr */ /* */ /* ************************************************************************** */ -#include "requests/HttpIMessage.hpp" -#include "requests/HttpRequest.hpp" -#include "requests/HttpResponse.hpp" #include "requests/default.hpp" -Cgi::Cgi(http::IRequest *req, config::Server *conf) : _conf(conf), _request(req) { +using namespace webserv; + +Cgi::Cgi(http::ARequest *req, config::Server *conf) : _conf(conf), _request(req) { _initEnvp(); } diff --git a/src/requests_handling/HttpRequests.cpp b/src/requests_handling/HttpRequests.cpp deleted file mode 100644 index 3ed417d..0000000 --- a/src/requests_handling/HttpRequests.cpp +++ /dev/null @@ -1,400 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* HttpRequests.cpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: mmoussou -#include - -#include -#include -#include -#include -#include - -#include - -using namespace webserv; - -std::string http::IRequest::str(void) const { - std::ostringstream response; - - response << this->_method << " " << this->_target << " " << this->_protocol; - response << "\r\n"; - - for (std::map::const_iterator it = - this->_headers.begin(); - it != this->_headers.end(); ++it) - response << it->first << ": " << it->second << "\r\n"; - - response << "\r\n"; - response << this->_body; - - return (response.str()); -} - -void parse(std::string const &data) { (void)data; } -http::Response execute(void) { return (http::Response()); } - -std::string http::IRequest::getMethod(void) const { return (this->_method); } - -std::string http::IRequest::getTarget(void) const { return (this->_target); } - -std::string http::IRequest::getProtocol(void) const { - return (this->_protocol); -} - -void http::IRequest::setMethod(std::string const method) { - this->_method = method; -} - -void http::IRequest::setTarget(std::string const target) { - this->_target = target; -} - -void http::IRequest::setProtocol(std::string const protocol) { - this->_protocol = protocol; -} - -// ------------------------------------------------------------------ -http::Get::Get(std::string &data) { this->parse(data); } - -void http::Get::parse(std::string const &data) { - std::istringstream stream(data); - std::string line; - - if (std::getline(stream, line)) { - std::istringstream line_stream(line); - line_stream >> this->_method >> this->_target >> this->_protocol; - /* this->_target.insert(this->_target.begin(), '.'); */ - } - - while (std::getline(stream, line) && line != "\r") { - size_t delimiter_index = line.find(':'); - if (delimiter_index != std::string::npos) { - std::string key = line.substr(0, delimiter_index); - std::string value = line.substr(delimiter_index + 2); - this->_headers.insert(std::make_pair(key, value)); - } - } - - std::ostringstream body_stream; - while (std::getline(stream, line)) - body_stream << line << "\n"; - this->_body = body_stream.str(); - - _url = new URL("http://" + _headers["Host"] + _target); - std::cout << *_url << std::endl; - - /* - std::cout << "-- start-line --" << std::endl; - std::cout << "method: " << this->_method << std::endl; - std::cout << "target: " << this->_target << std::You can use every macro and -define like FD_SET, FD_CLR, FD_ISSET and, FD_ZERO (understanding what they do -and how they work is very useful). • A request to your server should never hang -indefinitely. • Your server must be compatible with standard web browsers of -your choice. • We will consider that NGINX is HTTP 1.1 compliant and may be used -to compare headers and answer behaviors. • Your HTTP response status codes must -be accurate. • Your server must have default error pages if none are provided. -• You can’t use fork for anything other than CGI (like PHP, or Python, and so -forth). • You must be able to serve a fully static website. • Clients must be -able to upload files. • You need at least the GET, POST, and DELETE methodendl; - std::cout << "protocol: " << this->_protocol << std::endl; - std::cout << std::endl; - std::cout << "-- headers --" << std::endl; - for (std::map::const_iterator it = -this->_headers.begin(); it != this->_headers.end(); ++it) std::cout << it->first -<< ": " << it->second << std::endl; std::cout << std::endl; std::cout << "-- -body --" << std::endl << this->_body << std::endl; - */ -} - -char isDirectory(const std::string &path) { - struct stat file_stat; - - if (stat(path.c_str(), &file_stat) != 0) { - throw std::runtime_error("can't open file (non-existant ?)"); - } - return S_ISDIR(file_stat.st_mode); -} - -http::Response http::Get::execute(void) { - http::Response response; - - try { - 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::sort(files.begin(), files.end()); - - std::string body = ""; - - body += ""; - - 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); - response.addHeader("Content-Length", length.str()); - - response.setProtocol(this->_protocol); - response.setStatusCode(200); - response.addHeader("Content-Type", - http::Mime::getType(this->_target)); - -#ifdef VERBOSE - //_log->debug(response.str().c_str()); -#endif - } - } catch (...) { - // TODO: replace with a predefined array of error pages - response.setProtocol(this->_protocol); - response.setStatusCode(404); - response.addHeader("Content-Type", "text/html"); - response.setBody( - http::Errors::getResponseBody(response.getStatusCode())); - } - - return (response); -} - -// ------------------------------------------------------------------ - - -http::Delete::Delete(std::string &data) { this->parse(data); } - -void http::Delete::parse(std::string const &data) { - std::istringstream stream(data); - std::string line; - - if (std::getline(stream, line)) { - std::istringstream line_stream(line); - line_stream >> this->_method >> this->_target >> this->_protocol; - this->_target.insert(this->_target.begin(), '.'); - } - - while (std::getline(stream, line) && line != "\r") { - size_t delimiter_index = line.find(':'); - if (delimiter_index != std::string::npos) { - std::string key = line.substr(0, delimiter_index); - std::string value = line.substr(delimiter_index + 2); - this->_headers.insert(std::make_pair(key, value)); - } - } - - std::ostringstream body_stream; - while (std::getline(stream, line)) - body_stream << line << "\n"; - this->_body = body_stream.str(); - - _url = new URL(_target); - std::cout << *_url << std::endl; - - /* - std::cout << "-- start-line --" << std::endl; - std::cout << "method: " << this->_method << std::endl; - std::cout << "target: " << this->_target << std::endl; - std::cout << "protocol: " << this->_protocol << std::endl; - std::cout << std::endl; - std::cout << "-- headers --" << std::endl; - for (std::map::const_iterator it = - this->_headers.begin(); it != this->_headers.end(); ++it) std::cout << - it->first << ": " << it->second << std::endl; std::cout << std::endl; - std::cout << "-- body --" << std::endl << this->_body << std::endl; - */ -} - -http::Response http::Delete::execute(void) { - http::Response response; - - try { - if (std::remove(this->_target.c_str())) - throw std::runtime_error("can't remove file, FF"); - response.setProtocol(this->_protocol); - response.setStatusCode(204); - time_t now = std::time(NULL); - response.addHeader("Date", std::string(std::ctime(&now))); - } catch (...) { - // TODO: check errno value and get corresponding error page, check for - // corresponding error code : - // https://cdn.discordapp.com/attachments/784779058407014403/1350841524778307586/image.png?ex=67d8dd74&is=67d78bf4&hm=c030468d3862627d6402bf200960d1a15249ba2f8dac772af3283b368a77f2f5& - - response.setProtocol(this->_protocol); - response.setStatusCode(404); - response.addHeader("Content-Type", "text/html"); - response.setBody( - http::Errors::getResponseBody(response.getStatusCode())); - } - - return (response); -} - -// ------------------------------------------------------------------ - -http::Post::Post(std::string &data) { this->parse(data); } - -void http::Post::parse(std::string const &data) { - std::istringstream stream(data); - std::string line; - - if (std::getline(stream, line)) { - std::istringstream line_stream(line); - line_stream >> this->_method >> this->_target >> this->_protocol; - this->_target.insert(this->_target.begin(), '.'); - } - - while (std::getline(stream, line) && line != "\r") { - size_t delimiter_index = line.find(':'); - if (delimiter_index != std::string::npos) { - std::string key = line.substr(0, delimiter_index); - std::string value = line.substr(delimiter_index + 2); - this->_headers.insert(std::make_pair(key, value)); - } - } - - std::ostringstream body_stream; - while (std::getline(stream, line)) - body_stream << line << "\n"; - this->_body = body_stream.str(); - - _url = new URL(_target); - std::cout << *_url << std::endl; - - /* - std::cout << "-- start-line --" << std::endl; - std::cout << "method: " << this->_method << std::endl; - std::cout << "target: " << this->_target << std::endl; - std::cout << "protocol: " << this->_protocol << std::endl; - std::cout << std::endl; - std::cout << "-- headers --" << std::endl; - for (std::map::const_iterator it = - this->_headers.begin(); it != this->_headers.end(); ++it) std::cout << - it->first << ": " << it->second << std::endl; std::cout << std::endl; - //std::cout << "-- body --" << std::endl << this->_body << std::endl; - */ -} - -std::string extractFilename(const std::string &header) { - size_t start = header.find("filename=\"") + 10; - size_t end = header.find("\"", start); - return header.substr(start, end - start); -} - -void handleMultipartData(const std::string &body, const std::string &boundary) { - size_t i = 0; - std::string delim = "--" + boundary; - delim.erase(delim.size() - 1); - - while ((i = body.find(delim, i)) != std::string::npos) { - size_t start = i + delim.length(); - size_t end = body.find("\r\n\r\n", start); - - if (end != std::string::npos) { - std::string part_header = body.substr(start, end - start); - // std::cout << std::endl << std::endl << std::endl << std::endl; - std::string part_content = - body.substr(end + 4, body.find(delim, end) - end - 4); - - std::ofstream outfile(extractFilename(part_header).c_str(), - std::ios::binary); - if (outfile.is_open()) { - outfile.write(part_content.c_str(), part_content.length()); - outfile.close(); - } else { - std::cerr << "open failed" << std::endl; - } - } - - i += delim.length(); - } -} - -http::Response http::Post::execute(void) { - http::Response response; - - try { - handleMultipartData( - this->_body, - this->getHeaders()["Content-Type"].substr( - this->getHeaders()["Content-Type"].find( - "=", this->getHeaders()["Content-Type"].find(";")) + - 1)); - - response.setProtocol(this->_protocol); - response.setStatusCode(200); - response.addHeader("Content-Type", "text/html"); - response.setBody( - http::Errors::getResponseBody(response.getStatusCode())); - } catch (...) { - response.setProtocol(this->_protocol); - response.setStatusCode(500); - response.addHeader("Content-Type", "text/html"); - response.setBody( - http::Errors::getResponseBody(response.getStatusCode())); - } - return (response); -} - -// ------------------------------------------------------------------ diff --git a/src/requests_handling/HttpIMessage.cpp b/src/requests_handling/IMessage.cpp similarity index 56% rename from src/requests_handling/HttpIMessage.cpp rename to src/requests_handling/IMessage.cpp index 2b91323..409854a 100644 --- a/src/requests_handling/HttpIMessage.cpp +++ b/src/requests_handling/IMessage.cpp @@ -1,45 +1,33 @@ /* ************************************************************************** */ /* */ /* ::: :::::::: */ -/* HttpIMessage.cpp :+: :+: :+: */ +/* IMessage.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: mmoussou +#include -using namespace webserv; +using namespace webserv::http; -std::map http::IMessage::getHeaders(void) const -{ +std::map IMessage::getHeaders(void) const { return (this->_headers); } -std::string http::IMessage::getBody(void) const -{ - return (this->_body); -} +std::string IMessage::getBody(void) const { return (this->_body); } -void http::IMessage::setHeaders(std::map const headers) -{ +void IMessage::setHeaders(std::map const headers) { this->_headers = headers; } -void http::IMessage::setBody(std::string const body) -{ - this->_body = body; -} +void IMessage::setBody(std::string const body) { this->_body = body; } -void http::IMessage::addHeader(std::string const key, std::string const value) -{ +void IMessage::addHeader(std::string const key, std::string const value) { this->_headers.insert(std::make_pair(key, value)); } -void http::IMessage::rmHeader(std::string const key) -{ - this->_headers.erase(key); -} +void IMessage::rmHeader(std::string const key) { this->_headers.erase(key); } diff --git a/src/requests_handling/HttpResponse.cpp b/src/requests_handling/Response.cpp similarity index 91% rename from src/requests_handling/HttpResponse.cpp rename to src/requests_handling/Response.cpp index 5a9c329..73e92dd 100644 --- a/src/requests_handling/HttpResponse.cpp +++ b/src/requests_handling/Response.cpp @@ -1,18 +1,17 @@ /* ************************************************************************** */ /* */ /* ::: :::::::: */ -/* HttpResponse.cpp :+: :+: :+: */ +/* Response.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: mmoussou -#include #include +#include /* - do a map of all the status_text and get it from here, not storing them diff --git a/src/requests_handling/requestImplementation/Delete.cpp b/src/requests_handling/requestImplementation/Delete.cpp new file mode 100644 index 0000000..702058d --- /dev/null +++ b/src/requests_handling/requestImplementation/Delete.cpp @@ -0,0 +1,89 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Delete.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: adjoly +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/30 09:42:18 by adjoly #+# #+# */ +/* Updated: 2025/04/30 09:47:33 by adjoly ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include +#include +#include +#include + +#include + +using namespace webserv::http; + +Delete::Delete(std::string &data) { this->parse(data); } + +void Delete::parse(std::string const &data) { + std::istringstream stream(data); + std::string line; + + if (std::getline(stream, line)) { + std::istringstream line_stream(line); + line_stream >> this->_method >> this->_target >> this->_protocol; + this->_target.insert(this->_target.begin(), '.'); + } + + while (std::getline(stream, line) && line != "\r") { + size_t delimiter_index = line.find(':'); + if (delimiter_index != std::string::npos) { + std::string key = line.substr(0, delimiter_index); + std::string value = line.substr(delimiter_index + 2); + this->_headers.insert(std::make_pair(key, value)); + } + } + + std::ostringstream body_stream; + while (std::getline(stream, line)) + body_stream << line << "\n"; + this->_body = body_stream.str(); + + _url = new URL(_target); + std::cout << *_url << std::endl; + + /* + std::cout << "-- start-line --" << std::endl; + std::cout << "method: " << this->_method << std::endl; + std::cout << "target: " << this->_target << std::endl; + std::cout << "protocol: " << this->_protocol << std::endl; + std::cout << std::endl; + std::cout << "-- headers --" << std::endl; + for (std::map::const_iterator it = + this->_headers.begin(); it != this->_headers.end(); ++it) std::cout << + it->first << ": " << it->second << std::endl; std::cout << std::endl; + std::cout << "-- body --" << std::endl << this->_body << std::endl; + */ +} + +Response Delete::execute(void) { + http::Response response; + + try { + if (std::remove(this->_target.c_str())) + throw std::runtime_error("can't remove file, FF"); + response.setProtocol(this->_protocol); + response.setStatusCode(204); + time_t now = std::time(NULL); + response.addHeader("Date", std::string(std::ctime(&now))); + } catch (...) { + // TODO: check errno value and get corresponding error page, check for + // corresponding error code : + // https://cdn.discordapp.com/attachments/784779058407014403/1350841524778307586/image.png?ex=67d8dd74&is=67d78bf4&hm=c030468d3862627d6402bf200960d1a15249ba2f8dac772af3283b368a77f2f5& + + response.setProtocol(this->_protocol); + response.setStatusCode(404); + response.addHeader("Content-Type", "text/html"); + response.setBody( + http::Errors::getResponseBody(response.getStatusCode())); + } + + return (response); +} + diff --git a/src/requests_handling/requestImplementation/Get.cpp b/src/requests_handling/requestImplementation/Get.cpp new file mode 100644 index 0000000..6bcf749 --- /dev/null +++ b/src/requests_handling/requestImplementation/Get.cpp @@ -0,0 +1,176 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Get.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: adjoly +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/30 09:40:16 by adjoly #+# #+# */ +/* Updated: 2025/04/30 09:41:41 by adjoly ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include +#include +#include +#include + +#include + +using namespace webserv::http; + +Get::Get(std::string &data) { this->parse(data); } + +void Get::parse(std::string const &data) { + std::istringstream stream(data); + std::string line; + + if (std::getline(stream, line)) { + std::istringstream line_stream(line); + line_stream >> this->_method >> this->_target >> this->_protocol; + /* this->_target.insert(this->_target.begin(), '.'); */ + } + + while (std::getline(stream, line) && line != "\r") { + size_t delimiter_index = line.find(':'); + if (delimiter_index != std::string::npos) { + std::string key = line.substr(0, delimiter_index); + std::string value = line.substr(delimiter_index + 2); + this->_headers.insert(std::make_pair(key, value)); + } + } + + std::ostringstream body_stream; + while (std::getline(stream, line)) + body_stream << line << "\n"; + this->_body = body_stream.str(); + + _url = new URL("http://" + _headers["Host"] + _target); + std::cout << *_url << std::endl; + + /* + std::cout << "-- start-line --" << std::endl; + std::cout << "method: " << this->_method << std::endl; + std::cout << "target: " << this->_target << std::You can use every macro and +define like FD_SET, FD_CLR, FD_ISSET and, FD_ZERO (understanding what they do +and how they work is very useful). • A request to your server should never hang +indefinitely. • Your server must be compatible with standard web browsers of +your choice. • We will consider that NGINX is HTTP 1.1 compliant and may be used +to compare headers and answer behaviors. • Your HTTP response status codes must +be accurate. • Your server must have default error pages if none are provided. +• You can’t use fork for anything other than CGI (like PHP, or Python, and so +forth). • You must be able to serve a fully static website. • Clients must be +able to upload files. • You need at least the GET, POST, and DELETE methodendl; + std::cout << "protocol: " << this->_protocol << std::endl; + std::cout << std::endl; + std::cout << "-- headers --" << std::endl; + for (std::map::const_iterator it = +this->_headers.begin(); it != this->_headers.end(); ++it) std::cout << it->first +<< ": " << it->second << std::endl; std::cout << std::endl; std::cout << "-- +body --" << std::endl << this->_body << std::endl; + */ +} + +char isDirectory(const std::string &path) { + struct stat file_stat; + + if (stat(path.c_str(), &file_stat) != 0) { + throw std::runtime_error("can't open file (non-existant ?)"); + } + return S_ISDIR(file_stat.st_mode); +} + +Response Get::execute(void) { + http::Response response; + + try { + 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::sort(files.begin(), files.end()); + + std::string body = ""; + + body += ""; + + 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); + response.addHeader("Content-Length", length.str()); + + response.setProtocol(this->_protocol); + response.setStatusCode(200); + response.addHeader("Content-Type", + http::Mime::getType(this->_target)); + +#ifdef VERBOSE + //_log->debug(response.str().c_str()); +#endif + } + } catch (...) { + // TODO: replace with a predefined array of error pages + response.setProtocol(this->_protocol); + response.setStatusCode(404); + response.addHeader("Content-Type", "text/html"); + response.setBody( + http::Errors::getResponseBody(response.getStatusCode())); + } + + return (response); +} diff --git a/src/requests_handling/requestImplementation/Post.cpp b/src/requests_handling/requestImplementation/Post.cpp new file mode 100644 index 0000000..f90bf78 --- /dev/null +++ b/src/requests_handling/requestImplementation/Post.cpp @@ -0,0 +1,127 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Post.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: adjoly +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/30 09:50:20 by adjoly #+# #+# */ +/* Updated: 2025/04/30 09:50:22 by adjoly ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include +#include +#include +#include + +#include +#include +#include + +using namespace webserv::http; + +Post::Post(std::string &data) { this->parse(data); } + +void Post::parse(std::string const &data) { + std::istringstream stream(data); + std::string line; + + if (std::getline(stream, line)) { + std::istringstream line_stream(line); + line_stream >> this->_method >> this->_target >> this->_protocol; + this->_target.insert(this->_target.begin(), '.'); + } + + while (std::getline(stream, line) && line != "\r") { + size_t delimiter_index = line.find(':'); + if (delimiter_index != std::string::npos) { + std::string key = line.substr(0, delimiter_index); + std::string value = line.substr(delimiter_index + 2); + this->_headers.insert(std::make_pair(key, value)); + } + } + + std::ostringstream body_stream; + while (std::getline(stream, line)) + body_stream << line << "\n"; + this->_body = body_stream.str(); + + _url = new URL(_target); + std::cout << *_url << std::endl; + + /* + std::cout << "-- start-line --" << std::endl; + std::cout << "method: " << this->_method << std::endl; + std::cout << "target: " << this->_target << std::endl; + std::cout << "protocol: " << this->_protocol << std::endl; + std::cout << std::endl; + std::cout << "-- headers --" << std::endl; + for (std::map::const_iterator it = + this->_headers.begin(); it != this->_headers.end(); ++it) std::cout << + it->first << ": " << it->second << std::endl; std::cout << std::endl; + //std::cout << "-- body --" << std::endl << this->_body << std::endl; + */ +} + +std::string extractFilename(const std::string &header) { + size_t start = header.find("filename=\"") + 10; + size_t end = header.find("\"", start); + return header.substr(start, end - start); +} + +void handleMultipartData(const std::string &body, const std::string &boundary) { + size_t i = 0; + std::string delim = "--" + boundary; + delim.erase(delim.size() - 1); + + while ((i = body.find(delim, i)) != std::string::npos) { + size_t start = i + delim.length(); + size_t end = body.find("\r\n\r\n", start); + + if (end != std::string::npos) { + std::string part_header = body.substr(start, end - start); + // std::cout << std::endl << std::endl << std::endl << std::endl; + std::string part_content = + body.substr(end + 4, body.find(delim, end) - end - 4); + + std::ofstream outfile(extractFilename(part_header).c_str(), + std::ios::binary); + if (outfile.is_open()) { + outfile.write(part_content.c_str(), part_content.length()); + outfile.close(); + } else { + std::cerr << "open failed" << std::endl; + } + } + + i += delim.length(); + } +} + +Response Post::execute(void) { + http::Response response; + + try { + handleMultipartData( + this->_body, + this->getHeaders()["Content-Type"].substr( + this->getHeaders()["Content-Type"].find( + "=", this->getHeaders()["Content-Type"].find(";")) + + 1)); + + response.setProtocol(this->_protocol); + response.setStatusCode(200); + response.addHeader("Content-Type", "text/html"); + response.setBody( + http::Errors::getResponseBody(response.getStatusCode())); + } catch (...) { + response.setProtocol(this->_protocol); + response.setStatusCode(500); + response.addHeader("Content-Type", "text/html"); + response.setBody( + http::Errors::getResponseBody(response.getStatusCode())); + } + return (response); +} +