Wip chunked decoding

+ Need to test normal body parsing
+ path_is_valid() renamed eval_file_type()
+ replaced atoi with strtol/strtoul
This commit is contained in:
LuckyLaszlo
2022-08-12 05:50:00 +02:00
parent ab0bc2c4c0
commit 400efbe720
18 changed files with 185 additions and 82 deletions

View File

@@ -8,6 +8,7 @@
Client::Client()
: status(0),
header_complete(false),
body_complete(false),
request_complete(false),
read_body_size(0),
assigned_server(NULL),
@@ -23,6 +24,7 @@ Client::Client()
Client::Client(int afd, listen_socket *lsocket, std::string aport, std::string aip)
: status(0),
header_complete(false),
body_complete(false),
request_complete(false),
read_body_size(0),
assigned_server(NULL),
@@ -82,8 +84,9 @@ void Client::parse_request(std::vector<ServerConfig> &servers)
std::map<std::string, std::string> headers;
std::string body;
// DEBUG
// std::cout << "\nREQUEST ____________\n" << raw_request << "\n_____________\n";
if (raw_request.find(CRLF CRLF) == NPOS)
return ;
header_complete = true;
clear_request(); // not mandatory
_parse_request_line();
@@ -97,6 +100,7 @@ void Client::parse_request(std::vector<ServerConfig> &servers)
return;
_parse_port_hostname(this->get_rq_headers("Host"));
std::cerr << get_rq_method_str() << " " << get_rq_uri() << " " << get_rq_version() << "\n"; // DEBUG
/* dont clear raw_request, we need it for future reparsing of body
see call of parse_request() in _read_request() */
// raw_request.clear();
@@ -104,8 +108,89 @@ void Client::parse_request(std::vector<ServerConfig> &servers)
void Client::parse_request_body()
{
// TODO: check error and adjust status
_request.body = ::parse_http_body(raw_request);
size_t pos;
pos = raw_request.find(CRLF CRLF);
if (pos == NPOS)
{
std::cerr << "parse_request_body() bad call, header incomplete\n";
return;
}
pos += CRLF_SIZE*2;
// Chunked decoding WIP. Dont work.
if (!get_rq_headers("Transfer-Encoding").empty()
&& get_rq_headers("Transfer-Encoding") == "chunked")
{
size_t chunk_size = 1;
size_t chunk_field_end = 0;
char *endptr = NULL;
char *endptr_copy = NULL;
/* TODO: verify if last chunk in raw_request (to avoid multiples complete parsing)
but how ? with "raw_request.rfind("0" CRLF CRLF)", there no confirmation
that we have found the last last-chunk OR just some data */
_request.body = raw_request.substr(pos);
std::cerr << "______Chunked\n" << _request.body << "\n______\n";
pos = 0;
while (chunk_size != 0)
{
if (pos > _request.body.size())
{
std::cerr << "parse_request_body(), pos > size()\n";
// status = 400;
return;
}
if (pos == _request.body.size())
{
std::cerr << "parse_request_body(), will reread till last chunk\n";
return;
}
endptr_copy = endptr;
chunk_size = std::strtoul(&_request.body[pos], &endptr, 16);
if (chunk_size == LONG_MAX && errno == ERANGE)
status = 413;
if (endptr == endptr_copy)
{
std::cerr << "parse_request_body(), no conversion possible\n";
return;
}
chunk_field_end = _request.body.find(CRLF, pos);
if (chunk_field_end == NPOS)
{
std::cerr << "parse_request_body(), chunk_field no CRLF\n";
// status = 400;
return;
}
chunk_field_end += CRLF_SIZE;
_request.body.erase(pos, chunk_field_end);
pos += chunk_size + CRLF_SIZE;
}
_request.headers.erase("Transfer-Encoding");
body_complete = true;
}
else
{
if (raw_request.size() - pos >= std::strtoul(get_rq_headers("Content-Length").c_str(), NULL, 10))
{
_request.body = raw_request.substr(pos);
body_complete = true;
}
/* Should be equivalent */
// _request.body = raw_request.substr(pos);
// if (_request.body.size() >= std::strtoul(get_rq_headers("Content-Length").c_str(), NULL, 10))
// body_complete = true;
}
///////////////
// Body checks
if (_request.body.size() > assigned_server->client_body_limit)
status = 413;
}
@@ -132,6 +217,7 @@ void Client::clear()
{
clear_request();
header_complete = false;
body_complete = false;
request_complete = false;
read_body_size = 0;
assigned_server = NULL;
@@ -185,6 +271,7 @@ std::string Client::get_rq_port() const { return _request.port; }
std::string Client::get_rq_hostname() const { return _request.hostname; }
std::string Client::get_rq_script_path()const { return _request.script.path; }
std::string Client::get_rq_script_info()const { return _request.script.info; }
std::string Client::get_rq_headers(const std::string & key) const
{
std::map<std::string, std::string>::const_iterator it;
@@ -259,7 +346,7 @@ void Client::_parse_port_hostname(std::string host)
void Client::_check_request_errors()
{
//////////////////////
///////////////////////
// Request line checks
if (_request.method == UNKNOWN)
status = 501;
@@ -281,15 +368,21 @@ void Client::_check_request_errors()
response.append(CRLF CRLF);
}
if (status)
return;
/////////////////
//////////////////
// Headers checks
if (!this->get_rq_headers("Content-Length").empty()
&& ::atoi(this->get_rq_headers("Content-Length").c_str()) > (int)assigned_server->client_body_limit)
else if (!this->get_rq_headers("Content-Length").empty()
&& std::strtoul(this->get_rq_headers("Content-Length").c_str(), NULL, 10) > assigned_server->client_body_limit)
status = 413;
else if (!this->get_rq_headers("Transfer-Encoding").empty()
&& this->get_rq_headers("Transfer-Encoding") != "chunked" )
status = 501;
else if (!this->get_rq_headers("Content-Encoding").empty())
{
status = 415;
response.append("Accept-Encoding:"); // empty, no encoding accepted
response.append(CRLF);
}
return;
}
@@ -303,4 +396,3 @@ bool operator==(const Client& lhs, int fd)
{ return lhs.get_cl_fd() == fd; }
bool operator==(int fd, const Client& rhs)
{ return fd == rhs.get_cl_fd(); }