diff --git a/Makefile b/Makefile index 417d8e6..b8b6734 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,6 @@ 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/srcs/Client.cpp b/srcs/Client.cpp index c817f15..e10dca5 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -77,22 +77,26 @@ Client & Client::operator=( Client const & rhs ) // https://www.tutorialspoint.com/http/http_requests.htm void Client::parse_request(std::vector &servers) { - std::map headers; - std::string body; +// std::map headers; +// std::string body; + std::string copy_request; // DEBUG // std::cout << "\nREQUEST ____________\n" << raw_request << "\n_____________\n"; clear_request(); // not mandatory - _parse_request_line(); + _parse_request_line(copy_request); + if (status) + return; + _parse_request_headers(copy_request); if (status) return; - _parse_request_headers(); assigned_server = ::_determine_process_server(this, servers); assigned_location = ::_determine_location(*assigned_server, _request.abs_path); _check_request_errors(); if (status) return; + // use getter for headers because it works case insensitive _parse_port_hostname(this->get_rq_headers("Host")); /* dont clear raw_request, we need it for future reparsing of body @@ -203,7 +207,7 @@ void Client::_parse_request_line() std::string raw_line; int ret; - raw_line = extract_line(); + raw_line = ::get_line(raw_request, 0, CRLF); line = ::split_trim(raw_line, " ", ' '); if (line.size() != 3) { @@ -233,8 +237,22 @@ void Client::_parse_request_uri( std::string uri ) void Client::_parse_request_headers() { - // TODO: check error and adjust status - _request.headers = ::parse_http_headers(raw_request); + std::string headers; + size_t pos; + int ret; + + headers = raw_request; + // extract header part + ::extract_line(headers, 0, CRLF); + pos = headers.find(CRLF); + ::extract_line(headers, pos); // delete from pos to the end + // copy result of parser into headers + ret = ::parse_http_headers(raw_request, _request.headers); + if (ret > 0) + { + std::cerr << "err _parse_request_headers(): " << ret << " field are bad formated\n"; + status = 400; // "bad request" + } } void Client::_parse_port_hostname(std::string host) diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 43a0913..2b82f36 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -11,7 +11,6 @@ # include // htonl, htons, ntohl, ntohs, inet_addr, inet_ntoa # include "utils.hpp" # include "ServerConfig.hpp" -# include "parsing_message_http.hpp" struct Script { diff --git a/srcs/utils.cpp b/srcs/utils.cpp index e0ca568..b3d8173 100644 --- a/srcs/utils.cpp +++ b/srcs/utils.cpp @@ -9,6 +9,14 @@ void throw_test() throw std::bad_alloc(); } +// notice : the use of getline make it such as +// it doesn't identify multiple delim as one : +// " something \n else " -> 1 - something +// 2 - else +// is not the same as : +// " something \n\n else " -> 1 - something +// 2 - +// 3 - else std::vector split(std::string input, char delimiter) { std::vector answer; @@ -176,29 +184,91 @@ std::string str_tolower(std::string str) // identify a line in a string, by delim (ex. '\n') // delete this line from the string // and return the deleted line -std::string extract_line(std::string * str, size_t pos, std::string delim) +// if delim is empty, the extraction begin exactly at pos, and end at npos +std::string + extract_line(std::string & str, size_t pos = 0, std::string delim = "") { std::string del_str; size_t begin; size_t end; - begin = (*str).rfind(delim, pos); + 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 = str.find(delim, pos); + if (end != std::string::npos) end += delim.size(); + if (delim.empty()) + end = std::string::npos; - del_str = (*str).substr(begin, end - begin); - (*str).erase(begin, end - begin); + del_str = str.substr(begin, end - begin); + str.erase(begin, end - begin); return del_str; } +// get a line in a string, by delim +// same as extract, except it doesn't delete it +std::string get_line(std::string str, size_t pos = 0, std::string delim = "") +{ + std::string ret_str; + 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 += delim.size(); + if (delim.empty()) + end = std::string::npos; + + ret_str = str.substr(begin, end - begin); + return ret_str; +} + +std::map + parse_http_headers ( + std::string headers, + std::map fields ) +{ + std::vector list; + std::vector::iterator it; + std::vector::iterator it_end; + size_t err = 0; + size_t pos; + + list = ::split_trim(sub, CRLF, ' '); + + it_end = list.end(); + for (it = list.begin(); it != it_end; it++) + { + pos = (*it).find(':'); + if (pos == std::string::npos) + { + err++; + continue; + } + key = (*it).substr(0, pos); + if ( key.find(' ') != std::string::npos ) + { + err++; + continue; + } + key = ::str_tolower(key); // to make "key" case_insensitive + val = (*it).substr(pos + 1); + val = ::trim(val, ' '); + fields.insert( std::pair(key, val) ); + } + return err; +} + bool operator==(const listen_socket& lhs, int fd) { return lhs.fd == fd; } diff --git a/srcs/utils.hpp b/srcs/utils.hpp index 2d402fc..58bf2e8 100644 --- a/srcs/utils.hpp +++ b/srcs/utils.hpp @@ -45,7 +45,10 @@ std::string http_methods_to_str(unsigned int methods); int path_is_valid(std::string path); void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr); std::string str_tolower(std::string str); -std::string extract_line(std::string * str, size_t pos, std::string delim); +std::string extract_line(std::string & s, size_t p, std::string d); +std::string get_line(std::string str, size_t pos, std::string del); +std::map + parse_http_headers (std::string headers, std::map fields ); void throw_test(); #endif diff --git a/srcs/webserv/cgi_script.cpp b/srcs/webserv/cgi_script.cpp index 01c56a7..70a05ef 100644 --- a/srcs/webserv/cgi_script.cpp +++ b/srcs/webserv/cgi_script.cpp @@ -152,7 +152,7 @@ void Webserv::_check_script_status(Client *client, std::string output) { status_pos = pos + std::string("Status:").size(); client->status = atoi(output.c_str() + status_pos); - ::del_line_in_str(&output, pos, CRLF); + ::extract_line(output, pos, CRLF); } else client->status = 200; @@ -176,7 +176,7 @@ void Webserv::_check_script_fields(Client *client, std::string output) if (it_srv->first == it_scr->first) { pos = client->response.find(it_srv->first); - ::del_line_in_str(&client->response, pos, CRLF); + ::extract_line(client->response, pos, CRLF); } } } diff --git a/srcs/webserv/parsing_message_http.cpp b/srcs/webserv/parsing_message_http.cpp index 9b8adc8..2712f20 100644 --- a/srcs/webserv/parsing_message_http.cpp +++ b/srcs/webserv/parsing_message_http.cpp @@ -1,48 +1,6 @@ #include "parsing_message_http.hpp" -/* - - parse_http_first_line() : - - copy first line into a vector of 3 strings - / copy line into a vector of 3 strings - - parse_http_headers(std::string message) - - - - parse_http_body(std::string message) -*/ - -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'); - if ( maybe_http_first_line( *list.begin() ) ) - 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) { @@ -57,18 +15,3 @@ std::string return body; } -bool maybe_http_first_line(std::string str) -{ -// method SP target SP version https://www.rfc-editor.org/rfc/rfc7230.html#section-3.1.1 -// version SP status SP reason https://www.rfc-editor.org/rfc/rfc7230.html#section-3.1.2 - - std::vector sline; - - sline = ::split(str, ' '); - if (sline.size() != 3) - return false; - if (sline[0].find(':') != std::string::npos) - return false; - return true; -} - diff --git a/srcs/webserv/parsing_message_http.hpp b/srcs/webserv/parsing_message_http.hpp index 5024d8d..d1e77ed 100644 --- a/srcs/webserv/parsing_message_http.hpp +++ b/srcs/webserv/parsing_message_http.hpp @@ -9,14 +9,13 @@ # include "utils.hpp" std::map - parse_http_headers(std::string message); + parse_http_headers ( + std::string headers, + std::map fields ) std::string parse_http_body(std::string message); -bool - maybe_http_first_line(std::string); - // http message structure : // // start-line