wip integration of client.request and ServerConfig

+ Client get return reference
+ wip binary flags for http_method
+ moved config parser files
This commit is contained in:
LuckyLaszlo
2022-08-02 21:11:54 +02:00
parent 5aabeb6b46
commit 8f167d85f3
14 changed files with 107 additions and 70 deletions

View File

@@ -12,10 +12,13 @@ CXXFLAGS += -MMD -MP #header dependencie
VPATH = $(SRCS_D)
HEADERS_D = srcs \
srcs/webserv
srcs/webserv \
srcs/config
SRCS_D = srcs \
srcs/webserv
srcs/webserv \
srcs/config
SRCS = main.cpp \
base.cpp init.cpp close.cpp epoll_update.cpp signal.cpp \
accept.cpp request.cpp response.cpp \

View File

@@ -1,7 +1,14 @@
- un thread par serveur présent dans le fichier de config ?
----------------
----------------
- 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.
__________________________
--------------------------
----Discord 42------------
Un truc cool et surtout bien utile ici c'est d'utiliser un proxy entre ton navigateur et ton serveur pour vérifier ce qui est envoyé en raw. Les navigateurs peuvent avoir des comportements différents.
Vous avez des modules sur vos navigateur ou des logiciels externe. C'est assez rapide et gratuit.

View File

