Multiples minors changes (cgi env, comment, ...)

This commit is contained in:
LuckyLaszlo
2022-08-16 04:00:33 +02:00
parent 2a1aec8f1d
commit 4602844f5a
8 changed files with 207 additions and 194 deletions

View File

@@ -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<ServerConfig> &servers)
{
if (raw_request.find(CRLF CRLF) == NPOS)
@@ -96,8 +98,8 @@ void Client::parse_request_headers(std::vector<ServerConfig> &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<ServerConfig> &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<ServerConfig>::iterator it = servers.begin();
std::vector<ServerConfig>::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<LocationConfig>::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
*********************************************/

View File

@@ -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<ServerConfig> &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<ServerConfig> &servers);
const LocationConfig *_determine_location(const ServerConfig &server, const std::string &path);
#endif

View File

@@ -71,39 +71,53 @@ class Webserv
std::map<std::string, std::string> _mime_types;
// accept.cpp
void _accept_connection(listen_socket &lsocket);
void _accept_connection(listen_socket &lsocket);
std::map<std::string, std::string>
_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<listen_socket>::iterator it);
void _handle_epoll_error_lsocket(uint32_t events, std::vector<listen_socket>::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<listen_socket>::iterator it);
void _handle_epoll_error_lsocket(uint32_t events, std::vector<listen_socket>::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
*/

View File

@@ -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);
}

View File

@@ -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<std::string> &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"));

View File

@@ -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 :

View File

@@ -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(""));
}

View File

@@ -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<ServerConfig> &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<ServerConfig>::iterator it = servers.begin();
std::vector<ServerConfig>::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<LocationConfig>::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(""));
}