wip cgi handling, client contains it's own privates functions to handle request headers and body

This commit is contained in:
hugogogo
2022-08-01 19:30:07 +02:00
parent 031932e887
commit 979a3d20b8
12 changed files with 382 additions and 154 deletions

View File

@@ -3,33 +3,27 @@ NAME = webserv
CXX = c++
CXXFLAGS = -Wall -Wextra #-Werror
CXXFLAGS += $(HEADERS_I)
CXXFLAGS += $(HEADERS_D:%=-I%)
CXXFLAGS += -std=c++98
CXXFLAGS += -g
CXXFLAGS += -MMD -MP #header dependencie
#CXXFLAGS += -O3
#SHELL = /bin/zsh
VPATH = $(SRCS_D)
HEADERS_I = $(HEADERS_D:%=-I%)
HEADERS_D = srcs \
headers
HEADERS_F = Webserv.hpp \
ConfigParser.hpp \
ServerConfig.hpp \
LocationConfig.hpp \
Client.hpp \
MethodType.hpp \
utils.hpp
SRCS_D = srcs srcs/webserv
SRCS_D = srcs \
srcs/webserv
SRCS = main.cpp \
base.cpp init.cpp close.cpp epoll_update.cpp signal.cpp \
accept.cpp request.cpp response.cpp \
run_loop.cpp \
ConfigParser.cpp \
utils.cpp
utils.cpp \
cgi_script.cpp \
Client.cpp
OBJS_D = builds
OBJS = $(SRCS:%.cpp=$(OBJS_D)/%.o)

View File

