http message parsin wip but really better
This commit is contained in:
1
Makefile
1
Makefile
@@ -30,7 +30,6 @@ SRCS = main.cpp \
|
|||||||
utils.cpp \
|
utils.cpp \
|
||||||
cgi_script.cpp \
|
cgi_script.cpp \
|
||||||
Client.cpp \
|
Client.cpp \
|
||||||
parsing_message_http.cpp \
|
|
||||||
|
|
||||||
OBJS_D = builds
|
OBJS_D = builds
|
||||||
OBJS = $(SRCS:%.cpp=$(OBJS_D)/%.o)
|
OBJS = $(SRCS:%.cpp=$(OBJS_D)/%.o)
|
||||||
|
|||||||
@@ -77,22 +77,26 @@ Client & Client::operator=( Client const & rhs )
|
|||||||
// https://www.tutorialspoint.com/http/http_requests.htm
|
// https://www.tutorialspoint.com/http/http_requests.htm
|
||||||
void Client::parse_request(std::vector<ServerConfig> &servers)
|
void Client::parse_request(std::vector<ServerConfig> &servers)
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string> headers;
|
// std::map<std::string, std::string> headers;
|
||||||
std::string body;
|
// std::string body;
|
||||||
|
std::string copy_request;
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
// std::cout << "\nREQUEST ____________\n" << raw_request << "\n_____________\n";
|
// std::cout << "\nREQUEST ____________\n" << raw_request << "\n_____________\n";
|
||||||
clear_request(); // not mandatory
|
clear_request(); // not mandatory
|
||||||
|
|
||||||
_parse_request_line();
|
_parse_request_line(copy_request);
|
||||||
|
if (status)
|
||||||
|
return;
|
||||||
|
_parse_request_headers(copy_request);
|
||||||
if (status)
|
if (status)
|
||||||
return;
|
return;
|
||||||
_parse_request_headers();
|
|
||||||
assigned_server = ::_determine_process_server(this, servers);
|
assigned_server = ::_determine_process_server(this, servers);
|
||||||
assigned_location = ::_determine_location(*assigned_server, _request.abs_path);
|
assigned_location = ::_determine_location(*assigned_server, _request.abs_path);
|
||||||
_check_request_errors();
|
_check_request_errors();
|
||||||
if (status)
|
if (status)
|
||||||
return;
|
return;
|
||||||
|
// use getter for headers because it works case insensitive
|
||||||
_parse_port_hostname(this->get_rq_headers("Host"));
|
_parse_port_hostname(this->get_rq_headers("Host"));
|
||||||
|
|
||||||
/* dont clear raw_request, we need it for future reparsing of body
|
/* 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;
|
std::string raw_line;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
raw_line = extract_line();
|
raw_line = ::get_line(raw_request, 0, CRLF);
|
||||||
line = ::split_trim(raw_line, " ", ' ');
|
line = ::split_trim(raw_line, " ", ' ');
|
||||||
if (line.size() != 3)
|
if (line.size() != 3)
|
||||||
{
|
{
|
||||||
@@ -233,8 +237,22 @@ void Client::_parse_request_uri( std::string uri )
|
|||||||
|
|
||||||
void Client::_parse_request_headers()
|
void Client::_parse_request_headers()
|
||||||
{
|
{
|
||||||
// TODO: check error and adjust status
|
std::string headers;
|
||||||
_request.headers = ::parse_http_headers(raw_request);
|
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)
|
void Client::_parse_port_hostname(std::string host)
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
# include <arpa/inet.h> // htonl, htons, ntohl, ntohs, inet_addr, inet_ntoa
|
# include <arpa/inet.h> // htonl, htons, ntohl, ntohs, inet_addr, inet_ntoa
|
||||||
# include "utils.hpp"
|
# include "utils.hpp"
|
||||||
# include "ServerConfig.hpp"
|
# include "ServerConfig.hpp"
|
||||||
# include "parsing_message_http.hpp"
|
|
||||||
|
|
||||||
struct Script
|
struct Script
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,6 +9,14 @@ void throw_test()
|
|||||||
throw std::bad_alloc();
|
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<std::string> split(std::string input, char delimiter)
|
std::vector<std::string> split(std::string input, char delimiter)
|
||||||
{
|
{
|
||||||
std::vector<std::string> answer;
|
std::vector<std::string> answer;
|
||||||
@@ -176,29 +184,91 @@ std::string str_tolower(std::string str)
|
|||||||
// identify a line in a string, by delim (ex. '\n')
|
// identify a line in a string, by delim (ex. '\n')
|
||||||
// delete this line from the string
|
// delete this line from the string
|
||||||
// and return the deleted line
|
// 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;
|
std::string del_str;
|
||||||
size_t begin;
|
size_t begin;
|
||||||
size_t end;
|
size_t end;
|
||||||
|
|
||||||
begin = (*str).rfind(delim, pos);
|
begin = str.rfind(delim, pos);
|
||||||
if (begin == std::string::npos)
|
if (begin == std::string::npos)
|
||||||
begin = 0;
|
begin = 0;
|
||||||
else
|
else
|
||||||
begin += delim.size();
|
begin += delim.size();
|
||||||
|
|
||||||
end = (*str).find(delim, pos);
|
end = str.find(delim, pos);
|
||||||
if (end == std::string::npos)
|
if (end != std::string::npos)
|
||||||
end = 0;
|
|
||||||
else
|
|
||||||
end += delim.size();
|
end += delim.size();
|
||||||
|
if (delim.empty())
|
||||||
|
end = std::string::npos;
|
||||||
|
|
||||||
del_str = (*str).substr(begin, end - begin);
|
del_str = str.substr(begin, end - begin);
|
||||||
(*str).erase(begin, end - begin);
|
str.erase(begin, end - begin);
|
||||||
return del_str;
|
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<std::string, std::string>
|
||||||
|
parse_http_headers (
|
||||||
|
std::string headers,
|
||||||
|
std::map<std::string, std::string> fields )
|
||||||
|
{
|
||||||
|
std::vector<std::string> list;
|
||||||
|
std::vector<std::string>::iterator it;
|
||||||
|
std::vector<std::string>::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<std::string, std::string>(key, val) );
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const listen_socket& lhs, int fd)
|
bool operator==(const listen_socket& lhs, int fd)
|
||||||
{ return lhs.fd == fd; }
|
{ return lhs.fd == fd; }
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,10 @@ std::string http_methods_to_str(unsigned int methods);
|
|||||||
int path_is_valid(std::string path);
|
int path_is_valid(std::string path);
|
||||||
void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr);
|
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 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<std::string, std::string>
|
||||||
|
parse_http_headers (std::string headers, std::map<std::string, std::string> fields );
|
||||||
void throw_test();
|
void throw_test();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ void Webserv::_check_script_status(Client *client, std::string output)
|
|||||||
{
|
{
|
||||||
status_pos = pos + std::string("Status:").size();
|
status_pos = pos + std::string("Status:").size();
|
||||||
client->status = atoi(output.c_str() + status_pos);
|
client->status = atoi(output.c_str() + status_pos);
|
||||||
::del_line_in_str(&output, pos, CRLF);
|
::extract_line(output, pos, CRLF);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
client->status = 200;
|
client->status = 200;
|
||||||
@@ -176,7 +176,7 @@ void Webserv::_check_script_fields(Client *client, std::string output)
|
|||||||
if (it_srv->first == it_scr->first)
|
if (it_srv->first == it_scr->first)
|
||||||
{
|
{
|
||||||
pos = client->response.find(it_srv->first);
|
pos = client->response.find(it_srv->first);
|
||||||
::del_line_in_str(&client->response, pos, CRLF);
|
::extract_line(client->response, pos, CRLF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +1,6 @@
|
|||||||
|
|
||||||
#include "parsing_message_http.hpp"
|
#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<std::string, std::string>
|
|
||||||
parse_http_headers(std::string message)
|
|
||||||
{
|
|
||||||
std::map<std::string, std::string> headers;
|
|
||||||
std::vector<std::string> list;
|
|
||||||
std::vector<std::string>::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<std::string, std::string>(key, val) );
|
|
||||||
}
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
parse_http_body(std::string message)
|
parse_http_body(std::string message)
|
||||||
{
|
{
|
||||||
@@ -57,18 +15,3 @@ std::string
|
|||||||
return body;
|
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<std::string> sline;
|
|
||||||
|
|
||||||
sline = ::split(str, ' ');
|
|
||||||
if (sline.size() != 3)
|
|
||||||
return false;
|
|
||||||
if (sline[0].find(':') != std::string::npos)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,14 +9,13 @@
|
|||||||
# include "utils.hpp"
|
# include "utils.hpp"
|
||||||
|
|
||||||
std::map<std::string, std::string>
|
std::map<std::string, std::string>
|
||||||
parse_http_headers(std::string message);
|
parse_http_headers (
|
||||||
|
std::string headers,
|
||||||
|
std::map<std::string, std::string> fields )
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
parse_http_body(std::string message);
|
parse_http_body(std::string message);
|
||||||
|
|
||||||
bool
|
|
||||||
maybe_http_first_line(std::string);
|
|
||||||
|
|
||||||
// http message structure :
|
// http message structure :
|
||||||
//
|
//
|
||||||
// start-line
|
// start-line
|
||||||
|
|||||||
Reference in New Issue
Block a user