diff --git a/Makefile b/Makefile index 871c8e9..0168787 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/README.md b/README.md index 9fdd84e..07f3a72 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/headers/Client.hpp b/headers/Client.hpp index 65a9b46..652144c 100644 --- a/headers/Client.hpp +++ b/headers/Client.hpp @@ -5,25 +5,47 @@ # include # include # include +# include +# include "utils.hpp" -struct Client +struct Request { - // public: - // Client(Placeholder); - // Client(); - // Client(Client const &src); - // ~Client(); - // Client &operator=(Client const &rhs); + std::map headers; + std::string method; + std::string path; + std::string version; + std::string body; +}; - int fd; - std::string raw_request; - std::map request; - // std::map 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 list ); + void _parse_request_body( size_t pos ); }; #endif + diff --git a/headers/ServerConfig.hpp b/headers/ServerConfig.hpp index a08d8a1..868b0f8 100644 --- a/headers/ServerConfig.hpp +++ b/headers/ServerConfig.hpp @@ -1,14 +1,3 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* ServerConfig.hpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: me +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* 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 - - - - - - diff --git a/headers/Webserv.hpp b/headers/Webserv.hpp index 7f867e2..21b0138 100644 --- a/headers/Webserv.hpp +++ b/headers/Webserv.hpp @@ -76,9 +76,9 @@ class Webserv private: int _epfd; - std::vector _listen_sockets; + std::vector _listen_sockets; std::vector _servers; - std::vector _clients; + std::vector _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 list); - // - // END TMP HUGO TEST CGI }; #endif diff --git a/headers/utils.hpp b/headers/utils.hpp index ab47fa4..b45ea55 100644 --- a/headers/utils.hpp +++ b/headers/utils.hpp @@ -7,7 +7,7 @@ # include std::vector 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 diff --git a/srcs/Client.cpp b/srcs/Client.cpp new file mode 100644 index 0000000..e6c6f39 --- /dev/null +++ b/srcs/Client.cpp @@ -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 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 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 list ) +{ + std::string key; + std::string val; + std::vector::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(key, val) ); + } +} + +void Client::_parse_request_body( size_t pos ) +{ + std::string body = &raw_request[pos]; + + _request.body = body; +} + + diff --git a/srcs/cgi-bin/php-cgi b/srcs/cgi-bin/php-cgi index 7c58bf2..b51a88e 100755 --- a/srcs/cgi-bin/php-cgi +++ b/srcs/cgi-bin/php-cgi @@ -3,7 +3,27 @@ + diff --git a/srcs/utils.cpp b/srcs/utils.cpp index 72027ef..542bddc 100644 --- a/srcs/utils.cpp +++ b/srcs/utils.cpp @@ -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; diff --git a/srcs/webserv/cgi_script.cpp b/srcs/webserv/cgi_script.cpp new file mode 100644 index 0000000..ee1319e --- /dev/null +++ b/srcs/webserv/cgi_script.cpp @@ -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; +} + diff --git a/srcs/webserv/request.cpp b/srcs/webserv/request.cpp index 0e3870f..3bcde4a 100644 --- a/srcs/webserv/request.cpp +++ b/srcs/webserv/request.cpp @@ -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 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("Body-Message", &client->raw_request[pos + 4]) ); - - // TMP DEBUG -// std::map::iterator itm; -// std::map::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 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("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("Request-URI", tmp) ); - // http version - tmp = ::trim(sline[2], ' '); - tmp = ::trim(tmp, '\r'); - client->request.insert( std::pair("HTTP-Version", tmp) ); -} - -void Webserv::_parse_request_headers - ( Client *client - , std::vector list) -{ - std::string key; - std::string val; - std::vector::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(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 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("Body-Message", &client->raw_request[pos + 4]) ); +// } +// +// void Webserv::_parse_request_line(Client *client, std::string rline) +// { +// std::vector 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("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("Request-URI", tmp) ); +// // http version +// tmp = ::trim(sline[2], ' '); +// tmp = ::trim(tmp, '\r'); +// client->request.insert( +// std::pair("HTTP-Version", tmp) ); +// } +// +// void Webserv::_parse_request_headers( +// Client *client, +// std::vector list ) +// { +// std::string key; +// std::string val; +// std::vector::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(key, val) ); +// } +// } diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index dbd0219..f049352 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -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(); } } +