From 3dad938e3cba5a18953046a57e9f062a61525917 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Tue, 9 Aug 2022 11:19:46 +0200 Subject: [PATCH] add extern function for http message parsing + wip compare fields server and script + g tout cassey --- Makefile | 1 + README.md | 6 ++ srcs/Client.cpp | 84 +++++++++------------------ srcs/Client.hpp | 11 ++-- srcs/cgi-bin/php-cgi | 4 +- srcs/utils.cpp | 35 +++++++++-- srcs/utils.hpp | 1 + srcs/webserv/Webserv.hpp | 7 ++- srcs/webserv/cgi_script.cpp | 40 +++++++++++-- srcs/webserv/parsing_message_http.cpp | 75 ++++++++++++++++++++++++ srcs/webserv/parsing_message_http.hpp | 33 +++++++++++ srcs/webserv/parsing_request.cpp | 2 + srcs/webserv/response.cpp | 12 ++-- 13 files changed, 225 insertions(+), 86 deletions(-) create mode 100644 srcs/webserv/parsing_message_http.cpp create mode 100644 srcs/webserv/parsing_message_http.hpp create mode 100644 srcs/webserv/parsing_request.cpp diff --git a/Makefile b/Makefile index ad045bd..e1117aa 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,7 @@ SRCS = main.cpp \ utils.cpp \ cgi_script.cpp \ Client.cpp \ + parsing_message_http.cpp \ OBJS_D = builds OBJS = $(SRCS:%.cpp=$(OBJS_D)/%.o) diff --git a/README.md b/README.md index 7afc363..c118b54 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,12 @@ ## work together +#### message +- err access line response.cpp:169 +- g pas fini la gestion de sortie du cgi (comparaison des headers fields pour supprimer les doublons) +- g rendu independantes les fonctions qui parses un message http (requete ou response) dans `parsing_http_message.cpp` +- il y a une erreur importante dans la fonction qui parse les headers d'un message http : ca ne verifie pas si la premier ligne est un header ou la "first line" + #### TODO - `_is_cgi()` and `_fill_cgi_path()` - `_cgi_output()` change status in `client->status` diff --git a/srcs/Client.cpp b/srcs/Client.cpp index 354d1c3..8a54403 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -70,22 +70,15 @@ Client & Client::operator=( Client const & rhs ) // https://www.tutorialspoint.com/http/http_requests.htm void Client::parse_request() { - std::string sub; - std::vector list; - size_t pos; + std::map headers; + std::string body; // DEBUG -std::cout << "\nREQUEST _____________________\n" - << raw_request - << "\n\n"; +std::cout << "\nREQUEST ____________\n" << raw_request << "\n_____________\n"; - pos = (raw_request).find(CRLF CRLF); - sub = (raw_request).substr(0, pos); - list = split(sub, '\n'); - _parse_request_line(*list.begin()); - list.erase(list.begin()); - _parse_request_headers(list); - _parse_request_body(pos + 4); + _parse_request_line(); + _parse_request_headers(); + _parse_request_body(); _parse_port_hostname(this->get_rq_headers("Host")); raw_request.clear(); } @@ -176,30 +169,24 @@ std::string Client::get_rq_headers(const std::string & key) const * PRIVATE MEMBER FUNCTIONS *********************************************/ -void Client::_parse_request_line( std::string rline ) +void Client::_parse_request_line() { - std::vector sline; - std::string tmp; + std::vector line; + int ret; - sline = split(rline, ' '); - if (sline.size() != 3) + ret = ::parse_http_first_line(raw_request, line); + if (ret != 3) { - std::cerr << "err _parse_request_line(): "; - throw std::runtime_error("bad request-line header"); + std::cerr << "err _parse_first_line(): wrong number of elements (" << ret << " instead of 3)\n"; + status = 400; // "bad request" + } + else + { + _request.method = str_to_http_method(line[0]); + _request.uri = line[1]; + _parse_request_uri(line[1]); + _request.version = line[2]; } - // method - tmp = ::trim(sline[0], ' '); - tmp = ::trim(tmp, '\r'); - _request.method = str_to_http_method(tmp); - // uri - tmp = ::trim(sline[1], ' '); - tmp = ::trim(tmp, '\r'); - _request.uri = tmp; - _parse_request_uri( tmp ); - // http version - tmp = ::trim(sline[2], ' '); - tmp = ::trim(tmp, '\r'); - _request.version = tmp; } void Client::_parse_request_uri( std::string uri ) @@ -214,32 +201,16 @@ void Client::_parse_request_uri( std::string uri ) _request.abs_path = uri.substr(0, pos); } -void Client::_parse_request_headers( std::vector list ) +void Client::_parse_request_headers() { - 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'); - key = ::str_tolower(key); - val = (*it).substr( pos + 1 ); - val = ::trim(val, ' '); - val = ::trim(val, '\r'); - _request.headers.insert( std::pair(key, val) ); - } + // TODO: check error and adjust status + _request.headers = ::parse_http_headers(raw_request); } -void Client::_parse_request_body( size_t pos ) +void Client::_parse_request_body() { - std::string body = &raw_request[pos]; - - _request.body = body; + // TODO: check error and adjust status + _request.body = ::parse_http_body(raw_request); } void Client::_parse_port_hostname(std::string host) @@ -247,10 +218,7 @@ void Client::_parse_port_hostname(std::string host) size_t pos; if (host == "") - { std::cerr << "no host\n"; - throw std::runtime_error("no host in request"); - } pos = host.find(':'); // port : diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 64759f0..287f10f 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -7,9 +7,10 @@ # include # include # include // strdup -# include "utils.hpp" # include // sockaddr_in, struct in_addr # include // htonl, htons, ntohl, ntohs, inet_addr, inet_ntoa +# include "utils.hpp" +# include "parsing_message_http.hpp" struct Script { @@ -78,12 +79,12 @@ class Client std::string _port; std::string _ip; listen_socket * _lsocket; - struct Request _request; + struct Request _request; - void _parse_request_line( std::string rline ); + void _parse_request_line(); + void _parse_request_headers(); + void _parse_request_body(); void _parse_request_uri( std::string uri ); - void _parse_request_headers( std::vector list ); - void _parse_request_body( size_t pos ); void _parse_port_hostname(std::string host); }; diff --git a/srcs/cgi-bin/php-cgi b/srcs/cgi-bin/php-cgi index b51a88e..d3d3625 100755 --- a/srcs/cgi-bin/php-cgi +++ b/srcs/cgi-bin/php-cgi @@ -1,9 +1,9 @@ #! /usr/bin/php split(std::string input, char delimiter) std::string trim(std::string str, char c) { + // TODO: protect substr str = str.substr(str.find_first_not_of(c)); str = str.substr(0, str.find_last_not_of(c) + 1); @@ -100,15 +101,37 @@ void replace_all_substr(std::string &str, const std::string &ori_substr, const s } } -bool operator==(const listen_socket& lhs, int fd) - { return lhs.fd == fd; } - -bool operator==(int fd, const listen_socket& rhs) - { return fd == rhs.fd; } - std::string str_tolower(std::string str) { std::transform(str.begin(), str.end(), str.begin(), ::tolower); return str; } +void delete_line_in_string(std::string * str, size_t pos, std::string delim) +{ + size_t begin; + size_t end; + + begin = (*str).rfind(delim, pos); + if (begin == std::string::npos) + begin = 0; + else + begin += delim.size(); + + end = (*str).find(delim, pos); + if (end == std::string::npos) + end = 0; + else + end += delim.size(); + + (*str).erase(begin, end - begin); +} + + + +bool operator==(const listen_socket& lhs, int fd) + { return lhs.fd == fd; } + +bool operator==(int fd, const listen_socket& rhs) + { return fd == rhs.fd; } + diff --git a/srcs/utils.hpp b/srcs/utils.hpp index 5b271b4..e75f64a 100644 --- a/srcs/utils.hpp +++ b/srcs/utils.hpp @@ -49,5 +49,6 @@ http_method str_to_http_method(std::string &str); std::string http_methods_to_str(unsigned int methods); void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr); std::string str_tolower(std::string str); +void delete_line_in_string(std::string * str, size_t pos, std::string delim); #endif diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index 6d128f2..f9168cb 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -32,7 +32,7 @@ extern bool g_run; extern int g_last_signal; -void signal_handler(int signum); +void signal_handler(int signum); // these might only be TMP # define FAILURE -1 @@ -93,7 +93,6 @@ class Webserv ServerConfig &_determine_process_server(Client *client); LocationConfig &_determine_location(ServerConfig &server, std::string const &path); - void _response_correction(Client *client); // cgi_script.cpp bool _is_cgi(Client *client); std::string _exec_cgi(Client *client); @@ -101,6 +100,9 @@ class Webserv char* _dup_env(std::string var, std::string val); char* _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); // 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); @@ -115,6 +117,7 @@ class Webserv void _listen(int socket_fd, unsigned int max_connections); void _init_http_status_map(); void _init_mime_types_map(); + }; #endif diff --git a/srcs/webserv/cgi_script.cpp b/srcs/webserv/cgi_script.cpp index 5d1f08b..ec38d1b 100644 --- a/srcs/webserv/cgi_script.cpp +++ b/srcs/webserv/cgi_script.cpp @@ -102,7 +102,8 @@ std::string Webserv::_exec_script(Client *client, char **env) close(FD_RD_FR_CHLD); dup2(FD_RD_FR_PRNT, STDIN_FILENO); dup2(FD_WR_TO_PRNT, STDOUT_FILENO); - execve(client->get_rq_script_path().c_str(), nll, env); + //execve(client->get_rq_script_path().c_str(), nll, env); + execve("truc", nll, env); std::cerr << "execve crashed.\n"; } else @@ -119,13 +120,42 @@ std::string Webserv::_exec_script(Client *client, char **env) script_output += buf; memset(buf, '\0', CGI_BUF_SIZE); } + close(FD_RD_FR_CHLD); } if (script_output.empty()) script_output = "Status: 500\r\n\r\n"; - -// DEBUG -std::cout << "\n______response______\n" << script_output << "\n____end response____\n"; - return script_output; } +void Webserv::_check_script_output(Client *client, std::string output) +{ + // TODO: it doesn't work with execve error, i don't know why yet ? + _check_script_status(client, output); + _check_script_fields(client, output); +} + +void Webserv::_check_script_status(Client *client, std::string output) +{ + size_t pos; + int status_pos; + + pos = output.find("Status:"); + if (pos != std::string::npos) + { + status_pos = pos + std::string("Status:").size(); + client->status = atoi(output.c_str() + status_pos); + ::delete_line_in_string(&output, pos, CRLF); + } + client->status = 200; +} + +void Webserv::_check_script_fields(Client *client, std::string output) +{ + std::map server_fields; + std::map script_fields; + + server_fields = parse_http_headers(client->response); + script_fields = parse_http_headers(output); + // TODO: compare both map to supress duplicates +} + diff --git a/srcs/webserv/parsing_message_http.cpp b/srcs/webserv/parsing_message_http.cpp new file mode 100644 index 0000000..d66ee6c --- /dev/null +++ b/srcs/webserv/parsing_message_http.cpp @@ -0,0 +1,75 @@ + +#include "parsing_message_http.hpp" + +size_t + parse_http_first_line(std::string message, std::vector &line) +{ + std::vector sline; + std::string sub; + std::string tmp; + size_t pos; + size_t ret; + + // TODO: check for err in substr + pos = message.find(CRLF); + sub = message.substr(0, pos); + sline = ::split(sub, ' '); + ret = sline.size(); + if (ret != 3) + return ret; + for (int i = 0; i < 3; i++) + { + tmp = ::trim(sline[0], ' '); + tmp = ::trim(tmp, '\r'); + line.push_back(tmp); + } + return ret; +} + +std::map + parse_http_headers(std::string message) +{ + std::map headers; + std::vector list; + std::vector::iterator it; + std::string sub; + std::string key; + std::string val; + size_t pos; + + pos = (message).find(CRLF CRLF); + sub = (message).substr(0, pos); + list = ::split(sub, '\n'); + // TODO: if (list.begin() is "first line") + list.erase(list.begin()); + + for (it = list.begin(); it != list.end(); it++) + { + // TODO: if pattern is not "NAME: value" return error + pos = (*it).find(':'); + key = (*it).substr( 0, pos ); + key = ::trim(key, ' '); + key = ::trim(key, '\r'); + key = ::str_tolower(key); + val = (*it).substr( pos + 1 ); + val = ::trim(val, ' '); + val = ::trim(val, '\r'); + headers.insert( std::pair(key, val) ); + } + return headers; +} + +std::string + parse_http_body(std::string message) +{ + std::string body; + size_t pos; + + pos = message.find(CRLF CRLF); + pos += std::string(CRLF CRLF).size(); + // TODO: copying just like that might fail in case of binary or images + body = message.substr(pos); + + return body; +} + diff --git a/srcs/webserv/parsing_message_http.hpp b/srcs/webserv/parsing_message_http.hpp new file mode 100644 index 0000000..34b955c --- /dev/null +++ b/srcs/webserv/parsing_message_http.hpp @@ -0,0 +1,33 @@ + +#ifndef PARSING_MESSAGE_HTTP_HPP +# define PARSING_MESSAGE_HTTP_HPP + +# include +# include +# include +# include +# include "utils.hpp" + +size_t + parse_http_first_line(std::string message, std::vector &line); + +std::map + parse_http_headers(std::string message); + +std::string + parse_http_body(std::string message); + +// http message structure : +// +// start-line +// request-line +// method SP target SP version +// response-line +// version SP status SP reason +// header-fields +// name ":" SP value +// CRLF +// body + +#endif + diff --git a/srcs/webserv/parsing_request.cpp b/srcs/webserv/parsing_request.cpp new file mode 100644 index 0000000..d83d9e3 --- /dev/null +++ b/srcs/webserv/parsing_request.cpp @@ -0,0 +1,2 @@ +#include "parsing_request.hpp" + diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index e86761b..fd3cc19 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -145,10 +145,12 @@ void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &locatio // TMP HUGO // + std::string script_output; if (_is_cgi(client)) { - _exec_cgi(client); - _response_correction(client); + script_output = _exec_cgi(client); + _check_script_output(client, script_output); + std::cout << "_____________status:" << client->status << "\n"; return; } // @@ -224,12 +226,6 @@ void Webserv::_get_file(Client *client, const std::string &path) } } -// WIP HUGO -void Webserv::_response_correction(Client *client) -{ - (void)client; -} - void Webserv::_append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension) { /*