Work on tests. Bug fixes and tweaks.
Started work on tests for fr::HttpRequest. Fixed the final POST data variable containing header data it shouldn't (\r\n\r\n). Fixed fr::Http::header_exists, and family, not converting things to lowercase first.
This commit is contained in:
parent
d3b51f75a5
commit
f2cebd0847
@ -39,7 +39,7 @@ if(USE_SSL)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64 -fPIC -std=c++14 -pthread")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++14 -pthread")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Set the library output directory
|
# Set the library output directory
|
||||||
|
|||||||
@ -126,11 +126,6 @@ namespace fr
|
|||||||
*/
|
*/
|
||||||
void set_body(const std::string &body_);
|
void set_body(const std::string &body_);
|
||||||
|
|
||||||
/*!
|
|
||||||
* Clear current request data
|
|
||||||
*/
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Returns a reference to a get variable.
|
* Returns a reference to a get variable.
|
||||||
* Can be used to either set/get the value.
|
* Can be used to either set/get the value.
|
||||||
@ -140,7 +135,7 @@ namespace fr
|
|||||||
* @param key The name of the GET variable
|
* @param key The name of the GET variable
|
||||||
* @return A reference to the GET variable
|
* @return A reference to the GET variable
|
||||||
*/
|
*/
|
||||||
std::string &get(const std::string &key);
|
std::string &get(std::string &&key);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Returns a reference to a POST variable.
|
* Returns a reference to a POST variable.
|
||||||
@ -151,7 +146,7 @@ namespace fr
|
|||||||
* @param key The name of the POST variable
|
* @param key The name of the POST variable
|
||||||
* @return A reference to the POST variable
|
* @return A reference to the POST variable
|
||||||
*/
|
*/
|
||||||
std::string &post(const std::string &key);
|
std::string &post(std::string &&key);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Returns a reference to a header.
|
* Returns a reference to a header.
|
||||||
@ -171,7 +166,7 @@ namespace fr
|
|||||||
* @param key The name of the GET variable
|
* @param key The name of the GET variable
|
||||||
* @return True if it does. False otherwise.
|
* @return True if it does. False otherwise.
|
||||||
*/
|
*/
|
||||||
bool get_exists(const std::string &key) const;
|
bool get_exists(std::string &&key) const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Checks to see if a given POST variable exists
|
* Checks to see if a given POST variable exists
|
||||||
@ -179,16 +174,16 @@ namespace fr
|
|||||||
* @param key The name of the POST variable
|
* @param key The name of the POST variable
|
||||||
* @return True if it does. False otherwise.
|
* @return True if it does. False otherwise.
|
||||||
*/
|
*/
|
||||||
bool post_exists(const std::string &key) const;
|
bool post_exists(std::string &&key) const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Checks to see if a given header exists.
|
* Checks to see if a given header exists.
|
||||||
* Note: 'key' should be lower case.
|
* Note: key will be converted to lower case
|
||||||
*
|
*
|
||||||
* @param key The name of the header
|
* @param key The name of the header
|
||||||
* @return True if it does. False otherwise.
|
* @return True if it does. False otherwise.
|
||||||
*/
|
*/
|
||||||
bool header_exists(const std::string &key) const;
|
bool header_exists(std::string &&key) const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Returns the requested URI
|
* Returns the requested URI
|
||||||
|
|||||||
@ -17,7 +17,13 @@ namespace fr
|
|||||||
public:
|
public:
|
||||||
//Constructors
|
//Constructors
|
||||||
HttpRequest();
|
HttpRequest();
|
||||||
HttpRequest(HttpRequest &&other) = default;
|
HttpRequest(HttpRequest &&other)=default;
|
||||||
|
void operator=(const HttpRequest &other)
|
||||||
|
{
|
||||||
|
header_ended = other.header_ended;
|
||||||
|
last_parsed_character = other.last_parsed_character;
|
||||||
|
content_length = other.content_length;
|
||||||
|
}
|
||||||
virtual ~HttpRequest() = default;
|
virtual ~HttpRequest() = default;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
31
src/Http.cpp
31
src/Http.cpp
@ -13,8 +13,11 @@ namespace fr
|
|||||||
const static std::string request_type_strings[Http::RequestType::RequestTypeCount] = {"UNKNOWN", "GET", "POST"};
|
const static std::string request_type_strings[Http::RequestType::RequestTypeCount] = {"UNKNOWN", "GET", "POST"};
|
||||||
|
|
||||||
Http::Http()
|
Http::Http()
|
||||||
|
: request_type(Unknown),
|
||||||
|
uri("/"),
|
||||||
|
status(Ok)
|
||||||
{
|
{
|
||||||
clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Http::Http(Http &&o)
|
Http::Http(Http &&o)
|
||||||
@ -69,34 +72,27 @@ namespace fr
|
|||||||
body = body_;
|
body = body_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Http::clear()
|
std::string &Http::get(std::string &&key)
|
||||||
{
|
|
||||||
post_data.clear();
|
|
||||||
get_data.clear();
|
|
||||||
post_data.clear();
|
|
||||||
body.clear();
|
|
||||||
uri = "/";
|
|
||||||
status = Ok;
|
|
||||||
request_type = Unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string &Http::get(const std::string &key)
|
|
||||||
{
|
{
|
||||||
|
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
|
||||||
return get_data[key];
|
return get_data[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string &Http::post(const std::string &key)
|
std::string &Http::post(std::string &&key)
|
||||||
{
|
{
|
||||||
|
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
|
||||||
return post_data[key];
|
return post_data[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Http::get_exists(const std::string &key) const
|
bool Http::get_exists(std::string &&key) const
|
||||||
{
|
{
|
||||||
|
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
|
||||||
return get_data.find(key) != get_data.end();
|
return get_data.find(key) != get_data.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Http::post_exists(const std::string &key) const
|
bool Http::post_exists(std::string &&key) const
|
||||||
{
|
{
|
||||||
|
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
|
||||||
return post_data.find(key) != post_data.end();
|
return post_data.find(key) != post_data.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,8 +185,9 @@ namespace fr
|
|||||||
return header_data[key];
|
return header_data[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Http::header_exists(const std::string &key) const
|
bool Http::header_exists(std::string &&key) const
|
||||||
{
|
{
|
||||||
|
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
|
||||||
return header_data.find(key) != header_data.end();
|
return header_data.find(key) != header_data.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -134,15 +134,24 @@ namespace fr
|
|||||||
|
|
||||||
void HttpRequest::parse_post_body()
|
void HttpRequest::parse_post_body()
|
||||||
{
|
{
|
||||||
|
//Find beginning of post data
|
||||||
auto post_begin = body.find_first_not_of("\r\n");
|
auto post_begin = body.find_first_not_of("\r\n");
|
||||||
if(post_begin == std::string::npos)
|
if(post_begin == std::string::npos)
|
||||||
post_begin = body.find_first_not_of("\n");
|
post_begin = body.find_first_not_of("\n");
|
||||||
if(post_begin != std::string::npos)
|
|
||||||
{
|
//Find end of post data
|
||||||
auto post = parse_argument_list(body.substr(post_begin, body.size() - post_begin));
|
auto post_end = body.rfind("\r\n\r\n");
|
||||||
for(auto &c : post)
|
if(post_end == std::string::npos)
|
||||||
post_data.emplace(std::move(c.first), std::move(c.second));
|
post_end = body.rfind("\n\n");
|
||||||
}
|
|
||||||
|
//Sanity check
|
||||||
|
if(post_begin == post_end || post_begin == std::string::npos)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Split up the body and store each argument name and value
|
||||||
|
auto post = parse_argument_list(body.substr(post_begin, body.size() - post_begin - (body.size() - post_end)));
|
||||||
|
for(auto &c : post)
|
||||||
|
post_data.emplace(std::move(c.first), std::move(c.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpRequest::parse_header_type(const std::string &str)
|
void HttpRequest::parse_header_type(const std::string &str)
|
||||||
|
|||||||
105
tests/HttpRequestTest.cpp
Normal file
105
tests/HttpRequestTest.cpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include <frnetlib/HttpRequest.h>
|
||||||
|
|
||||||
|
TEST(HttpRequestTest, get_request_parse)
|
||||||
|
{
|
||||||
|
//The test request to parse
|
||||||
|
const std::string raw_request =
|
||||||
|
"GET /index.html HTTP/1.1\n"
|
||||||
|
"Host: frednicolson.co.uk\r\n"
|
||||||
|
"Content-Type: application/x-www-form-urlencoded\r\n"
|
||||||
|
"My-Header: header1\n"
|
||||||
|
"My-Other-Header:header2\r\n"
|
||||||
|
"Cache-Control: no-cache\r\n\r\n";
|
||||||
|
|
||||||
|
//Parse it
|
||||||
|
fr::HttpRequest request;
|
||||||
|
ASSERT_EQ(request.parse(raw_request.c_str(), raw_request.size()), false);
|
||||||
|
|
||||||
|
//Check that the request type is intact
|
||||||
|
ASSERT_EQ(request.get_type(), fr::Http::Get);
|
||||||
|
|
||||||
|
//Test that URI is intact
|
||||||
|
ASSERT_EQ(request.get_uri(), "/index.html");
|
||||||
|
|
||||||
|
//Test that headers exist
|
||||||
|
ASSERT_EQ(request.header_exists("host"), true);
|
||||||
|
ASSERT_EQ(request.header_exists("contEnt-type"), true);
|
||||||
|
ASSERT_EQ(request.header_exists("my-HeadEr"), true);
|
||||||
|
ASSERT_EQ(request.header_exists("my-other-header"), true);
|
||||||
|
ASSERT_EQ(request.header_exists("cache-control"), true);
|
||||||
|
ASSERT_EQ(request.header_exists("non-existant"), false);
|
||||||
|
|
||||||
|
//Check that headers are intact
|
||||||
|
ASSERT_EQ(request.header("host"), "frednicolson.co.uk");
|
||||||
|
ASSERT_EQ(request.header("content-type"), "application/x-www-form-urlencoded");
|
||||||
|
ASSERT_EQ(request.header("My-Other-Header"), "header2");
|
||||||
|
ASSERT_EQ(request.header("My-Header"), "header1");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HttpRequestTest, post_request_parse)
|
||||||
|
{
|
||||||
|
const std::string raw_request =
|
||||||
|
"POST /index.html HTTP/1.1\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"post_data=data1&some_more_post_data=data23\r\n\r\n";
|
||||||
|
|
||||||
|
//Parse it
|
||||||
|
fr::HttpRequest request;
|
||||||
|
ASSERT_EQ(request.parse(raw_request.c_str(), raw_request.size()), false);
|
||||||
|
|
||||||
|
//Check that the request type is intact
|
||||||
|
ASSERT_EQ(request.get_type(), fr::Http::Post);
|
||||||
|
|
||||||
|
//Test that URI is intact
|
||||||
|
ASSERT_EQ(request.get_uri(), "/index.html");
|
||||||
|
|
||||||
|
//Parse code is the same for GET, so skip header checks. Test if POST data exists.
|
||||||
|
ASSERT_EQ(request.post_exists("post_data"), true);
|
||||||
|
ASSERT_EQ(request.post_exists("some_mOre_posT_data"), true);
|
||||||
|
ASSERT_EQ(request.post_exists("non_existant"), false);
|
||||||
|
|
||||||
|
//Check that the POST data is valid
|
||||||
|
ASSERT_EQ(request.post("post_dAta"), "data1");
|
||||||
|
ASSERT_EQ(request.post("some_more_post_data"), "data23");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HttpRequestTest, request_type_parse)
|
||||||
|
{
|
||||||
|
const std::string get_request = "GET / HTTP/1.1\r\n\r\n";
|
||||||
|
const std::string post_request = "POST / HTTP/1.1\r\n\r\n";
|
||||||
|
const std::string put_request = "PUT / HTTP/1.1\r\n\r\n";
|
||||||
|
const std::string delete_request = "DELETE / HTTP/1.1\r\n\r\n";
|
||||||
|
const std::string patch_request = "PATCH / HTTP/1.1\r\n\r\n";
|
||||||
|
const std::string invalid_request = "INVALID / HTTP/1.1\r\n\r\n";
|
||||||
|
|
||||||
|
fr::HttpRequest request;
|
||||||
|
request.parse(get_request.c_str(), get_request.size());
|
||||||
|
ASSERT_EQ(request.get_type(), fr::Http::Get);
|
||||||
|
request = {};
|
||||||
|
|
||||||
|
request.parse(post_request.c_str(), post_request.size());
|
||||||
|
ASSERT_EQ(request.get_type(), fr::Http::Post);
|
||||||
|
request = {};
|
||||||
|
|
||||||
|
request.parse(put_request.c_str(), put_request.size());
|
||||||
|
ASSERT_EQ(request.get_type(), fr::Http::Put);
|
||||||
|
request = {};
|
||||||
|
|
||||||
|
request.parse(delete_request.c_str(), delete_request.size());
|
||||||
|
ASSERT_EQ(request.get_type(), fr::Http::Delete);
|
||||||
|
request = {};
|
||||||
|
|
||||||
|
request.parse(patch_request.c_str(), patch_request.size());
|
||||||
|
ASSERT_EQ(request.get_type(), fr::Http::Patch);
|
||||||
|
request = {};
|
||||||
|
|
||||||
|
request.parse(invalid_request.c_str(), invalid_request.size());
|
||||||
|
ASSERT_EQ(request.get_type(), fr::Http::Unknown);
|
||||||
|
request = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HttpRequestTest, request_construction)
|
||||||
|
{
|
||||||
|
//todo: more tests
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user