From 4602844f5ae81d18934403f4434fc89c648b63de Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Tue, 16 Aug 2022 04:00:33 +0200 Subject: [PATCH] Multiples minors changes (cgi env, comment, ...) --- srcs/Client.cpp | 107 ++++++++++++++++++++++++++++-- srcs/Client.hpp | 10 +-- srcs/webserv/Webserv.hpp | 98 +++++++++++++++------------- srcs/webserv/accept.cpp | 4 +- srcs/webserv/cgi.cpp | 25 ++++--- srcs/webserv/http_status.hpp | 4 +- srcs/webserv/method_get.cpp | 30 ++++----- srcs/webserv/response.cpp | 123 +++++------------------------------ 8 files changed, 207 insertions(+), 194 deletions(-) diff --git a/srcs/Client.cpp b/srcs/Client.cpp index 6b04f61..06d0de5 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -75,10 +75,12 @@ Client & Client::operator=( Client const & rhs ) * PUBLIC MEMBER FUNCTIONS *********************************************/ -// http headers : -// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers -// https://www.ibm.com/docs/en/cics-ts/5.3?topic=protocol-http-requests -// https://www.tutorialspoint.com/http/http_requests.htm +/* HTTP Headers : + https://www.iana.org/assignments/http-fields/http-fields.xhtml + https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers + https://www.ibm.com/docs/en/cics-ts/5.3?topic=protocol-http-requests + https://www.tutorialspoint.com/http/http_requests.htm +*/ void Client::parse_request_headers(std::vector &servers) { if (raw_request.find(CRLF CRLF) == NPOS) @@ -96,8 +98,8 @@ void Client::parse_request_headers(std::vector &servers) if (status) return; - assigned_server = ::_determine_process_server(this, servers); - assigned_location = ::_determine_location(*assigned_server, _request.abs_path); + assigned_server = _determine_process_server(this, servers); + assigned_location = _determine_location(*assigned_server, _request.abs_path); _check_request_errors(); if (status) return; @@ -389,6 +391,7 @@ void Client::_parse_request_fields() ::str_map_key_tolower(_request.headers); } +// TODO : I think its now useless. Probably to delete. void Client::_parse_port_hostname(std::string host) { size_t pos; @@ -453,6 +456,98 @@ void Client::_check_request_errors() return; } +ServerConfig *Client::_determine_process_server(Client *client, std::vector &servers) +{ +/* + Behavior like this : + http://nginx.org/en/docs/http/request_processing.html +*/ + + std::string server_name = client->get_rq_headers("Host"); + std::cerr << "server_name = " << server_name << "\n"; + size_t pos = server_name.rfind(':'); + if (pos != NPOS) + server_name.erase(pos); + std::cerr << "server_name = " << server_name << "\n"; + + std::vector::iterator it = servers.begin(); + std::vector::iterator default_server = servers.end(); + + while (it != servers.end()) + { + if (it->host == client->get_cl_lsocket()->host + && it->port == client->get_cl_lsocket()->port) + { + if ( std::find(it->server_name.begin(), it->server_name.end(), server_name) != it->server_name.end() ) + break; + else if (default_server == servers.end()) + default_server = it; + } + ++it; + } + if (it != servers.end()) + return (&(*it)); + else + return (&(*default_server)); +} + +// const? +const LocationConfig *Client::_determine_location(const ServerConfig &server, const std::string &path) +{ +/* RULES *** + +If a path coresponds exactly to a location, use that one +if no path coresponds then use the most correct one + most correct means the most precise branch that is still above + the point we are aiming for + +New Rule for location paths, they never end in / +Sooo +If we get a url that ends in / ignore the last / + +*/ + + std::string uri = path; + if (uri[uri.size() - 1] == '/' && uri.size() != 1) + uri.erase(uri.size() - 1); + + + for (std::vector::const_iterator it = server.locations.begin(); it != server.locations.end(); it++) + { +// std::cout << it->path << " -- "; + if (it->path.size() > uri.size()) + continue ; + + if (uri.compare(0, it->path.size(), it->path) == 0) + { + if (it->path.size() == uri.size()) + return (&(*it)); + else if (uri[it->path.size()] == '/') + return (&(*it)); + // this works cuz only ever looking for a / burried in a longer path + } + } + return (&(server.locations.back())); + + +// /test/mdr +// /test/mdr/ +// /test/mdrBST + +/////// More stuff to check this still works with + +// /test/test_ +// /test/test_/ +// /test/test_deeper +// /test/test_deeper/ +// /test/test_deepei +// /test/test_deepei/ +// /test/test_deeperi +// /test/test_deeper/super_deep/ +// /test/aaaaaaaaaaa/super_deep/ + +} + /********************************************* * OVERLOAD *********************************************/ diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 958d482..eac8c44 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -105,15 +105,15 @@ class Client void _parse_chunked_body(size_t pos); void _parse_multipart_body(size_t pos); void _check_request_errors(); + + ServerConfig* + _determine_process_server(Client *client, std::vector &servers); + const LocationConfig* + _determine_location(const ServerConfig &server, const std::string &path); }; bool operator==(const Client& lhs, const Client& rhs); bool operator==(const Client& lhs, int fd); bool operator==(int fd, const Client& rhs); -// Temporary Global Scope. Probably move to Client in the future. -ServerConfig *_determine_process_server(Client *client, std::vector &servers); -const LocationConfig *_determine_location(const ServerConfig &server, const std::string &path); - #endif - diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index ddb784c..c7937cf 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -71,39 +71,53 @@ class Webserv std::map _mime_types; // accept.cpp - void _accept_connection(listen_socket &lsocket); + void _accept_connection(listen_socket &lsocket); std::map - _extract_infos(struct sockaddr_in addr); + _extract_infos(struct sockaddr_in addr); // request.cpp - void _request(Client *client); - int _read_request(Client *client); + void _request(Client *client); + int _read_request(Client *client); // response.cpp - void _response(Client *client); - int _send_response(Client *client); - void _append_base_headers(Client *client); - void _construct_response(Client *client); - void _process_method(Client *client, std::string &path); - void _insert_status_line(Client *client); - void _error_html_response(Client *client); - void _append_body(Client *client, const std::string &body, const std::string &file_extension = ""); - // 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; - // method_get.cpp - -// move later + void _response(Client *client); + int _send_response(Client *client); + void _append_base_headers(Client *client); + void _construct_response(Client *client); + void _process_method(Client *client, std::string &path); std::string _replace_url_root(Client *client, std::string path); - - void _get(Client *client, std::string &path); - void _get_file(Client *client, const std::string &path); - void _autoindex(Client *client, const std::string &path); + void _insert_status_line(Client *client); + void _error_html_response(Client *client); + void _append_body(Client *client, const std::string &body, const std::string &file_extension = ""); + // method_get.cpp + void _get(Client *client, std::string &path); + void _get_file(Client *client, const std::string &path); + void _autoindex(Client *client, const std::string &path); + std::string _determine_file_extension(const std::string &path) const; // method_post.cpp - void _post(Client *client, const std::string &path); - void _upload_files(Client *client); + void _post(Client *client, const std::string &path); + void _upload_files(Client *client); // method_delete.cpp - void _delete(Client *client, const std::string &path); - void _delete_file(Client *client, const std::string &path); - // cgi_script.cpp + void _delete(Client *client, const std::string &path); + void _delete_file(Client *client, const std::string &path); + // epoll_update.cpp + int _epoll_update(int fd, uint32_t events, int op); + int _epoll_update(int fd, uint32_t events, int op, void *ptr); + // signal.cpp + void _handle_last_signal(); + // close.cpp + void _close_client(int fd); + void _close_all_clients(); + void _close_all_listen_sockets(); + void _reopen_lsocket(std::vector::iterator it); + void _handle_epoll_error_lsocket(uint32_t events, std::vector::iterator it); + void _handle_epoll_error_client(uint32_t events, int fd); + // init.cpp + void _bind(int socket_fd, in_port_t port, std::string host); + void _listen(int socket_fd, unsigned int max_connections); + void _init_http_status_map(); + void _init_mime_types_map(); + // timeout.cpp + void _timeout(); + // cgi.cpp bool _is_cgi(Client *client, std::string path); size_t _cgi_pos(Client *client, std::string &path, size_t pos); std::string _exec_cgi(Client *client); @@ -117,26 +131,18 @@ class Webserv void _check_script_fields(Client *client, std::string & output); void _add_script_body_length_header(std::string & output); void _remove_body_leading_empty_lines(std::string & output); - // epoll_update.cpp - int _epoll_update(int fd, uint32_t events, int op); - int _epoll_update(int fd, uint32_t events, int op, void *ptr); - // signal.cpp - void _handle_last_signal(); - // close.cpp - void _close_client(int fd); - void _close_all_clients(); - void _close_all_listen_sockets(); - void _reopen_lsocket(std::vector::iterator it); - void _handle_epoll_error_lsocket(uint32_t events, std::vector::iterator it); - void _handle_epoll_error_client(uint32_t events, int fd); - // init.cpp - void _bind(int socket_fd, in_port_t port, std::string host); - void _listen(int socket_fd, unsigned int max_connections); - void _init_http_status_map(); - void _init_mime_types_map(); - // timeout.cpp - void _timeout(); }; #endif +/* + HTTP Semantics: + https://www.rfc-editor.org/rfc/rfc9110.html + https://www.bortzmeyer.org/9110.html + https://www.bortzmeyer.org/cours-http-cnam.html + HTTP/1.1: + https://www.rfc-editor.org/rfc/rfc9112.html + https://www.bortzmeyer.org/9112.html + CGI: + https://www.rfc-editor.org/rfc/rfc3875.html +*/ diff --git a/srcs/webserv/accept.cpp b/srcs/webserv/accept.cpp index e74efc5..fbadcb4 100644 --- a/srcs/webserv/accept.cpp +++ b/srcs/webserv/accept.cpp @@ -21,8 +21,8 @@ void Webserv::_accept_connection(listen_socket &lsocket) ::fcntl(accepted_fd, F_SETFL, O_NONBLOCK); infos = _extract_infos(addr); - Client client(accepted_fd, &lsocket, infos["port"], infos["ip"]); - _clients.push_back(client); + Client new_client(accepted_fd, &lsocket, infos["port"], infos["ip"]); + _clients.push_back(new_client); _epoll_update(accepted_fd, EPOLLIN, EPOLL_CTL_ADD); } diff --git a/srcs/webserv/cgi.cpp b/srcs/webserv/cgi.cpp index 2795f71..b28ba05 100644 --- a/srcs/webserv/cgi.cpp +++ b/srcs/webserv/cgi.cpp @@ -1,5 +1,9 @@ #include "Webserv.hpp" +/* + CGI RFC: + https://www.rfc-editor.org/rfc/rfc3875.html +*/ bool Webserv::_is_cgi(Client *client, std::string path) { @@ -99,23 +103,26 @@ std::string Webserv::_dup_env(std::string var, int i) } // TODO : verifier que les variables sont corrects +/* + https://www.rfc-editor.org/rfc/rfc3875#section-4.1 +*/ void Webserv::_set_env_vector(Client *client, std::vector &env_vector) { env_vector.push_back(_dup_env("AUTH_TYPE")); // authentification not supporte env_vector.push_back(_dup_env("CONTENT_LENGTH" , client->get_rq_body().size())); env_vector.push_back(_dup_env("CONTENT_TYPE" , client->get_rq_headers("Content-Type"))); - env_vector.push_back(_dup_env("GATEWAY_INTERFACE" , "CGI/1.1")); // https://www.rfc-editor.org/rfc/rfc387) - env_vector.push_back(_dup_env("PATH_INFO" , client->get_rq_script_info())); - env_vector.push_back(_dup_env("PATH_TRANSLATED")); // not supported + env_vector.push_back(_dup_env("GATEWAY_INTERFACE" , "CGI/1.1")); // https://www.rfc-editor.org/rfc/rfc3875#section-4.1.4 + env_vector.push_back(_dup_env("PATH_INFO" , client->get_rq_script_info())); // LUKE: To Check + env_vector.push_back(_dup_env("PATH_TRANSLATED")); // not supported // LUKE: Why not supported ? env_vector.push_back(_dup_env("QUERY_STRING" , client->get_rq_query())); env_vector.push_back(_dup_env("REMOTE_ADDR" , client->get_cl_ip())); - env_vector.push_back(_dup_env("REMOTE_HOST" , client->get_rq_headers("Host"))); // just tes - env_vector.push_back(_dup_env("REMOTE_IDENT")); // authentification not supporte - env_vector.push_back(_dup_env("REMOTE_USER")); // authentification not supporte + env_vector.push_back(_dup_env("REMOTE_HOST" , client->get_cl_ip())); // equal to REMOTE_ADDR or empty + env_vector.push_back(_dup_env("REMOTE_IDENT")); // authentification not supported + env_vector.push_back(_dup_env("REMOTE_USER")); // authentification not supported env_vector.push_back(_dup_env("REQUEST_METHOD" , client->get_rq_method_str())); - env_vector.push_back(_dup_env("SCRIPT_NAME" , client->get_rq_script_path())); - env_vector.push_back(_dup_env("SERVER_NAME" , client->get_rq_hostname())); - env_vector.push_back(_dup_env("SERVER_PORT" , client->get_rq_port())); + env_vector.push_back(_dup_env("SCRIPT_NAME" , client->get_rq_script_path())); // LUKE: To Check + env_vector.push_back(_dup_env("SERVER_NAME" , client->get_cl_lsocket()->host)); + env_vector.push_back(_dup_env("SERVER_PORT" , client->get_cl_lsocket()->port)); env_vector.push_back(_dup_env("SERVER_PROTOCOL" , "HTTP/1.1")); env_vector.push_back(_dup_env("SERVER_SOFTWARE" , "Webserv/0.1")); env_vector.push_back(_dup_env("REDIRECT_STATUS" , "200")); diff --git a/srcs/webserv/http_status.hpp b/srcs/webserv/http_status.hpp index f519ec7..8217cf5 100644 --- a/srcs/webserv/http_status.hpp +++ b/srcs/webserv/http_status.hpp @@ -2,7 +2,9 @@ #ifndef HTTP_STATUS_HPP # define HTTP_STATUS_HPP -// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml +/* + https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml +*/ /* First version of macro HTML_ERROR(STATUS) dont work with call like this : diff --git a/srcs/webserv/method_get.cpp b/srcs/webserv/method_get.cpp index 77d5add..35b1d92 100644 --- a/srcs/webserv/method_get.cpp +++ b/srcs/webserv/method_get.cpp @@ -1,24 +1,13 @@ #include "Webserv.hpp" - -std::string Webserv::_replace_url_root(Client *client, std::string path) -{ - std::cerr << "assigned_location->path = " << client->assigned_location->path << "\n"; // debug - std::cerr << "path before = " << path << "\n"; // DEBUG - if (client->assigned_location->path == "/") - path.insert(0, client->assigned_location->root); - else - path.replace(0, client->assigned_location->path.size(), client->assigned_location->root); - std::cerr << "path after = " << path << "\n"; // DEBUG - return path; -} +#define MAX_FILESIZE 1 * MB // unused // const? -void Webserv::_get(Client *client, std::string &path) -{ /* https://www.rfc-editor.org/rfc/rfc9110.html#name-get */ +void Webserv::_get(Client *client, std::string &path) +{ std::cout << "_get()\n"; if (eval_file_type(path) == IS_DIR) { @@ -42,14 +31,13 @@ void Webserv::_get(Client *client, std::string &path) _get_file(client, path); } -# define MAX_FILESIZE 1 * MB // unused -void Webserv::_get_file(Client *client, const std::string &path) -{ /* 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. */ +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() ? std::stringstream buf; @@ -155,3 +143,11 @@ void Webserv::_autoindex(Client *client, const std::string &path) return ; } } + +std::string Webserv::_determine_file_extension(const std::string &path) const +{ + size_t dot_pos = path.rfind("."); + if (dot_pos != NPOS && dot_pos + 1 < path.size()) + return ( path.substr(dot_pos + 1) ); + return (std::string("")); +} diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 97a3577..9e8357e 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -119,6 +119,21 @@ void Webserv::_process_method(Client *client, std::string &path) } } +std::string Webserv::_replace_url_root(Client *client, std::string path) +{ + std::cerr << "assigned_location->path = " << client->assigned_location->path << "\n"; // debug + std::cerr << "path before = " << path << "\n"; // DEBUG + if (client->assigned_location->path == "/") + path.insert(0, client->assigned_location->root); + else + path.replace(0, client->assigned_location->path.size(), client->assigned_location->root); + std::cerr << "path after = " << path << "\n"; // DEBUG + return path; +} + +/* + https://www.rfc-editor.org/rfc/rfc9112.html#name-status-line +*/ void Webserv::_insert_status_line(Client *client) { std::string status_line; @@ -176,111 +191,3 @@ void Webserv::_append_body(Client *client, const std::string &body, const std::s client->response.append(CRLF); client->response.append(body); } - -// Temporary Global Scope. Probably move to Client in the future. -ServerConfig *_determine_process_server(Client *client, std::vector &servers) -{ -/* - Behavior like this : - http://nginx.org/en/docs/http/request_processing.html -*/ - - std::string server_name = client->get_rq_headers("Host"); - std::cerr << "server_name = " << server_name << "\n"; - size_t pos = server_name.rfind(':'); - if (pos != NPOS) - server_name.erase(pos); - std::cerr << "server_name = " << server_name << "\n"; - - std::vector::iterator it = servers.begin(); - std::vector::iterator default_server = servers.end(); - - while (it != servers.end()) - { - if (it->host == client->get_cl_lsocket()->host - && it->port == client->get_cl_lsocket()->port) - { - if ( std::find(it->server_name.begin(), it->server_name.end(), server_name) != it->server_name.end() ) - break; - else if (default_server == servers.end()) - default_server = it; - } - ++it; - } - if (it != servers.end()) - return (&(*it)); - else - return (&(*default_server)); -} - -// const? -// Temporary Global Scope. Probably move to Client in the future. -// is it still TMP Global Scope? -const LocationConfig *_determine_location(const ServerConfig &server, const std::string &path) -{ -/* RULES *** - -If a path coresponds exactly to a location, use that one -if no path coresponds then use the most correct one - most correct means the most precise branch that is still above - the point we are aiming for - -New Rule for location paths, they never end in / -Sooo -If we get a url that ends in / ignore the last / - -*/ - - std::string uri = path; - if (uri[uri.size() - 1] == '/' && uri.size() != 1) - uri.erase(uri.size() - 1); - - - for (std::vector::const_iterator it = server.locations.begin(); it != server.locations.end(); it++) - { -// std::cout << it->path << " -- "; - if (it->path.size() > uri.size()) - continue ; - - if (uri.compare(0, it->path.size(), it->path) == 0) - { - if (it->path.size() == uri.size()) - return (&(*it)); - else if (uri[it->path.size()] == '/') - return (&(*it)); - // this works cuz only ever looking for a / burried in a longer path - } - } - return (&(server.locations.back())); - - -// /test/mdr -// /test/mdr/ -// /test/mdrBST - -/* More stuff to check this still works with *** - -/test/test_ -/test/test_/ -/test/test_deeper -/test/test_deeper/ -/test/test_deepei -/test/test_deepei/ -/test/test_deeperi -/test/test_deeper/super_deep/ -/test/aaaaaaaaaaa/super_deep/ - -*/ - -} - - - - -std::string Webserv::_determine_file_extension(const std::string &path) const -{ - size_t dot_pos = path.rfind("."); - if (dot_pos != NPOS && dot_pos + 1 < path.size()) - return ( path.substr(dot_pos + 1) ); - return (std::string("")); -}