successful merge?

This commit is contained in:
Me
2022-08-08 15:25:16 +02:00
11 changed files with 334 additions and 247 deletions

View File

@@ -1,13 +1,23 @@
- do correct handling of special character in url (/rfc2119_files/errata.js.t%C3%A9l%C3%A9chargement -> /rfc2119_files/errata.js.téléchargement)
IN 42 SUBJECT, PRIORITY :
- chunked request (response not mandatory it seems)
- upload files with confif "upload_dir"
- 505 HTTP Version Not Supported
- CGI
- handle redirection
- index and autoindex
- Ecrire des tests !
-----------------------------
- replace atoi() with a better function
- 408 Request Timeout
- gerer le champ "Accept" du client
- gerer les ".." dans un URL (verifier que l'on ne sort pas du dossier "root")
- do correct handling of special character in url (/rfc2119_files/errata.js.t%C3%A9l%C3%A9chargement -> /rfc2119_files/errata.js.téléchargement)
- maybe add a "last_action_time" in Client for timeout handling
little global timeout on epoll, like 100ms, then find client that actualy need to timeout
if (actual_time - client.last_action_time > 10000ms){timeout(client)}
- add headers "Date" and "Last-Modified" to response
- change "std::string" to reference "std::string &" in most functions
and add "const" if apropriate.
- http_method en mode binary flags. "std::vector<http_method> allow_methods" -> "unsigned int allow_methods;"
- Dans le parsing, trier les "locations" par ordre de precision.
Compter les "/" dans le chemin, les locations avec le plus de "/" seront en premier dans le vector.
- Il faut vérifier le path de la requête, voir si le serveur est bien censé délivrer cette ressource et si le client y a accès, avant d'appeler le CGI.

View File

@@ -1,13 +1,19 @@
#include "Client.hpp"
char Client::buf[MAX_FILESIZE+1];
/*********************************************
* COPLIENS
*********************************************/
Client::Client() : fd(0), body_size(0), status(0) {
Client::Client()
: fd(0),
lsocket(NULL),
status(0),
header_complete(false),
read_body_size(0),
assigned_server(NULL),
assigned_location(NULL)
{
return;
}
@@ -54,9 +60,12 @@ void Client::parse_request()
void Client::clear()
{
clear_request();
header_complete = false;
read_body_size = 0;
assigned_server = NULL;
assigned_location = NULL;
raw_request.clear();
response.clear();
body_size = 0;
status = 0;
}
@@ -128,6 +137,8 @@ void Client::_parse_request_headers( std::vector<std::string> list )
void Client::_parse_request_body( size_t pos )
{
// TODO : a revoir avec une std::string,
// pour ne pas avoir le probleme d'un '0' qui marque la fin des données
std::string body = &raw_request[pos];
_request.body = body;

View File

@@ -7,6 +7,7 @@
# include <map>
# include <vector>
# include "utils.hpp"
# include "ServerConfig.hpp"
struct Request
{
@@ -17,7 +18,6 @@ struct Request
std::string body;
};
# define MAX_FILESIZE 1000000 // (1Mo)
class Client
{
public:
@@ -27,12 +27,16 @@ class Client
//Client &operator=(Client const &rhs);
int fd;
const listen_socket *lsocket;
std::string raw_request;
std::string response;
static char buf[MAX_FILESIZE+1];
size_t body_size;
unsigned int status;
listen_socket *lsocket;
bool header_complete;
size_t read_body_size;
ServerConfig *assigned_server; // cant be const cause of error_pages.operator[]
const LocationConfig *assigned_location;
// const functions ?
http_method get_method();

View File

@@ -44,7 +44,7 @@ int main(int ac, char **av)
}
catch (std::exception& e)
{
std::cout << e.what() << '\n';
std::cerr << e.what() << '\n';
}
return (0);

View File

@@ -1,6 +1,14 @@
#include "utils.hpp"
void throw_test()
{
static int i = 0;
++i;
if (i % 8 == 0)
throw std::bad_alloc();
}
std::vector<std::string> split(std::string input, char delimiter)
{
std::vector<std::string> answer;

View File

@@ -50,5 +50,6 @@ http_method str_to_http_method(std::string &str);
std::string http_methods_to_str(unsigned int methods);
int path_is_valid(std::string path);
void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr);
void throw_test();
#endif

View File

@@ -40,6 +40,8 @@ void signal_handler(int signum);
# define FAILURE -1
# define SUCCESS 1
# define MIME_TYPE_DEFAULT "application/octet-stream"
class Webserv
{
public:
@@ -73,16 +75,17 @@ class Webserv
void _read_request(Client *client);
// response.cpp
void _response(Client *client);
void _send_response(Client *client, ServerConfig &server);
void _send_response(Client *client);
void _append_base_headers(Client *client);
void _construct_response(Client *client, ServerConfig &server);
void _process_method(Client *client, ServerConfig &server, LocationConfig &location);
void _construct_response(Client *client);
void _process_method(Client *client);
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 _error_html_response(Client *client);
void _append_body(Client *client, const std::string &body, const std::string &file_extension = "");
void _get(Client *client, ServerConfig &server, LocationConfig &location);
void _get(Client *client);
// void _get(Client *client, ServerConfig &server, LocationConfig &location);
// in progress
void _autoindex(Client *client, LocationConfig &location, std::string &path);
@@ -90,14 +93,15 @@ class Webserv
void _get_file(Client *client, const std::string &path);
void _post(Client *client, ServerConfig &server, LocationConfig &location);
void _post(Client *client);
void _post_file(Client *client, const std::string &path);
void _delete(Client *client, ServerConfig &server, LocationConfig &location);
void _delete(Client *client);
void _delete_file(Client *client, const std::string &path);
ServerConfig &_determine_process_server(Client *client);
LocationConfig &_determine_location(ServerConfig &server, std::string &path);
ServerConfig *_determine_process_server(Client *client); // cant be const cause of error_pages.operator[]
const LocationConfig *_determine_location(const ServerConfig &server, const std::string &path) const;
std::string _determine_file_extension(const std::string &path) const;
// cgi_script.cpp
bool _is_cgi(Client *client);
void _exec_cgi(Client *client);

View File

@@ -89,132 +89,144 @@ void Webserv::_listen(int socket_fd, unsigned int max_connections)
void Webserv::_init_http_status_map()
{
_http_status[200] = S200;
_http_status[201] = S201;
_http_status[204] = S204;
/* "map.insert()" over "map.operator[]" :
** http://www.uml.org.cn/c%2B%2B/pdf/EffectiveSTL.pdf#page=93
*/
typedef std::map<int, std::string>::value_type status_pair;
_http_status[400] = S400;
_http_status[403] = S403;
_http_status[404] = S404;
_http_status[405] = S405;
_http_status[413] = S413;
// _http_status.insert(std::make_pair(200, S200)); // equivalent
_http_status.insert(status_pair(200, S200));
_http_status.insert(status_pair(201, S201));
_http_status.insert(status_pair(204, S204));
_http_status[500] = S500;
_http_status[501] = S501;
_http_status.insert(status_pair(400, S400));
_http_status.insert(status_pair(403, S403));
_http_status.insert(status_pair(404, S404));
_http_status.insert(status_pair(405, S405));
_http_status.insert(status_pair(413, S413));
_http_status.insert(status_pair(500, S500));
_http_status.insert(status_pair(501, S501));
}
void Webserv::_init_mime_types_map()
{
_mime_types[""] = "application/octet-stream";
/* From :
** http://nginx.org/en/docs/http/ngx_http_core_module.html#types
*/
typedef std::map<std::string, std::string>::value_type mime_pair;
_mime_types["html"] = "text/html";
_mime_types["htm"] = "text/html";
_mime_types["shtml"] = "text/html";
_mime_types["css"] = "text/css";
_mime_types["xml"] = "text/xml";
_mime_types["gif"] = "image/gif";
_mime_types["jpeg"] = "image/jpeg";
_mime_types["jpg"] = "image/jpeg";
_mime_types["js"] = "application/javascript";
_mime_types["atom"] = "application/atom+xml";
_mime_types["rss"] = "application/rss+xml";
_mime_types.insert(mime_pair("", MIME_TYPE_DEFAULT));
_mime_types["mml"] = "text/mathml";
_mime_types["txt"] = "text/plain";
_mime_types["jad"] = "text/vnd.sun.j2me.app-descriptor";
_mime_types["wml"] = "text/vnd.wap.wml";
_mime_types["htc"] = "text/x-component";
_mime_types.insert(mime_pair("html", "text/html"));
_mime_types.insert(mime_pair("html", "text/html"));
_mime_types.insert(mime_pair("htm", "text/html"));
_mime_types.insert(mime_pair("shtml", "text/html"));
_mime_types.insert(mime_pair("css", "text/css"));
_mime_types.insert(mime_pair("xml", "text/xml"));
_mime_types.insert(mime_pair("gif", "image/gif"));
_mime_types.insert(mime_pair("jpeg", "image/jpeg"));
_mime_types.insert(mime_pair("jpg", "image/jpeg"));
_mime_types.insert(mime_pair("js", "application/javascript"));
_mime_types.insert(mime_pair("atom", "application/atom+xml"));
_mime_types.insert(mime_pair("rss", "application/rss+xml"));
_mime_types["png"] = "image/png";
_mime_types["tif"] = "image/tiff";
_mime_types["tiff"] = "image/tiff";
_mime_types["wbmp"] = "image/vnd.wap.wbmp";
_mime_types["ico"] = "image/x-icon";
_mime_types["jng"] = "image/x-jng";
_mime_types["bmp"] = "image/x-ms-bmp";
_mime_types["svg"] = "image/svg+xml";
_mime_types["svgz"] = "image/svg+xml";
_mime_types["webp"] = "image/webp";
_mime_types.insert(mime_pair("mml", "text/mathml"));
_mime_types.insert(mime_pair("txt", "text/plain"));
_mime_types.insert(mime_pair("jad", "text/vnd.sun.j2me.app-descriptor"));
_mime_types.insert(mime_pair("wml", "text/vnd.wap.wml"));
_mime_types.insert(mime_pair("htc", "text/x-component"));
_mime_types["woff"] = "application/font-woff";
_mime_types["jar"] = "application/java-archive";
_mime_types["war"] = "application/java-archive";
_mime_types["ear"] = "application/java-archive";
_mime_types["json"] = "application/json";
_mime_types["hqx"] = "application/mac-binhex40";
_mime_types["doc"] = "application/msword";
_mime_types["pdf"] = "application/pdf";
_mime_types["ps"] = "application/postscript";
_mime_types["eps"] = "application/postscript";
_mime_types["ai"] = "application/postscript";
_mime_types["rtf"] = "application/rtf";
_mime_types["m3u8"] = "application/vnd.apple.mpegurl";
_mime_types["xls"] = "application/vnd.ms-excel";
_mime_types["eot"] = "application/vnd.ms-fontobject";
_mime_types["ppt"] = "application/vnd.ms-powerpoint";
_mime_types["wmlc"] = "application/vnd.wap.wmlc";
_mime_types["kml"] = "application/vnd.google-earth.kml+xml";
_mime_types["kmz"] = "application/vnd.google-earth.kmz";
_mime_types["7z"] = "application/x-7z-compressed";
_mime_types["cco"] = "application/x-cocoa";
_mime_types["jardiff"] = "application/x-java-archive-diff";
_mime_types["jnlp"] = "application/x-java-jnlp-file";
_mime_types["run"] = "application/x-makeself";
_mime_types["pl"] = "application/x-perl";
_mime_types["pm"] = "application/x-perl";
_mime_types["prc"] = "application/x-pilot";
_mime_types["pdb"] = "application/x-pilot";
_mime_types["rar"] = "application/x-rar-compressed";
_mime_types["rpm"] = "application/x-redhat-package-manager";
_mime_types["sea"] = "application/x-sea";
_mime_types["swf"] = "application/x-shockwave-flash";
_mime_types["sit"] = "application/x-stuffit";
_mime_types["tcl"] = "application/x-tcl";
_mime_types["tk"] = "application/x-tcl";
_mime_types["der"] = "application/x-x509-ca-cert";
_mime_types["pem"] = "application/x-x509-ca-cert";
_mime_types["crt"] = "application/x-x509-ca-cert";
_mime_types["xpi"] = "application/x-xpinstall";
_mime_types["xhtml"] = "application/xhtml+xml";
_mime_types["xspf"] = "application/xspf+xml";
_mime_types["zip"] = "application/zip";
_mime_types.insert(mime_pair("png", "image/png"));
_mime_types.insert(mime_pair("tif", "image/tiff"));
_mime_types.insert(mime_pair("tiff", "image/tiff"));
_mime_types.insert(mime_pair("wbmp", "image/vnd.wap.wbmp"));
_mime_types.insert(mime_pair("ico", "image/x-icon"));
_mime_types.insert(mime_pair("jng", "image/x-jng"));
_mime_types.insert(mime_pair("bmp", "image/x-ms-bmp"));
_mime_types.insert(mime_pair("svg", "image/svg+xml"));
_mime_types.insert(mime_pair("svgz", "image/svg+xml"));
_mime_types.insert(mime_pair("webp", "image/webp"));
_mime_types["bin"] = "application/octet-stream";
_mime_types["exe"] = "application/octet-stream";
_mime_types["dll"] = "application/octet-stream";
_mime_types["deb"] = "application/octet-stream";
_mime_types["dmg"] = "application/octet-stream";
_mime_types["iso"] = "application/octet-stream";
_mime_types["img"] = "application/octet-stream";
_mime_types["msi"] = "application/octet-stream";
_mime_types["msp"] = "application/octet-stream";
_mime_types["msm"] = "application/octet-stream";
_mime_types.insert(mime_pair("woff", "application/font-woff"));
_mime_types.insert(mime_pair("jar", "application/java-archive"));
_mime_types.insert(mime_pair("war", "application/java-archive"));
_mime_types.insert(mime_pair("ear", "application/java-archive"));
_mime_types.insert(mime_pair("json", "application/json"));
_mime_types.insert(mime_pair("hqx", "application/mac-binhex40"));
_mime_types.insert(mime_pair("doc", "application/msword"));
_mime_types.insert(mime_pair("pdf", "application/pdf"));
_mime_types.insert(mime_pair("ps", "application/postscript"));
_mime_types.insert(mime_pair("eps", "application/postscript"));
_mime_types.insert(mime_pair("ai", "application/postscript"));
_mime_types.insert(mime_pair("rtf", "application/rtf"));
_mime_types.insert(mime_pair("m3u8", "application/vnd.apple.mpegurl"));
_mime_types.insert(mime_pair("xls", "application/vnd.ms-excel"));
_mime_types.insert(mime_pair("eot", "application/vnd.ms-fontobject"));
_mime_types.insert(mime_pair("ppt", "application/vnd.ms-powerpoint"));
_mime_types.insert(mime_pair("wmlc", "application/vnd.wap.wmlc"));
_mime_types.insert(mime_pair("kml", "application/vnd.google-earth.kml+xml"));
_mime_types.insert(mime_pair("kmz", "application/vnd.google-earth.kmz"));
_mime_types.insert(mime_pair("7z", "application/x-7z-compressed"));
_mime_types.insert(mime_pair("cco", "application/x-cocoa"));
_mime_types.insert(mime_pair("jardiff", "application/x-java-archive-diff"));
_mime_types.insert(mime_pair("jnlp", "application/x-java-jnlp-file"));
_mime_types.insert(mime_pair("run", "application/x-makeself"));
_mime_types.insert(mime_pair("pl", "application/x-perl"));
_mime_types.insert(mime_pair("pm", "application/x-perl"));
_mime_types.insert(mime_pair("prc", "application/x-pilot"));
_mime_types.insert(mime_pair("pdb", "application/x-pilot"));
_mime_types.insert(mime_pair("rar", "application/x-rar-compressed"));
_mime_types.insert(mime_pair("rpm", "application/x-redhat-package-manager"));
_mime_types.insert(mime_pair("sea", "application/x-sea"));
_mime_types.insert(mime_pair("swf", "application/x-shockwave-flash"));
_mime_types.insert(mime_pair("sit", "application/x-stuffit"));
_mime_types.insert(mime_pair("tcl", "application/x-tcl"));
_mime_types.insert(mime_pair("tk", "application/x-tcl"));
_mime_types.insert(mime_pair("der", "application/x-x509-ca-cert"));
_mime_types.insert(mime_pair("pem", "application/x-x509-ca-cert"));
_mime_types.insert(mime_pair("crt", "application/x-x509-ca-cert"));
_mime_types.insert(mime_pair("xpi", "application/x-xpinstall"));
_mime_types.insert(mime_pair("xhtml", "application/xhtml+xml"));
_mime_types.insert(mime_pair("xspf", "application/xspf+xml"));
_mime_types.insert(mime_pair("zip", "application/zip"));
_mime_types["docx"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
_mime_types["xlsx"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
_mime_types["pptx"] = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
_mime_types.insert(mime_pair("bin", "application/octet-stream"));
_mime_types.insert(mime_pair("exe", "application/octet-stream"));
_mime_types.insert(mime_pair("dll", "application/octet-stream"));
_mime_types.insert(mime_pair("deb", "application/octet-stream"));
_mime_types.insert(mime_pair("dmg", "application/octet-stream"));
_mime_types.insert(mime_pair("iso", "application/octet-stream"));
_mime_types.insert(mime_pair("img", "application/octet-stream"));
_mime_types.insert(mime_pair("msi", "application/octet-stream"));
_mime_types.insert(mime_pair("msp", "application/octet-stream"));
_mime_types.insert(mime_pair("msm", "application/octet-stream"));
_mime_types["mid"] = "audio/midi";
_mime_types["midi"] = "audio/midi";
_mime_types["kar"] = "audio/midi";
_mime_types["mp3"] = "audio/mpeg";
_mime_types["ogg"] = "audio/ogg";
_mime_types["m4a"] = "audio/x-m4a";
_mime_types["ra"] = "audio/x-realaudio";
_mime_types.insert(mime_pair("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"));
_mime_types.insert(mime_pair("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
_mime_types.insert(mime_pair("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"));
_mime_types["3gpp"] = "video/3gpp";
_mime_types["3gp"] = "video/3gpp";
_mime_types["ts"] = "video/mp2t";
_mime_types["mp4"] = "video/mp4";
_mime_types["mpeg"] = "video/mpeg";
_mime_types["mpg"] = "video/mpeg";
_mime_types["mov"] = "video/quicktime";
_mime_types["webm"] = "video/webm";
_mime_types["flv"] = "video/x-flv";
_mime_types["m4v"] = "video/x-m4v";
_mime_types["mng"] = "video/x-mng";
_mime_types["asx"] = "video/x-ms-asf";
_mime_types["asf"] = "video/x-ms-asf";
_mime_types["wmv"] = "video/x-ms-wmv";
_mime_types["avi"] = "video/x-msvideo";
_mime_types.insert(mime_pair("mid", "audio/midi"));
_mime_types.insert(mime_pair("midi", "audio/midi"));
_mime_types.insert(mime_pair("kar", "audio/midi"));
_mime_types.insert(mime_pair("mp3", "audio/mpeg"));
_mime_types.insert(mime_pair("ogg", "audio/ogg"));
_mime_types.insert(mime_pair("m4a", "audio/x-m4a"));
_mime_types.insert(mime_pair("ra", "audio/x-realaudio"));
_mime_types.insert(mime_pair("3gpp", "video/3gpp"));
_mime_types.insert(mime_pair("3gp", "video/3gpp"));
_mime_types.insert(mime_pair("ts", "video/mp2t"));
_mime_types.insert(mime_pair("mp4", "video/mp4"));
_mime_types.insert(mime_pair("mpeg", "video/mpeg"));
_mime_types.insert(mime_pair("mpg", "video/mpeg"));
_mime_types.insert(mime_pair("mov", "video/quicktime"));
_mime_types.insert(mime_pair("webm", "video/webm"));
_mime_types.insert(mime_pair("flv", "video/x-flv"));
_mime_types.insert(mime_pair("m4v", "video/x-m4v"));
_mime_types.insert(mime_pair("mng", "video/x-mng"));
_mime_types.insert(mime_pair("asx", "video/x-ms-asf"));
_mime_types.insert(mime_pair("asf", "video/x-ms-asf"));
_mime_types.insert(mime_pair("wmv", "video/x-ms-wmv"));
_mime_types.insert(mime_pair("avi", "video/x-msvideo"));
}

View File

@@ -2,6 +2,7 @@
#include "Webserv.hpp"
#define BUFSIZE 8192
#define MAX_HEADER_SIZE 42000 // arbitrary
void Webserv::_request(Client *client)
{
@@ -10,11 +11,12 @@ void Webserv::_request(Client *client)
_handle_last_signal();
}
void Webserv::_read_request(Client *client)
void Webserv::_read_request(Client *client) // Messy, Need refactoring
{
char buf[BUFSIZE+1];
char buf[BUFSIZE];
ssize_t ret;
std::cerr << "call recv()" << "\n" ;
ret = ::recv(client->fd, buf, BUFSIZE, 0);
std::cerr << "recv() on fd(" << client->fd << ") returned = " << ret << "\n" ;
if (ret == -1)
@@ -25,20 +27,58 @@ void Webserv::_read_request(Client *client)
_close_client(client->fd);
return ;
}
if (ret == 0) // Not sure what to do in case of 0. Just close ?
if (ret == 0)
{
_close_client(client->fd);
return ;
}
/*
if (ret == BUFSIZE)
// send error like "request too long" to client
*/
buf[ret] = '\0';
client->raw_request.append(buf);
client->parse_request();
client->raw_request.append(buf, ret);
if (!client->header_complete)
{
if (client->raw_request.find(CRLF CRLF) != std::string::npos)
{
client->header_complete = true;
client->parse_request(); // TODO : split function to avoid useless parsing ?
client->assigned_server = _determine_process_server(client);
client->assigned_location = _determine_location(*client->assigned_server, client->get_path());
if (!client->get_headers("Content-Length").empty()
&& ::atoi(client->get_headers("Content-Length").c_str()) > (int)client->assigned_server->client_body_limit)
{
client->status = 413;
_epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD);
return;
}
}
else if (client->raw_request.size() > MAX_HEADER_SIZE)
{
client->status = 400;
_epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD);
return;
}
}
else if (client->header_complete)
{
client->read_body_size += ret;
if (client->read_body_size > client->assigned_server->client_body_limit)
{
client->status = 413;
_epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD);
return;
}
if ((int)client->read_body_size > ::atoi(client->get_headers("Content-Length").c_str()))
{
client->parse_request(); // reparse for the body
_epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD);
return;
}
}
_epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD);
if (client->header_complete && client->get_headers("Content-Type").empty() && client->get_headers("Content-Length").empty() )
{
_epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD);
return;
}
}

View File

@@ -3,26 +3,25 @@
void Webserv::_response(Client *client)
{
client->status = 200; // default value
ServerConfig &server = _determine_process_server(client);
_send_response(client, server);
_send_response(client);
if (g_last_signal)
_handle_last_signal();
}
void Webserv::_send_response(Client *client, ServerConfig &server)
void Webserv::_send_response(Client *client)
{
ssize_t ret;
std::cerr << "send()\n";
_append_base_headers(client);
_construct_response(client, server);
if (!client->status)
_construct_response(client);
_insert_status_line(client);
if (client->status >= 400)
_error_html_response(client, server);
_error_html_response(client);
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 +30,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);
@@ -64,19 +51,18 @@ void Webserv::_append_base_headers(Client *client)
client->response.append("Connection: keep-alive" CRLF);
}
void Webserv::_construct_response(Client *client, ServerConfig &server)
void Webserv::_construct_response(Client *client)
{
// TODO : Move this in read(), stop read if content too large
if (client->get_body().size() > server.client_body_limit)
if (client->get_body().size() > client->assigned_server->client_body_limit)
{
client->status = 413;
return;
}
LocationConfig &location = _determine_location(server, client->get_path());
_process_method(client, server, location);
_process_method(client);
}
void Webserv::_process_method(Client *client, ServerConfig &server, LocationConfig &location)
void Webserv::_process_method(Client *client)
{
unsigned int allow_methods = ANY_METHODS; // TEMP VARIABLE
// after update in ConfigParser, use the "allow_methods" of location.
@@ -91,11 +77,11 @@ void Webserv::_process_method(Client *client, ServerConfig &server, LocationConf
switch (client->get_method())
{
case (GET):
_get(client, server, location); break;
_get(client); break;
case (POST):
_post(client, server, location); break;
_post(client); break;
case (DELETE):
_delete(client, server, location); break;
_delete(client); break;
default:
break;
}
@@ -119,20 +105,20 @@ void Webserv::_insert_status_line(Client *client)
client->response.insert(0, status_line);
}
void Webserv::_error_html_response(Client *client, ServerConfig &server)
void Webserv::_error_html_response(Client *client)
{
if (server.error_pages[client->status].empty())
if (client->assigned_server->error_pages[client->status].empty())
{
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]);
_get_file(client, client->assigned_server->error_pages[client->status]);
}
#define INDEX "index.html" // temp wip
void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &location)
//#define INDEX "index.html" // temp wip
void Webserv::_get(Client *client)
{
/* RULES **
@@ -150,11 +136,13 @@ THIS NEEDS WORK...
/* if (path == "/") // TODO : index and autoindex
path.append(INDEX);
<<<<<<< HEAD
path.insert(0, location.root);
*/
path.insert(0, client->assigned_location->root);
// that was actually a horrible idea...
path.insert(0, location.root);
// path.insert(0, location.root);
std::cerr << "path = " << path << "\n";
// path = root + location.path
@@ -266,10 +254,16 @@ void Webserv::_autoindex(Client *client, LocationConfig &location, std::string &
# 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;
std::cout << "made it to get_file\n";
@@ -287,7 +281,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';
@@ -303,13 +297,12 @@ void Webserv::_get_file(Client *client, const std::string &path)
// Then chunk
client->status = 500; // WIP temp
std::cerr << "File too large for non chunk body\n";
ifd.close();
return ;
}
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;
@@ -317,59 +310,46 @@ 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 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)
void Webserv::_post(Client *client)
{
(void)server; // To remove from arg if we determine its useless
/*
WIP
https://www.rfc-editor.org/rfc/rfc9110.html#name-post
*/
std::string path = client->get_path();
path.insert(0, location.root);
path.insert(0, client->assigned_location->root);
/* CGI Here ? */
@@ -394,7 +374,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';
@@ -402,11 +382,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';
@@ -422,20 +402,17 @@ void Webserv::_post_file(Client *client, const std::string &path)
client->status = 201;
// WIP https://www.rfc-editor.org/rfc/rfc9110.html#section-9.3.3-4
}
ofd.close();
}
}
void Webserv::_delete(Client *client, ServerConfig &server, LocationConfig &location)
void Webserv::_delete(Client *client)
{
(void)server; // To remove from arg if we determine its useless
/*
WIP
https://www.rfc-editor.org/rfc/rfc9110.html#name-delete
*/
std::string path = client->get_path();
path.insert(0, location.root);
path.insert(0, client->assigned_location->root);
/* CGI Here ? */
@@ -466,7 +443,7 @@ void Webserv::_delete_file(Client *client, const std::string &path)
}
}
ServerConfig &Webserv::_determine_process_server(Client *client)
ServerConfig *Webserv::_determine_process_server(Client *client)
{
/*
http://nginx.org/en/docs/http/request_processing.html
@@ -491,16 +468,16 @@ ServerConfig &Webserv::_determine_process_server(Client *client)
++it;
}
if (it != _servers.end())
return (*it);
return (&(*it));
else
return (*default_server);
return (&(*default_server));
}
LocationConfig &Webserv::_determine_location(ServerConfig &server, std::string &path)
const LocationConfig *Webserv::_determine_location(const ServerConfig &server, const std::string &path) const
{
// std::cout << "determin location path sent: " << path << '\n';
std::vector<LocationConfig>::iterator it = server.locations.begin();
std::vector<LocationConfig>::const_iterator it = server.locations.begin();
while (it != server.locations.end())
{
// std::cout << it->path << " -- ";
@@ -514,7 +491,15 @@ LocationConfig &Webserv::_determine_location(ServerConfig &server, std::string &
++it;
}
if (it != server.locations.end())
return (*it);
return (&(*it));
else
return (server.locations.front());
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(""));
}

View File

@@ -34,17 +34,29 @@ void Webserv::run()
i = 0;
while (i < nfds)
{
// TODO : handle EPOLLERR and EPOLLHUP
it_socket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd);
if (it_socket != _listen_sockets.end() && events[i].events & EPOLLIN)
_accept_connection(*it_socket);
else if (events[i].events & EPOLLIN)
_request( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) );
else if (events[i].events & EPOLLOUT)
_response( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) );
++i;
if (!g_run)
try
{
// TODO : handle EPOLLERR and EPOLLHUP
it_socket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd);
if (it_socket != _listen_sockets.end() && events[i].events & EPOLLIN)
_accept_connection(*it_socket);
else if (events[i].events & EPOLLIN)
_request( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) );
else if (events[i].events & EPOLLOUT)
_response( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) );
++i;
if (!g_run)
break;
}
catch (const std::bad_alloc& e)
{
std::cerr << e.what() << '\n';
_close_all_clients();
/* Swap to free the memory
From : http://www.uml.org.cn/c%2B%2B/pdf/EffectiveSTL.pdf#page=66 */
std::vector<Client>().swap(_clients);
break;
}
}
}
}