@@ -1,4 +1,20 @@
---
## questions
- mettre les fonctions specifiques a la requete, dans la class client ?
- où est-ce que j'inclus le cgi ?
- est-ce que le cgi est appellé par `/cgi-bin` ?
- non
- g rajouté `char ** env` dans client.cpp
- non
- ajouter un champ "message body" dans client ?
- non
- comment organiser la creation du message reponse (cgi ou pas) et des headers ?
- comment je gere le path `/cgi-bin/` avec la suite ?
- qu'est-ce que le cgi renvoit comme headers ? comment c'est géré ?
- https://www.rfc-editor.org/rfc/rfc3875
---
## man
@@ -115,4 +131,7 @@ REDIRECT_STATUS : for exemple, 200
- [hack with CGI](https://www.youtube.com/watch?v=ph6-AKByBU4)
- [http headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)
- [list of http headers fields](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields)
- [http request ibm](https://www.ibm.com/docs/en/cics-ts/5.3?topic=protocol-http-requests)
- [http request other](https://www.tutorialspoint.com/http/http_requests.htm)
- [request line uri](https://stackoverflow.com/questions/40311306/when-is-absoluteuri-used-from-the-http-request-specs)

View File

@@ -5,25 +5,47 @@
# include <iostream>
# include <string>
# include <map>
# include <vector>
# include "utils.hpp"
struct Client
struct Request
{
// public:
// Client(Placeholder);
// Client();
// Client(Client const &src);
// ~Client();
// Client &operator=(Client const &rhs);
std::map<std::string, std::string> headers;
std::string method;
std::string path;
std::string version;
std::string body;
};
int fd;
std::string raw_request;
std::map<std::string, std::string> request;
// std::map<std::string, std::string> response;
class Client
{
public:
Client();
~Client();
//Client(Client const &src);
//Client &operator=(Client const &rhs);
int fd;
std::string raw_request;
std::string response;
unsigned int status;
// private:
std::string get_method();
std::string get_path();
std::string get_version();
std::string get_body();
std::string get_headers(std::string key);
void parse_request();
private:
struct Request _request;
void _parse_request_line( std::string rline );
void _parse_request_headers( std::vector<std::string> list );
void _parse_request_body( size_t pos );
};
#endif

View File

@@ -1,14 +1,3 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ServerConfig.hpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: me <erlazo@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/07/23 15:55:16 by me #+# #+# */
/* Updated: 2022/07/23 16:19:43 by me ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef SERVERCONFIG_HPP
# define SERVERCONFIG_HPP
@@ -27,7 +16,6 @@ public:
// i mean i guess i need some canonic stuff?
// although maybe if i make it a struct i can barebones it?
std::string server_name;
std::string root;
@@ -54,10 +42,8 @@ public:
std::string host;
std::string port;
// do i need a print all for testing?
void print_all()
{
std::cout << "PRINTING A FULL SERVER CONFIG\n\n";
@@ -87,18 +73,7 @@ public:
std::cout << "\n----------\n";
}
};
#endif

View File

@@ -76,9 +76,9 @@ class Webserv
private:
int _epfd;
std::vector<int> _listen_sockets;
std::vector<int> _listen_sockets;
std::vector<ServerConfig> _servers;
std::vector<Client> _clients;
std::vector<Client> _clients;
// accept.cpp
void _accept_connection(int fd);
@@ -91,6 +91,13 @@ class Webserv
void _construct_response(Client *client);
void _insert_status_line(Client *client);
void _get_ressource(Client *client);
// cgi_script.cpp
bool _is_cgi(Client *client);
void _exec_cgi(Client *client);
void _construct_client(Client *client);
char** _set_env(Client *client);
char* _dup_env(std::string var, std::string val);
void _exec_script(Client *client, char **env);
// 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);
@@ -102,18 +109,6 @@ class Webserv
// init.cpp
void _bind(int socket_fd, in_port_t port, std::string host);
void _listen(int socket_fd, unsigned int max_connections);
// TMP HUGO TEST CGI
//
void _serve_file(Client *client, std::string page);
void _exec_cgi_script(Client *client);
void _parse_request(Client *client);
void _parse_request_line(Client *client, std::string rline);
void _parse_request_headers
( Client *client
, std::vector<std::string> list);
//
// END TMP HUGO TEST CGI
};
#endif

View File

@@ -7,7 +7,7 @@
# include <vector>
std::vector<std::string> split(std::string input, char delimiter);
std::string itoa(int n);
std::string itos(int n);
std::string trim(std::string str, char c);
#endif

116
srcs/Client.cpp Normal file
View File

@@ -0,0 +1,116 @@
#include "Client.hpp"
/*********************************************
* COPLIENS
*********************************************/
Client::Client( ) {
return;
}
Client::~Client() {
return;
}
// copy constructor :
// Client::Client( Client const & src ) {}
// assignement operator :
// 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
void Client::parse_request()
{
std::string sub;
std::vector<std::string> list;
size_t pos;
pos = (raw_request).find("\r\n\r\n");
sub = (raw_request).substr(0, pos);
list = split(sub, '\n');
// request_line
_parse_request_line(*list.begin());
list.erase(list.begin());
// headers
_parse_request_headers(list);
//body- message
_parse_request_body(pos + 4);
}
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]; }
/*********************************************
* PRIVATE MEMBER FUNCTIONS
*********************************************/
void Client::_parse_request_line( std::string rline )
{
std::vector<std::string> sline;
std::string tmp;
sline = split(rline, ' ');
if (sline.size() != 3)
{
std::cerr << "err _parse_request_line(): ";
throw std::runtime_error("bad request-line header");
}
// method
tmp = ::trim(sline[0], ' ');
tmp = ::trim(tmp, '\r');
_request.method = tmp;
// TODO uri in request_line
// https://www.rfc-editor.org/rfc/rfc7230#section-5.3
// https://stackoverflow.com/questions/40311306/when-is-absoluteuri-used-from-the-http-request-specs
tmp = ::trim(sline[1], ' ');
tmp = ::trim(tmp, '\r');
_request.path = tmp;
// http version
tmp = ::trim(sline[2], ' ');
tmp = ::trim(tmp, '\r');
_request.version = tmp;
}
void Client::_parse_request_headers( std::vector<std::string> list )
{
std::string key;
std::string val;
std::vector<std::string>::iterator it;
size_t pos;
for (it = list.begin(); it != list.end(); it++)
{
pos = (*it).find(':');
key = (*it).substr( 0, pos );
key = ::trim(key, ' ');
key = ::trim(key, '\r');
val = (*it).substr( pos + 1 );
val = ::trim(val, ' ');
val = ::trim(val, '\r');
_request.headers.insert( std::pair<std::string, std::string>(key, val) );
}
}
void Client::_parse_request_body( size_t pos )
{
std::string body = &raw_request[pos];
_request.body = body;
}

View File

@@ -3,7 +3,27 @@
<?php
echo "BEGIN PHP-CGI\n-----------\n\n";
//phpinfo();
echo getenv('REQUEST_METHOD');
echo $_POST['REQUEST_METHOD'];
echo "AUTH_TYPE: " . getenv("AUTH_TYPE");
echo "\nCONTENT_LENGTH: " . getenv("CONTENT_LENGTH");
echo "\nCONTENT_TYPE: " . getenv("CONTENT_TYPE");
echo "\nGATEWAY_INTERFACE: " . getenv("GATEWAY_INTERFACE");
echo "\nPATH_INFO: " . getenv("PATH_INFO");
echo "\nPATH_TRANSLATED: " . getenv("PATH_TRANSLATED");
echo "\nQUERY_STRING: " . getenv("QUERY_STRING");
echo "\nREMOTE_ADDR: " . getenv("REMOTE_ADDR");
echo "\nREMOTE_HOST: " . getenv("REMOTE_HOST");
echo "\nREMOTE_IDENT: " . getenv("REMOTE_IDENT");
echo "\nREMOTE_USER: " . getenv("REMOTE_USER");
echo "\nREQUEST_METHOD: " . getenv("REQUEST_METHOD");
echo "\nSCRIPT_NAME: " . getenv("SCRIPT_NAME");
echo "\nSERVER_NAME: " . getenv("SERVER_NAME");
echo "\nSERVER_PORT: " . getenv("SERVER_PORT");
echo "\nSERVER_PROTOCOL: " . getenv("SERVER_PROTOCOL");
echo "\nSERVER_SOFTWARE: " . getenv("SERVER_SOFTWARE");
echo "\nREDIRECT_STATUS: " . getenv("REDIRECT_STATUS");
// echo $_POST['REQUEST_METHOD'];
echo "\n\n-----------\nEND PHP-CGI\n\n";
?>

View File

@@ -21,7 +21,7 @@ std::string trim(std::string str, char c)
return str;
}
std::string itoa(int n)
std::string itos(int n)
{
std::stringstream strs;

View File

@@ -0,0 +1,80 @@
#include "Webserv.hpp"
bool Webserv::_is_cgi(Client *client)
{
if (client->get_path().find("/cgi-bin/") != std::string::npos)
return true;
return false;
}
void Webserv::_exec_cgi(Client *client)
{
char** env;
env = _set_env(client);
_exec_script(client, env);
// _construct_response(client);
}
char* Webserv::_dup_env(std::string var, std::string val = "")
{
std::string str;
str = var + "=" + val;
return ( strdup(str.c_str()) );
}
char** Webserv::_set_env(Client *client)
{
char** env = new char*[19];
env[0] = _dup_env("AUTH_TYPE");
env[1] = _dup_env("CONTENT_LENGTH", "665");
env[2] = _dup_env("CONTENT_TYPE");
env[3] = _dup_env("GATEWAY_INTERFACE");
env[4] = _dup_env("PATH_INFO");
env[5] = _dup_env("PATH_TRANSLATED");
env[6] = _dup_env("QUERY_STRING");
env[7] = _dup_env("REMOTE_ADDR");
env[8] = _dup_env("REMOTE_HOST", client->get_headers("Host")); // just test
env[9] = _dup_env("REMOTE_IDENT");
env[10] = _dup_env("REMOTE_USER");
env[11] = _dup_env("REQUEST_METHOD", client->get_method());
env[12] = _dup_env("SCRIPT_NAME");
env[13] = _dup_env("SERVER_NAME");
env[14] = _dup_env("SERVER_PORT");
env[15] = _dup_env("SERVER_PROTOCOL", client->get_version());
env[16] = _dup_env("SERVER_SOFTWARE");
env[17] = _dup_env("REDIRECT_STATUS");
env[18] = NULL;
return env;
}
void Webserv::_exec_script(Client *client, char **env)
{
int save_stdout;
char * const * nll = NULL;
// save STDOUT
save_stdout = dup(STDOUT_FILENO);
// inside child process
if (fork() == 0)
{
dup2(client->fd, STDOUT_FILENO);
// execve("./srcs/cgi-bin/cgi_cpp.cgi", nll, client->env);
execve("./srcs/cgi-bin/php-cgi", nll, env);
}
// inside parent process
else
waitpid(-1, NULL, 0);
// restore stdout
dup2(save_stdout, STDOUT_FILENO);
}
void Webserv::_construct_client(Client *client)
{
(void)client;
}

View File

@@ -32,87 +32,82 @@ void Webserv::_read_request(Client *client)
buf[ret] = '\0';
client->raw_request.append(buf);
_parse_request(client);
client->parse_request();
// _parse_request(client);
_epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD, client);
}
// 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
void Webserv::_parse_request(Client *client)
{
std::string sub;
std::vector<std::string> list;
size_t pos;
pos = (client->raw_request).find("\r\n\r\n");
sub = (client->raw_request).substr(0, pos);
list = split(sub, '\n');
// request_line
_parse_request_line(client, *list.begin());
list.erase(list.begin());
// headers
_parse_request_headers(client, list);
// message-body
client->request.insert( std::pair<std::string, std::string>("Body-Message", &client->raw_request[pos + 4]) );
// TMP DEBUG
// std::map<std::string, std::string>::iterator itm;
// std::map<std::string, std::string>::iterator itm_end;
// std::cout << "\n====== REQUEST HEADERS\n";
// for (itm = client->request.begin(), itm_end = client->request.end(); itm != itm_end; itm++)
// std::cout << "[" << itm->first << "] [" << itm->second << "]\n";
// std::cout << "\n====== END\n";
}
void Webserv::_parse_request_line(Client *client, std::string rline)
{
std::vector<std::string> sline;
std::string tmp;
sline = split(rline, ' ');
if (sline.size() != 3)
{
std::cerr << "err _parse_request_line(): ";
throw std::runtime_error("bad request-line header");
}
// method
tmp = ::trim(sline[0], ' ');
tmp = ::trim(tmp, '\r');
client->request.insert( std::pair<std::string, std::string>("Method", tmp) );
// TODO uri in request_line :
// https://www.rfc-editor.org/rfc/rfc7230#section-5.3
// https://stackoverflow.com/questions/40311306/when-is-absoluteuri-used-from-the-http-request-specs
tmp = ::trim(sline[1], ' ');
tmp = ::trim(tmp, '\r');
client->request.insert( std::pair<std::string, std::string>("Request-URI", tmp) );
// http version
tmp = ::trim(sline[2], ' ');
tmp = ::trim(tmp, '\r');
client->request.insert( std::pair<std::string, std::string>("HTTP-Version", tmp) );
}
void Webserv::_parse_request_headers
( Client *client
, std::vector<std::string> list)
{
std::string key;
std::string val;
std::vector<std::string>::iterator it;
size_t pos;
for (it = list.begin(); it != list.end(); it++)
{
pos = (*it).find(':');
key = (*it).substr( 0, pos );
key = ::trim(key, ' ');
key = ::trim(key, '\r');
val = (*it).substr( pos + 1 );
val = ::trim(val, ' ');
val = ::trim(val, '\r');
client->request.insert( std::pair<std::string, std::string>(key, val) );
}
}
// // 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
// void Webserv::_parse_request(Client *client)
// {
// std::string sub;
// std::vector<std::string> list;
// size_t pos;
//
// pos = (client->raw_request).find("\r\n\r\n");
// sub = (client->raw_request).substr(0, pos);
// list = split(sub, '\n');
// // request_line
// _parse_request_line(client, *list.begin());
// list.erase(list.begin());
// // headers
// _parse_request_headers(client, list);
// //body- message
// client->request.insert( std::pair<std::string, std::string>("Body-Message", &client->raw_request[pos + 4]) );
// }
//
// void Webserv::_parse_request_line(Client *client, std::string rline)
// {
// std::vector<std::string> sline;
// std::string tmp;
//
// sline = split(rline, ' ');
// if (sline.size() != 3)
// {
// std::cerr << "err _parse_request_line(): ";
// throw std::runtime_error("bad request-line header");
// }
// // method
// tmp = ::trim(sline[0], ' ');
// tmp = ::trim(tmp, '\r');
// client->request.insert( std::pair<std::string, std::string>("Method", tmp) );
// // TODO uri in request_line
// // https://www.rfc-editor.org/rfc/rfc7230#section-5.3
// // https://stackoverflow.com/questions/40311306/when-is-absoluteuri-used-from-the-http-request-specs
// tmp = ::trim(sline[1], ' ');
// tmp = ::trim(tmp, '\r');
// client->request.insert(
// std::pair<std::string, std::string>("Request-URI", tmp) );
// // http version
// tmp = ::trim(sline[2], ' ');
// tmp = ::trim(tmp, '\r');
// client->request.insert(
// std::pair<std::string, std::string>("HTTP-Version", tmp) );
// }
//
// void Webserv::_parse_request_headers(
// Client *client,
// std::vector<std::string> list )
// {
// std::string key;
// std::string val;
// std::vector<std::string>::iterator it;
// size_t pos;
//
// for (it = list.begin(); it != list.end(); it++)
// {
// pos = (*it).find(':');
// key = (*it).substr( 0, pos );
// key = ::trim(key, ' ');
// key = ::trim(key, '\r');
// val = (*it).substr( pos + 1 );
// val = ::trim(val, ' ');
// val = ::trim(val, '\r');
// client->request.insert( std::pair<std::string, std::string>(key, val) );
// }
// }

View File

@@ -79,12 +79,22 @@ void Webserv::_insert_status_line(Client *client)
#define ROOT "website"
#define INDEX "index.html"
#define MAX_FILESIZE 1000000 // (1Mo)
#define MAX_FILESIZE 1000000 // (1Mo)
void Webserv::_get_ressource(Client *client)
{
std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ?
char buf[MAX_FILESIZE+1];
const char *tmp;
std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ?
char buf[MAX_FILESIZE+1];
std::string tmp;
// TMP HUGO
//
if (_is_cgi(client))
{
_exec_cgi(client);
return;
}
//
// END TMP HUGO
// Mini parsing à l'arrache du PATH
std::string path;
@@ -128,15 +138,17 @@ void Webserv::_get_ressource(Client *client)
client->response.append("Content-Type: text/html; charset=UTF-8\r\n");
client->response.append("Content-Length: ");
tmp = ::itoa(ifd.gcount()).c_str();
client->response.append(tmp);
tmp = ::itos(ifd.gcount());
client->response.append(tmp.c_str());
client->response.append("\r\n");
// Body
client->response.append("\r\n");
client->response.append(buf);
client->response.append(buf);
ifd.close();
}
}