@@ -49,11 +49,11 @@ void Client::parse_request()
std::string Client::get_method() { return _request.method; }
std::string Client::get_path() { return _request.path; }
std::string Client::get_version() { return _request.version; }
std::string Client::get_body() { return _request.body; }
std::string Client::get_headers(std::string key) { return _request.headers[key]; }
std::string &Client::get_method() { return _request.method; }
std::string &Client::get_path() { return _request.path; }
std::string &Client::get_version() { return _request.version; }
std::string &Client::get_body() { return _request.body; }
std::string &Client::get_headers(const std::string &key) { return _request.headers[key]; }
/*********************************************
* PRIVATE MEMBER FUNCTIONS

View File

@@ -30,11 +30,12 @@ class Client
std::string response;
unsigned int status;
std::string get_method();
std::string get_path();
std::string get_version();
std::string get_body();
std::string get_headers(std::string key);
// const functions ?
std::string &get_method();
std::string &get_path();
std::string &get_version();
std::string &get_body();
std::string &get_headers(const std::string &key);
void parse_request();

View File

@@ -6,7 +6,7 @@
/* By: lperrey <lperrey@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/07/13 22:11:17 by me #+# #+# */
/* Updated: 2022/08/02 14:05:03 by lperrey ### ########.fr */
/* Updated: 2022/08/02 19:21:49 by lperrey ### ########.fr */
/* */
/* ************************************************************************** */
@@ -263,7 +263,7 @@ void ConfigParser::_set_server_values(ServerConfig *server, \
for (unsigned long i = 0; i != tmp_val.size(); i++)
{
http_method m = _str_to_method_type(tmp_val[i]);
if (m == 3)
if (m == INVALID)
throw std::invalid_argument("not a valid method");
server->allow_methods.push_back(m);
}
@@ -348,7 +348,7 @@ void ConfigParser::_set_location_values(LocationConfig *location, \
for (unsigned long i = 0; i != tmp_val.size(); i++)
{
http_method m = _str_to_method_type(tmp_val[i]);
if (m == 3)
if (m == INVALID)
throw std::invalid_argument("not a valid method");
location->allow_methods.push_back(m);
}

View File

@@ -7,12 +7,20 @@
# include <sstream>
# include <cstdlib> // atoi
// enum http_method
// {
// GET = 0b000001,
// POST = 0b000010,
// DELETE = 0b000100,
// INVALID = 0b001000,
// };
enum http_method
{
GET = 1,
POST,
DELETE,
INVALID,
POST = 1 << 1,
DELETE = 1 << 2,
INVALID = 1 << 3,
};
std::vector<std::string> split(std::string input, char delimiter);

View File

@@ -22,7 +22,7 @@
// # include <netinet/ip.h> // usefull for what ? -> 'man (7) ip' says it's a superset of 'netinet/in.h'
# include <algorithm> // find
# include <string> // string
# include <cstdio> // perror
# include <cstdio> // perror, remove
# include <cstdlib> // atoi (athough it's already cover by <string>)
# include "Client.hpp"
@@ -68,10 +68,11 @@ class Webserv
void _read_request(Client *client);
// response.cpp
void _response(Client *client);
void _send_response(Client *client);
void _construct_response(Client *client);
void _insert_status_line(Client *client);
void _get_ressource(Client *client);
ServerConfig &_determine_process_server(Client *client);
void _send_response(Client *client, ServerConfig &server);
void _construct_response(Client *client, ServerConfig &server);
void _insert_status_line(Client *client, ServerConfig &server);
void _get_ressource(Client *client, ServerConfig &server);
// cgi_script.cpp
bool _is_cgi(Client *client);
void _exec_cgi(Client *client);

View File

@@ -6,7 +6,7 @@ void Webserv::_close_client(int fd)
std::vector<Client>::iterator it = _clients.begin();
while (it != _clients.end())
{
if (it->fd == fd)
if (*it == fd)
{
// _epoll_update(fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
if (::close(fd) == -1)

View File

@@ -3,25 +3,48 @@
void Webserv::_response(Client *client)
{
_send_response(client);
ServerConfig &server = _determine_process_server(client);
_send_response(client, server);
if (g_last_signal)
_handle_last_signal();
}
void Webserv::_send_response(Client *client)
ServerConfig &Webserv::_determine_process_server(Client *client)
{
/*
TODO : determine virtual server based on ip_address::port and server_name
Ior now its just based on server_name.
(maybe with a map< string, std::vector<ServerConfig> > where the string is "ip_adress::port")
http://nginx.org/en/docs/http/request_processing.html
*/
std::string &server_name = client->get_headers("Host");
std::vector<ServerConfig>::iterator it = _servers.begin();
while (it != _servers.end())
{
if ( std::find(it->server_name.begin(), it->server_name.end(), server_name) != it->server_name.end() )
break;
++it;
}
if (it != _servers.end())
return (*it);
else
return (_servers.front());
}
void Webserv::_send_response(Client *client, ServerConfig &server)
{
ssize_t ret;
std::cerr << "send()\n";
std::cerr << "RAW_REQUEST\n|\n" << client->raw_request << "|\n"; // DEBUG
// std::cerr << "RAW_REQUEST\n|\n" << client->raw_request << "|\n"; // DEBUG
_construct_response(client);
_construct_response(client, server);
ret = ::send(client->fd, client->response.data(), client->response.size(), 0);
ret = ::send(client->fd, client->response.c_str(), client->response.size(), 0);
if (ret == -1)
{
std::perror("err send()");
std::cerr << "client ptr =" << client << "\n"; // DEBUG
std::cerr << "client.fd =" << client->fd << "\n"; // DEBUG
_close_client(client->fd);
return ;
@@ -37,25 +60,29 @@ void Webserv::_send_response(Client *client)
}
}
void Webserv::_construct_response(Client *client)
void Webserv::_construct_response(Client *client, ServerConfig &server)
{
client->status = 200;
client->response.append("Server: Webserv/0.1\r\n");
if (client->raw_request.find("Connection: close") != std::string::npos)
if (client->get_headers("Connection") == "close")
client->response.append("Connection: close\r\n");
else
client->response.append("Connection: keep-alive\r\n");
_get_ressource(client);
// TODO : Method switch (GET, POST, DELETE)
_get_ressource(client, server);
_insert_status_line(client);
_insert_status_line(client, server);
}
#define E400 "\r\n<!DOCTYPE html><html><head><title>400 Bad Request</title></head><body><h1 style=\"text-align:center\">400 Bad Request</h1><hr><p style=\"text-align:center\">Le Webserv/0.1</p></body></html>"
#define E404 "\r\n<!DOCTYPE html><html><head><title>404 Not Found</title></head><body><h1 style=\"text-align:center\">404 Not Found</h1><hr><p style=\"text-align:center\">Le Webserv/0.1</p></body></html>"
#define E500 "\r\n<!DOCTYPE html><html><head><title>500 Internal Server Error</title></head><body><h1 style=\"text-align:center\">500 Internal Server Error</h1><hr><p style=\"text-align:center\">Le Webserv/0.1</p></body></html>"
void Webserv::_insert_status_line(Client *client)
// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
#define HTML_ERROR(STATUS) "\r\n<!DOCTYPE html><html><head><title>"STATUS"</title></head><body><h1 style=\"text-align:center\">"STATUS"</h1><hr><p style=\"text-align:center\">Le Webserv/0.1</p></body></html>"
#define S200 "200 OK"
#define S400 "400 Bad Request"
#define S404 "404 Not Found"
#define S500 "500 Internal Server Error"
void Webserv::_insert_status_line(Client *client, ServerConfig &server)
{
std::string status_line;
@@ -64,19 +91,19 @@ void Webserv::_insert_status_line(Client *client)
switch (client->status)
{
case (200):
status_line.append("200 OK");
status_line.append(S200);
break;
case (400):
status_line.append("400 Not Found");
client->response.append(E400);
status_line.append(S400);
client->response.append(HTML_ERROR(S400));
break;
case (404):
status_line.append("404 Not Found");
client->response.append(E404);
status_line.append(S404);
client->response.append(HTML_ERROR(S404));
break;
case (500):
status_line.append("500 Internal Server Error");
client->response.append(E500);
status_line.append(S500);
client->response.append(HTML_ERROR(S500));
break;
}
status_line.append("\r\n");
@@ -87,11 +114,18 @@ void Webserv::_insert_status_line(Client *client)
#define ROOT "www"
#define INDEX "index.html"
#define MAX_FILESIZE 1000000 // (1Mo)
void Webserv::_get_ressource(Client *client)
void Webserv::_get_ressource(Client *client, ServerConfig &server)
{
std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ?
char buf[MAX_FILESIZE+1];
std::string tmp;
std::string path = client->get_path();
if (path == "/") // TODO ; With server config
path.append(INDEX);
path.insert(0, ROOT);
std::cerr << "path = " << path << "\n";
// TMP HUGO
//
@@ -103,32 +137,15 @@ void Webserv::_get_ressource(Client *client)
//
// END TMP HUGO
// Mini parsing à l'arrache du PATH
std::string path;
try
{
path = client->raw_request.substr(0, client->raw_request.find("\r\n"));
path = path.substr(0, path.rfind(" "));
path = path.substr(path.find("/"));
if (path == "/")
path.append(INDEX);
path.insert(0, ROOT);
}
catch (std::out_of_range& e)
{
std::cout << e.what() << '\n';
client->status = 400;
return ;
}
if (access(path.data(), R_OK) == -1)
if (access(path.c_str(), R_OK) == -1)
{
std::perror("err access()");
client->status = 404;
return ;
}
ifd.open(path.data(), std::ios::binary | std::ios::ate); // std::ios::binary (binary for files like images ?)
ifd.open(path.c_str(), std::ios::binary | std::ios::ate); // std::ios::binary (binary for files like images ?)
if (!ifd)
{
std::cerr << path << ": open fail" << '\n';
@@ -151,7 +168,7 @@ void Webserv::_get_ressource(Client *client)
ifd.read(buf, size);
buf[ifd.gcount()] = '\0';
client->response.append("Content-Type: text/html; charset=UTF-8\r\n");
client->response.append("Content-Type: text/html; charset=UTF-8\r\n"); // TODO : determine Content-Type
client->response.append("Content-Length: ");