From 8ec1353723b61d0b3197434344e61ac207c848ed Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Sun, 7 Aug 2022 01:38:33 +0200 Subject: [PATCH] fixed response.append(body) problem. + File I/O working but maybe not perfect (it seems complicated to do it with std::filebuf) + fixed Content-Type for unknown file extension --- srcs/Client.cpp | 5 +- srcs/Client.hpp | 3 -- srcs/webserv/Webserv.hpp | 7 ++- srcs/webserv/init.cpp | 5 +- srcs/webserv/response.cpp | 96 ++++++++++++++++++--------------------- 5 files changed, 54 insertions(+), 62 deletions(-) diff --git a/srcs/Client.cpp b/srcs/Client.cpp index f994d57..c63cc91 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -1,13 +1,11 @@ #include "Client.hpp" -char Client::buf[MAX_FILESIZE+1]; - /********************************************* * COPLIENS *********************************************/ -Client::Client() : fd(0), body_size(0), status(0) { +Client::Client() : fd(0), status(0) { return; } @@ -56,7 +54,6 @@ void Client::clear() clear_request(); raw_request.clear(); response.clear(); - body_size = 0; status = 0; } diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 5a67601..eee05aa 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -17,7 +17,6 @@ struct Request std::string body; }; -# define MAX_FILESIZE 1000000 // (1Mo) class Client { public: @@ -29,8 +28,6 @@ class Client int fd; std::string raw_request; std::string response; - static char buf[MAX_FILESIZE+1]; - size_t body_size; unsigned int status; listen_socket *lsocket; diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index c5d6409..d2de04f 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -38,6 +38,8 @@ void signal_handler(int signum); # define FAILURE -1 # define SUCCESS 1 +# define MIME_TYPE_DEFAULT "application/octet-stream" + class Webserv { public: @@ -78,7 +80,7 @@ class Webserv void _process_method(Client *client, ServerConfig &server, LocationConfig &location); void _insert_status_line(Client *client); void _error_html_response(Client *client, ServerConfig &server); - void _append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension = ""); + void _append_body(Client *client, const std::string &body, const std::string &file_extension = ""); void _get(Client *client, ServerConfig &server, LocationConfig &location); void _get_file(Client *client, const std::string &path); @@ -90,7 +92,8 @@ class Webserv void _delete_file(Client *client, const std::string &path); ServerConfig &_determine_process_server(Client *client); - LocationConfig &_determine_location(ServerConfig &server, std::string &path); + LocationConfig &_determine_location(ServerConfig &server, const std::string &path); + std::string _determine_file_extension(const std::string &path) const; // cgi_script.cpp bool _is_cgi(Client *client); void _exec_cgi(Client *client); diff --git a/srcs/webserv/init.cpp b/srcs/webserv/init.cpp index 3a33ed1..f86d5ee 100644 --- a/srcs/webserv/init.cpp +++ b/srcs/webserv/init.cpp @@ -105,7 +105,10 @@ void Webserv::_init_http_status_map() void Webserv::_init_mime_types_map() { - _mime_types[""] = "application/octet-stream"; +/* +** From : http://nginx.org/en/docs/http/ngx_http_core_module.html#types +*/ + _mime_types[""] = MIME_TYPE_DEFAULT; _mime_types["html"] = "text/html"; _mime_types["htm"] = "text/html"; diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 134dcff..927d103 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -23,6 +23,7 @@ void Webserv::_send_response(Client *client, ServerConfig &server) if (client->status >= 400) _error_html_response(client, server); + std::cerr << "client->response.size() = " << client->response.size() << "\n"; // DEBUG ret = ::send(client->fd, client->response.c_str(), client->response.size(), 0); if (ret == -1) { @@ -31,19 +32,7 @@ void Webserv::_send_response(Client *client, ServerConfig &server) _close_client(client->fd); return ; } - - // Body send (WIP for working binary files) - if (client->body_size) - { - ret = ::send(client->fd, client->buf, client->body_size, 0); - if (ret == -1) - { - std::perror("err send()"); - std::cerr << "client.fd =" << client->fd << "\n"; // DEBUG - _close_client(client->fd); - return ; - } - } + std::cerr << "ret send() = " << ret << "\n"; // DEBUG if (client->get_headers("Connection") == "close") _close_client(client->fd); @@ -125,7 +114,7 @@ void Webserv::_error_html_response(Client *client, ServerConfig &server) { std::string html_page = HTML_ERROR; ::replace_all_substr(html_page, STATUS_PLACEHOLDER, _http_status[client->status]); - _append_body(client, html_page.c_str(), html_page.size(), "html"); + _append_body(client, html_page, "html"); } else _get_file(client, server.error_pages[client->status]); @@ -156,10 +145,16 @@ void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &locatio _get_file(client, path); } +# define MAX_FILESIZE 1000000 // (1Mo) void Webserv::_get_file(Client *client, const std::string &path) { - std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ? - // char buf[MAX_FILESIZE+1]; +/* + std::ios::binary + https://gcc.gnu.org/onlinedocs/libstdc++/manual/fstreams.html#std.io.filestreams.binary + tldr : its seems to not be so simple to do read/write of binary file in a portable way. +*/ + std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ? + std::stringstream buf; if (access(path.c_str(), F_OK) == -1) { @@ -175,7 +170,7 @@ void Webserv::_get_file(Client *client, const std::string &path) return ; } - ifd.open(path.c_str(), std::ios::binary | std::ios::ate); // std::ios::binary (binary for files like images ?) + ifd.open(path.c_str(), std::ios::ate); if (!ifd) { std::cerr << path << ": ifd.open fail" << '\n'; @@ -196,8 +191,8 @@ void Webserv::_get_file(Client *client, const std::string &path) } ifd.seekg(0, std::ios::beg); - ifd.read(client->buf, size); - if (!ifd) + buf << ifd.rdbuf(); + if (!ifd || !buf) { std::cerr << path << ": ifd.read fail" << '\n'; client->status = 500; @@ -205,47 +200,36 @@ void Webserv::_get_file(Client *client, const std::string &path) else { client->status = 200; - client->buf[ifd.gcount()] = '\0'; - - std::string file_ext = ""; - size_t dot_pos = path.rfind("."); - std::cerr << "dot_pos = " << dot_pos << "\n"; - if (dot_pos != std::string::npos && dot_pos + 1 < path.size()) - file_ext = path.substr(dot_pos + 1); - std::cerr << "file_ext = " << file_ext << "\n"; - - client->body_size = ifd.gcount(); - // WIP, pass empty body argument because append to string mess up binary file - _append_body(client, "", client->body_size, file_ext); + std::string file_ext = _determine_file_extension(path); + _append_body(client, buf.str(), file_ext); } ifd.close(); } } -void Webserv::_append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension) +void Webserv::_append_body(Client *client, const std::string &body, const std::string &file_extension) { -/* - TODO : determine Content-Type - how ? read the body ? - or before in other way (like based and file extension) and pass here as argument ? - http://nginx.org/en/docs/http/ngx_http_core_module.html#types - Need to look "conf/mime.types" of nginx. Maybe make a map<> based on that. -*/ - const std::string &mime_type = _mime_types[file_extension]; - client->response.append("Content-Type: "); + const std::string &mime_type = _mime_types[file_extension]; + + client->response.append("Content-Type: "); + if (mime_type.empty()) + client->response.append(MIME_TYPE_DEFAULT); + else + { client->response.append(mime_type); if (mime_type.find("text/") != std::string::npos) client->response.append("; charset=UTF-8"); - client->response.append(CRLF); + } + client->response.append(CRLF); - client->response.append("Content-Length: "); - std::string tmp = ::itos(body_size); - client->response.append(tmp); - client->response.append(CRLF); + client->response.append("Content-Length: "); + std::string tmp = ::itos(body.size()); + client->response.append(tmp); + client->response.append(CRLF); - client->response.append(CRLF); - client->response.append(body); + client->response.append(CRLF); + client->response.append(body); } void Webserv::_post(Client *client, ServerConfig &server, LocationConfig &location) @@ -281,7 +265,7 @@ void Webserv::_post_file(Client *client, const std::string &path) return ; } - ofd.open(path.c_str(), std::ios::binary | std::ios::trunc); + ofd.open(path.c_str(), std::ios::trunc); if (!ofd) { std::cerr << path << ": ofd.open fail" << '\n'; @@ -289,11 +273,11 @@ void Webserv::_post_file(Client *client, const std::string &path) } else { - // Used body.size() so Content-Length useless at this point ? + // Content-Length useless at this point ? // Maybe usefull in _read_request() for rejecting too big content. // Need to _determine_process_server() as soon as possible, // like in _read_request() for stopping read if body is too big ? - ofd.write(client->get_body().c_str(), client->get_body().size()); + ofd << client->get_body(); if (!ofd) { std::cerr << path << ": ofd.write fail" << '\n'; @@ -383,7 +367,7 @@ ServerConfig &Webserv::_determine_process_server(Client *client) return (*default_server); } -LocationConfig &Webserv::_determine_location(ServerConfig &server, std::string &path) +LocationConfig &Webserv::_determine_location(ServerConfig &server, const std::string &path) { /* Assume there is at least one location in vector for path "/" @@ -404,3 +388,11 @@ LocationConfig &Webserv::_determine_location(ServerConfig &server, std::string & else return (server.locations.front()); } + +std::string Webserv::_determine_file_extension(const std::string &path) const +{ + size_t dot_pos = path.rfind("."); + if (dot_pos != std::string::npos && dot_pos + 1 < path.size()) + return ( path.substr(dot_pos + 1) ); + return (std::string("")); +}