Moving enums to enum classes
This commit is contained in:
parent
277a74430c
commit
32767786af
@ -1,4 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.2)
|
cmake_minimum_required(VERSION 3.9)
|
||||||
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||||
project(frnetlib)
|
project(frnetlib)
|
||||||
set(FRNETLIB_LINK_LIBRARIES "")
|
set(FRNETLIB_LINK_LIBRARIES "")
|
||||||
|
|
||||||
@ -6,7 +7,7 @@ set(FRNETLIB_LINK_LIBRARIES "")
|
|||||||
set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules)
|
set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules)
|
||||||
|
|
||||||
#User options
|
#User options
|
||||||
option(USE_SSL "Enable SSL support" OFF)
|
option(USE_SSL "Enable SSL support" ON)
|
||||||
option(BUILD_EXAMPLES "Build frnetlib examples" ON)
|
option(BUILD_EXAMPLES "Build frnetlib examples" ON)
|
||||||
option(BUILD_TESTS "Build frnetlib tests" ON)
|
option(BUILD_TESTS "Build frnetlib tests" ON)
|
||||||
option(BUILD_WEBSOCK "Enable WebSocket support" ON)
|
option(BUILD_WEBSOCK "Enable WebSocket support" ON)
|
||||||
|
|||||||
@ -32,7 +32,7 @@ int main()
|
|||||||
//port multiple times. Each thread should have its own fr::SocketSelector, this will
|
//port multiple times. Each thread should have its own fr::SocketSelector, this will
|
||||||
//spread connections over multiple workers.
|
//spread connections over multiple workers.
|
||||||
auto listener = std::make_shared<fr::TcpListener>();
|
auto listener = std::make_shared<fr::TcpListener>();
|
||||||
if(listener->listen("8080") != fr::Socket::Success)
|
if(listener->listen("8080") != fr::Socket::Status::Success)
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to bind to port" << std::endl;
|
std::cerr << "Failed to bind to port" << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@ -53,7 +53,7 @@ int main()
|
|||||||
if(ready_socket.first->get_socket_descriptor() == listener->get_socket_descriptor())
|
if(ready_socket.first->get_socket_descriptor() == listener->get_socket_descriptor())
|
||||||
{
|
{
|
||||||
auto client = std::make_shared<fr::TcpSocket>(); //Or fr::SSLSocket
|
auto client = std::make_shared<fr::TcpSocket>(); //Or fr::SSLSocket
|
||||||
if(listener->accept(*client) == fr::Socket::Success)
|
if(listener->accept(*client) == fr::Socket::Status::Success)
|
||||||
{
|
{
|
||||||
client->set_blocking(false); //This is important
|
client->set_blocking(false); //This is important
|
||||||
listen_loop_selector.add(client, new SessionState()); //We assign a 'SessionState' object for each connection as opaque data
|
listen_loop_selector.add(client, new SessionState()); //We assign a 'SessionState' object for each connection as opaque data
|
||||||
@ -69,23 +69,23 @@ int main()
|
|||||||
char data[0x1000];
|
char data[0x1000];
|
||||||
size_t received = 0;
|
size_t received = 0;
|
||||||
auto recv_status = client->receive_raw(data, sizeof(data), received);
|
auto recv_status = client->receive_raw(data, sizeof(data), received);
|
||||||
if(recv_status == fr::Socket::Success)
|
if(recv_status == fr::Socket::Status::Success)
|
||||||
{
|
{
|
||||||
//We received data, so parse it using the partial HTTP request associated with this connection
|
//We received data, so parse it using the partial HTTP request associated with this connection
|
||||||
auto parse_status = session->partial_request.parse(data, received);
|
auto parse_status = session->partial_request.parse(data, received);
|
||||||
if(parse_status == fr::Socket::Success)
|
if(parse_status == fr::Socket::Status::Success)
|
||||||
{
|
{
|
||||||
//The client has sent a full request, queue it for processing
|
//The client has sent a full request, queue it for processing
|
||||||
process_complete_request(client, std::move(session->partial_request));
|
process_complete_request(client, std::move(session->partial_request));
|
||||||
session->partial_request = fr::HttpRequest();
|
session->partial_request = fr::HttpRequest();
|
||||||
}
|
}
|
||||||
else if(parse_status != fr::Socket::NotEnoughData)
|
else if(parse_status != fr::Socket::Status::NotEnoughData)
|
||||||
{
|
{
|
||||||
//HTTP error, disconnect the client. Remove from socket selector, and delete opaque data.
|
//HTTP error, disconnect the client. Remove from socket selector, and delete opaque data.
|
||||||
delete (SessionState*)listen_loop_selector.remove(client);
|
delete (SessionState*)listen_loop_selector.remove(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(recv_status != fr::Socket::WouldBlock)
|
else if(recv_status != fr::Socket::Status::WouldBlock)
|
||||||
{
|
{
|
||||||
//Error, disconnect it. Remove from socket selector, and delete opaque data.
|
//Error, disconnect it. Remove from socket selector, and delete opaque data.
|
||||||
delete (SessionState*)listen_loop_selector.remove(client);
|
delete (SessionState*)listen_loop_selector.remove(client);
|
||||||
|
|||||||
@ -29,7 +29,7 @@ int main()
|
|||||||
fr::TcpListener listener;
|
fr::TcpListener listener;
|
||||||
|
|
||||||
//Try to connect to the parsed address
|
//Try to connect to the parsed address
|
||||||
if((err = socket.connect(parsed_url.get_host(), parsed_url.get_port(), {})) != fr::Socket::Success)
|
if((err = socket.connect(parsed_url.get_host(), parsed_url.get_port(), {})) != fr::Socket::Status::Success)
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to connect to the specified URL: " << fr::Socket::status_to_string(err) << std::endl;
|
std::cerr << "Failed to connect to the specified URL: " << fr::Socket::status_to_string(err) << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@ -38,7 +38,7 @@ int main()
|
|||||||
//Construct a request, requesting the user provided URI
|
//Construct a request, requesting the user provided URI
|
||||||
fr::HttpRequest request;
|
fr::HttpRequest request;
|
||||||
request.set_uri(parsed_url.get_uri());
|
request.set_uri(parsed_url.get_uri());
|
||||||
if((err = socket.send(request)) != fr::Socket::Success)
|
if((err = socket.send(request)) != fr::Socket::Status::Success)
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to send HTTP request: " + fr::Socket::status_to_string(err) << std::endl;
|
std::cerr << "Failed to send HTTP request: " + fr::Socket::status_to_string(err) << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@ -46,7 +46,7 @@ int main()
|
|||||||
|
|
||||||
//Now wait for a response
|
//Now wait for a response
|
||||||
fr::HttpResponse response;
|
fr::HttpResponse response;
|
||||||
if(socket.receive(response) != fr::Socket::Success)
|
if(socket.receive(response) != fr::Socket::Status::Success)
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to receive HTTP response" << std::endl;
|
std::cerr << "Failed to receive HTTP response" << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|||||||
@ -15,13 +15,13 @@ namespace fr
|
|||||||
class Http : public Sendable
|
class Http : public Sendable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum RequestVersion
|
enum class RequestVersion
|
||||||
{
|
{
|
||||||
V1 = 1, // HTTP/1.0
|
V1 = 1, // HTTP/1.0
|
||||||
V1_1 = 2, // HTTP/1.1
|
V1_1 = 2, // HTTP/1.1
|
||||||
VersionCount = 3
|
VersionCount = 3
|
||||||
};
|
};
|
||||||
enum RequestType
|
enum class RequestType
|
||||||
{
|
{
|
||||||
Get = 0,
|
Get = 0,
|
||||||
Post = 1,
|
Post = 1,
|
||||||
@ -32,7 +32,7 @@ namespace fr
|
|||||||
Unknown = 6,
|
Unknown = 6,
|
||||||
Partial = 7,
|
Partial = 7,
|
||||||
};
|
};
|
||||||
enum RequestStatus
|
enum class RequestStatus
|
||||||
{
|
{
|
||||||
Continue = 100,
|
Continue = 100,
|
||||||
SwitchingProtocols = 101,
|
SwitchingProtocols = 101,
|
||||||
@ -274,7 +274,19 @@ namespace fr
|
|||||||
* @param type The RequestType to convert
|
* @param type The RequestType to convert
|
||||||
* @return The printable version of the enum value
|
* @return The printable version of the enum value
|
||||||
*/
|
*/
|
||||||
static std::string request_type_to_string(RequestType type);
|
static std::string request_type_to_string(RequestType type)
|
||||||
|
{
|
||||||
|
static_assert((uint32_t)RequestType::RequestTypeCount == 5, "Update request_type_to_string");
|
||||||
|
const static std::string request_type_strings[(uint32_t)RequestType::RequestTypeCount] = {"GET",
|
||||||
|
"POST",
|
||||||
|
"PUT",
|
||||||
|
"DELETE",
|
||||||
|
"PATCH"};
|
||||||
|
|
||||||
|
if(type >= RequestType::RequestTypeCount)
|
||||||
|
return "UNKNOWN";
|
||||||
|
return request_type_strings[(uint32_t)type];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Converts a string value into a 'RequestType' enum value.
|
* Converts a string value into a 'RequestType' enum value.
|
||||||
@ -282,7 +294,26 @@ namespace fr
|
|||||||
* @param str The string to convert
|
* @param str The string to convert
|
||||||
* @return The converted RequestType. Unknown on failure. Or Partial if str is part of a request type.
|
* @return The converted RequestType. Unknown on failure. Or Partial if str is part of a request type.
|
||||||
*/
|
*/
|
||||||
static RequestType string_to_request_type(const std::string &str);
|
static RequestType string_to_request_type(const std::string &str)
|
||||||
|
{
|
||||||
|
//Find the request type
|
||||||
|
static_assert((uint32_t)Http::RequestType::RequestTypeCount == 5, "Update parse_header_type()");
|
||||||
|
|
||||||
|
RequestType type = Http::RequestType::Unknown;
|
||||||
|
for(size_t a = 0; a < (uint32_t)Http::RequestType::RequestTypeCount; ++a)
|
||||||
|
{
|
||||||
|
std::string type_string = request_type_to_string(static_cast<RequestType>(a));
|
||||||
|
int cmp_ret = str.compare(0, type_string.size(), type_string);
|
||||||
|
if(cmp_ret == 0)
|
||||||
|
return static_cast<RequestType>(a);
|
||||||
|
if(str.size() < type_string.size() && cmp_ret < 0)
|
||||||
|
type = Http::RequestType::Partial;
|
||||||
|
if(type != Http::RequestType::Partial && str.size() < type_string.size() && cmp_ret > 0)
|
||||||
|
type = Http::RequestType::Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@ -710,7 +710,7 @@ namespace fr
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
state = socket->send_raw(&buffer[0], buffer.size(), sent);
|
state = socket->send_raw(&buffer[0], buffer.size(), sent);
|
||||||
} while(state == fr::Socket::WouldBlock);
|
} while(state == fr::Socket::Status::WouldBlock);
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -737,7 +737,7 @@ namespace fr
|
|||||||
|
|
||||||
//Check that packet_length doesn't exceed the limit, if any
|
//Check that packet_length doesn't exceed the limit, if any
|
||||||
if(socket->get_max_receive_size() && packet_length > socket->get_max_receive_size())
|
if(socket->get_max_receive_size() && packet_length > socket->get_max_receive_size())
|
||||||
return fr::Socket::MaxPacketSizeExceeded;
|
return fr::Socket::Status::MaxPacketSizeExceeded;
|
||||||
|
|
||||||
//Now we've got the length, read the rest of the data in
|
//Now we've got the length, read the rest of the data in
|
||||||
if(packet_length + PACKET_HEADER_LENGTH > buffer.size())
|
if(packet_length + PACKET_HEADER_LENGTH > buffer.size())
|
||||||
@ -746,9 +746,9 @@ namespace fr
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
status = socket->receive_all(&buffer[PACKET_HEADER_LENGTH], packet_length);
|
status = socket->receive_all(&buffer[PACKET_HEADER_LENGTH], packet_length);
|
||||||
} while(status == fr::Socket::WouldBlock);
|
} while(status == fr::Socket::Status::WouldBlock);
|
||||||
if(status == fr::Socket::Timeout)
|
if(status == fr::Socket::Status::Timeout)
|
||||||
status = fr::Socket::Disconnected;
|
status = fr::Socket::Status::Disconnected;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -72,14 +72,14 @@ namespace fr
|
|||||||
*
|
*
|
||||||
* @return True if connected, false otherwise
|
* @return True if connected, false otherwise
|
||||||
*/
|
*/
|
||||||
bool connected() const noexcept override;
|
bool connected() const override;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Gets the underlying socket descriptor.
|
* Gets the underlying socket descriptor.
|
||||||
*
|
*
|
||||||
* @return The socket descriptor.
|
* @return The socket descriptor.
|
||||||
*/
|
*/
|
||||||
int32_t get_socket_descriptor() const noexcept override;
|
int32_t get_socket_descriptor() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mbedtls_net_context listen_fd;
|
mbedtls_net_context listen_fd;
|
||||||
|
|||||||
@ -17,7 +17,7 @@ namespace fr
|
|||||||
class Socket : public SocketDescriptor
|
class Socket : public SocketDescriptor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Status
|
enum class Status
|
||||||
{
|
{
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
Success = 1,
|
Success = 1,
|
||||||
@ -44,7 +44,7 @@ namespace fr
|
|||||||
//Remember to update status_to_string if more are added
|
//Remember to update status_to_string if more are added
|
||||||
};
|
};
|
||||||
|
|
||||||
enum IP
|
enum class IP
|
||||||
{
|
{
|
||||||
v4 = 1,
|
v4 = 1,
|
||||||
v6 = 2,
|
v6 = 2,
|
||||||
@ -163,7 +163,7 @@ namespace fr
|
|||||||
* 'WouldBlock' or 'Timeout': No data received. Object still valid though.
|
* 'WouldBlock' or 'Timeout': No data received. Object still valid though.
|
||||||
* Anything else: Object invalid. Call disconnect().
|
* Anything else: Object invalid. Call disconnect().
|
||||||
*/
|
*/
|
||||||
Status receive_all(void *dest, size_t buffer_size);
|
Socket::Status receive_all(void *dest, size_t buffer_size);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Calls the shutdown syscall on the socket.
|
* Calls the shutdown syscall on the socket.
|
||||||
@ -278,9 +278,9 @@ namespace fr
|
|||||||
*
|
*
|
||||||
* @return The string address
|
* @return The string address
|
||||||
*/
|
*/
|
||||||
inline const std::string &get_remote_address() const
|
const std::string &get_remote_address() const
|
||||||
{
|
{
|
||||||
return remote_address;
|
return fr_socket_remote_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -290,7 +290,7 @@ namespace fr
|
|||||||
*/
|
*/
|
||||||
inline void set_remote_address(const std::string &addr)
|
inline void set_remote_address(const std::string &addr)
|
||||||
{
|
{
|
||||||
remote_address = addr;
|
fr_socket_remote_address = addr;
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@ -305,7 +305,7 @@ namespace fr
|
|||||||
*/
|
*/
|
||||||
virtual void reconfigure_socket()=0;
|
virtual void reconfigure_socket()=0;
|
||||||
|
|
||||||
std::string remote_address;
|
std::string fr_socket_remote_address;
|
||||||
int ai_family;
|
int ai_family;
|
||||||
uint32_t max_receive_size;
|
uint32_t max_receive_size;
|
||||||
uint32_t socket_read_timeout;
|
uint32_t socket_read_timeout;
|
||||||
|
|||||||
@ -64,14 +64,14 @@ public:
|
|||||||
*
|
*
|
||||||
* @return True if connected, false otherwise
|
* @return True if connected, false otherwise
|
||||||
*/
|
*/
|
||||||
bool connected() const noexcept override;
|
bool connected() const override;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Gets the underlying socket descriptor.
|
* Gets the underlying socket descriptor.
|
||||||
*
|
*
|
||||||
* @return The socket descriptor.
|
* @return The socket descriptor.
|
||||||
*/
|
*/
|
||||||
int32_t get_socket_descriptor() const noexcept override;
|
int32_t get_socket_descriptor() const override;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#define FRNETLIB_URLPARSER_H
|
#define FRNETLIB_URLPARSER_H
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
//Note, a URL looks like this: scheme:[//host[:port]][/path][?query][#fragment]
|
//Note, a URL looks like this: scheme:[//host[:port]][/path][?query][#fragment]
|
||||||
namespace fr
|
namespace fr
|
||||||
@ -39,7 +40,7 @@ namespace fr
|
|||||||
*
|
*
|
||||||
* @param url The URL to parse
|
* @param url The URL to parse
|
||||||
*/
|
*/
|
||||||
void parse(std::string url);
|
void parse(const std::string &url);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Get the URL scheme
|
* Get the URL scheme
|
||||||
@ -141,7 +142,12 @@ namespace fr
|
|||||||
* @param str The string to convert
|
* @param str The string to convert
|
||||||
* @return The converted string
|
* @return The converted string
|
||||||
*/
|
*/
|
||||||
static std::string to_lower(const std::string &str);
|
static std::string to_lower(const std::string &str)
|
||||||
|
{
|
||||||
|
std::string out = str;
|
||||||
|
std::transform(out.begin(), out.end(), out.begin(), ::tolower);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
//State
|
//State
|
||||||
Scheme scheme;
|
Scheme scheme;
|
||||||
|
|||||||
@ -14,7 +14,7 @@ namespace fr
|
|||||||
class WebFrame : public fr::Sendable
|
class WebFrame : public fr::Sendable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Opcode : uint8_t
|
enum class Opcode : uint8_t
|
||||||
{
|
{
|
||||||
Continuation = 0,
|
Continuation = 0,
|
||||||
Text = 1,
|
Text = 1,
|
||||||
@ -29,7 +29,7 @@ namespace fr
|
|||||||
*
|
*
|
||||||
* @param type The opcode type. See set_opcode. Text by default.
|
* @param type The opcode type. See set_opcode. Text by default.
|
||||||
*/
|
*/
|
||||||
explicit WebFrame(Opcode type = Text);
|
explicit WebFrame(Opcode type = Opcode::Text);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Get's the receied payload data. (Data received).
|
* Get's the receied payload data. (Data received).
|
||||||
|
|||||||
@ -49,7 +49,7 @@ namespace fr
|
|||||||
{
|
{
|
||||||
//Establish a connection using the parent class
|
//Establish a connection using the parent class
|
||||||
Socket::Status status = SocketType::connect(address, port, timeout);
|
Socket::Status status = SocketType::connect(address, port, timeout);
|
||||||
if(status != fr::Socket::Success)
|
if(status != Socket::Status::Success)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
//Send an upgrade request header
|
//Send an upgrade request header
|
||||||
@ -60,19 +60,19 @@ namespace fr
|
|||||||
request.header("connection") = "upgrade";
|
request.header("connection") = "upgrade";
|
||||||
request.header("upgrade") = "websocket";
|
request.header("upgrade") = "websocket";
|
||||||
status = SocketType::send(request);
|
status = SocketType::send(request);
|
||||||
if(status != fr::Socket::Success)
|
if(status != Socket::Status::Success)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
//Receive the response
|
//Receive the response
|
||||||
HttpResponse response;
|
HttpResponse response;
|
||||||
status = SocketType::receive(response);
|
status = SocketType::receive(response);
|
||||||
if(status != fr::Socket::Success)
|
if(status != Socket::Status::Success)
|
||||||
return status;
|
return status;
|
||||||
if(response.get_status() != Http::SwitchingProtocols)
|
if(response.get_status() != Http::RequestStatus::SwitchingProtocols)
|
||||||
{
|
{
|
||||||
disconnect();
|
disconnect();
|
||||||
errno = EPROTO;
|
errno = EPROTO;
|
||||||
return Socket::HandshakeFailed;
|
return Socket::Status::HandshakeFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Verify the sec-websocket-accept header
|
//Verify the sec-websocket-accept header
|
||||||
@ -81,10 +81,10 @@ namespace fr
|
|||||||
{
|
{
|
||||||
disconnect();
|
disconnect();
|
||||||
errno = EPROTO;
|
errno = EPROTO;
|
||||||
return Socket::HandshakeFailed;
|
return Socket::Status::HandshakeFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fr::Socket::Success;
|
return Socket::Status::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -94,7 +94,7 @@ namespace fr
|
|||||||
void disconnect() override
|
void disconnect() override
|
||||||
{
|
{
|
||||||
WebFrame frame;
|
WebFrame frame;
|
||||||
frame.set_opcode(WebFrame::Disconnect);
|
frame.set_opcode(WebFrame::Opcode::Disconnect);
|
||||||
if(SocketType::connected())
|
if(SocketType::connected())
|
||||||
SocketType::send(frame);
|
SocketType::send(frame);
|
||||||
SocketType::close_socket();
|
SocketType::close_socket();
|
||||||
@ -117,16 +117,16 @@ namespace fr
|
|||||||
|
|
||||||
//Initialise connection, receive the handshake
|
//Initialise connection, receive the handshake
|
||||||
HttpRequest request;
|
HttpRequest request;
|
||||||
if(SocketType::receive(request) != fr::Socket::Success)
|
if(SocketType::receive(request) != Socket::Status::Success)
|
||||||
throw std::runtime_error("Failed to receive WebSock handshake");
|
throw std::runtime_error("Failed to receive WebSock handshake");
|
||||||
|
|
||||||
if(request.header("Upgrade") != "websocket" || request.get_type() != fr::Http::Get)
|
if(request.header("Upgrade") != "websocket" || request.get_type() != Http::RequestType::Get)
|
||||||
throw std::runtime_error("Client isn't using the WebSock protocol");
|
throw std::runtime_error("Client isn't using the WebSock protocol");
|
||||||
|
|
||||||
//Calculate the derived key, then send back our response
|
//Calculate the derived key, then send back our response
|
||||||
std::string derived_key = Base64::encode(Sha1::sha1_digest(request.header("sec-websocket-key") + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
|
std::string derived_key = Base64::encode(Sha1::sha1_digest(request.header("sec-websocket-key") + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
|
||||||
HttpResponse response;
|
HttpResponse response;
|
||||||
response.set_status(fr::Http::SwitchingProtocols);
|
response.set_status(Http::RequestStatus::SwitchingProtocols);
|
||||||
response.header("Upgrade") = "websocket";
|
response.header("Upgrade") = "websocket";
|
||||||
response.header("Connection") = "Upgrade";
|
response.header("Connection") = "Upgrade";
|
||||||
response.header("Sec-WebSocket-Accept") = derived_key;
|
response.header("Sec-WebSocket-Accept") = derived_key;
|
||||||
|
|||||||
52
src/Http.cpp
52
src/Http.cpp
@ -13,10 +13,10 @@
|
|||||||
namespace fr
|
namespace fr
|
||||||
{
|
{
|
||||||
Http::Http()
|
Http::Http()
|
||||||
: request_type(Unknown),
|
: request_type(Http::RequestType::Unknown),
|
||||||
uri("/"),
|
uri("/"),
|
||||||
status(Ok),
|
status(Http::RequestStatus::Ok),
|
||||||
version(V1_1)
|
version(Http::RequestVersion::V1_1)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -115,42 +115,6 @@ namespace fr
|
|||||||
uri = '/' + str;
|
uri = '/' + str;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Http::request_type_to_string(RequestType type)
|
|
||||||
{
|
|
||||||
static_assert(RequestType::RequestTypeCount == 5, "Update request_type_to_string");
|
|
||||||
const static std::string request_type_strings[RequestType::RequestTypeCount] = {"GET",
|
|
||||||
"POST",
|
|
||||||
"PUT",
|
|
||||||
"DELETE",
|
|
||||||
"PATCH"};
|
|
||||||
|
|
||||||
if(type >= RequestType::RequestTypeCount)
|
|
||||||
return "UNKNOWN";
|
|
||||||
return request_type_strings[type];
|
|
||||||
}
|
|
||||||
|
|
||||||
Http::RequestType Http::string_to_request_type(const std::string &str)
|
|
||||||
{
|
|
||||||
//Find the request type
|
|
||||||
static_assert(Http::RequestTypeCount == 5, "Update parse_header_type()");
|
|
||||||
|
|
||||||
RequestType type = Http::Unknown;
|
|
||||||
for(size_t a = 0; a < Http::RequestTypeCount; ++a)
|
|
||||||
{
|
|
||||||
std::string type_string = request_type_to_string(static_cast<RequestType>(a));
|
|
||||||
int cmp_ret = str.compare(0, type_string.size(), type_string);
|
|
||||||
if(cmp_ret == 0)
|
|
||||||
return static_cast<RequestType>(a);
|
|
||||||
if(str.size() < type_string.size() && cmp_ret < 0)
|
|
||||||
type = Http::Partial;
|
|
||||||
if(type != Http::Partial && str.size() < type_string.size() && cmp_ret > 0)
|
|
||||||
type = Http::Unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Http::set_type(Http::RequestType type)
|
void Http::set_type(Http::RequestType type)
|
||||||
{
|
{
|
||||||
request_type = type;
|
request_type = type;
|
||||||
@ -1001,7 +965,7 @@ namespace fr
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
state = socket->send_raw(&data[0], data.size(), sent);
|
state = socket->send_raw(&data[0], data.size(), sent);
|
||||||
} while(state == fr::Socket::WouldBlock);
|
} while(state == fr::Socket::Status::WouldBlock);
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1016,18 +980,18 @@ namespace fr
|
|||||||
//Receive the request
|
//Receive the request
|
||||||
auto status = socket->receive_raw(recv_buffer, RECV_CHUNK_SIZE, received);
|
auto status = socket->receive_raw(recv_buffer, RECV_CHUNK_SIZE, received);
|
||||||
total_received += received;
|
total_received += received;
|
||||||
if(status != Socket::Success)
|
if(status != Socket::Status::Success)
|
||||||
{
|
{
|
||||||
if(total_received == 0)
|
if(total_received == 0)
|
||||||
return status;
|
return status;
|
||||||
if(status == Socket::WouldBlock)
|
if(status == Socket::Status::WouldBlock)
|
||||||
continue;
|
continue;
|
||||||
return Socket::Disconnected;
|
return Socket::Status::Disconnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Parse it
|
//Parse it
|
||||||
state = parse(recv_buffer, received);
|
state = parse(recv_buffer, received);
|
||||||
} while(state == fr::Socket::NotEnoughData);
|
} while(state == fr::Socket::Status::NotEnoughData);
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,8 +22,8 @@ namespace fr
|
|||||||
if(!header_ended)
|
if(!header_ended)
|
||||||
{
|
{
|
||||||
//Verify that it's a valid HTTP header so far
|
//Verify that it's a valid HTTP header so far
|
||||||
if(!body.empty() && Http::string_to_request_type(body) == fr::Http::Unknown)
|
if(!body.empty() && Http::string_to_request_type(body) == Http::RequestType::Unknown)
|
||||||
return fr::Socket::ParseError;
|
return fr::Socket::Status::ParseError;
|
||||||
|
|
||||||
//Check to see if this request data contains the end of the header
|
//Check to see if this request data contains the end of the header
|
||||||
uint16_t header_end_size = 4;
|
uint16_t header_end_size = 4;
|
||||||
@ -38,16 +38,16 @@ namespace fr
|
|||||||
//Ensure that the header doesn't exceed max length
|
//Ensure that the header doesn't exceed max length
|
||||||
if((!header_ended && body.size() > MAX_HTTP_HEADER_SIZE) || (header_ended && header_end > MAX_HTTP_HEADER_SIZE))
|
if((!header_ended && body.size() > MAX_HTTP_HEADER_SIZE) || (header_ended && header_end > MAX_HTTP_HEADER_SIZE))
|
||||||
{
|
{
|
||||||
return fr::Socket::HttpHeaderTooBig;
|
return fr::Socket::Status::HttpHeaderTooBig;
|
||||||
}
|
}
|
||||||
|
|
||||||
//If the header end has not been found, ask for more data.
|
//If the header end has not been found, ask for more data.
|
||||||
if(!header_ended)
|
if(!header_ended)
|
||||||
return fr::Socket::NotEnoughData;
|
return fr::Socket::Status::NotEnoughData;
|
||||||
|
|
||||||
//Else parse it
|
//Else parse it
|
||||||
if(!parse_header(header_end))
|
if(!parse_header(header_end))
|
||||||
return fr::Socket::ParseError;
|
return fr::Socket::Status::ParseError;
|
||||||
|
|
||||||
//Leave things after the header intact
|
//Leave things after the header intact
|
||||||
body.erase(0, header_end + header_end_size);
|
body.erase(0, header_end + header_end_size);
|
||||||
@ -56,7 +56,7 @@ namespace fr
|
|||||||
//Ensure that body doesn't exceed maximum length
|
//Ensure that body doesn't exceed maximum length
|
||||||
if(body.size() > MAX_HTTP_BODY_SIZE)
|
if(body.size() > MAX_HTTP_BODY_SIZE)
|
||||||
{
|
{
|
||||||
return fr::Socket::HttpBodyTooBig;
|
return fr::Socket::Status::HttpBodyTooBig;
|
||||||
}
|
}
|
||||||
|
|
||||||
//If we've got the whole request, parse the POST if it exists
|
//If we've got the whole request, parse the POST if it exists
|
||||||
@ -64,10 +64,10 @@ namespace fr
|
|||||||
{
|
{
|
||||||
if(request_type == RequestType::Post)
|
if(request_type == RequestType::Post)
|
||||||
parse_post_body();
|
parse_post_body();
|
||||||
return fr::Socket::Success;
|
return fr::Socket::Status::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fr::Socket::NotEnoughData;
|
return fr::Socket::Status::NotEnoughData;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HttpRequest::parse_header(int64_t header_end_pos)
|
bool HttpRequest::parse_header(int64_t header_end_pos)
|
||||||
@ -82,7 +82,7 @@ namespace fr
|
|||||||
|
|
||||||
//Parse request type & uri
|
//Parse request type & uri
|
||||||
request_type = parse_header_type(header_lines[line]);
|
request_type = parse_header_type(header_lines[line]);
|
||||||
if(request_type > Http::RequestTypeCount)
|
if(request_type > Http::RequestType::RequestTypeCount)
|
||||||
return false;
|
return false;
|
||||||
parse_header_uri(header_lines[line]);
|
parse_header_uri(header_lines[line]);
|
||||||
line++;
|
line++;
|
||||||
@ -107,7 +107,7 @@ namespace fr
|
|||||||
std::string HttpRequest::construct(const std::string &host) const
|
std::string HttpRequest::construct(const std::string &host) const
|
||||||
{
|
{
|
||||||
//Add HTTP header
|
//Add HTTP header
|
||||||
std::string request = request_type_to_string(request_type == Http::Unknown ? Http::Get : request_type) + " " + uri;
|
std::string request = request_type_to_string(request_type == Http::RequestType::Unknown ? Http::RequestType::Get : request_type) + " " + uri;
|
||||||
if(!get_data.empty())
|
if(!get_data.empty())
|
||||||
{
|
{
|
||||||
request += "?";
|
request += "?";
|
||||||
@ -119,7 +119,7 @@ namespace fr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(RequestVersion::VersionCount == 3, "Update me");
|
static_assert((uint32_t)RequestVersion::VersionCount == 3, "Update me");
|
||||||
request += (version == RequestVersion::V1) ? " HTTP/1.0\r\n" : " HTTP/1.1\r\n";
|
request += (version == RequestVersion::V1) ? " HTTP/1.0\r\n" : " HTTP/1.1\r\n";
|
||||||
|
|
||||||
//Add the headers to the request
|
//Add the headers to the request
|
||||||
@ -192,7 +192,7 @@ namespace fr
|
|||||||
{
|
{
|
||||||
return string_to_request_type(str.substr(0, type_end));
|
return string_to_request_type(str.substr(0, type_end));
|
||||||
}
|
}
|
||||||
return Http::Unknown;
|
return Http::RequestType::Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpRequest::parse_header_uri(const std::string &str)
|
void HttpRequest::parse_header_uri(const std::string &str)
|
||||||
@ -223,7 +223,7 @@ namespace fr
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Parse HTTP version. HTTP/1.0 or HTTP/1.1
|
//Parse HTTP version. HTTP/1.0 or HTTP/1.1
|
||||||
static_assert(RequestVersion::VersionCount == 3, "Update me");
|
static_assert((uint32_t)RequestVersion::VersionCount == 3, "Update me");
|
||||||
version = str.compare(uri_end + 1, 8, "HTTP/1.0") == 0 ? RequestVersion::V1 : RequestVersion::V1_1;
|
version = str.compare(uri_end + 1, 8, "HTTP/1.0") == 0 ? RequestVersion::V1 : RequestVersion::V1_1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -16,7 +16,7 @@ namespace fr
|
|||||||
{
|
{
|
||||||
//Verify that it's a valid HTTP response if there's enough data
|
//Verify that it's a valid HTTP response if there's enough data
|
||||||
if(body.size() >= 4 && body.compare(0, 4, "HTTP") != 0)
|
if(body.size() >= 4 && body.compare(0, 4, "HTTP") != 0)
|
||||||
return fr::Socket::ParseError;
|
return fr::Socket::Status::ParseError;
|
||||||
|
|
||||||
//Check to see if this request data contains the end of the header
|
//Check to see if this request data contains the end of the header
|
||||||
uint16_t header_end_size = 4;
|
uint16_t header_end_size = 4;
|
||||||
@ -31,16 +31,16 @@ namespace fr
|
|||||||
//Ensure that the header doesn't exceed max length
|
//Ensure that the header doesn't exceed max length
|
||||||
if((!header_ended && body.size() > MAX_HTTP_HEADER_SIZE) || (header_ended && header_end > MAX_HTTP_HEADER_SIZE))
|
if((!header_ended && body.size() > MAX_HTTP_HEADER_SIZE) || (header_ended && header_end > MAX_HTTP_HEADER_SIZE))
|
||||||
{
|
{
|
||||||
return fr::Socket::HttpHeaderTooBig;
|
return fr::Socket::Status::HttpHeaderTooBig;
|
||||||
}
|
}
|
||||||
|
|
||||||
//If the header end has not been found, ask for more data.
|
//If the header end has not been found, ask for more data.
|
||||||
if(!header_ended)
|
if(!header_ended)
|
||||||
return fr::Socket::NotEnoughData;
|
return fr::Socket::Status::NotEnoughData;
|
||||||
|
|
||||||
//Else parse it
|
//Else parse it
|
||||||
if(!parse_header(header_end))
|
if(!parse_header(header_end))
|
||||||
return fr::Socket::ParseError;
|
return fr::Socket::Status::ParseError;
|
||||||
|
|
||||||
//Leave things after the header intact
|
//Leave things after the header intact
|
||||||
body.erase(0, header_end + header_end_size);
|
body.erase(0, header_end + header_end_size);
|
||||||
@ -48,14 +48,14 @@ namespace fr
|
|||||||
|
|
||||||
//Ensure that body doesn't exceed maximum length
|
//Ensure that body doesn't exceed maximum length
|
||||||
if(body.size() > MAX_HTTP_BODY_SIZE)
|
if(body.size() > MAX_HTTP_BODY_SIZE)
|
||||||
return fr::Socket::HttpBodyTooBig;
|
return fr::Socket::Status::HttpBodyTooBig;
|
||||||
|
|
||||||
//Cut off any data if it exceeds content length, todo: potentially an issue, could cut the next request off
|
//Cut off any data if it exceeds content length, todo: potentially an issue, could cut the next request off
|
||||||
if(body.size() > content_length)
|
if(body.size() > content_length)
|
||||||
body.resize(content_length);
|
body.resize(content_length);
|
||||||
else if(body.size() < content_length)
|
else if(body.size() < content_length)
|
||||||
return fr::Socket::NotEnoughData;
|
return fr::Socket::Status::NotEnoughData;
|
||||||
return fr::Socket::Success;
|
return fr::Socket::Status::Success;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,8 +63,8 @@ namespace fr
|
|||||||
{
|
{
|
||||||
//Add HTTP header
|
//Add HTTP header
|
||||||
|
|
||||||
static_assert(RequestVersion::VersionCount == 3, "Update me");
|
static_assert((uint32_t)RequestVersion::VersionCount == 3, "Update me");
|
||||||
std::string response = ((version == RequestVersion::V1) ? "HTTP/1.0 " : "HTTP/1.1 ") + std::to_string(status) + " \r\n";
|
std::string response = ((version == RequestVersion::V1) ? "HTTP/1.0 " : "HTTP/1.1 ") + std::to_string((uint32_t)status) + " \r\n";
|
||||||
|
|
||||||
//Add the headers to the response
|
//Add the headers to the response
|
||||||
for(const auto &header : header_data)
|
for(const auto &header : header_data)
|
||||||
@ -107,7 +107,7 @@ namespace fr
|
|||||||
status = (RequestStatus)std::stoi(header_lines[0].substr(status_begin, end_pos - status_begin));
|
status = (RequestStatus)std::stoi(header_lines[0].substr(status_begin, end_pos - status_begin));
|
||||||
|
|
||||||
//Get HTTP version
|
//Get HTTP version
|
||||||
static_assert(RequestVersion::VersionCount == 3, "Update me");
|
static_assert((uint32_t)RequestVersion::VersionCount == 3, "Update me");
|
||||||
version = header_lines[0].compare(0, status_begin, "HTTP/1.0") == 0 ? RequestVersion::V1 : RequestVersion::V1_1;
|
version = header_lines[0].compare(0, status_begin, "HTTP/1.0") == 0 ? RequestVersion::V1 : RequestVersion::V1_1;
|
||||||
line++;
|
line++;
|
||||||
|
|
||||||
|
|||||||
@ -74,14 +74,14 @@ namespace fr
|
|||||||
mbedtls_net_init(&listen_fd);
|
mbedtls_net_init(&listen_fd);
|
||||||
fr::TcpListener tcp_listen;
|
fr::TcpListener tcp_listen;
|
||||||
tcp_listen.set_inet_version(ai_family);
|
tcp_listen.set_inet_version(ai_family);
|
||||||
if(tcp_listen.listen(port) != fr::Socket::Success)
|
if(tcp_listen.listen(port) != fr::Socket::Status::Success)
|
||||||
{
|
{
|
||||||
return Socket::BindFailed;
|
return Socket::Status::BindFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
listen_fd.fd = tcp_listen.get_socket_descriptor();
|
listen_fd.fd = tcp_listen.get_socket_descriptor();
|
||||||
tcp_listen.set_socket_descriptor(-1); //The socket wont close if it's -1 when we destruct it
|
tcp_listen.set_socket_descriptor(-1); //The socket wont close if it's -1 when we destruct it
|
||||||
return Socket::Success;
|
return Socket::Status::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
Socket::Status SSLListener::accept(Socket &client_)
|
Socket::Status SSLListener::accept(Socket &client_)
|
||||||
@ -100,7 +100,7 @@ namespace fr
|
|||||||
if((error = mbedtls_ssl_setup(ssl.get(), &conf)) != 0)
|
if((error = mbedtls_ssl_setup(ssl.get(), &conf)) != 0)
|
||||||
{
|
{
|
||||||
free_contexts();
|
free_contexts();
|
||||||
return Socket::Error;
|
return Socket::Status::Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Accept a connection
|
//Accept a connection
|
||||||
@ -109,7 +109,7 @@ namespace fr
|
|||||||
if((error = mbedtls_net_accept(&listen_fd, client_fd.get(), client_ip, sizeof(client_ip), &ip_len)) != 0)
|
if((error = mbedtls_net_accept(&listen_fd, client_fd.get(), client_ip, sizeof(client_ip), &ip_len)) != 0)
|
||||||
{
|
{
|
||||||
free_contexts();
|
free_contexts();
|
||||||
return Socket::AcceptError;
|
return Socket::Status::AcceptError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ namespace fr
|
|||||||
client.set_ssl_context(std::move(ssl));
|
client.set_ssl_context(std::move(ssl));
|
||||||
client.set_descriptor(client_fd.release());
|
client.set_descriptor(client_fd.release());
|
||||||
client.set_remote_address(client_printable_addr);
|
client.set_remote_address(client_printable_addr);
|
||||||
return Socket::Success;
|
return Socket::Status::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSLListener::shutdown()
|
void SSLListener::shutdown()
|
||||||
@ -152,7 +152,7 @@ namespace fr
|
|||||||
::shutdown(listen_fd.fd, 0);
|
::shutdown(listen_fd.fd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t SSLListener::get_socket_descriptor() const noexcept
|
int32_t SSLListener::get_socket_descriptor() const
|
||||||
{
|
{
|
||||||
return listen_fd.fd;
|
return listen_fd.fd;
|
||||||
}
|
}
|
||||||
@ -171,7 +171,7 @@ namespace fr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SSLListener::connected() const noexcept
|
bool SSLListener::connected() const
|
||||||
{
|
{
|
||||||
return listen_fd.fd > -1;
|
return listen_fd.fd > -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -168,10 +168,10 @@ namespace fr
|
|||||||
{
|
{
|
||||||
fr::TcpSocket socket;
|
fr::TcpSocket socket;
|
||||||
auto ret = socket.connect(address, port, timeout);
|
auto ret = socket.connect(address, port, timeout);
|
||||||
if(ret != fr::Socket::Success)
|
if(ret != fr::Socket::Status::Success)
|
||||||
return ret;
|
return ret;
|
||||||
ssl_socket_descriptor->fd = socket.get_socket_descriptor();
|
ssl_socket_descriptor->fd = socket.get_socket_descriptor();
|
||||||
remote_address = socket.get_remote_address();
|
set_remote_address(socket.get_remote_address());
|
||||||
socket.set_descriptor(nullptr);
|
socket.set_descriptor(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,11 +249,11 @@ namespace fr
|
|||||||
if(ret != 0)
|
if(ret != 0)
|
||||||
{
|
{
|
||||||
errno = ret;
|
errno = ret;
|
||||||
return fr::Socket::SSLError;
|
return fr::Socket::Status::SSLError;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_blocking = should_block;
|
is_blocking = should_block;
|
||||||
return fr::Socket::Success;
|
return fr::Socket::Status::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSLSocket::reconfigure_socket()
|
void SSLSocket::reconfigure_socket()
|
||||||
|
|||||||
@ -27,7 +27,7 @@ namespace fr
|
|||||||
Socket::Status Socket::send(const Sendable &obj)
|
Socket::Status Socket::send(const Sendable &obj)
|
||||||
{
|
{
|
||||||
if(!connected())
|
if(!connected())
|
||||||
return Socket::Disconnected;
|
return Socket::Status::Disconnected;
|
||||||
|
|
||||||
return obj.send(this);
|
return obj.send(this);
|
||||||
}
|
}
|
||||||
@ -45,13 +45,13 @@ namespace fr
|
|||||||
size_t received = 0;
|
size_t received = 0;
|
||||||
Status status = receive_raw((char*)dest + (buffer_size - bytes_remaining), (size_t)bytes_remaining, received);
|
Status status = receive_raw((char*)dest + (buffer_size - bytes_remaining), (size_t)bytes_remaining, received);
|
||||||
bytes_remaining -= received;
|
bytes_remaining -= received;
|
||||||
if(status != Socket::Success)
|
if(status != Socket::Status::Success)
|
||||||
{
|
{
|
||||||
if((ssize_t)buffer_size == bytes_remaining)
|
if((ssize_t)buffer_size == bytes_remaining)
|
||||||
return status;
|
return status;
|
||||||
if(status == Socket::WouldBlock)
|
if(status == Socket::Status::WouldBlock)
|
||||||
continue;
|
continue;
|
||||||
return Socket::Disconnected;
|
return Socket::Status::Disconnected;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,49 +99,49 @@ namespace fr
|
|||||||
|
|
||||||
switch(status)
|
switch(status)
|
||||||
{
|
{
|
||||||
case Unknown:
|
case Socket::Status::Unknown:
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
case Success:
|
case Socket::Status::Success:
|
||||||
return "Success";
|
return "Success";
|
||||||
case ListenFailed:
|
case Socket::Status::ListenFailed:
|
||||||
return std::string("Listen Failed (").append(ERR_STR).append(")");
|
return std::string("Listen Failed (").append(ERR_STR).append(")");
|
||||||
case BindFailed:
|
case Socket::Status::BindFailed:
|
||||||
return std::string("Bind Failed (").append(ERR_STR).append(")");
|
return std::string("Bind Failed (").append(ERR_STR).append(")");
|
||||||
case Disconnected:
|
case Socket::Status::Disconnected:
|
||||||
return "The Socket Is Not Connected";
|
return "The Socket Is Not Connected";
|
||||||
case Error:
|
case Socket::Status::Error:
|
||||||
return "Error";
|
return "Error";
|
||||||
case WouldBlock:
|
case Socket::Status::WouldBlock:
|
||||||
return "Would Block";
|
return "Would Block";
|
||||||
case ConnectionFailed:
|
case Socket::Status::ConnectionFailed:
|
||||||
return "Connection Failed";
|
return "Connection Failed";
|
||||||
case HandshakeFailed:
|
case Socket::Status::HandshakeFailed:
|
||||||
return "Handshake Failed";
|
return "Handshake Failed";
|
||||||
case VerificationFailed:
|
case Socket::Status::VerificationFailed:
|
||||||
return "Verification Failed";
|
return "Verification Failed";
|
||||||
case MaxPacketSizeExceeded:
|
case Socket::Status::MaxPacketSizeExceeded:
|
||||||
return "Max Packet Size Exceeded";
|
return "Max Packet Size Exceeded";
|
||||||
case NotEnoughData:
|
case Socket::Status::NotEnoughData:
|
||||||
return "Not Enough Data";
|
return "Not Enough Data";
|
||||||
case ParseError:
|
case Socket::Status::ParseError:
|
||||||
return "Parse Error";
|
return "Parse Error";
|
||||||
case HttpHeaderTooBig:
|
case Socket::Status::HttpHeaderTooBig:
|
||||||
return "HTTP Header Too Big";
|
return "HTTP Header Too Big";
|
||||||
case HttpBodyTooBig:
|
case Socket::Status::HttpBodyTooBig:
|
||||||
return "HTTP Body Too Big";
|
return "HTTP Body Too Big";
|
||||||
case AddressLookupFailure:
|
case Socket::Status::AddressLookupFailure:
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return std::string("Address Lookup Failure (").append(wsa_err_to_str(WSAGetLastError())).append(")");
|
return std::string("Address Lookup Failure (").append(wsa_err_to_str(WSAGetLastError())).append(")");
|
||||||
#else
|
#else
|
||||||
return std::string("Address Lookup Failure (").append(gai_strerror(errno)).append(")");
|
return std::string("Address Lookup Failure (").append(gai_strerror(errno)).append(")");
|
||||||
#endif
|
#endif
|
||||||
case SendError:
|
case Socket::Status::SendError:
|
||||||
return std::string("Send Error (").append(ERR_STR).append(")");
|
return std::string("Send Error (").append(ERR_STR).append(")");
|
||||||
case ReceiveError:
|
case Socket::Status::ReceiveError:
|
||||||
return std::string("Receive Error (").append(ERR_STR).append(")");
|
return std::string("Receive Error (").append(ERR_STR).append(")");
|
||||||
case AcceptError:
|
case Socket::Status::AcceptError:
|
||||||
return std::string("Accept Error (").append(ERR_STR).append(")");
|
return std::string("Accept Error (").append(ERR_STR).append(")");
|
||||||
case SSLError:
|
case Socket::Status::SSLError:
|
||||||
{
|
{
|
||||||
#ifdef USE_SSL
|
#ifdef USE_SSL
|
||||||
char buff[256] = {0};
|
char buff[256] = {0};
|
||||||
@ -151,9 +151,9 @@ namespace fr
|
|||||||
return "Generic SSL Error";
|
return "Generic SSL Error";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
case NoRouteToHost:
|
case Socket::Status::NoRouteToHost:
|
||||||
return "No Route To Host";
|
return "No Route To Host";
|
||||||
case Timeout:
|
case Socket::Status::Timeout:
|
||||||
return "Timeout";
|
return "Timeout";
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
|
|||||||
@ -91,9 +91,9 @@ namespace fr
|
|||||||
//Listen to socket
|
//Listen to socket
|
||||||
if(::listen(socket_descriptor, LISTEN_QUEUE_SIZE) == SOCKET_ERROR)
|
if(::listen(socket_descriptor, LISTEN_QUEUE_SIZE) == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
return Socket::ListenFailed;
|
return Socket::Status::ListenFailed;
|
||||||
}
|
}
|
||||||
return Socket::Success;
|
return Socket::Status::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
Socket::Status TcpListener::accept(Socket &client_)
|
Socket::Status TcpListener::accept(Socket &client_)
|
||||||
@ -110,7 +110,7 @@ namespace fr
|
|||||||
socklen_t client_addr_len = sizeof client_addr;
|
socklen_t client_addr_len = sizeof client_addr;
|
||||||
client_descriptor = ::accept(socket_descriptor, (sockaddr*)&client_addr, &client_addr_len);
|
client_descriptor = ::accept(socket_descriptor, (sockaddr*)&client_addr, &client_addr_len);
|
||||||
if(client_descriptor == SOCKET_ERROR)
|
if(client_descriptor == SOCKET_ERROR)
|
||||||
return Socket::AcceptError;
|
return Socket::Status::AcceptError;
|
||||||
|
|
||||||
//Get printable address. If we failed then set it as just 'unknown'
|
//Get printable address. If we failed then set it as just 'unknown'
|
||||||
int err = getnameinfo((sockaddr*)&client_addr, client_addr_len, client_printable_addr, sizeof(client_printable_addr), nullptr, 0, NI_NUMERICHOST);
|
int err = getnameinfo((sockaddr*)&client_addr, client_addr_len, client_printable_addr, sizeof(client_printable_addr), nullptr, 0, NI_NUMERICHOST);
|
||||||
@ -123,7 +123,7 @@ namespace fr
|
|||||||
client.set_descriptor(&client_descriptor);
|
client.set_descriptor(&client_descriptor);
|
||||||
client.set_remote_address(client_printable_addr);
|
client.set_remote_address(client_printable_addr);
|
||||||
|
|
||||||
return Socket::Success;
|
return Socket::Status::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TcpListener::shutdown()
|
void TcpListener::shutdown()
|
||||||
@ -131,7 +131,7 @@ namespace fr
|
|||||||
::shutdown(socket_descriptor, 0);
|
::shutdown(socket_descriptor, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t TcpListener::get_socket_descriptor() const noexcept
|
int32_t TcpListener::get_socket_descriptor() const
|
||||||
{
|
{
|
||||||
return socket_descriptor;
|
return socket_descriptor;
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ namespace fr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TcpListener::connected() const noexcept
|
bool TcpListener::connected() const
|
||||||
{
|
{
|
||||||
return socket_descriptor > -1;
|
return socket_descriptor > -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,8 +13,8 @@ namespace fr
|
|||||||
{
|
{
|
||||||
|
|
||||||
TcpSocket::TcpSocket() noexcept
|
TcpSocket::TcpSocket() noexcept
|
||||||
: socket_descriptor(-1),
|
: socket_descriptor(-1),
|
||||||
is_blocking(true)
|
is_blocking(true)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -192,7 +192,7 @@ namespace fr
|
|||||||
return Socket::Status::Error;
|
return Socket::Status::Error;
|
||||||
|
|
||||||
//Update state now we've got a valid socket descriptor
|
//Update state now we've got a valid socket descriptor
|
||||||
remote_address = address + ":" + port;
|
set_remote_address(address + ":" + port);
|
||||||
reconfigure_socket();
|
reconfigure_socket();
|
||||||
|
|
||||||
return Socket::Status::Success;
|
return Socket::Status::Success;
|
||||||
@ -203,7 +203,7 @@ namespace fr
|
|||||||
if(!set_unix_socket_blocking(socket_descriptor, is_blocking, should_block))
|
if(!set_unix_socket_blocking(socket_descriptor, is_blocking, should_block))
|
||||||
return Status::Error;
|
return Status::Error;
|
||||||
is_blocking = should_block;
|
is_blocking = should_block;
|
||||||
return Socket::Success;
|
return fr::Socket::Status::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t TcpSocket::get_socket_descriptor() const noexcept
|
int32_t TcpSocket::get_socket_descriptor() const noexcept
|
||||||
|
|||||||
@ -26,7 +26,7 @@ namespace fr
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void URL::parse(std::string url)
|
void URL::parse(const std::string &url)
|
||||||
{
|
{
|
||||||
scheme = Scheme::Unknown;
|
scheme = Scheme::Unknown;
|
||||||
size_t parse_offset = 0;
|
size_t parse_offset = 0;
|
||||||
@ -133,13 +133,6 @@ namespace fr
|
|||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string URL::to_lower(const std::string &str)
|
|
||||||
{
|
|
||||||
std::string out = str;
|
|
||||||
std::transform(out.begin(), out.end(), out.begin(), ::tolower);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string &URL::scheme_to_string(URL::Scheme scheme)
|
const std::string &URL::scheme_to_string(URL::Scheme scheme)
|
||||||
{
|
{
|
||||||
auto iter = std::find_if(scheme_string_map.begin(), scheme_string_map.end(), [&](const auto &i)
|
auto iter = std::find_if(scheme_string_map.begin(), scheme_string_map.end(), [&](const auto &i)
|
||||||
|
|||||||
@ -20,7 +20,7 @@ namespace fr
|
|||||||
{
|
{
|
||||||
auto *socket = dynamic_cast<WebSocketBase*>(socket_);
|
auto *socket = dynamic_cast<WebSocketBase*>(socket_);
|
||||||
if(!socket)
|
if(!socket)
|
||||||
return Socket::Error;
|
return Socket::Status::Error;
|
||||||
|
|
||||||
uint16_t first_2bytes = 0;
|
uint16_t first_2bytes = 0;
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
@ -29,7 +29,7 @@ namespace fr
|
|||||||
first_2bytes |= final << 15;
|
first_2bytes |= final << 15;
|
||||||
|
|
||||||
//Set opcode bit
|
//Set opcode bit
|
||||||
first_2bytes |= opcode << 8;
|
first_2bytes |= (uint8_t)opcode << 8;
|
||||||
|
|
||||||
//Set mask bit (dependent on is_client flag, only client -> server messages are masked)
|
//Set mask bit (dependent on is_client flag, only client -> server messages are masked)
|
||||||
first_2bytes |= socket->is_client() << 7;
|
first_2bytes |= socket->is_client() << 7;
|
||||||
@ -82,7 +82,7 @@ namespace fr
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
state = socket_->send_raw(buffer.c_str(), buffer.size(), sent);
|
state = socket_->send_raw(buffer.c_str(), buffer.size(), sent);
|
||||||
} while(state == fr::Socket::WouldBlock);
|
} while(state == fr::Socket::Status::WouldBlock);
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,13 +90,13 @@ namespace fr
|
|||||||
{
|
{
|
||||||
auto *socket_ = dynamic_cast<WebSocketBase*>(socket);
|
auto *socket_ = dynamic_cast<WebSocketBase*>(socket);
|
||||||
if(!socket_)
|
if(!socket_)
|
||||||
return Socket::Error;
|
return Socket::Status::Error;
|
||||||
payload.clear();
|
payload.clear();
|
||||||
Socket::Status status;
|
Socket::Status status;
|
||||||
|
|
||||||
uint16_t first_2bytes;
|
uint16_t first_2bytes;
|
||||||
status = socket->receive_all(&first_2bytes, sizeof(first_2bytes));
|
status = socket->receive_all(&first_2bytes, sizeof(first_2bytes));
|
||||||
if(status != fr::Socket::Success)
|
if(status != fr::Socket::Status::Success)
|
||||||
return status;
|
return status;
|
||||||
first_2bytes = ntohs(first_2bytes);
|
first_2bytes = ntohs(first_2bytes);
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ namespace fr
|
|||||||
auto mask = static_cast<bool>((first_2bytes >> 7) & 0x1);
|
auto mask = static_cast<bool>((first_2bytes >> 7) & 0x1);
|
||||||
if(mask == socket_->is_client())
|
if(mask == socket_->is_client())
|
||||||
{
|
{
|
||||||
return fr::Socket::Error;
|
return fr::Socket::Status::Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -122,11 +122,11 @@ namespace fr
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
status = socket->receive_all(&length, sizeof(length));
|
status = socket->receive_all(&length, sizeof(length));
|
||||||
} while(status == fr::Socket::WouldBlock);
|
} while(status == fr::Socket::Status::WouldBlock);
|
||||||
if(status == fr::Socket::Timeout)
|
if(status == fr::Socket::Status::Timeout)
|
||||||
status = fr::Socket::Disconnected;
|
status = fr::Socket::Status::Disconnected;
|
||||||
payload_length = ntohs(length);
|
payload_length = ntohs(length);
|
||||||
if(status != fr::Socket::Success)
|
if(status != fr::Socket::Status::Success)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
else if(payload_length == 127) //Length is longer than 16 bit, so read 64bit length
|
else if(payload_length == 127) //Length is longer than 16 bit, so read 64bit length
|
||||||
@ -134,18 +134,18 @@ namespace fr
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
status = socket->receive_all(&payload_length, sizeof(payload_length));
|
status = socket->receive_all(&payload_length, sizeof(payload_length));
|
||||||
} while(status == fr::Socket::WouldBlock);
|
} while(status == fr::Socket::Status::WouldBlock);
|
||||||
if(status == fr::Socket::Timeout)
|
if(status == fr::Socket::Status::Timeout)
|
||||||
status = fr::Socket::Disconnected;
|
status = fr::Socket::Status::Disconnected;
|
||||||
payload_length = fr_ntohll(payload_length);
|
payload_length = fr_ntohll(payload_length);
|
||||||
if(status != fr::Socket::Success)
|
if(status != fr::Socket::Status::Success)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Verify that payload length isn't too large
|
//Verify that payload length isn't too large
|
||||||
if(socket->get_max_receive_size() && payload_length > socket->get_max_receive_size())
|
if(socket->get_max_receive_size() && payload_length > socket->get_max_receive_size())
|
||||||
{
|
{
|
||||||
return Socket::MaxPacketSizeExceeded;
|
return Socket::Status::MaxPacketSizeExceeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Read masking key if the mask bit is set
|
//Read masking key if the mask bit is set
|
||||||
@ -159,10 +159,10 @@ namespace fr
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
status = socket->receive_all(&mask_union.mask_key, 4);
|
status = socket->receive_all(&mask_union.mask_key, 4);
|
||||||
} while(status == fr::Socket::WouldBlock);
|
} while(status == fr::Socket::Status::WouldBlock);
|
||||||
if(status == fr::Socket::Timeout)
|
if(status == fr::Socket::Status::Timeout)
|
||||||
status = fr::Socket::Disconnected;
|
status = fr::Socket::Status::Disconnected;
|
||||||
if(status != fr::Socket::Success)
|
if(status != fr::Socket::Status::Success)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,10 +171,10 @@ namespace fr
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
status = socket->receive_all(&payload[0], payload_length);
|
status = socket->receive_all(&payload[0], payload_length);
|
||||||
} while(status == fr::Socket::WouldBlock);
|
} while(status == fr::Socket::Status::WouldBlock);
|
||||||
if(status == fr::Socket::Timeout)
|
if(status == fr::Socket::Status::Timeout)
|
||||||
status = fr::Socket::Disconnected;
|
status = fr::Socket::Status::Disconnected;
|
||||||
if(status != fr::Socket::Success)
|
if(status != fr::Socket::Status::Success)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
//Decode the payload if the mask bit is set
|
//Decode the payload if the mask bit is set
|
||||||
@ -186,7 +186,7 @@ namespace fr
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return fr::Socket::Success;
|
return fr::Socket::Status::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,10 +14,10 @@ TEST(HttpRequestTest, get_request_parse)
|
|||||||
|
|
||||||
//Parse it
|
//Parse it
|
||||||
fr::HttpRequest request;
|
fr::HttpRequest request;
|
||||||
ASSERT_EQ(request.parse(raw_request.c_str(), raw_request.size()), fr::Socket::Success);
|
ASSERT_EQ(request.parse(raw_request.c_str(), raw_request.size()), fr::Socket::Status::Success);
|
||||||
|
|
||||||
//Check that the request type is intact
|
//Check that the request type is intact
|
||||||
ASSERT_EQ(request.get_type(), fr::Http::Get);
|
ASSERT_EQ(request.get_type(), fr::Http::RequestType::Get);
|
||||||
|
|
||||||
//Test that URI is intact
|
//Test that URI is intact
|
||||||
ASSERT_EQ(request.get_uri(), "/index.html");
|
ASSERT_EQ(request.get_uri(), "/index.html");
|
||||||
@ -57,10 +57,10 @@ TEST(HttpRequestTest, post_request_parse)
|
|||||||
|
|
||||||
//Parse it
|
//Parse it
|
||||||
fr::HttpRequest request;
|
fr::HttpRequest request;
|
||||||
ASSERT_EQ(request.parse(raw_request.c_str(), raw_request.size()), fr::Socket::Success);
|
ASSERT_EQ(request.parse(raw_request.c_str(), raw_request.size()), fr::Socket::Status::Success);
|
||||||
|
|
||||||
//Check that the request type is intact
|
//Check that the request type is intact
|
||||||
ASSERT_EQ(request.get_type(), fr::Http::Post);
|
ASSERT_EQ(request.get_type(), fr::Http::RequestType::Post);
|
||||||
|
|
||||||
//Test that URI is intact
|
//Test that URI is intact
|
||||||
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
||||||
@ -89,48 +89,48 @@ TEST(HttpRequestTest, request_type_parse)
|
|||||||
const std::string invalid_request2 = "PU / HTTP/1.1\r\n\r\n";
|
const std::string invalid_request2 = "PU / HTTP/1.1\r\n\r\n";
|
||||||
|
|
||||||
fr::HttpRequest request;
|
fr::HttpRequest request;
|
||||||
ASSERT_EQ(request.parse(get_request.c_str(), get_request.size()), fr::Socket::Success);
|
ASSERT_EQ(request.parse(get_request.c_str(), get_request.size()), fr::Socket::Status::Success);
|
||||||
ASSERT_EQ(request.get_type(), fr::Http::Get);
|
ASSERT_EQ(request.get_type(), fr::Http::RequestType::Get);
|
||||||
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
||||||
request = {};
|
request = {};
|
||||||
|
|
||||||
ASSERT_EQ(request.parse(post_request.c_str(), post_request.size()), fr::Socket::Success);
|
ASSERT_EQ(request.parse(post_request.c_str(), post_request.size()), fr::Socket::Status::Success);
|
||||||
ASSERT_EQ(request.get_type(), fr::Http::Post);
|
ASSERT_EQ(request.get_type(), fr::Http::RequestType::Post);
|
||||||
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
||||||
request = {};
|
request = {};
|
||||||
|
|
||||||
ASSERT_EQ(request.parse(get_request_v2.c_str(), get_request_v2.size()), fr::Socket::Success);
|
ASSERT_EQ(request.parse(get_request_v2.c_str(), get_request_v2.size()), fr::Socket::Status::Success);
|
||||||
ASSERT_EQ(request.get_type(), fr::Http::Get);
|
ASSERT_EQ(request.get_type(), fr::Http::RequestType::Get);
|
||||||
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1);
|
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1);
|
||||||
request = {};
|
request = {};
|
||||||
|
|
||||||
ASSERT_EQ(request.parse(post_request_v2.c_str(), post_request_v2.size()), fr::Socket::Success);
|
ASSERT_EQ(request.parse(post_request_v2.c_str(), post_request_v2.size()), fr::Socket::Status::Success);
|
||||||
ASSERT_EQ(request.get_type(), fr::Http::Post);
|
ASSERT_EQ(request.get_type(), fr::Http::RequestType::Post);
|
||||||
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1);
|
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1);
|
||||||
request = {};
|
request = {};
|
||||||
|
|
||||||
ASSERT_EQ(request.parse(put_request.c_str(), put_request.size()), fr::Socket::Success);
|
ASSERT_EQ(request.parse(put_request.c_str(), put_request.size()), fr::Socket::Status::Success);
|
||||||
ASSERT_EQ(request.get_type(), fr::Http::Put);
|
ASSERT_EQ(request.get_type(), fr::Http::RequestType::Put);
|
||||||
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
||||||
request = {};
|
request = {};
|
||||||
|
|
||||||
ASSERT_EQ(request.parse(delete_request.c_str(), delete_request.size()), fr::Socket::Success);
|
ASSERT_EQ(request.parse(delete_request.c_str(), delete_request.size()), fr::Socket::Status::Success);
|
||||||
ASSERT_EQ(request.get_type(), fr::Http::Delete);
|
ASSERT_EQ(request.get_type(), fr::Http::RequestType::Delete);
|
||||||
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
||||||
request = {};
|
request = {};
|
||||||
|
|
||||||
ASSERT_EQ(request.parse(patch_request.c_str(), patch_request.size()), fr::Socket::Success);
|
ASSERT_EQ(request.parse(patch_request.c_str(), patch_request.size()), fr::Socket::Status::Success);
|
||||||
ASSERT_EQ(request.get_type(), fr::Http::Patch);
|
ASSERT_EQ(request.get_type(), fr::Http::RequestType::Patch);
|
||||||
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
||||||
request = {};
|
request = {};
|
||||||
|
|
||||||
ASSERT_EQ(request.parse(invalid_request.c_str(), invalid_request.size()), fr::Socket::ParseError);
|
ASSERT_EQ(request.parse(invalid_request.c_str(), invalid_request.size()), fr::Socket::Status::ParseError);
|
||||||
ASSERT_EQ(request.get_type(), fr::Http::Unknown);
|
ASSERT_EQ(request.get_type(), fr::Http::RequestType::Unknown);
|
||||||
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
||||||
request = {};
|
request = {};
|
||||||
|
|
||||||
ASSERT_EQ(request.parse(invalid_request2.c_str(), invalid_request2.size()), fr::Socket::ParseError);
|
ASSERT_EQ(request.parse(invalid_request2.c_str(), invalid_request2.size()), fr::Socket::Status::ParseError);
|
||||||
ASSERT_EQ(request.get_type(), fr::Http::Unknown);
|
ASSERT_EQ(request.get_type(), fr::Http::RequestType::Unknown);
|
||||||
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
||||||
request = {};
|
request = {};
|
||||||
}
|
}
|
||||||
@ -147,7 +147,7 @@ TEST(HttpRequestTest, get_request_construction)
|
|||||||
request.get("my_get") = "var1";
|
request.get("my_get") = "var1";
|
||||||
request.get("my_other_get") = "var2";
|
request.get("my_other_get") = "var2";
|
||||||
request.set_uri("heyo/bobby");
|
request.set_uri("heyo/bobby");
|
||||||
request.set_type(fr::Http::Get);
|
request.set_type(fr::Http::RequestType::Get);
|
||||||
std::string constructed_request = request.construct("frednicolson.co.uk");
|
std::string constructed_request = request.construct("frednicolson.co.uk");
|
||||||
|
|
||||||
//Parse it and check that everything's correct
|
//Parse it and check that everything's correct
|
||||||
@ -158,7 +158,7 @@ TEST(HttpRequestTest, get_request_construction)
|
|||||||
ASSERT_EQ(request.get("my_get"), "var1");
|
ASSERT_EQ(request.get("my_get"), "var1");
|
||||||
ASSERT_EQ(request.get("my_other_get"), "var2");
|
ASSERT_EQ(request.get("my_other_get"), "var2");
|
||||||
ASSERT_EQ(request.get_uri(), "/heyo/bobby");
|
ASSERT_EQ(request.get_uri(), "/heyo/bobby");
|
||||||
ASSERT_EQ(request.get_type(), fr::Http::Get);
|
ASSERT_EQ(request.get_type(), fr::Http::RequestType::Get);
|
||||||
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
ASSERT_EQ(request.get_version(), fr::Http::RequestVersion::V1_1);
|
||||||
|
|
||||||
//Quick v1 test
|
//Quick v1 test
|
||||||
@ -179,7 +179,7 @@ TEST(HttpRequestTest, post_request_construction)
|
|||||||
request.get("var") = "20";
|
request.get("var") = "20";
|
||||||
request.post("my_post") = "post_data";
|
request.post("my_post") = "post_data";
|
||||||
request.post("some_post") = "more_post";
|
request.post("some_post") = "more_post";
|
||||||
request.set_type(fr::Http::Post);
|
request.set_type(fr::Http::RequestType::Post);
|
||||||
const std::string constructed_request = request.construct("frednicolson.co.uk");
|
const std::string constructed_request = request.construct("frednicolson.co.uk");
|
||||||
|
|
||||||
//Parse it
|
//Parse it
|
||||||
@ -191,7 +191,7 @@ TEST(HttpRequestTest, post_request_construction)
|
|||||||
ASSERT_EQ(request.get("var"), "20");
|
ASSERT_EQ(request.get("var"), "20");
|
||||||
ASSERT_EQ(request.post("my_post"), "post_data");
|
ASSERT_EQ(request.post("my_post"), "post_data");
|
||||||
ASSERT_EQ(request.post("some_post"), "more_post");
|
ASSERT_EQ(request.post("some_post"), "more_post");
|
||||||
ASSERT_EQ(request.get_type(), fr::Http::Post);
|
ASSERT_EQ(request.get_type(), fr::Http::RequestType::Post);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(HttpRequestTest, partial_parse)
|
TEST(HttpRequestTest, partial_parse)
|
||||||
@ -211,13 +211,13 @@ TEST(HttpRequestTest, partial_parse)
|
|||||||
|
|
||||||
//Parse part 1
|
//Parse part 1
|
||||||
fr::HttpRequest request;
|
fr::HttpRequest request;
|
||||||
ASSERT_EQ(request.parse(raw_request1.c_str(), raw_request1.size()), fr::Socket::NotEnoughData);
|
ASSERT_EQ(request.parse(raw_request1.c_str(), raw_request1.size()), fr::Socket::Status::NotEnoughData);
|
||||||
|
|
||||||
//Parse part 2
|
//Parse part 2
|
||||||
ASSERT_EQ(request.parse(raw_request2.c_str(), raw_request2.size()), fr::Socket::Success);
|
ASSERT_EQ(request.parse(raw_request2.c_str(), raw_request2.size()), fr::Socket::Status::Success);
|
||||||
|
|
||||||
//Verify it
|
//Verify it
|
||||||
ASSERT_EQ(request.get_type(), fr::Http::Get);
|
ASSERT_EQ(request.get_type(), fr::Http::RequestType::Get);
|
||||||
ASSERT_EQ(request.header("content-type"), "application/x-www-form-urlencoded");
|
ASSERT_EQ(request.header("content-type"), "application/x-www-form-urlencoded");
|
||||||
ASSERT_EQ(request.header("Cache-Control"), "no-cache");
|
ASSERT_EQ(request.header("Cache-Control"), "no-cache");
|
||||||
}
|
}
|
||||||
@ -230,7 +230,7 @@ TEST(HttpRequestTest, awkward_parse)
|
|||||||
"Test=bob\n"
|
"Test=bob\n"
|
||||||
"\n";
|
"\n";
|
||||||
fr::HttpRequest request;
|
fr::HttpRequest request;
|
||||||
ASSERT_EQ(request.parse(request_data.c_str(), request_data.size()), fr::Socket::Success);
|
ASSERT_EQ(request.parse(request_data.c_str(), request_data.size()), fr::Socket::Status::Success);
|
||||||
ASSERT_EQ(request.get_uri(), "/my/url");
|
ASSERT_EQ(request.get_uri(), "/my/url");
|
||||||
ASSERT_EQ(request.post("Test"), "bob");
|
ASSERT_EQ(request.post("Test"), "bob");
|
||||||
}
|
}
|
||||||
@ -242,7 +242,7 @@ TEST(HttpRequestTest, awkward_parse2)
|
|||||||
"Test=bob";
|
"Test=bob";
|
||||||
|
|
||||||
fr::HttpRequest request;
|
fr::HttpRequest request;
|
||||||
ASSERT_EQ(request.parse(request_data.c_str(), request_data.size()), fr::Socket::Success);
|
ASSERT_EQ(request.parse(request_data.c_str(), request_data.size()), fr::Socket::Status::Success);
|
||||||
ASSERT_EQ(request.get_uri(), "/my/url");
|
ASSERT_EQ(request.get_uri(), "/my/url");
|
||||||
ASSERT_EQ(request.get("Bob"), "10");
|
ASSERT_EQ(request.get("Bob"), "10");
|
||||||
ASSERT_EQ(request.post("Test"), "bob");
|
ASSERT_EQ(request.post("Test"), "bob");
|
||||||
|
|||||||
@ -18,7 +18,7 @@ TEST(HttpResponseTest, response_parse_v1)
|
|||||||
|
|
||||||
//Parse response
|
//Parse response
|
||||||
fr::HttpResponse test;
|
fr::HttpResponse test;
|
||||||
ASSERT_EQ(test.parse(raw_response.c_str(), raw_response.size()), fr::Socket::Success);
|
ASSERT_EQ(test.parse(raw_response.c_str(), raw_response.size()), fr::Socket::Status::Success);
|
||||||
|
|
||||||
//Verify it
|
//Verify it
|
||||||
ASSERT_EQ(test.get_version(), fr::Http::RequestVersion::V1);
|
ASSERT_EQ(test.get_version(), fr::Http::RequestVersion::V1);
|
||||||
@ -54,11 +54,11 @@ TEST(HttpResponseTest, response_parse_v2)
|
|||||||
|
|
||||||
//Parse response
|
//Parse response
|
||||||
fr::HttpResponse test;
|
fr::HttpResponse test;
|
||||||
ASSERT_EQ(test.parse(raw_response.c_str(), raw_response.size()), fr::Socket::Success);
|
ASSERT_EQ(test.parse(raw_response.c_str(), raw_response.size()), fr::Socket::Status::Success);
|
||||||
|
|
||||||
//Verify it
|
//Verify it
|
||||||
ASSERT_EQ(test.get_version(), fr::Http::RequestVersion::V1_1);
|
ASSERT_EQ(test.get_version(), fr::Http::RequestVersion::V1_1);
|
||||||
ASSERT_EQ(test.get_status(), fr::Http::MovedPermanently);
|
ASSERT_EQ(test.get_status(), fr::Http::RequestStatus::MovedPermanently);
|
||||||
ASSERT_EQ(test.header("Content-length"), "177");
|
ASSERT_EQ(test.header("Content-length"), "177");
|
||||||
ASSERT_EQ(test.get_body(), response_body);
|
ASSERT_EQ(test.get_body(), response_body);
|
||||||
}
|
}
|
||||||
@ -97,12 +97,12 @@ TEST(HttpResponseTest, response_partial_parse)
|
|||||||
|
|
||||||
//Parse response
|
//Parse response
|
||||||
fr::HttpResponse test;
|
fr::HttpResponse test;
|
||||||
ASSERT_EQ(test.parse(raw_response1.c_str(), raw_response1.size()), fr::Socket::NotEnoughData);
|
ASSERT_EQ(test.parse(raw_response1.c_str(), raw_response1.size()), fr::Socket::Status::NotEnoughData);
|
||||||
ASSERT_EQ(test.parse(raw_response2.c_str(), raw_response2.size()), fr::Socket::NotEnoughData);
|
ASSERT_EQ(test.parse(raw_response2.c_str(), raw_response2.size()), fr::Socket::Status::NotEnoughData);
|
||||||
ASSERT_EQ(test.parse(raw_response3.c_str(), raw_response3.size()), fr::Socket::Success);
|
ASSERT_EQ(test.parse(raw_response3.c_str(), raw_response3.size()), fr::Socket::Status::Success);
|
||||||
|
|
||||||
//Verify it
|
//Verify it
|
||||||
ASSERT_EQ(test.get_status(), fr::Http::MovedPermanently);
|
ASSERT_EQ(test.get_status(), fr::Http::RequestStatus::MovedPermanently);
|
||||||
ASSERT_EQ(test.header("Content-length"), "177");
|
ASSERT_EQ(test.header("Content-length"), "177");
|
||||||
ASSERT_EQ(test.get_body(), response_body);
|
ASSERT_EQ(test.get_body(), response_body);
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ TEST(HttpResponseTest, header_length_test)
|
|||||||
std::string buff(MAX_HTTP_HEADER_SIZE + 1, '\0');
|
std::string buff(MAX_HTTP_HEADER_SIZE + 1, '\0');
|
||||||
fr::HttpResponse response;
|
fr::HttpResponse response;
|
||||||
buff.insert(0, "HTTP");
|
buff.insert(0, "HTTP");
|
||||||
ASSERT_EQ(response.parse(buff.c_str(), buff.size()), fr::Socket::HttpHeaderTooBig);
|
ASSERT_EQ(response.parse(buff.c_str(), buff.size()), fr::Socket::Status::HttpHeaderTooBig);
|
||||||
response = {};
|
response = {};
|
||||||
|
|
||||||
//Now try short header but long data, this should work
|
//Now try short header but long data, this should work
|
||||||
@ -122,7 +122,7 @@ TEST(HttpResponseTest, header_length_test)
|
|||||||
"Content-Length: " + std::to_string(MAX_HTTP_BODY_SIZE - 1) + "\n"
|
"Content-Length: " + std::to_string(MAX_HTTP_BODY_SIZE - 1) + "\n"
|
||||||
"Connection: keep-alive\n"
|
"Connection: keep-alive\n"
|
||||||
"\n" + std::string(MAX_HTTP_BODY_SIZE - 1, '\0');
|
"\n" + std::string(MAX_HTTP_BODY_SIZE - 1, '\0');
|
||||||
ASSERT_EQ(response.parse(buff.c_str(), buff.size()), fr::Socket::Success);
|
ASSERT_EQ(response.parse(buff.c_str(), buff.size()), fr::Socket::Status::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(HttpResponseTest, body_length_test)
|
TEST(HttpResponseTest, body_length_test)
|
||||||
@ -135,14 +135,14 @@ TEST(HttpResponseTest, body_length_test)
|
|||||||
"\n";
|
"\n";
|
||||||
buff += std::string(MAX_HTTP_BODY_SIZE + 1, '\0');
|
buff += std::string(MAX_HTTP_BODY_SIZE + 1, '\0');
|
||||||
fr::HttpResponse response;
|
fr::HttpResponse response;
|
||||||
ASSERT_EQ(response.parse(buff.c_str(), buff.size()), fr::Socket::HttpBodyTooBig);
|
ASSERT_EQ(response.parse(buff.c_str(), buff.size()), fr::Socket::Status::HttpBodyTooBig);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(HttpResponseTest, HttpResponseConstruction)
|
TEST(HttpResponseTest, HttpResponseConstruction)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
fr::HttpResponse response;
|
fr::HttpResponse response;
|
||||||
response.set_status(fr::Http::ImATeapot);
|
response.set_status(fr::Http::RequestStatus::ImATeapot);
|
||||||
response.header("bob") = "trob";
|
response.header("bob") = "trob";
|
||||||
response.set_body("lob");
|
response.set_body("lob");
|
||||||
auto constructed = response.construct("frednicolson.co.uk");
|
auto constructed = response.construct("frednicolson.co.uk");
|
||||||
|
|||||||
@ -7,31 +7,31 @@
|
|||||||
|
|
||||||
TEST(HttpTest, test_request_type_to_string)
|
TEST(HttpTest, test_request_type_to_string)
|
||||||
{
|
{
|
||||||
for(size_t a = 0; a < fr::Http::RequestTypeCount; ++a)
|
for(size_t a = 0; a < (uint32_t)fr::Http::RequestType::RequestTypeCount; ++a)
|
||||||
{
|
{
|
||||||
ASSERT_EQ(fr::Http::string_to_request_type(fr::Http::request_type_to_string((fr::Http::RequestType)a)), a);
|
ASSERT_EQ((size_t)fr::Http::string_to_request_type(fr::Http::request_type_to_string((fr::Http::RequestType)a)), a);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_EQ(fr::Http::request_type_to_string(fr::Http::Partial), "UNKNOWN");
|
ASSERT_EQ(fr::Http::request_type_to_string(fr::Http::RequestType::Partial), "UNKNOWN");
|
||||||
ASSERT_EQ(fr::Http::request_type_to_string(fr::Http::RequestTypeCount), "UNKNOWN");
|
ASSERT_EQ(fr::Http::request_type_to_string(fr::Http::RequestType::RequestTypeCount), "UNKNOWN");
|
||||||
ASSERT_EQ(fr::Http::request_type_to_string(fr::Http::Unknown), "UNKNOWN");
|
ASSERT_EQ(fr::Http::request_type_to_string(fr::Http::RequestType::Unknown), "UNKNOWN");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(HttpTest, test_string_to_request_type)
|
TEST(HttpTest, test_string_to_request_type)
|
||||||
{
|
{
|
||||||
std::vector<std::pair<fr::Http::RequestType, std::string>> strings = {
|
std::vector<std::pair<fr::Http::RequestType, std::string>> strings = {
|
||||||
{fr::Http::Get, "GET"},
|
{fr::Http::RequestType::Get, "GET"},
|
||||||
{fr::Http::Put, "PUT"},
|
{fr::Http::RequestType::Put, "PUT"},
|
||||||
{fr::Http::Delete, "DELETE"},
|
{fr::Http::RequestType::Delete, "DELETE"},
|
||||||
{fr::Http::Patch, "PATCH"},
|
{fr::Http::RequestType::Patch, "PATCH"},
|
||||||
{fr::Http::Patch, "PATCHid-=wa"},
|
{fr::Http::RequestType::Patch, "PATCHid-=wa"},
|
||||||
{fr::Http::Partial, "PA"},
|
{fr::Http::RequestType::Partial, "PA"},
|
||||||
{fr::Http::Partial, "PU"},
|
{fr::Http::RequestType::Partial, "PU"},
|
||||||
{fr::Http::Partial, "DELET"},
|
{fr::Http::RequestType::Partial, "DELET"},
|
||||||
{fr::Http::Unknown, "DELETa"},
|
{fr::Http::RequestType::Unknown, "DELETa"},
|
||||||
{fr::Http::Unknown, "U"},
|
{fr::Http::RequestType::Unknown, "U"},
|
||||||
{fr::Http::Unknown, "dwaouidhwi"},
|
{fr::Http::RequestType::Unknown, "dwaouidhwi"},
|
||||||
{fr::Http::Unknown, "get"},
|
{fr::Http::RequestType::Unknown, "get"},
|
||||||
};
|
};
|
||||||
|
|
||||||
for(auto &str : strings)
|
for(auto &str : strings)
|
||||||
|
|||||||
@ -11,7 +11,7 @@ TEST(TcpListenerTest, listner_listen)
|
|||||||
fr::TcpListener listener;
|
fr::TcpListener listener;
|
||||||
ASSERT_EQ(listener.get_socket_descriptor(), -1);
|
ASSERT_EQ(listener.get_socket_descriptor(), -1);
|
||||||
fr::Socket::Status ret = listener.listen("9090");
|
fr::Socket::Status ret = listener.listen("9090");
|
||||||
ASSERT_EQ(ret, fr::Socket::Success);
|
ASSERT_EQ(ret, fr::Socket::Status::Success);
|
||||||
listener.close_socket();
|
listener.close_socket();
|
||||||
ASSERT_EQ(listener.get_socket_descriptor(), -1);
|
ASSERT_EQ(listener.get_socket_descriptor(), -1);
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ TEST(TcpListenerTest, listener_accept)
|
|||||||
{
|
{
|
||||||
fr::TcpListener listener;
|
fr::TcpListener listener;
|
||||||
listener.set_inet_version(fr::Socket::IP::v4);
|
listener.set_inet_version(fr::Socket::IP::v4);
|
||||||
if(listener.listen("9095") != fr::Socket::Success)
|
if(listener.listen("9095") != fr::Socket::Status::Success)
|
||||||
FAIL();
|
FAIL();
|
||||||
|
|
||||||
auto client_thread = []()
|
auto client_thread = []()
|
||||||
@ -29,13 +29,13 @@ TEST(TcpListenerTest, listener_accept)
|
|||||||
fr::TcpSocket socket;
|
fr::TcpSocket socket;
|
||||||
socket.set_inet_version(fr::Socket::IP::v4);
|
socket.set_inet_version(fr::Socket::IP::v4);
|
||||||
auto ret = socket.connect("127.0.0.1", "9095", std::chrono::seconds(5));
|
auto ret = socket.connect("127.0.0.1", "9095", std::chrono::seconds(5));
|
||||||
ASSERT_EQ(ret, fr::Socket::Success);
|
ASSERT_EQ(ret, fr::Socket::Status::Success);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::thread t1(client_thread);
|
std::thread t1(client_thread);
|
||||||
fr::TcpSocket socket;
|
fr::TcpSocket socket;
|
||||||
auto ret = listener.accept(socket);
|
auto ret = listener.accept(socket);
|
||||||
ASSERT_EQ(ret, fr::Socket::Success);
|
ASSERT_EQ(ret, fr::Socket::Status::Success);
|
||||||
t1.join();
|
t1.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user