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 * PUBLIC MEMBER FUNCTIONS
*********************************************/ *********************************************/
// http headers : /* HTTP Headers :
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers https://www.iana.org/assignments/http-fields/http-fields.xhtml
// https://www.ibm.com/docs/en/cics-ts/5.3?topic=protocol-http-requests https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers
// https://www.tutorialspoint.com/http/http_requests.htm 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) void Client::parse_request_headers(std::vector<ServerConfig> &servers)
{ {
if (raw_request.find(CRLF CRLF) == NPOS) if (raw_request.find(CRLF CRLF) == NPOS)
@@ -96,8 +98,8 @@ void Client::parse_request_headers(std::vector<ServerConfig> &servers)
if (status) if (status)
return; return;
assigned_server = ::_determine_process_server(this, servers); assigned_server = _determine_process_server(this, servers);
assigned_location = ::_determine_location(*assigned_server, _request.abs_path); assigned_location = _determine_location(*assigned_server, _request.abs_path);
_check_request_errors(); _check_request_errors();
if (status) if (status)
return; return;
@@ -389,6 +391,7 @@ void Client::_parse_request_fields()
::str_map_key_tolower(_request.headers); ::str_map_key_tolower(_request.headers);
} }
// TODO : I think its now useless. Probably to delete.
void Client::_parse_port_hostname(std::string host) void Client::_parse_port_hostname(std::string host)
{ {
size_t pos; size_t pos;
@@ -453,6 +456,98 @@ void Client::_check_request_errors()
return; 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 * OVERLOAD
*********************************************/ *********************************************/

View File

@@ -105,15 +105,15 @@ class Client
void _parse_chunked_body(size_t pos); void _parse_chunked_body(size_t pos);
void _parse_multipart_body(size_t pos); void _parse_multipart_body(size_t pos);
void _check_request_errors(); 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, const Client& rhs);
bool operator==(const Client& lhs, int fd); bool operator==(const Client& lhs, int fd);
bool operator==(int fd, const Client& rhs); 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 #endif

View File

@@ -83,40 +83,21 @@ class Webserv
void _append_base_headers(Client *client); void _append_base_headers(Client *client);
void _construct_response(Client *client); void _construct_response(Client *client);
void _process_method(Client *client, std::string &path); void _process_method(Client *client, std::string &path);
std::string _replace_url_root(Client *client, std::string path);
void _insert_status_line(Client *client); void _insert_status_line(Client *client);
void _error_html_response(Client *client); void _error_html_response(Client *client);
void _append_body(Client *client, const std::string &body, const std::string &file_extension = ""); 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 // method_get.cpp
// move later
std::string _replace_url_root(Client *client, std::string path);
void _get(Client *client, std::string &path); void _get(Client *client, std::string &path);
void _get_file(Client *client, const std::string &path); void _get_file(Client *client, const std::string &path);
void _autoindex(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 // method_post.cpp
void _post(Client *client, const std::string &path); void _post(Client *client, const std::string &path);
void _upload_files(Client *client); void _upload_files(Client *client);
// method_delete.cpp // method_delete.cpp
void _delete(Client *client, const std::string &path); void _delete(Client *client, const std::string &path);
void _delete_file(Client *client, const std::string &path); void _delete_file(Client *client, const std::string &path);
// cgi_script.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);
void _set_env_vector(Client *client, std::vector<std::string> &env_vector);
void _set_env_cstr(char *env_cstr[], std::vector<std::string> &env_vector);
std::string _dup_env(std::string var, std::string val);
std::string _dup_env(std::string var, int i);
std::string _exec_script(Client *client, char *env[]);
void _check_script_output(Client *client, std::string & output);
void _check_script_status(Client *client, std::string & output);
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 // epoll_update.cpp
int _epoll_update(int fd, uint32_t events, int op); int _epoll_update(int fd, uint32_t events, int op);
int _epoll_update(int fd, uint32_t events, int op, void *ptr); int _epoll_update(int fd, uint32_t events, int op, void *ptr);
@@ -136,7 +117,32 @@ class Webserv
void _init_mime_types_map(); void _init_mime_types_map();
// timeout.cpp // timeout.cpp
void _timeout(); 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);
void _set_env_vector(Client *client, std::vector<std::string> &env_vector);
void _set_env_cstr(char *env_cstr[], std::vector<std::string> &env_vector);
std::string _dup_env(std::string var, std::string val);
std::string _dup_env(std::string var, int i);
std::string _exec_script(Client *client, char *env[]);
void _check_script_output(Client *client, std::string & output);
void _check_script_status(Client *client, std::string & output);
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);
}; };
#endif #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); ::fcntl(accepted_fd, F_SETFL, O_NONBLOCK);
infos = _extract_infos(addr); infos = _extract_infos(addr);
Client client(accepted_fd, &lsocket, infos["port"], infos["ip"]); Client new_client(accepted_fd, &lsocket, infos["port"], infos["ip"]);
_clients.push_back(client); _clients.push_back(new_client);
_epoll_update(accepted_fd, EPOLLIN, EPOLL_CTL_ADD); _epoll_update(accepted_fd, EPOLLIN, EPOLL_CTL_ADD);
} }

