Added tests. Improved error checking. Bug fixes.
Added fr::TcpListener tests.
This commit is contained in:
parent
08ed4a2354
commit
028677b01a
@ -41,7 +41,7 @@ namespace fr
|
||||
*
|
||||
* @param header_end_pos The position in 'body' of the end of the header
|
||||
*/
|
||||
void parse_header(int32_t header_end_pos);
|
||||
bool parse_header(int32_t header_end_pos);
|
||||
|
||||
/*!
|
||||
* Parses the POST data from the body
|
||||
|
||||
@ -41,7 +41,7 @@ namespace fr
|
||||
*
|
||||
* @param header_end_pos The position in 'body' of the end of the header
|
||||
*/
|
||||
void parse_header(int32_t header_end_pos);
|
||||
bool parse_header(int32_t header_end_pos);
|
||||
|
||||
//State
|
||||
bool header_ended;
|
||||
|
||||
@ -39,12 +39,19 @@ namespace fr
|
||||
* Calls the shutdown syscall on the socket.
|
||||
* So you can receive data but not send.
|
||||
*
|
||||
* Note: THIS DOES NOT CLOSE THE SOCKET. SHUTDOWN AND CLOSE ARE TWO DIFFERENT THINGS.
|
||||
*
|
||||
* This can be called on a blocking socket to force
|
||||
* it to immediately return (you might want to do this if
|
||||
* you're exiting and need the blocking socket to return).
|
||||
*/
|
||||
virtual void shutdown()=0;
|
||||
|
||||
/*!
|
||||
* Closes the socket
|
||||
*/
|
||||
virtual void close_socket()=0;
|
||||
|
||||
/*!
|
||||
* Gets the socket descriptor.
|
||||
*
|
||||
|
||||
@ -44,6 +44,11 @@ namespace fr
|
||||
*/
|
||||
virtual Socket::Status accept(Socket &client) override;
|
||||
|
||||
/*!
|
||||
* Closes the socket
|
||||
*/
|
||||
virtual void close_socket() override;
|
||||
|
||||
/*!
|
||||
* Calls the shutdown syscall on the socket.
|
||||
* So you can receive data but not send.
|
||||
|
||||
@ -16,7 +16,7 @@ namespace fr
|
||||
class TcpListener : public Listener
|
||||
{
|
||||
public:
|
||||
TcpListener() = default;
|
||||
TcpListener();
|
||||
virtual ~TcpListener() override;
|
||||
TcpListener(TcpListener &&o) = default;
|
||||
|
||||
@ -60,6 +60,11 @@ public:
|
||||
*/
|
||||
virtual void set_socket_descriptor(int32_t descriptor) override;
|
||||
|
||||
/*!
|
||||
* Closes the socket
|
||||
*/
|
||||
virtual void close_socket() override;
|
||||
|
||||
|
||||
private:
|
||||
int32_t socket_descriptor;
|
||||
|
||||
@ -33,7 +33,8 @@ namespace fr
|
||||
}
|
||||
else
|
||||
{
|
||||
parse_header(header_end);
|
||||
if(!parse_header(header_end))
|
||||
return false;
|
||||
body.clear();
|
||||
}
|
||||
content_length += 2; //The empty line between header and data
|
||||
@ -52,29 +53,38 @@ namespace fr
|
||||
return true;
|
||||
}
|
||||
|
||||
void HttpRequest::parse_header(int32_t header_end_pos)
|
||||
bool HttpRequest::parse_header(int32_t header_end_pos)
|
||||
{
|
||||
//Split the header into lines
|
||||
size_t line = 0;
|
||||
std::vector<std::string> header_lines = split_string(body.substr(0, header_end_pos));
|
||||
if(header_lines.empty())
|
||||
return;
|
||||
|
||||
//Parse request type & uri
|
||||
parse_header_type(header_lines[line]);
|
||||
parse_header_uri(header_lines[line]);
|
||||
line++;
|
||||
|
||||
//Read in headers
|
||||
for(; line < header_lines.size(); line++)
|
||||
try
|
||||
{
|
||||
parse_header_line(header_lines[line]);
|
||||
}
|
||||
//Split the header into lines
|
||||
size_t line = 0;
|
||||
std::vector<std::string> header_lines = split_string(body.substr(0, header_end_pos));
|
||||
if(header_lines.empty())
|
||||
return false;
|
||||
|
||||
//Parse request type & uri
|
||||
parse_header_type(header_lines[line]);
|
||||
parse_header_uri(header_lines[line]);
|
||||
line++;
|
||||
|
||||
//Read in headers
|
||||
for(; line < header_lines.size(); line++)
|
||||
{
|
||||
parse_header_line(header_lines[line]);
|
||||
}
|
||||
|
||||
//Store content length value if it exists
|
||||
auto length_header_iter = header_data.find("content-length");
|
||||
if(length_header_iter != header_data.end())
|
||||
content_length = (size_t)std::stoull(length_header_iter->second);
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
//Store content length value if it exists
|
||||
auto length_header_iter = header_data.find("content-length");
|
||||
if(length_header_iter != header_data.end())
|
||||
content_length = (size_t)std::stoull(length_header_iter->second);
|
||||
}
|
||||
|
||||
std::string HttpRequest::construct(const std::string &host) const
|
||||
|
||||
@ -62,24 +62,32 @@ namespace fr
|
||||
return response;
|
||||
}
|
||||
|
||||
void HttpResponse::parse_header(int32_t header_end_pos)
|
||||
bool HttpResponse::parse_header(int32_t header_end_pos)
|
||||
{
|
||||
//Split the header into lines
|
||||
size_t line = 0;
|
||||
std::vector<std::string> header_lines = split_string(body.substr(0, header_end_pos));
|
||||
if(header_lines.empty())
|
||||
return;
|
||||
line++;
|
||||
|
||||
//Read in headers
|
||||
for(; line < header_lines.size(); line++)
|
||||
try
|
||||
{
|
||||
parse_header_line(header_lines[line]);
|
||||
}
|
||||
//Split the header into lines
|
||||
size_t line = 0;
|
||||
std::vector<std::string> header_lines = split_string(body.substr(0, header_end_pos));
|
||||
if(header_lines.empty())
|
||||
return false;
|
||||
line++;
|
||||
|
||||
//Store content length value if it exists
|
||||
auto length_header_iter = header_data.find("content-length");
|
||||
if(length_header_iter != header_data.end())
|
||||
content_length = std::stoull(length_header_iter->second);
|
||||
//Read in headers
|
||||
for(; line < header_lines.size(); line++)
|
||||
{
|
||||
parse_header_line(header_lines[line]);
|
||||
}
|
||||
|
||||
//Store content length value if it exists
|
||||
auto length_header_iter = header_data.find("content-length");
|
||||
if(length_header_iter != header_data.end())
|
||||
content_length = std::stoull(length_header_iter->second);
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -15,7 +15,7 @@ namespace fr
|
||||
: ssl_context(ssl_context_)
|
||||
{
|
||||
//Initialise SSL objects required
|
||||
mbedtls_net_init(&listen_fd);
|
||||
listen_fd.fd = -1;
|
||||
mbedtls_ssl_config_init(&conf);
|
||||
mbedtls_x509_crt_init(&srvcert);
|
||||
mbedtls_pk_init(&pkey);
|
||||
@ -64,7 +64,7 @@ namespace fr
|
||||
|
||||
SSLListener::~SSLListener()
|
||||
{
|
||||
mbedtls_net_free(&listen_fd);
|
||||
close_socket();
|
||||
mbedtls_x509_crt_free(&srvcert);
|
||||
mbedtls_pk_free(&pkey);
|
||||
mbedtls_ssl_config_free(&conf);
|
||||
@ -73,6 +73,8 @@ namespace fr
|
||||
Socket::Status fr::SSLListener::listen(const std::string &port)
|
||||
{
|
||||
//This is a hack. mbedtls doesn't support specifying the address family.
|
||||
close_socket();
|
||||
mbedtls_net_init(&listen_fd);
|
||||
fr::TcpListener tcp_listen;
|
||||
tcp_listen.set_inet_version(ai_family);
|
||||
if(tcp_listen.listen(port) != fr::Socket::Success)
|
||||
@ -142,5 +144,14 @@ namespace fr
|
||||
listen_fd.fd = descriptor;
|
||||
}
|
||||
|
||||
void SSLListener::close_socket()
|
||||
{
|
||||
if(listen_fd.fd != -1)
|
||||
{
|
||||
mbedtls_net_free(&listen_fd);
|
||||
listen_fd.fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
@ -9,13 +9,16 @@ namespace fr
|
||||
|
||||
const int yes = 1;
|
||||
const int no = 0;
|
||||
|
||||
TcpListener::TcpListener()
|
||||
: socket_descriptor(-1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TcpListener::~TcpListener()
|
||||
{
|
||||
if(socket_descriptor > -1)
|
||||
{
|
||||
closesocket(socket_descriptor);
|
||||
socket_descriptor = -1;
|
||||
}
|
||||
close_socket();
|
||||
}
|
||||
|
||||
Socket::Status TcpListener::listen(const std::string &port)
|
||||
@ -122,4 +125,13 @@ namespace fr
|
||||
{
|
||||
socket_descriptor = descriptor;
|
||||
}
|
||||
|
||||
void TcpListener::close_socket()
|
||||
{
|
||||
if(socket_descriptor > -1)
|
||||
{
|
||||
closesocket(socket_descriptor);
|
||||
socket_descriptor = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
tests/TcpListenerTest.cpp
Normal file
47
tests/TcpListenerTest.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
//
|
||||
// Created by fred on 05/06/17.
|
||||
//
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <frnetlib/TcpListener.h>
|
||||
#include <thread>
|
||||
|
||||
TEST(TcpListenerTest, listner_listen)
|
||||
{
|
||||
fr::TcpListener listener;
|
||||
ASSERT_EQ(listener.get_socket_descriptor(), -1);
|
||||
fr::Socket::Status ret = listener.listen("9090");
|
||||
ASSERT_EQ(ret, fr::Socket::Success);
|
||||
listener.close_socket();
|
||||
ASSERT_EQ(listener.get_socket_descriptor(), -1);
|
||||
}
|
||||
|
||||
|
||||
TEST(TcpListenerTest, listener_accept)
|
||||
{
|
||||
fr::TcpListener listener;
|
||||
listener.set_inet_version(fr::Socket::IP::v4);
|
||||
if(listener.listen("9095") != fr::Socket::Success)
|
||||
FAIL();
|
||||
|
||||
auto client_thread = []()
|
||||
{
|
||||
fr::TcpSocket socket;
|
||||
socket.set_inet_version(fr::Socket::IP::v4);
|
||||
auto ret = socket.connect("127.0.0.1", "9095");
|
||||
ASSERT_EQ(ret, fr::Socket::Success);
|
||||
};
|
||||
|
||||
std::thread t1(client_thread);
|
||||
fr::TcpSocket socket;
|
||||
auto ret = listener.accept(socket);
|
||||
ASSERT_EQ(ret, fr::Socket::Success);
|
||||
t1.join();
|
||||
}
|
||||
|
||||
TEST(TcpListenerTest, set_descriptor)
|
||||
{
|
||||
fr::TcpListener listener;
|
||||
listener.set_socket_descriptor(-20);
|
||||
ASSERT_EQ(listener.get_socket_descriptor(), -20);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user