View File

@@ -1,5 +1,9 @@
#include "Webserv.hpp" #include "Webserv.hpp"
/*
CGI RFC:
https://www.rfc-editor.org/rfc/rfc3875.html
*/
bool Webserv::_is_cgi(Client *client, std::string path) 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 // 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) 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("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_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("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("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())); 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 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("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_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_HOST" , client->get_cl_ip())); // equal to REMOTE_ADDR or empty
env_vector.push_back(_dup_env("REMOTE_IDENT")); // authentification not supporte env_vector.push_back(_dup_env("REMOTE_IDENT")); // authentification not supported
env_vector.push_back(_dup_env("REMOTE_USER")); // authentification not supporte 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("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("SCRIPT_NAME" , client->get_rq_script_path())); // LUKE: To Check
env_vector.push_back(_dup_env("SERVER_NAME" , client->get_rq_hostname())); env_vector.push_back(_dup_env("SERVER_NAME" , client->get_cl_lsocket()->host));
env_vector.push_back(_dup_env("SERVER_PORT" , client->get_rq_port())); 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_PROTOCOL" , "HTTP/1.1"));
env_vector.push_back(_dup_env("SERVER_SOFTWARE" , "Webserv/0.1")); env_vector.push_back(_dup_env("SERVER_SOFTWARE" , "Webserv/0.1"));
env_vector.push_back(_dup_env("REDIRECT_STATUS" , "200")); env_vector.push_back(_dup_env("REDIRECT_STATUS" , "200"));

View File

@@ -2,7 +2,9 @@
#ifndef HTTP_STATUS_HPP #ifndef HTTP_STATUS_HPP
# define 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 : First version of macro HTML_ERROR(STATUS) dont work with call like this :

View File

@@ -1,24 +1,13 @@
#include "Webserv.hpp" #include "Webserv.hpp"
#define MAX_FILESIZE 1 * MB // unused
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;
}
// const? // const?
void Webserv::_get(Client *client, std::string &path)
{
/* /*
https://www.rfc-editor.org/rfc/rfc9110.html#name-get https://www.rfc-editor.org/rfc/rfc9110.html#name-get
*/ */
void Webserv::_get(Client *client, std::string &path)
{
std::cout << "_get()\n"; std::cout << "_get()\n";
if (eval_file_type(path) == IS_DIR) if (eval_file_type(path) == IS_DIR)
{ {
@@ -42,14 +31,13 @@ void Webserv::_get(Client *client, std::string &path)
_get_file(client, path); _get_file(client, path);
} }
# define MAX_FILESIZE 1 * MB // unused
void Webserv::_get_file(Client *client, const std::string &path)
{
/* /*
std::ios::binary std::ios::binary
https://gcc.gnu.org/onlinedocs/libstdc++/manual/fstreams.html#std.io.filestreams.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. 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::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ?
std::stringstream buf; std::stringstream buf;
@@ -155,3 +143,11 @@ void Webserv::_autoindex(Client *client, const std::string &path)
return ; 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) void Webserv::_insert_status_line(Client *client)
{ {
std::string status_line; 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(CRLF);
client->response.append(body); 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(""));
}