Rewrote the server in cpp with the frontend in svelte
This commit is contained in:
26
lib/restbed-4.8/source/corvusoft/restbed/byte.hpp
Normal file
26
lib/restbed-4.8/source/corvusoft/restbed/byte.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
typedef uint8_t Byte;
|
||||
|
||||
typedef std::vector< Byte > Bytes;
|
||||
}
|
||||
141
lib/restbed-4.8/source/corvusoft/restbed/common.hpp
Normal file
141
lib/restbed-4.8/source/corvusoft/restbed/common.hpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
|
||||
//Project Includes
|
||||
#include <corvusoft/restbed/string.hpp>
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
class Common
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
template< typename Type >
|
||||
static Type parse_parameter( const std::string& value, const Type default_value )
|
||||
{
|
||||
std::istringstream stream( value );
|
||||
|
||||
Type parameter;
|
||||
stream >> parameter;
|
||||
|
||||
if ( stream.fail( ) )
|
||||
{
|
||||
return default_value;
|
||||
}
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
template< typename Type >
|
||||
static bool has_parameter( const std::string& name, const Type& parameters )
|
||||
{
|
||||
const auto key = String::lowercase( name );
|
||||
const auto iterator = std::find_if( parameters.begin( ), parameters.end( ), [ &key ]( const std::pair< std::string, std::string >& value )
|
||||
{
|
||||
return ( key == String::lowercase( value.first ) );
|
||||
} );
|
||||
|
||||
return iterator not_eq parameters.end( );
|
||||
}
|
||||
|
||||
static std::string transform( const std::string& value, const std::function< std::string ( const std::string& ) >& transform )
|
||||
{
|
||||
return ( transform == nullptr ) ? value : transform( value );
|
||||
}
|
||||
|
||||
//Getters
|
||||
template< typename Type >
|
||||
static Type get_parameters( const std::string& name, const Type& parameters )
|
||||
{
|
||||
if ( name.empty( ) )
|
||||
{
|
||||
return parameters;
|
||||
}
|
||||
|
||||
const auto key = String::lowercase( name );
|
||||
Type results;
|
||||
|
||||
for ( const auto& parameter : parameters )
|
||||
{
|
||||
if ( key == String::lowercase( parameter.first ) )
|
||||
{
|
||||
results.insert( parameter );
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Common( void ) = delete;
|
||||
|
||||
Common( const Common& original ) = delete;
|
||||
|
||||
virtual ~Common( void ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
Common& operator =( const Common& value ) = delete;
|
||||
|
||||
//Properties
|
||||
};
|
||||
}
|
||||
113
lib/restbed-4.8/source/corvusoft/restbed/context_placeholder.hpp
Normal file
113
lib/restbed-4.8/source/corvusoft/restbed/context_placeholder.hpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <typeinfo>
|
||||
|
||||
//Project Includes
|
||||
#include <corvusoft/restbed/context_placeholder_base.hpp>
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define CONTEXT_PLACEHOLDER_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define CONTEXT_PLACEHOLDER_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define CONTEXT_PLACEHOLDER_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
template< typename Type >
|
||||
class CONTEXT_PLACEHOLDER_EXPORT ContextPlaceholder : public ContextPlaceholderBase
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructor
|
||||
ContextPlaceholder( const Type& value ) : ContextPlaceholderBase( ),
|
||||
m_value( value )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
virtual ~ContextPlaceholder( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
const std::type_info& type( void ) const
|
||||
{
|
||||
return typeid( Type );
|
||||
}
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
operator Type( void )
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
ContextPlaceholder( void ) = delete;
|
||||
|
||||
ContextPlaceholder( const ContextPlaceholder& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
ContextPlaceholder& operator =( const ContextPlaceholder& value ) = delete;
|
||||
|
||||
//Properties
|
||||
const Type m_value;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <typeinfo>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define CONTEXT_PLACEHOLDER_BASE_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define CONTEXT_PLACEHOLDER_BASE_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define CONTEXT_PLACEHOLDER_BASE_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
class CONTEXT_PLACEHOLDER_BASE_EXPORT ContextPlaceholderBase
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructor
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
virtual const std::type_info& type( void ) const = 0;
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
ContextPlaceholderBase( void ) = default;
|
||||
|
||||
virtual ~ContextPlaceholderBase( void ) = default;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
ContextPlaceholderBase( const ContextPlaceholderBase& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
ContextPlaceholderBase& operator =( const ContextPlaceholderBase& value ) = delete;
|
||||
|
||||
//Properties
|
||||
};
|
||||
}
|
||||
121
lib/restbed-4.8/source/corvusoft/restbed/context_value.hpp
Normal file
121
lib/restbed-4.8/source/corvusoft/restbed/context_value.hpp
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <memory>
|
||||
#include <ciso646>
|
||||
#include <typeinfo>
|
||||
#include <stdexcept>
|
||||
|
||||
//Project Includes
|
||||
#include <corvusoft/restbed/context_placeholder.hpp>
|
||||
#include <corvusoft/restbed/context_placeholder_base.hpp>
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define CONTEXT_VALUE_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define CONTEXT_VALUE_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define CONTEXT_VALUE_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
class CONTEXT_VALUE_EXPORT ContextValue
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
template< typename Type >
|
||||
ContextValue( const Type& value ) : m_placeholder( new ContextPlaceholder< Type >( value ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ContextValue( const ContextValue& original ) : m_placeholder( original.m_placeholder )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
virtual ~ContextValue( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
template< typename Type > operator Type( void ) const
|
||||
{
|
||||
if ( typeid( Type ) not_eq m_placeholder->type( ) )
|
||||
{
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
|
||||
auto placeholder = static_cast< ContextPlaceholder< Type >* >( m_placeholder.get( ) );
|
||||
return *placeholder;
|
||||
}
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
ContextValue( void ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
ContextValue& operator =( const ContextValue& value ) = delete;
|
||||
|
||||
//Properties
|
||||
const std::shared_ptr< ContextPlaceholderBase > m_placeholder;
|
||||
};
|
||||
}
|
||||
321
lib/restbed-4.8/source/corvusoft/restbed/detail/http_impl.cpp
Normal file
321
lib/restbed-4.8/source/corvusoft/restbed/detail/http_impl.cpp
Normal file
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <clocale>
|
||||
#include <ciso646>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/uri.hpp"
|
||||
#include "corvusoft/restbed/string.hpp"
|
||||
#include "corvusoft/restbed/request.hpp"
|
||||
#include "corvusoft/restbed/response.hpp"
|
||||
#include "corvusoft/restbed/settings.hpp"
|
||||
#include "corvusoft/restbed/ssl_settings.hpp"
|
||||
#include "corvusoft/restbed/detail/http_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/request_impl.hpp"
|
||||
|
||||
#ifdef BUILD_IPC
|
||||
#include "corvusoft/restbed/detail/ipc_socket_impl.hpp"
|
||||
#endif
|
||||
|
||||
//External Includes
|
||||
#include <asio/error.hpp>
|
||||
#include <asio/ip/tcp.hpp>
|
||||
#include <asio/buffer.hpp>
|
||||
#include <asio/streambuf.hpp>
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
#include <asio/ssl.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_IPC
|
||||
#include <asio/local/stream_protocol.hpp>
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
using std::free;
|
||||
using std::bind;
|
||||
using std::stod;
|
||||
using std::regex;
|
||||
using std::smatch;
|
||||
using std::string;
|
||||
using std::istream;
|
||||
using std::function;
|
||||
using std::multimap;
|
||||
using std::setlocale;
|
||||
using std::to_string;
|
||||
using std::shared_ptr;
|
||||
using std::error_code;
|
||||
using std::make_shared;
|
||||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
|
||||
#ifdef BUILD_IPC
|
||||
using asio::local::stream_protocol;
|
||||
#endif
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
using asio::buffer;
|
||||
using asio::ip::tcp;
|
||||
using asio::streambuf;
|
||||
using asio::io_service;
|
||||
#ifdef BUILD_SSL
|
||||
using asio::ssl::stream;
|
||||
#endif
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
Bytes HttpImpl::to_bytes( const shared_ptr< Request >& request )
|
||||
{
|
||||
auto path = request->get_path( );
|
||||
|
||||
auto parameters = request->get_query_parameters( );
|
||||
|
||||
if ( not parameters.empty( ) )
|
||||
{
|
||||
string query = String::empty;
|
||||
|
||||
for ( const auto parameter : parameters )
|
||||
{
|
||||
query += Uri::encode_parameter( parameter.first ) + "=" + Uri::encode_parameter( parameter.second ) + "&";
|
||||
}
|
||||
|
||||
path += "?" + query.substr( 0, query.length( ) - 1 );
|
||||
}
|
||||
|
||||
auto uri = request->m_pimpl->m_uri;
|
||||
|
||||
if ( uri not_eq nullptr and not uri->get_fragment( ).empty( ) )
|
||||
{
|
||||
path += "#" + uri->get_fragment( );
|
||||
}
|
||||
|
||||
char* locale = nullptr;
|
||||
if (auto current_locale = setlocale( LC_NUMERIC, nullptr ) )
|
||||
{
|
||||
locale = strdup(current_locale);
|
||||
setlocale( LC_NUMERIC, "C" );
|
||||
}
|
||||
|
||||
auto data = String::format( "%s %s %s/%.1f\r\n",
|
||||
request->get_method( ).data( ),
|
||||
path.data( ),
|
||||
"HTTP",
|
||||
request->get_version( ) );
|
||||
|
||||
if (locale)
|
||||
{
|
||||
setlocale( LC_NUMERIC, locale );
|
||||
free( locale );
|
||||
}
|
||||
|
||||
auto headers = request->get_headers( );
|
||||
|
||||
if ( not headers.empty( ) )
|
||||
{
|
||||
data += String::join( headers, ": ", "\r\n" ) + "\r\n";
|
||||
}
|
||||
|
||||
data += "\r\n";
|
||||
|
||||
auto bytes = String::to_bytes( data );
|
||||
auto body = request->get_body( );
|
||||
|
||||
if ( not body.empty( ) )
|
||||
{
|
||||
bytes.insert( bytes.end( ), body.begin( ), body.end( ) );
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void HttpImpl::socket_setup( const shared_ptr< Request >& request, const shared_ptr< const Settings >& settings )
|
||||
{
|
||||
if ( request->m_pimpl->m_socket == nullptr )
|
||||
{
|
||||
if ( request->m_pimpl->m_io_service == nullptr )
|
||||
{
|
||||
request->m_pimpl->m_io_service = make_shared< asio::io_service >( );
|
||||
}
|
||||
|
||||
if ( String::uppercase( request->m_pimpl->m_protocol ) == "HTTP" )
|
||||
{
|
||||
auto socket = make_shared< tcp::socket >( *request->m_pimpl->m_io_service );
|
||||
request->m_pimpl->m_socket = make_shared< SocketImpl >( *request->m_pimpl->m_io_service, socket );
|
||||
}
|
||||
#ifdef BUILD_SSL
|
||||
else if ( String::uppercase( request->m_pimpl->m_protocol ) == "HTTPS" )
|
||||
{
|
||||
ssl_socket_setup( request, settings->get_ssl_settings( ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_IPC
|
||||
else if ( String::uppercase( request->m_pimpl->m_protocol ) == "LOCAL" )
|
||||
{
|
||||
auto socket = make_shared< stream_protocol::socket >( *request->m_pimpl->m_io_service );
|
||||
request->m_pimpl->m_socket = make_shared< IPCSocketImpl >( *request->m_pimpl->m_io_service, socket );
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
auto socket = make_shared< tcp::socket >( *request->m_pimpl->m_io_service );
|
||||
request->m_pimpl->m_socket = make_shared< SocketImpl >( *request->m_pimpl->m_io_service, socket );
|
||||
}
|
||||
}
|
||||
|
||||
request->m_pimpl->m_socket->set_timeout( settings->get_connection_timeout( ) );
|
||||
}
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
void HttpImpl::ssl_socket_setup( const shared_ptr< Request >& request, const shared_ptr< const SSLSettings >& settings )
|
||||
{
|
||||
asio::ssl::context context( asio::ssl::context::sslv23 );
|
||||
shared_ptr< asio::ssl::stream< asio::ip::tcp::socket > > socket = nullptr;
|
||||
|
||||
if ( settings not_eq nullptr )
|
||||
{
|
||||
const auto pool = settings->get_certificate_authority_pool( );
|
||||
|
||||
if ( pool.empty( ) )
|
||||
{
|
||||
context.set_default_verify_paths( );
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _WIN32
|
||||
context.load_verify_file(settings->get_certificate_authority_pool());
|
||||
#else
|
||||
context.add_verify_path( settings->get_certificate_authority_pool( ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
socket = make_shared< asio::ssl::stream< asio::ip::tcp::socket > >( *request->m_pimpl->m_io_service, context );
|
||||
socket->set_verify_mode( asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert );
|
||||
}
|
||||
else
|
||||
{
|
||||
socket = make_shared< asio::ssl::stream< asio::ip::tcp::socket > >( *request->m_pimpl->m_io_service, context );
|
||||
socket->set_verify_mode( asio::ssl::verify_none );
|
||||
}
|
||||
|
||||
socket->set_verify_callback( asio::ssl::rfc2818_verification( request->get_host( ) ) );
|
||||
request->m_pimpl->m_socket = make_shared< SocketImpl >( *request->m_pimpl->m_io_service, socket );
|
||||
}
|
||||
#endif
|
||||
void HttpImpl::request_handler( const error_code& error, const shared_ptr< Request >& request, const function< void ( const shared_ptr< Request >, const shared_ptr< Response > ) >& callback )
|
||||
{
|
||||
if ( error )
|
||||
{
|
||||
const auto body = String::format( "Failed to locate HTTP endpoint: %s", error.message( ).data( ) );
|
||||
return callback( request, create_error_response( request, body ) );
|
||||
}
|
||||
|
||||
request->m_pimpl->m_socket->start_write( to_bytes( request ), bind( write_handler, _1, _2, request, callback ) );
|
||||
}
|
||||
|
||||
void HttpImpl::write_handler( const error_code& error, const size_t, const shared_ptr< Request >& request, const function< void ( const shared_ptr< Request >, const shared_ptr< Response > ) >& callback )
|
||||
{
|
||||
if ( error )
|
||||
{
|
||||
const auto body = String::format( "Socket write failed: %s", error.message( ).data( ) );
|
||||
return callback( request, create_error_response( request, body ) );
|
||||
}
|
||||
|
||||
request->m_pimpl->m_buffer = make_shared< asio::streambuf >( );
|
||||
request->m_pimpl->m_socket->start_read( request->m_pimpl->m_buffer, "\r\n", bind( read_status_handler, _1, _2, request, callback ) );
|
||||
}
|
||||
|
||||
const shared_ptr< Response > HttpImpl::create_error_response( const shared_ptr< Request >& request, const string& message )
|
||||
{
|
||||
auto response = request->m_pimpl->m_response;
|
||||
response->set_protocol( request->get_protocol( ) );
|
||||
response->set_version( request->get_version( ) );
|
||||
response->set_status_code( 0 );
|
||||
response->set_status_message( "Error" );
|
||||
response->set_header( "Content-Type", "text/plain; utf-8" );
|
||||
response->set_header( "Content-Length", ::to_string( message.length( ) ) );
|
||||
response->set_body( message );
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
void HttpImpl::read_status_handler( const error_code& error, const size_t, const shared_ptr< Request >& request, const function< void ( const shared_ptr< Request >, const shared_ptr< Response > ) >& callback )
|
||||
{
|
||||
if ( error )
|
||||
{
|
||||
const auto body = String::format( "Failed to read HTTP response status line: %s", error.message( ).data( ) );
|
||||
return callback( request, create_error_response( request, body ) );
|
||||
}
|
||||
|
||||
istream response_stream( request->m_pimpl->m_buffer.get( ) );
|
||||
string status_line = String::empty;
|
||||
getline( response_stream, status_line );
|
||||
|
||||
smatch matches;
|
||||
static const regex status_line_pattern( "^([a-zA-Z]+)\\/(\\d*\\.?\\d*) (-?\\d+) (.*)\\r$" );
|
||||
|
||||
if ( not regex_match( status_line, matches, status_line_pattern ) or matches.size( ) not_eq 5 )
|
||||
{
|
||||
const auto body = String::format( "HTTP response status line malformed: '%s'", status_line.data( ) );
|
||||
return callback( request, create_error_response( request, body ) );
|
||||
}
|
||||
|
||||
auto response = request->m_pimpl->m_response;
|
||||
response->set_protocol( matches[ 1 ].str( ) );
|
||||
response->set_version( stod( matches[ 2 ].str( ) ) );
|
||||
response->set_status_code( stoi( matches[ 3 ].str( ) ) );
|
||||
response->set_status_message( matches[ 4 ].str( ) );
|
||||
|
||||
request->m_pimpl->m_socket->start_read( request->m_pimpl->m_buffer, "\r\n\r\n", bind( read_headers_handler, _1, _2, request, callback ) );
|
||||
}
|
||||
|
||||
void HttpImpl::read_headers_handler( const error_code& error, const size_t, const shared_ptr< Request >& request, const function< void ( const shared_ptr< Request >, const shared_ptr< Response > ) >& callback )
|
||||
{
|
||||
if ( error == asio::error::eof )
|
||||
{
|
||||
return callback( request, request->m_pimpl->m_response );
|
||||
}
|
||||
|
||||
if ( error )
|
||||
{
|
||||
const auto body = String::format( "Failed to read HTTP response status headers: '%s'", error.message( ).data( ) );
|
||||
return callback( request, create_error_response( request, body ) );
|
||||
}
|
||||
|
||||
string header = String::empty;
|
||||
multimap< string, string > headers = { };
|
||||
istream response_stream( request->m_pimpl->m_buffer.get( ) );
|
||||
|
||||
while ( getline( response_stream, header ) and header not_eq "\r" )
|
||||
{
|
||||
static const regex header_pattern( "^([^:.]*): *(.*)\\s*$" );
|
||||
smatch matches;
|
||||
|
||||
if ( not regex_match( header, matches, header_pattern ) or matches.size( ) not_eq 3 )
|
||||
{
|
||||
const auto body = String::format( "Malformed HTTP response header: '%s'", header.data( ) );
|
||||
return callback( request, create_error_response( request, body ) );
|
||||
}
|
||||
|
||||
headers.insert( make_pair( matches[ 1 ], matches[ 2 ] ) );
|
||||
}
|
||||
|
||||
auto response = request->m_pimpl->m_response;
|
||||
response->set_headers( headers );
|
||||
|
||||
callback( request, response );
|
||||
}
|
||||
}
|
||||
}
|
||||
110
lib/restbed-4.8/source/corvusoft/restbed/detail/http_impl.hpp
Normal file
110
lib/restbed-4.8/source/corvusoft/restbed/detail/http_impl.hpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <system_error>
|
||||
|
||||
//Project Includes
|
||||
#include <corvusoft/restbed/byte.hpp>
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Fordward Declarations
|
||||
class Request;
|
||||
class Response;
|
||||
class Settings;
|
||||
class SSLSettings;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
class HttpImpl
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
static Bytes to_bytes( const std::shared_ptr< Request >& value );
|
||||
|
||||
static void socket_setup( const std::shared_ptr< Request >& request, const std::shared_ptr< const Settings >& settings );
|
||||
#ifdef BUILD_SSL
|
||||
static void ssl_socket_setup( const std::shared_ptr< Request >& request, const std::shared_ptr< const SSLSettings >& settings );
|
||||
#endif
|
||||
static void request_handler( const std::error_code& error, const std::shared_ptr< Request >& request, const std::function< void ( const std::shared_ptr< Request >, const std::shared_ptr< Response > ) >& callback );
|
||||
|
||||
static void write_handler( const std::error_code& error, const std::size_t length, const std::shared_ptr< Request >& request, const std::function< void ( const std::shared_ptr< Request >, const std::shared_ptr< Response > ) >& callback );
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
HttpImpl( void ) = delete;
|
||||
|
||||
virtual ~HttpImpl( void ) = delete;
|
||||
|
||||
HttpImpl( const HttpImpl& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
static const std::shared_ptr< Response > create_error_response( const std::shared_ptr< Request >& request, const std::string& message );
|
||||
|
||||
static void read_status_handler( const std::error_code& error, const std::size_t length, const std::shared_ptr< Request >& request, const std::function< void ( const std::shared_ptr< Request >, const std::shared_ptr< Response > ) >& callback );
|
||||
|
||||
static void read_headers_handler( const std::error_code& error, const std::size_t length, const std::shared_ptr< Request >& request, const std::function< void ( const std::shared_ptr< Request >, const std::shared_ptr< Response > ) >& callback );
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
HttpImpl& operator =( const HttpImpl& value ) = delete;
|
||||
|
||||
//Properties
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
#ifdef BUILD_IPC
|
||||
|
||||
//System Includes
|
||||
#include <future>
|
||||
#include <ciso646>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/logger.hpp"
|
||||
#include "corvusoft/restbed/detail/socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/ipc_socket_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
#include <asio/read.hpp>
|
||||
#include <asio/write.hpp>
|
||||
#include <asio/connect.hpp>
|
||||
#include <asio/read_until.hpp>
|
||||
|
||||
//System Namespaces
|
||||
using std::get;
|
||||
using std::bind;
|
||||
using std::size_t;
|
||||
using std::string;
|
||||
using std::promise;
|
||||
using std::function;
|
||||
using std::to_string;
|
||||
using std::error_code;
|
||||
using std::shared_ptr;
|
||||
using std::make_shared;
|
||||
using std::runtime_error;
|
||||
using std::placeholders::_1;
|
||||
using std::chrono::milliseconds;
|
||||
using std::chrono::steady_clock;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::IPCSocketImpl;
|
||||
|
||||
//External Namespaces
|
||||
using asio::io_service;
|
||||
using asio::steady_timer;
|
||||
using asio::local::stream_protocol;
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
IPCSocketImpl::IPCSocketImpl( asio::io_context& context, const shared_ptr< stream_protocol::socket >& socket, const shared_ptr< Logger >& logger ) : SocketImpl( context ),
|
||||
m_error_handler( nullptr ),
|
||||
m_is_open( socket->is_open( ) ),
|
||||
m_pending_writes( ),
|
||||
m_logger( logger ),
|
||||
m_timeout( 0 ),
|
||||
m_io_service( context ),
|
||||
m_timer( make_shared< asio::steady_timer >( m_io_service ) ),
|
||||
m_strand( make_shared< io_service::strand > ( m_io_service ) ),
|
||||
m_socket( socket )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void IPCSocketImpl::close( void )
|
||||
{
|
||||
m_is_open = false;
|
||||
|
||||
if ( m_timer not_eq nullptr )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
}
|
||||
|
||||
if ( m_socket not_eq nullptr )
|
||||
{
|
||||
m_socket->close( );
|
||||
}
|
||||
}
|
||||
|
||||
bool IPCSocketImpl::is_open( void ) const
|
||||
{
|
||||
return m_is_open;
|
||||
}
|
||||
|
||||
bool IPCSocketImpl::is_closed( void ) const
|
||||
{
|
||||
return not m_is_open;
|
||||
}
|
||||
|
||||
void IPCSocketImpl::connect( const string&, const uint16_t, const function< void ( const error_code& ) >& callback )
|
||||
{
|
||||
m_socket->async_connect( stream_protocol::endpoint("/tmp/restbed.sock"), [ this, callback ]( const error_code & error )
|
||||
{
|
||||
m_is_open = true;
|
||||
callback( error );
|
||||
} );
|
||||
}
|
||||
|
||||
void IPCSocketImpl::sleep_for( const milliseconds& delay, const function< void ( const error_code& ) >& callback )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( delay );
|
||||
m_timer->async_wait( callback );
|
||||
}
|
||||
|
||||
void IPCSocketImpl::start_write(const Bytes& data, const std::function< void ( const std::error_code&, std::size_t ) >& callback)
|
||||
{
|
||||
m_strand->post([this, data, callback] { write_helper(data, callback); });
|
||||
}
|
||||
|
||||
size_t IPCSocketImpl::start_read(const shared_ptr< asio::streambuf >& data, const string& delimiter, error_code& error)
|
||||
{
|
||||
return read( data, delimiter,error );
|
||||
}
|
||||
|
||||
size_t IPCSocketImpl::start_read(const shared_ptr< asio::streambuf >& data, const size_t length, error_code& error)
|
||||
{
|
||||
return read( data, length, error );
|
||||
}
|
||||
|
||||
void IPCSocketImpl::start_read( const std::size_t length, const function< void ( const Bytes ) > success, const function< void ( const error_code ) > failure )
|
||||
{
|
||||
m_strand->post([this, length, success, failure] {
|
||||
read(length, success, failure);
|
||||
});
|
||||
}
|
||||
|
||||
void IPCSocketImpl::start_read(const shared_ptr< asio::streambuf >& data, const size_t length, const function< void ( const error_code&, size_t ) >& callback)
|
||||
{
|
||||
m_strand->post([this, data, length, callback]
|
||||
{
|
||||
read(data, length, callback);
|
||||
});
|
||||
}
|
||||
|
||||
void IPCSocketImpl::start_read(const shared_ptr< asio::streambuf >& data, const string& delimiter, const function< void ( const error_code&, size_t ) >& callback)
|
||||
{
|
||||
m_strand->post([this, data, delimiter, callback]
|
||||
{
|
||||
read(data, delimiter, callback);
|
||||
});
|
||||
}
|
||||
|
||||
string IPCSocketImpl::get_local_endpoint( void )
|
||||
{
|
||||
return "/tmp/restbed.sock";
|
||||
}
|
||||
|
||||
string IPCSocketImpl::get_remote_endpoint( void )
|
||||
{
|
||||
return "/tmp/restbed.sock";
|
||||
}
|
||||
|
||||
void IPCSocketImpl::set_timeout( const milliseconds& value )
|
||||
{
|
||||
m_timeout = value;
|
||||
}
|
||||
|
||||
void IPCSocketImpl::set_keep_alive( const uint32_t, const uint32_t, const uint32_t)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
shared_ptr< IPCSocketImpl > IPCSocketImpl::shared_from_this( void )
|
||||
{
|
||||
return std::dynamic_pointer_cast< IPCSocketImpl >( SocketImpl::shared_from_this( ) );
|
||||
//return shared_ptr< IPCSocketImpl >( this ); //test for circular reference and memory leak.
|
||||
}
|
||||
|
||||
void IPCSocketImpl::connection_timeout_handler( const shared_ptr< IPCSocketImpl > socket, const error_code& error )
|
||||
{
|
||||
if ( error or socket == nullptr or socket->m_timer->expires_at( ) > steady_clock::now( ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
socket->close( );
|
||||
|
||||
if ( m_error_handler not_eq nullptr )
|
||||
{
|
||||
m_error_handler( 408, runtime_error( "The socket timed out waiting for the request." ), nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
void IPCSocketImpl::write( void )
|
||||
{
|
||||
if(m_is_open)
|
||||
{
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( m_timeout );
|
||||
m_timer->async_wait( m_strand->wrap( bind( &IPCSocketImpl::connection_timeout_handler, this, shared_from_this( ), _1 ) ) );
|
||||
|
||||
asio::async_write( *m_socket, asio::buffer( get<0>(m_pending_writes.front()).data( ), get<0>(m_pending_writes.front()).size( ) ), m_strand->wrap( [ this ]( const error_code & error, size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
auto callback = get<2>(m_pending_writes.front());
|
||||
auto & retries = get<1>(m_pending_writes.front());
|
||||
auto & buffer = get<0>(m_pending_writes.front());
|
||||
if(length < buffer.size() && retries < MAX_WRITE_RETRIES && error not_eq asio::error::operation_aborted)
|
||||
{
|
||||
++retries;
|
||||
buffer.erase(buffer.begin(),buffer.begin() + length);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pending_writes.pop();
|
||||
}
|
||||
if ( error not_eq asio::error::operation_aborted )
|
||||
{
|
||||
callback( error, length );
|
||||
}
|
||||
if(!m_pending_writes.empty())
|
||||
{
|
||||
write();
|
||||
}
|
||||
} ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
while(!m_pending_writes.empty())
|
||||
{
|
||||
m_pending_writes.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IPCSocketImpl::write( const Bytes& data, const function< void ( const error_code&, size_t ) >& callback )
|
||||
{
|
||||
const auto buffer = make_shared< Bytes >( data );
|
||||
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( m_timeout );
|
||||
m_timer->async_wait( m_strand->wrap( bind( &IPCSocketImpl::connection_timeout_handler, this, shared_from_this( ), _1 ) ) );
|
||||
|
||||
asio::async_write( *m_socket, asio::buffer( buffer->data( ), buffer->size( ) ), m_strand->wrap( [ this, callback, buffer ]( const error_code & error, size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
if ( error not_eq asio::error::operation_aborted )
|
||||
{
|
||||
callback( error, length );
|
||||
}
|
||||
} ) );
|
||||
}
|
||||
|
||||
void IPCSocketImpl::write_helper(const Bytes& data, const function< void ( const error_code&, size_t ) >& callback)
|
||||
{
|
||||
const uint8_t retries = 0;
|
||||
m_pending_writes.push(make_tuple(data, retries, callback));
|
||||
if(m_pending_writes.size() == 1)
|
||||
{
|
||||
write();
|
||||
}
|
||||
}
|
||||
|
||||
size_t IPCSocketImpl::read( const shared_ptr< asio::streambuf >& data, const size_t length, error_code& error )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( m_timeout );
|
||||
m_timer->async_wait( m_strand->wrap( bind( &IPCSocketImpl::connection_timeout_handler, this, shared_from_this( ), _1 ) ) );
|
||||
|
||||
size_t size = 0;
|
||||
auto finished = std::make_shared<bool>(false);
|
||||
auto sharedError = std::make_shared<error_code>();
|
||||
auto sharedSize = std::make_shared<size_t>(0);
|
||||
|
||||
asio::async_read( *m_socket, *data, asio::transfer_at_least( length ),
|
||||
[ finished, sharedSize, sharedError ]( const error_code & error, size_t size ) {
|
||||
*sharedError = error;
|
||||
*sharedSize = size;
|
||||
*finished = true;
|
||||
});
|
||||
|
||||
while (!*finished)
|
||||
m_io_service.run_one();
|
||||
error = *sharedError;
|
||||
size = *sharedSize;
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void IPCSocketImpl::read( const std::size_t length, const function< void ( const Bytes ) > success, const function< void ( const error_code ) > failure )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( m_timeout );
|
||||
m_timer->async_wait( m_strand->wrap( bind( &IPCSocketImpl::connection_timeout_handler, this, shared_from_this( ), _1 ) ) );
|
||||
|
||||
auto data = make_shared< asio::streambuf >( );
|
||||
asio::async_read( *m_socket, *data, asio::transfer_exactly( length ), [ this, data, success, failure ]( const error_code code, const size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( code )
|
||||
{
|
||||
m_is_open = false;
|
||||
failure( code );
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto data_ptr = asio::buffer_cast< const Byte* >( data->data( ) );
|
||||
success( Bytes( data_ptr, data_ptr + length ) );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
void IPCSocketImpl::read( const shared_ptr< asio::streambuf >& data, const size_t length, const function< void ( const error_code&, size_t ) >& callback )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( m_timeout );
|
||||
m_timer->async_wait( m_strand->wrap( bind( &IPCSocketImpl::connection_timeout_handler, this, shared_from_this( ), _1 ) ) );
|
||||
|
||||
asio::async_read( *m_socket, *data, asio::transfer_at_least( length ), m_strand->wrap( [ this, callback ]( const error_code & error, size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
if ( error not_eq asio::error::operation_aborted )
|
||||
{
|
||||
callback( error, length );
|
||||
}
|
||||
} ) );
|
||||
}
|
||||
|
||||
size_t IPCSocketImpl::read( const shared_ptr< asio::streambuf >& data, const string& delimiter, error_code& error )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( m_timeout );
|
||||
m_timer->async_wait( bind( &IPCSocketImpl::connection_timeout_handler, this, shared_from_this( ), _1 ) );
|
||||
|
||||
size_t length = 0;
|
||||
auto finished = std::make_shared<bool>(false);
|
||||
auto sharedError = std::make_shared<error_code>();
|
||||
auto sharedLength = std::make_shared<size_t>(0);
|
||||
|
||||
asio::async_read_until( *m_socket, *data, delimiter,
|
||||
[ finished, sharedLength, sharedError ]( const error_code & error, size_t length ) {
|
||||
*sharedError = error;
|
||||
*sharedLength = length;
|
||||
*finished = true;
|
||||
});
|
||||
|
||||
while (!*finished)
|
||||
m_io_service.run_one();
|
||||
error = *sharedError;
|
||||
length = *sharedLength;
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
void IPCSocketImpl::read( const shared_ptr< asio::streambuf >& data, const string& delimiter, const function< void ( const error_code&, size_t ) >& callback )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( m_timeout );
|
||||
m_timer->async_wait( m_strand->wrap( bind( &IPCSocketImpl::connection_timeout_handler, this, shared_from_this( ), _1 ) ) );
|
||||
|
||||
asio::async_read_until( *m_socket, *data, delimiter, m_strand->wrap( [ this, callback ]( const error_code & error, size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
if ( error not_eq asio::error::operation_aborted )
|
||||
{
|
||||
callback( error, length );
|
||||
}
|
||||
} ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef BUILD_IPC
|
||||
|
||||
//System Includes
|
||||
#include <queue>
|
||||
#include <tuple>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <system_error>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/byte.hpp"
|
||||
#include "corvusoft/restbed/detail/socket_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
#include <asio/streambuf.hpp>
|
||||
#include <asio/steady_timer.hpp>
|
||||
#include <asio/io_service.hpp>
|
||||
#include <asio/io_service_strand.hpp>
|
||||
#include <asio/local/stream_protocol.hpp>
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Logger;
|
||||
class Session;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
class IPCSocketImpl : virtual public SocketImpl
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
IPCSocketImpl( asio::io_context& context, const std::shared_ptr< asio::local::stream_protocol::socket >& socket, const std::shared_ptr< Logger >& logger = nullptr );
|
||||
|
||||
~IPCSocketImpl( void ) = default;
|
||||
|
||||
//Functionality
|
||||
void close( void ) override;
|
||||
|
||||
bool is_open( void ) const override;
|
||||
|
||||
bool is_closed( void ) const override;
|
||||
|
||||
void connect( const std::string& hostname, const uint16_t port, const std::function< void ( const std::error_code& ) >& callback ) override;
|
||||
|
||||
void sleep_for( const std::chrono::milliseconds& delay, const std::function< void ( const std::error_code& ) >& callback ) override;
|
||||
|
||||
void start_write(const Bytes& data, const std::function< void ( const std::error_code&, std::size_t ) >& callback) override;
|
||||
|
||||
size_t start_read( const std::shared_ptr< asio::streambuf >& data, const std::string& delimiter, std::error_code& error ) override;
|
||||
|
||||
size_t start_read( const std::shared_ptr< asio::streambuf >& data, const std::size_t length, std::error_code& error ) override;
|
||||
|
||||
void start_read(const std::size_t length, const std::function< void ( const Bytes ) > success, const std::function< void ( const std::error_code ) > failure ) override;
|
||||
|
||||
void start_read( const std::shared_ptr< asio::streambuf >& data, const std::size_t length, const std::function< void ( const std::error_code&, std::size_t ) >& callback ) override;
|
||||
|
||||
void start_read(const std::shared_ptr< asio::streambuf >& data, const std::string& delimiter, const std::function< void ( const std::error_code&, std::size_t ) >& callback ) override;
|
||||
|
||||
//Getters
|
||||
std::string get_local_endpoint( void ) override;
|
||||
|
||||
std::string get_remote_endpoint( void ) override;
|
||||
|
||||
//Setters
|
||||
void set_timeout( const std::chrono::milliseconds& value ) override;
|
||||
|
||||
void set_keep_alive( const uint32_t start, const uint32_t interval, const uint32_t cnt) override;
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
std::function< void ( const int, const std::exception&, const std::shared_ptr< Session > ) > m_error_handler;
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
IPCSocketImpl( const IPCSocketImpl& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
std::shared_ptr< IPCSocketImpl > shared_from_this( void );
|
||||
|
||||
void connection_timeout_handler( const std::shared_ptr< IPCSocketImpl > socket, const std::error_code& error );
|
||||
|
||||
void write( void );
|
||||
|
||||
void write( const Bytes& data, const std::function< void ( const std::error_code&, std::size_t ) >& callback );
|
||||
|
||||
void write_helper( const Bytes& data, const std::function< void ( const std::error_code&, std::size_t ) >& callback );
|
||||
|
||||
size_t read( const std::shared_ptr< asio::streambuf >& data, const std::size_t length, std::error_code& error );
|
||||
|
||||
void read( const std::size_t length, const std::function< void ( const Bytes ) > success, const std::function< void ( const std::error_code ) > failure );
|
||||
|
||||
void read( const std::shared_ptr< asio::streambuf >& data, const std::size_t length, const std::function< void ( const std::error_code&, std::size_t ) >& callback );
|
||||
|
||||
size_t read( const std::shared_ptr< asio::streambuf >& data, const std::string& delimiter, std::error_code& error );
|
||||
|
||||
void read( const std::shared_ptr< asio::streambuf >& data, const std::string& delimiter, const std::function< void ( const std::error_code&, std::size_t ) >& callback );
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
IPCSocketImpl& operator =( const IPCSocketImpl& value ) = delete;
|
||||
|
||||
//Properties
|
||||
bool m_is_open;
|
||||
|
||||
const uint8_t MAX_WRITE_RETRIES = 5;
|
||||
|
||||
std::queue< std::tuple< Bytes, uint8_t, std::function< void ( const std::error_code&, std::size_t ) > > > m_pending_writes;
|
||||
|
||||
std::shared_ptr< Logger > m_logger;
|
||||
|
||||
std::chrono::milliseconds m_timeout;
|
||||
|
||||
asio::io_context &m_io_service;
|
||||
|
||||
std::shared_ptr< asio::steady_timer > m_timer;
|
||||
|
||||
std::shared_ptr< asio::io_service::strand > m_strand;
|
||||
|
||||
std::shared_ptr< asio::local::stream_protocol::socket > m_socket;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
//Project Includes
|
||||
#include <corvusoft/restbed/byte.hpp>
|
||||
|
||||
//External Includes
|
||||
#include <asio/streambuf.hpp>
|
||||
#include <asio/io_service.hpp>
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Uri;
|
||||
class Response;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
class SocketImpl;
|
||||
|
||||
struct RequestImpl
|
||||
{
|
||||
Bytes m_body { };
|
||||
|
||||
uint16_t m_port = 80;
|
||||
|
||||
double m_version = 1.1;
|
||||
|
||||
std::string m_host = "";
|
||||
|
||||
std::string m_path = "/";
|
||||
|
||||
std::string m_method = "GET";
|
||||
|
||||
std::string m_protocol = "HTTP";
|
||||
|
||||
std::shared_ptr< Uri > m_uri = nullptr;
|
||||
|
||||
std::shared_ptr< Response > m_response = nullptr;
|
||||
|
||||
std::multimap< std::string, std::string > m_headers { };
|
||||
|
||||
std::map< std::string, std::string > m_path_parameters { };
|
||||
|
||||
std::multimap< std::string, std::string > m_query_parameters { };
|
||||
|
||||
std::shared_ptr< asio::io_service > m_io_service = nullptr;
|
||||
|
||||
std::shared_ptr< SocketImpl > m_socket = nullptr;
|
||||
|
||||
std::shared_ptr< asio::streambuf > m_buffer = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Rule;
|
||||
class Session;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
struct ResourceImpl
|
||||
{
|
||||
std::set< std::string > m_paths { };
|
||||
|
||||
std::set< std::string > m_methods { };
|
||||
|
||||
std::vector< std::shared_ptr< Rule > > m_rules { };
|
||||
|
||||
std::multimap< std::string, std::string > m_default_headers { };
|
||||
|
||||
std::function< void ( const std::shared_ptr< Session > ) > m_failed_filter_validation_handler = nullptr;
|
||||
|
||||
std::function< void ( const int, const std::exception&, const std::shared_ptr< Session > ) > m_error_handler = nullptr;
|
||||
|
||||
std::function< void ( const std::shared_ptr< Session >, const std::function< void ( const std::shared_ptr< Session > ) >& ) > m_authentication_handler = nullptr;
|
||||
|
||||
std::multimap< std::string, std::pair< std::multimap< std::string, std::string >, std::function< void ( const std::shared_ptr< Session > ) > > > m_method_handlers { };
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/byte.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Request;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
struct ResponseImpl
|
||||
{
|
||||
Bytes m_body { };
|
||||
|
||||
double m_version = 1.1;
|
||||
|
||||
int m_status_code = 0;
|
||||
|
||||
Request* m_request = nullptr;
|
||||
|
||||
std::string m_protocol = "HTTP";
|
||||
|
||||
std::string m_status_message = "";
|
||||
|
||||
std::multimap< std::string, std::string > m_headers { };
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstddef>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Rule;
|
||||
class Session;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
static void rule_engine( const std::shared_ptr< Session > session,
|
||||
const std::vector< std::shared_ptr< Rule > >& rules,
|
||||
const std::function< void ( const std::shared_ptr< Session > ) >& callback,
|
||||
std::size_t index = 0 )
|
||||
{
|
||||
while ( index not_eq rules.size( ) )
|
||||
{
|
||||
auto rule = rules.at( index );
|
||||
index++;
|
||||
|
||||
if ( rule->condition( session ) )
|
||||
{
|
||||
rule->action( session, bind( rule_engine, session, rules, callback, index ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( index == rules.size( ) )
|
||||
{
|
||||
callback( session );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <memory>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
struct RuleImpl
|
||||
{
|
||||
int m_priority = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
951
lib/restbed-4.8/source/corvusoft/restbed/detail/service_impl.cpp
Normal file
951
lib/restbed-4.8/source/corvusoft/restbed/detail/service_impl.cpp
Normal file
@@ -0,0 +1,951 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <regex>
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <ciso646>
|
||||
#include <cstdlib>
|
||||
#include <clocale>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/uri.hpp"
|
||||
#include "corvusoft/restbed/rule.hpp"
|
||||
#include "corvusoft/restbed/logger.hpp"
|
||||
#include "corvusoft/restbed/string.hpp"
|
||||
#include "corvusoft/restbed/request.hpp"
|
||||
#include "corvusoft/restbed/session.hpp"
|
||||
#include "corvusoft/restbed/resource.hpp"
|
||||
#include "corvusoft/restbed/settings.hpp"
|
||||
#include "corvusoft/restbed/status_code.hpp"
|
||||
#include "corvusoft/restbed/ssl_settings.hpp"
|
||||
#include "corvusoft/restbed/session_manager.hpp"
|
||||
#include "corvusoft/restbed/detail/socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/request_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/service_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/session_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/resource_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/ipc_socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/rule_engine_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/web_socket_manager_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::set;
|
||||
using std::map;
|
||||
using std::free;
|
||||
using std::pair;
|
||||
using std::bind;
|
||||
using std::regex;
|
||||
using std::string;
|
||||
using std::smatch;
|
||||
using std::istream;
|
||||
using std::find_if;
|
||||
using std::function;
|
||||
using std::setlocale;
|
||||
using std::multimap;
|
||||
using std::to_string;
|
||||
using std::exception;
|
||||
using std::shared_ptr;
|
||||
using std::error_code;
|
||||
using std::regex_error;
|
||||
using std::make_shared;
|
||||
using std::runtime_error;
|
||||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
using std::placeholders::_3;
|
||||
using std::current_exception;
|
||||
using std::rethrow_exception;
|
||||
using std::chrono::steady_clock;
|
||||
using std::regex_constants::icase;
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
using asio::ip::tcp;
|
||||
using asio::io_service;
|
||||
using asio::signal_set;
|
||||
using asio::ip::address;
|
||||
using asio::socket_base;
|
||||
using asio::system_error;
|
||||
|
||||
#if BUILD_IPC
|
||||
using asio::local::stream_protocol;
|
||||
#endif
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
ServiceImpl::ServiceImpl( void ) : m_uptime( steady_clock::time_point::min( ) ),
|
||||
m_logger( nullptr ),
|
||||
m_supported_methods( ),
|
||||
m_settings( nullptr ),
|
||||
m_io_service( make_shared< ::io_service >( ) ),
|
||||
m_signal_set( nullptr ),
|
||||
m_session_manager( nullptr ),
|
||||
m_web_socket_manager( nullptr ),
|
||||
m_rules( ),
|
||||
m_workers_stopped( ),
|
||||
#ifdef BUILD_SSL
|
||||
m_ssl_settings( nullptr ),
|
||||
m_ssl_context( nullptr ),
|
||||
m_ssl_acceptor( nullptr ),
|
||||
#endif
|
||||
#ifdef BUILD_IPC
|
||||
m_ipc_acceptor( nullptr ),
|
||||
#endif
|
||||
m_acceptor( nullptr ),
|
||||
m_resource_paths( ),
|
||||
m_resource_routes( ),
|
||||
m_ready_handler( nullptr ),
|
||||
m_signal_handlers( ),
|
||||
m_not_found_handler( nullptr ),
|
||||
m_method_not_allowed_handler( nullptr ),
|
||||
m_method_not_implemented_handler( nullptr ),
|
||||
m_failed_filter_validation_handler( nullptr ),
|
||||
m_error_handler( ServiceImpl::default_error_handler ),
|
||||
m_authentication_handler( nullptr )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceImpl::~ServiceImpl( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void ServiceImpl::http_start( void )
|
||||
{
|
||||
#ifdef BUILD_SSL
|
||||
|
||||
if ( m_ssl_settings == nullptr or m_ssl_settings->has_disabled_http( ) == false )
|
||||
{
|
||||
#endif
|
||||
|
||||
if ( not m_settings->get_bind_address( ).empty( ) )
|
||||
{
|
||||
const auto address = address::from_string( m_settings->get_bind_address( ) );
|
||||
m_acceptor = make_shared< tcp::acceptor >( *m_io_service, tcp::endpoint( address, m_settings->get_port( ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_acceptor = make_shared< tcp::acceptor >( *m_io_service, tcp::endpoint( tcp::v6( ), m_settings->get_port( ) ) );
|
||||
}
|
||||
|
||||
m_acceptor->set_option( socket_base::reuse_address( m_settings->get_reuse_address( ) ) );
|
||||
m_acceptor->listen( m_settings->get_connection_limit( ) );
|
||||
|
||||
http_listen( );
|
||||
|
||||
const auto location = get_http_uri( )->to_string( );
|
||||
log( Logger::INFO, String::format( "Service accepting HTTP connections at '%s'.", location.data( ) ) );
|
||||
#ifdef BUILD_SSL
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void ServiceImpl::http_listen( void ) const
|
||||
{
|
||||
auto socket = make_shared< tcp::socket >( *m_io_service );
|
||||
m_acceptor->async_accept( *socket, bind( &ServiceImpl::create_session, this, socket, _1 ) );
|
||||
}
|
||||
|
||||
void ServiceImpl::setup_signal_handler( void )
|
||||
{
|
||||
if ( m_signal_handlers.empty( ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_signal_set = make_shared< signal_set >( *m_io_service );
|
||||
|
||||
for ( const auto signal_handler : m_signal_handlers )
|
||||
{
|
||||
m_signal_set->add( signal_handler.first );
|
||||
}
|
||||
|
||||
m_signal_set->async_wait( bind( &ServiceImpl::signal_handler, this, _1, _2 ) );
|
||||
}
|
||||
|
||||
void ServiceImpl::signal_handler( const error_code& error, const int signal_number ) const
|
||||
{
|
||||
if ( error )
|
||||
{
|
||||
log( Logger::WARNING, String::format( "Failed to process signal '%i', '%s'.", signal_number, error.message( ).data( ) ) );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_signal_handlers.count( signal_number ) )
|
||||
{
|
||||
m_signal_handlers.at( signal_number )( signal_number );
|
||||
}
|
||||
|
||||
m_signal_set->async_wait( bind( &ServiceImpl::signal_handler, this, _1, _2 ) );
|
||||
}
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
void ServiceImpl::https_start( void )
|
||||
{
|
||||
if ( m_ssl_settings not_eq nullptr )
|
||||
{
|
||||
m_ssl_context = make_shared< asio::ssl::context >( asio::ssl::context::sslv23 );
|
||||
m_ssl_context->set_default_verify_paths( );
|
||||
|
||||
auto passphrase = m_ssl_settings->get_passphrase( );
|
||||
m_ssl_context->set_password_callback( [ passphrase ]( size_t, asio::ssl::context::password_purpose )
|
||||
{
|
||||
return passphrase;
|
||||
} );
|
||||
|
||||
auto filename = m_ssl_settings->get_temporary_diffie_hellman( );
|
||||
|
||||
if ( not filename.empty( ) )
|
||||
{
|
||||
m_ssl_context->use_tmp_dh_file( filename );
|
||||
}
|
||||
|
||||
filename = m_ssl_settings->get_certificate_authority_pool( );
|
||||
|
||||
if ( not filename.empty( ) )
|
||||
{
|
||||
m_ssl_context->add_verify_path( filename );
|
||||
}
|
||||
|
||||
filename = m_ssl_settings->get_certificate_chain( );
|
||||
|
||||
if ( not filename.empty( ) )
|
||||
{
|
||||
m_ssl_context->use_certificate_chain_file( filename );
|
||||
}
|
||||
|
||||
filename = m_ssl_settings->get_certificate( );
|
||||
|
||||
if ( not filename.empty( ) )
|
||||
{
|
||||
m_ssl_context->use_certificate_file( filename, asio::ssl::context::pem );
|
||||
}
|
||||
|
||||
filename = m_ssl_settings->get_private_key( );
|
||||
|
||||
if ( not filename.empty( ) )
|
||||
{
|
||||
m_ssl_context->use_private_key_file( filename, asio::ssl::context::pem );
|
||||
}
|
||||
|
||||
filename = m_ssl_settings->get_private_rsa_key( );
|
||||
|
||||
if ( not filename.empty( ) )
|
||||
{
|
||||
m_ssl_context->use_rsa_private_key_file( filename, asio::ssl::context::pem );
|
||||
}
|
||||
|
||||
asio::ssl::context::options options = 0;
|
||||
options = ( m_ssl_settings->has_enabled_tlsv1( ) ) ? options : options | asio::ssl::context::no_tlsv1;
|
||||
options = ( m_ssl_settings->has_enabled_sslv2( ) ) ? options : options | asio::ssl::context::no_sslv2;
|
||||
options = ( m_ssl_settings->has_enabled_sslv3( ) ) ? options : options | asio::ssl::context::no_sslv3;
|
||||
options = ( m_ssl_settings->has_enabled_tlsv11( ) ) ? options : options | asio::ssl::context::no_tlsv1_1;
|
||||
options = ( m_ssl_settings->has_enabled_tlsv12( ) ) ? options : options | asio::ssl::context::no_tlsv1_2;
|
||||
options = ( m_ssl_settings->has_enabled_compression( ) ) ? options : options | asio::ssl::context::no_compression;
|
||||
options = ( m_ssl_settings->has_enabled_default_workarounds( ) ) ? options | asio::ssl::context::default_workarounds : options;
|
||||
options = ( m_ssl_settings->has_enabled_single_diffie_hellman_use( ) ) ? options | asio::ssl::context::single_dh_use : options;
|
||||
m_ssl_context->set_options( options );
|
||||
|
||||
if ( not m_ssl_settings->get_bind_address( ).empty( ) )
|
||||
{
|
||||
const auto address = address::from_string( m_ssl_settings->get_bind_address( ) );
|
||||
m_ssl_acceptor = make_shared< tcp::acceptor >( *m_io_service, tcp::endpoint( address, m_ssl_settings->get_port( ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ssl_acceptor = make_shared< tcp::acceptor >( *m_io_service, tcp::endpoint( tcp::v6( ), m_ssl_settings->get_port( ) ) );
|
||||
}
|
||||
|
||||
m_ssl_acceptor->set_option( socket_base::reuse_address( m_settings->get_reuse_address( ) ) );
|
||||
m_ssl_acceptor->listen( m_settings->get_connection_limit( ) );
|
||||
|
||||
https_listen( );
|
||||
|
||||
const auto location = get_https_uri( )->to_string( );
|
||||
log( Logger::INFO, String::format( "Service accepting HTTPS connections at '%s'.", location.data( ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceImpl::https_listen( void ) const
|
||||
{
|
||||
auto socket = make_shared< asio::ssl::stream< tcp::socket > >( *m_io_service, *m_ssl_context );
|
||||
m_ssl_acceptor->async_accept( socket->lowest_layer( ), bind( &ServiceImpl::create_ssl_session, this, socket, _1 ) );
|
||||
}
|
||||
|
||||
void ServiceImpl::create_ssl_session( const shared_ptr< asio::ssl::stream< tcp::socket > >& socket, const error_code& error ) const
|
||||
{
|
||||
if ( not error )
|
||||
{
|
||||
socket->async_handshake( asio::ssl::stream_base::server, [ this, socket ]( const error_code & error )
|
||||
{
|
||||
if ( error )
|
||||
{
|
||||
log( Logger::SECURITY, String::format( "Failed SSL handshake, '%s'.", error.message( ).data( ) ) );
|
||||
return;
|
||||
}
|
||||
|
||||
auto connection = make_shared< SocketImpl >( *m_io_service, socket, m_logger );
|
||||
connection->set_timeout( m_settings->get_connection_timeout( ) );
|
||||
if (m_settings->get_keep_alive()) {
|
||||
connection->set_keep_alive( m_settings->get_keep_alive_start(),
|
||||
m_settings->get_keep_alive_interval(),
|
||||
m_settings->get_keep_alive_cnt());
|
||||
}
|
||||
|
||||
m_session_manager->create( [ this, connection ]( const shared_ptr< Session > session )
|
||||
{
|
||||
session->m_pimpl->m_settings = m_settings;
|
||||
session->m_pimpl->m_manager = m_session_manager;
|
||||
session->m_pimpl->m_web_socket_manager = m_web_socket_manager;
|
||||
session->m_pimpl->m_error_handler = m_error_handler;
|
||||
session->m_pimpl->m_request = make_shared< Request >( );
|
||||
session->m_pimpl->m_request->m_pimpl->m_socket = connection;
|
||||
session->m_pimpl->m_request->m_pimpl->m_socket->m_error_handler = m_error_handler;
|
||||
session->m_pimpl->m_request->m_pimpl->m_buffer = make_shared< asio::streambuf >( );
|
||||
session->m_pimpl->m_keep_alive_callback = bind( &ServiceImpl::parse_request, this, _1, _2, _3 );
|
||||
session->m_pimpl->m_request->m_pimpl->m_socket->start_read( session->m_pimpl->m_request->m_pimpl->m_buffer, "\r\n\r\n", bind( &ServiceImpl::parse_request, this, _1, _2, session ) );
|
||||
} );
|
||||
} );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( socket not_eq nullptr and socket->lowest_layer( ).is_open( ) )
|
||||
{
|
||||
socket->lowest_layer( ).close( );
|
||||
}
|
||||
|
||||
log( Logger::WARNING, String::format( "Failed to create session, '%s'.", error.message( ).data( ) ) );
|
||||
}
|
||||
|
||||
https_listen( );
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_IPC
|
||||
void ServiceImpl::ipc_start( void )
|
||||
{
|
||||
const string location = "/tmp/restbed.sock";
|
||||
::remove( location.data( ) );
|
||||
|
||||
m_ipc_acceptor = make_shared< stream_protocol::acceptor >( *m_io_service, stream_protocol::endpoint( location ) );
|
||||
m_ipc_acceptor->set_option( socket_base::reuse_address( m_settings->get_reuse_address( ) ) );
|
||||
m_ipc_acceptor->listen( m_settings->get_connection_limit( ) );
|
||||
ipc_listen( );
|
||||
|
||||
log( Logger::INFO, String::format( "Service accepting HTTP connections at '%s'.", location.data( ) ) );
|
||||
}
|
||||
|
||||
void ServiceImpl::ipc_listen( void ) const
|
||||
{
|
||||
auto socket = make_shared< stream_protocol::socket >( *m_io_service );
|
||||
m_ipc_acceptor->async_accept( *socket, bind( &ServiceImpl::create_ipc_session, this, socket, _1 ) );
|
||||
}
|
||||
|
||||
void ServiceImpl::create_ipc_session( const shared_ptr< stream_protocol::socket >& socket, const error_code& error ) const
|
||||
{
|
||||
if ( not error )
|
||||
{
|
||||
auto connection = make_shared< IPCSocketImpl >( *m_io_service, socket, m_logger );
|
||||
connection->set_timeout( m_settings->get_connection_timeout( ) );
|
||||
if (m_settings->get_keep_alive()) {
|
||||
connection->set_keep_alive( m_settings->get_keep_alive_start(),
|
||||
m_settings->get_keep_alive_interval(),
|
||||
m_settings->get_keep_alive_cnt());
|
||||
}
|
||||
|
||||
m_session_manager->create( [ this, connection ]( const shared_ptr< Session > session )
|
||||
{
|
||||
session->m_pimpl->m_settings = m_settings;
|
||||
session->m_pimpl->m_manager = m_session_manager;
|
||||
session->m_pimpl->m_web_socket_manager = m_web_socket_manager;
|
||||
session->m_pimpl->m_error_handler = m_error_handler;
|
||||
session->m_pimpl->m_request = make_shared< Request >( );
|
||||
session->m_pimpl->m_request->m_pimpl->m_socket = connection;
|
||||
session->m_pimpl->m_request->m_pimpl->m_socket->m_error_handler = m_error_handler;
|
||||
session->m_pimpl->m_request->m_pimpl->m_buffer = make_shared< asio::streambuf >( );
|
||||
session->m_pimpl->m_keep_alive_callback = bind( &ServiceImpl::parse_request, this, _1, _2, _3 );
|
||||
session->m_pimpl->m_request->m_pimpl->m_socket->start_read( session->m_pimpl->m_request->m_pimpl->m_buffer, "\r\n\r\n", bind( &ServiceImpl::parse_request, this, _1, _2, session ) );
|
||||
} );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( socket not_eq nullptr and socket->is_open( ) )
|
||||
{
|
||||
socket->close( );
|
||||
}
|
||||
|
||||
log( Logger::WARNING, String::format( "Failed to create session, '%s'.", error.message( ).data( ) ) );
|
||||
}
|
||||
|
||||
ipc_listen( );
|
||||
}
|
||||
#endif
|
||||
|
||||
string ServiceImpl::sanitise_path( const string& path ) const
|
||||
{
|
||||
if ( path == "/" )
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
smatch matches;
|
||||
string sanitised_path = "";
|
||||
static const regex pattern( "^\\{[a-zA-Z0-9_\\-]+: ?(.*)\\}$" );
|
||||
|
||||
for ( auto folder : String::split( path, '/' ) )
|
||||
{
|
||||
if ( folder.front( ) == '{' and folder.back( ) == '}' )
|
||||
{
|
||||
if ( not regex_match( folder, matches, pattern ) or matches.size( ) not_eq 2 )
|
||||
{
|
||||
throw runtime_error( String::format( "Resource path parameter declaration is malformed '%s'.", folder.data( ) ) );
|
||||
}
|
||||
|
||||
sanitised_path += '/' + matches[ 1 ].str( );
|
||||
}
|
||||
else
|
||||
{
|
||||
sanitised_path += '/' + folder;
|
||||
}
|
||||
}
|
||||
|
||||
if ( path.back( ) == '/' )
|
||||
{
|
||||
sanitised_path += '/';
|
||||
}
|
||||
|
||||
return sanitised_path;
|
||||
}
|
||||
|
||||
void ServiceImpl::not_found( const shared_ptr< Session > session ) const
|
||||
{
|
||||
log( Logger::INFO, String::format( "'%s' resource route not found '%s'.",
|
||||
session->get_origin( ).data( ),
|
||||
session->get_request( )->get_path( ).data( ) ) );
|
||||
|
||||
if ( m_not_found_handler not_eq nullptr )
|
||||
{
|
||||
m_not_found_handler( session );
|
||||
}
|
||||
else
|
||||
{
|
||||
session->close( NOT_FOUND );
|
||||
}
|
||||
}
|
||||
|
||||
bool ServiceImpl::has_unique_paths( const set< string >& paths ) const
|
||||
{
|
||||
if ( paths.empty( ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( const auto& path : paths )
|
||||
{
|
||||
if ( m_resource_routes.count( path ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ServiceImpl::log( const Logger::Level level, const string& message ) const
|
||||
{
|
||||
if ( m_logger not_eq nullptr )
|
||||
{
|
||||
try
|
||||
{
|
||||
m_logger->log( level, "%s", message.data( ) );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
fprintf( stderr, "Failed to create log entry: %s", message.data( ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceImpl::method_not_allowed( const shared_ptr< Session > session ) const
|
||||
{
|
||||
log( Logger::INFO, String::format( "'%s' '%s' method not allowed '%s'.",
|
||||
session->get_origin( ).data( ),
|
||||
session->get_request( )->get_method( ).data( ),
|
||||
session->get_request( )->get_path( ).data( ) ) );
|
||||
|
||||
if ( m_method_not_allowed_handler not_eq nullptr )
|
||||
{
|
||||
m_method_not_allowed_handler( session );
|
||||
}
|
||||
else
|
||||
{
|
||||
session->close( METHOD_NOT_ALLOWED );
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceImpl::method_not_implemented( const shared_ptr< Session > session ) const
|
||||
{
|
||||
log( Logger::INFO, String::format( "'%s' '%s' method not implemented '%s'.",
|
||||
session->get_origin( ).data( ),
|
||||
session->get_request( )->get_method( ).data( ),
|
||||
session->get_request( )->get_path( ).data( ) ) );
|
||||
|
||||
if ( m_method_not_implemented_handler not_eq nullptr )
|
||||
{
|
||||
m_method_not_implemented_handler( session );
|
||||
}
|
||||
else
|
||||
{
|
||||
session->close( NOT_IMPLEMENTED );
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceImpl::failed_filter_validation( const shared_ptr< Session > session ) const
|
||||
{
|
||||
log( Logger::INFO, String::format( "'%s' failed filter validation '%s'.",
|
||||
session->get_origin( ).data( ),
|
||||
session->get_request( )->get_path( ).data( ) ) );
|
||||
|
||||
if ( m_failed_filter_validation_handler not_eq nullptr )
|
||||
{
|
||||
m_failed_filter_validation_handler( session );
|
||||
}
|
||||
else
|
||||
{
|
||||
session->close( BAD_REQUEST, { { "Connection", "close" } } );
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceImpl::router( const shared_ptr< Session > session ) const
|
||||
{
|
||||
log( Logger::INFO, String::format( "Incoming '%s' request from '%s' for route '%s'.",
|
||||
session->get_request( )->get_method( ).data( ),
|
||||
session->get_origin( ).data( ),
|
||||
session->get_request( )->get_path( ).data( ) ) );
|
||||
|
||||
if ( session->is_closed( ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rule_engine( session, m_rules, [ this ]( const shared_ptr< Session > session )
|
||||
{
|
||||
const auto resource_route = find_if( m_resource_routes.begin( ), m_resource_routes.end( ), bind( &ServiceImpl::resource_router, this, session, _1 ) );
|
||||
|
||||
if ( resource_route == m_resource_routes.end( ) )
|
||||
{
|
||||
return not_found( session );
|
||||
}
|
||||
|
||||
const auto path = resource_route->first;
|
||||
session->m_pimpl->m_resource = resource_route->second;
|
||||
const auto request = session->get_request( );
|
||||
extract_path_parameters( path, request );
|
||||
|
||||
const auto callback = [ this ]( const shared_ptr< Session > session )
|
||||
{
|
||||
rule_engine( session, session->m_pimpl->m_resource->m_pimpl->m_rules, [ this ]( const shared_ptr< Session > session )
|
||||
{
|
||||
if ( session->is_closed( ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto request = session->get_request( );
|
||||
auto method_handler = find_method_handler( session );
|
||||
|
||||
if ( method_handler == nullptr )
|
||||
{
|
||||
if ( m_supported_methods.count( request->get_method( ) ) == 0 )
|
||||
{
|
||||
method_handler = bind( &ServiceImpl::method_not_implemented, this, _1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
method_handler = bind( &ServiceImpl::method_not_allowed, this, _1 );
|
||||
}
|
||||
}
|
||||
|
||||
method_handler( session );
|
||||
} );
|
||||
};
|
||||
|
||||
if ( session->m_pimpl->m_resource->m_pimpl->m_authentication_handler not_eq nullptr )
|
||||
{
|
||||
session->m_pimpl->m_resource->m_pimpl->m_authentication_handler( session, callback );
|
||||
}
|
||||
else
|
||||
{
|
||||
callback( session );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
void ServiceImpl::create_session( const shared_ptr< tcp::socket >& socket, const error_code& error ) const
|
||||
{
|
||||
if ( not error )
|
||||
{
|
||||
auto connection = make_shared< SocketImpl >( *m_io_service, socket, m_logger );
|
||||
connection->set_timeout( m_settings->get_connection_timeout( ) );
|
||||
if (m_settings->get_keep_alive()) {
|
||||
connection->set_keep_alive( m_settings->get_keep_alive_start(),
|
||||
m_settings->get_keep_alive_interval(),
|
||||
m_settings->get_keep_alive_cnt());
|
||||
}
|
||||
|
||||
m_session_manager->create( [ this, connection ]( const shared_ptr< Session > session )
|
||||
{
|
||||
session->m_pimpl->m_settings = m_settings;
|
||||
session->m_pimpl->m_manager = m_session_manager;
|
||||
session->m_pimpl->m_web_socket_manager = m_web_socket_manager;
|
||||
session->m_pimpl->m_error_handler = m_error_handler;
|
||||
session->m_pimpl->m_request = make_shared< Request >( );
|
||||
session->m_pimpl->m_request->m_pimpl->m_socket = connection;
|
||||
session->m_pimpl->m_request->m_pimpl->m_socket->m_error_handler = m_error_handler;
|
||||
session->m_pimpl->m_request->m_pimpl->m_buffer = make_shared< asio::streambuf >( );
|
||||
session->m_pimpl->m_keep_alive_callback = bind( &ServiceImpl::parse_request, this, _1, _2, _3 );
|
||||
session->m_pimpl->m_request->m_pimpl->m_socket->start_read( session->m_pimpl->m_request->m_pimpl->m_buffer, "\r\n\r\n", bind( &ServiceImpl::parse_request, this, _1, _2, session ) );
|
||||
} );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( socket not_eq nullptr and socket->is_open( ) )
|
||||
{
|
||||
socket->close( );
|
||||
}
|
||||
|
||||
log( Logger::WARNING, String::format( "Failed to create session, '%s'.", error.message( ).data( ) ) );
|
||||
}
|
||||
|
||||
http_listen( );
|
||||
}
|
||||
|
||||
void ServiceImpl::extract_path_parameters( const string& sanitised_path, const shared_ptr< const Request >& request ) const
|
||||
{
|
||||
smatch matches;
|
||||
static const regex pattern( "^\\{([a-zA-Z0-9_\\-]+): ?.*\\}$" );
|
||||
|
||||
const auto folders = String::split( request->get_path( ), '/' );
|
||||
const auto declarations = String::split( m_settings->get_root( ) + "/" + m_resource_paths.at( sanitised_path ), '/' );
|
||||
|
||||
// Clear previous parameters in case of "keep-alive" request
|
||||
request->m_pimpl->m_path_parameters.clear();
|
||||
|
||||
for ( size_t index = 0; index < folders.size( ) and index < declarations.size( ); index++ )
|
||||
{
|
||||
const auto declaration = declarations[ index ];
|
||||
|
||||
if ( declaration.front( ) == '{' and declaration.back( ) == '}' )
|
||||
{
|
||||
regex_match( declaration, matches, pattern );
|
||||
request->m_pimpl->m_path_parameters.insert( make_pair( matches[ 1 ].str( ), folders[ index ] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function< void ( const shared_ptr< Session > ) > ServiceImpl::find_method_handler( const shared_ptr< Session > session ) const
|
||||
{
|
||||
const auto request = session->get_request( );
|
||||
const auto resource = session->get_resource( );
|
||||
const auto method_handlers = resource->m_pimpl->m_method_handlers.equal_range( request->get_method( ) );
|
||||
|
||||
bool failed_filter_validation = false;
|
||||
function< void ( const shared_ptr< Session > ) > method_handler = nullptr;
|
||||
|
||||
for ( auto handler = method_handlers.first; handler not_eq method_handlers.second and method_handler == nullptr; handler++ )
|
||||
{
|
||||
method_handler = handler->second.second;
|
||||
|
||||
for ( const auto& filter : handler->second.first )
|
||||
{
|
||||
for ( const auto& header : request->get_headers( filter.first ) )
|
||||
{
|
||||
if ( not regex_match( header.second, regex( filter.second ) ) )
|
||||
{
|
||||
method_handler = nullptr;
|
||||
failed_filter_validation = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( failed_filter_validation and method_handler == nullptr )
|
||||
{
|
||||
const auto handler = resource->m_pimpl->m_failed_filter_validation_handler;
|
||||
method_handler = ( handler == nullptr ) ? bind( &ServiceImpl::failed_filter_validation, this, _1 ) : handler;
|
||||
}
|
||||
|
||||
return method_handler;
|
||||
}
|
||||
|
||||
void ServiceImpl::authenticate( const shared_ptr< Session > session ) const
|
||||
{
|
||||
if ( m_authentication_handler not_eq nullptr )
|
||||
{
|
||||
m_authentication_handler( session, [ this ]( const shared_ptr< Session > session )
|
||||
{
|
||||
m_session_manager->load( session, bind( &ServiceImpl::router, this, _1 ) );
|
||||
} );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_session_manager->load( session, bind( &ServiceImpl::router, this, _1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
bool ServiceImpl::resource_router( const shared_ptr< Session > session, const pair< string, shared_ptr< const Resource > >& route ) const
|
||||
{
|
||||
const auto request = session->get_request( );
|
||||
const auto path_folders = String::split( request->get_path( ), '/' );
|
||||
const auto route_folders = String::split( m_settings->get_root( ) + "/" + route.first, '/' );
|
||||
|
||||
if ( path_folders.empty( ) and route_folders.empty( ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool match = false;
|
||||
|
||||
if ( path_folders.size( ) == route_folders.size( ) )
|
||||
{
|
||||
for ( size_t index = 0; index < path_folders.size( ); index++ )
|
||||
{
|
||||
if ( m_settings->get_case_insensitive_uris( ) )
|
||||
{
|
||||
match = regex_match( path_folders[ index ], regex( route_folders[ index ], icase ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
match = regex_match( path_folders[ index ], regex( route_folders[ index ] ) );
|
||||
}
|
||||
|
||||
if ( not match )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
void ServiceImpl::default_error_handler( const int status, const exception& error, const shared_ptr< Session > session )
|
||||
{
|
||||
if ( session not_eq nullptr and session->is_open( ) )
|
||||
{
|
||||
string body = error.what( );
|
||||
session->close( status, body, { { "Content-Type", "text/plain" }, { "Content-Length", ::to_string( body.length( ) ) } } );
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceImpl::discard_request( istream& stream )
|
||||
{
|
||||
string line = String::empty;
|
||||
|
||||
while ( getline( stream, line ) )
|
||||
{
|
||||
if ( line == "\r" )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const map< string, string > ServiceImpl::parse_request_line( istream& stream )
|
||||
{
|
||||
smatch matches;
|
||||
static const regex pattern( "^([0-9a-zA-Z]*) ([a-zA-Z0-9:@_~!,;=#%&'\\-\\.\\/\\?\\$\\(\\)\\*\\+]+) (HTTP\\/[0-9]\\.[0-9])\\s*$" );
|
||||
string data = "";
|
||||
getline( stream, data );
|
||||
|
||||
if ( not regex_match( data, matches, pattern ) or matches.size( ) not_eq 4 )
|
||||
{
|
||||
throw runtime_error( "Your client has issued a malformed or illegal request status line. That’s all we know." );
|
||||
}
|
||||
|
||||
const string protocol = matches[ 3 ].str( );
|
||||
const auto delimiter = protocol.find_first_of( "/" );
|
||||
|
||||
return map< string, string >
|
||||
{
|
||||
{ "path", matches[ 2 ].str( ) },
|
||||
{ "method", matches[ 1 ].str( ) },
|
||||
{ "version", protocol.substr( delimiter + 1 ) },
|
||||
{ "protocol", protocol.substr( 0, delimiter ) }
|
||||
};
|
||||
}
|
||||
|
||||
const multimap< string, string > ServiceImpl::parse_request_headers( istream& stream )
|
||||
{
|
||||
smatch matches;
|
||||
string data = "";
|
||||
multimap< string, string > headers;
|
||||
static const regex pattern( "^([^:.]*): *(.*)\\s*$" );
|
||||
|
||||
while ( getline( stream, data ) and data not_eq "\r" )
|
||||
{
|
||||
if ( not regex_match( data, matches, pattern ) or matches.size( ) not_eq 3 )
|
||||
{
|
||||
throw runtime_error( "Your client has issued a malformed or illegal request header. That’s all we know." );
|
||||
}
|
||||
|
||||
headers.insert( make_pair( matches[ 1 ].str( ), matches[ 2 ].str( ) ) );
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
void ServiceImpl::parse_request( const error_code& error, size_t, const shared_ptr< Session > session ) const
|
||||
{
|
||||
istream stream( session->m_pimpl->m_request->m_pimpl->m_buffer.get( ) );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
discard_request( stream );
|
||||
const auto error_handler = get_error_handler( session );
|
||||
return error_handler( 400, runtime_error( error.message( ) ), session );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
const auto items = parse_request_line( stream );
|
||||
const auto uri = Uri::parse( "http://localhost" + items.at( "path" ) );
|
||||
|
||||
session->m_pimpl->m_request->m_pimpl->m_body.clear( );
|
||||
session->m_pimpl->m_request->m_pimpl->m_path = Uri::decode( uri.get_path( ) );
|
||||
session->m_pimpl->m_request->m_pimpl->m_method = items.at( "method" );
|
||||
session->m_pimpl->m_request->m_pimpl->m_headers = parse_request_headers( stream );
|
||||
session->m_pimpl->m_request->m_pimpl->m_query_parameters = uri.get_query_parameters( );
|
||||
|
||||
char* locale = strdup( setlocale( LC_NUMERIC, nullptr ) );
|
||||
setlocale( LC_NUMERIC, "C" );
|
||||
session->m_pimpl->m_request->m_pimpl->m_version = stod( items.at( "version" ) );
|
||||
setlocale( LC_NUMERIC, locale );
|
||||
free( locale );
|
||||
|
||||
authenticate( session );
|
||||
}
|
||||
catch ( const int status_code )
|
||||
{
|
||||
discard_request( stream );
|
||||
const auto error_handler = get_error_handler( session );
|
||||
error_handler( status_code, runtime_error( m_settings->get_status_message( status_code ) ), session );
|
||||
}
|
||||
catch ( const regex_error& re )
|
||||
{
|
||||
discard_request( stream );
|
||||
const auto error_handler = get_error_handler( session );
|
||||
error_handler( 500, re, session );
|
||||
}
|
||||
catch ( const runtime_error& re )
|
||||
{
|
||||
discard_request( stream );
|
||||
const auto error_handler = get_error_handler( session );
|
||||
error_handler( 400, re, session );
|
||||
}
|
||||
catch ( const exception& ex )
|
||||
{
|
||||
discard_request( stream );
|
||||
const auto error_handler = get_error_handler( session );
|
||||
error_handler( 500, ex, session );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
discard_request( stream );
|
||||
auto cex = current_exception( );
|
||||
|
||||
if ( cex not_eq nullptr )
|
||||
{
|
||||
try
|
||||
{
|
||||
rethrow_exception( cex );
|
||||
}
|
||||
catch ( const exception& ex )
|
||||
{
|
||||
const auto error_handler = get_error_handler( session );
|
||||
error_handler( 500, ex, session );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
const auto error_handler = get_error_handler( session );
|
||||
error_handler( 500, runtime_error( "Internal Server Error" ), session );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto error_handler = get_error_handler( session );
|
||||
error_handler( 500, runtime_error( "Internal Server Error" ), session );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const shared_ptr< const Uri > ServiceImpl::get_http_uri( void ) const
|
||||
{
|
||||
if ( m_acceptor == nullptr )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto endpoint = m_acceptor->local_endpoint( );
|
||||
auto address = endpoint.address( );
|
||||
auto uri = String::empty;
|
||||
|
||||
if ( address.is_v6( ) )
|
||||
{
|
||||
uri = String::format( "http://[%s]:%u", address.to_string( ).data( ), endpoint.port( ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
uri = String::format( "http://%s:%u", address.to_string( ).data( ), endpoint.port( ) );
|
||||
}
|
||||
|
||||
return make_shared< const Uri >( uri );
|
||||
}
|
||||
|
||||
const shared_ptr< const Uri > ServiceImpl::get_https_uri( void ) const
|
||||
{
|
||||
#ifdef BUILD_SSL
|
||||
|
||||
if ( m_ssl_acceptor == nullptr )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto endpoint = m_ssl_acceptor->local_endpoint( );
|
||||
auto address = endpoint.address( );
|
||||
auto uri = String::empty;
|
||||
|
||||
if ( address.is_v6( ) )
|
||||
{
|
||||
uri = String::format( "https://[%s]:%u", address.to_string( ).data( ), endpoint.port( ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
uri = String::format( "https://%s:%u", address.to_string( ).data( ), endpoint.port( ) );
|
||||
}
|
||||
|
||||
return make_shared< const Uri >( uri );
|
||||
#else
|
||||
throw runtime_error( "Not Implemented! Rebuild Restbed with SSL funcationality enabled." );
|
||||
#endif
|
||||
}
|
||||
|
||||
const function< void ( const int, const exception&, const shared_ptr< Session > ) > ServiceImpl::get_error_handler( const shared_ptr< Session >& session ) const
|
||||
{
|
||||
return ( session->m_pimpl->m_resource not_eq nullptr and session->m_pimpl->m_resource->m_pimpl->m_error_handler not_eq nullptr ) ? session->m_pimpl->m_resource->m_pimpl->m_error_handler : m_error_handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
230
lib/restbed-4.8/source/corvusoft/restbed/detail/service_impl.hpp
Normal file
230
lib/restbed-4.8/source/corvusoft/restbed/detail/service_impl.hpp
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <system_error>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
#include <asio/ip/tcp.hpp>
|
||||
#include <asio/signal_set.hpp>
|
||||
#include <asio/io_service.hpp>
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
#include <asio/ssl.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_IPC
|
||||
#include <asio/local/stream_protocol.hpp>
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Uri;
|
||||
class Rule;
|
||||
class Logger;
|
||||
class Session;
|
||||
class Resource;
|
||||
class Settings;
|
||||
class SessionManager;
|
||||
class SSLSettings;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
class WebSocketManagerImpl;
|
||||
|
||||
class ServiceImpl
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
ServiceImpl( void );
|
||||
|
||||
virtual ~ServiceImpl( void );
|
||||
|
||||
//Functionality
|
||||
void http_start( void );
|
||||
|
||||
void http_listen( void ) const;
|
||||
#ifdef BUILD_SSL
|
||||
void https_start( void );
|
||||
|
||||
void https_listen( void ) const;
|
||||
|
||||
void create_ssl_session( const std::shared_ptr< asio::ssl::stream< asio::ip::tcp::socket > >& socket, const std::error_code& error ) const;
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_IPC
|
||||
void ipc_start( void );
|
||||
|
||||
void ipc_listen( void ) const;
|
||||
|
||||
void create_ipc_session( const std::shared_ptr< asio::local::stream_protocol::socket >& socket, const std::error_code& error ) const;
|
||||
#endif
|
||||
|
||||
void setup_signal_handler( void );
|
||||
|
||||
void signal_handler( const std::error_code& error, const int signal_number ) const;
|
||||
|
||||
std::string sanitise_path( const std::string& path ) const;
|
||||
|
||||
void not_found( const std::shared_ptr< Session > session ) const;
|
||||
|
||||
bool has_unique_paths( const std::set< std::string >& paths ) const;
|
||||
|
||||
void log( const Logger::Level level, const std::string& message ) const;
|
||||
|
||||
void method_not_allowed( const std::shared_ptr< Session > session ) const;
|
||||
|
||||
void method_not_implemented( const std::shared_ptr< Session > session ) const;
|
||||
|
||||
void failed_filter_validation( const std::shared_ptr< Session > session ) const;
|
||||
|
||||
void router( const std::shared_ptr< Session > session ) const;
|
||||
|
||||
void create_session( const std::shared_ptr< asio::ip::tcp::socket >& socket, const std::error_code& error ) const;
|
||||
|
||||
void extract_path_parameters( const std::string& sanitised_path, const std::shared_ptr< const Request >& request ) const;
|
||||
|
||||
std::function< void ( const std::shared_ptr< Session > ) > find_method_handler( const std::shared_ptr< Session > session ) const;
|
||||
|
||||
void authenticate( const std::shared_ptr< Session > session ) const;
|
||||
|
||||
bool resource_router( const std::shared_ptr< Session > session, const std::pair< std::string, std::shared_ptr< const Resource > >& route ) const;
|
||||
|
||||
static void default_error_handler( const int status, const std::exception& error, const std::shared_ptr< Session > session );
|
||||
|
||||
static void discard_request( std::istream& stream );
|
||||
|
||||
static const std::map< std::string, std::string > parse_request_line( std::istream& stream );
|
||||
|
||||
static const std::multimap< std::string, std::string > parse_request_headers( std::istream& stream );
|
||||
|
||||
void parse_request( const std::error_code& error, std::size_t length, const std::shared_ptr< Session > session ) const;
|
||||
|
||||
//Getters
|
||||
const std::shared_ptr< const Uri > get_http_uri( void ) const;
|
||||
|
||||
const std::shared_ptr< const Uri > get_https_uri( void ) const;
|
||||
|
||||
const std::function< void ( const int, const std::exception&, const std::shared_ptr< Session > ) > get_error_handler( const std::shared_ptr< Session >& session ) const;
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
std::chrono::steady_clock::time_point m_uptime;
|
||||
|
||||
std::shared_ptr< Logger > m_logger;
|
||||
|
||||
std::set< std::string > m_supported_methods;
|
||||
|
||||
std::shared_ptr< const Settings > m_settings;
|
||||
|
||||
std::shared_ptr< asio::io_service > m_io_service;
|
||||
|
||||
std::shared_ptr< asio::signal_set > m_signal_set;
|
||||
|
||||
std::shared_ptr< SessionManager > m_session_manager;
|
||||
|
||||
std::shared_ptr< WebSocketManagerImpl > m_web_socket_manager;
|
||||
|
||||
std::vector< std::shared_ptr< Rule > > m_rules;
|
||||
|
||||
std::unique_ptr< std::future<void > > m_workers_stopped;
|
||||
#ifdef BUILD_SSL
|
||||
std::shared_ptr< const SSLSettings > m_ssl_settings;
|
||||
|
||||
std::shared_ptr< asio::ssl::context > m_ssl_context;
|
||||
|
||||
std::shared_ptr< asio::ip::tcp::acceptor > m_ssl_acceptor;
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_IPC
|
||||
std::shared_ptr< asio::local::stream_protocol::acceptor > m_ipc_acceptor;
|
||||
#endif
|
||||
std::shared_ptr< asio::ip::tcp::acceptor > m_acceptor;
|
||||
|
||||
std::map< std::string, std::string > m_resource_paths;
|
||||
|
||||
std::map< std::string, std::shared_ptr< const Resource > > m_resource_routes;
|
||||
|
||||
std::function< void ( void ) > m_ready_handler;
|
||||
|
||||
std::map< int, std::function< void ( const int ) > > m_signal_handlers;
|
||||
|
||||
std::function< void ( const std::shared_ptr< Session > ) > m_not_found_handler;
|
||||
|
||||
std::function< void ( const std::shared_ptr< Session > ) > m_method_not_allowed_handler;
|
||||
|
||||
std::function< void ( const std::shared_ptr< Session > ) > m_method_not_implemented_handler;
|
||||
|
||||
std::function< void ( const std::shared_ptr< Session > ) > m_failed_filter_validation_handler;
|
||||
|
||||
std::function< void ( const int, const std::exception&, const std::shared_ptr< Session > ) > m_error_handler;
|
||||
|
||||
std::function< void ( const std::shared_ptr< Session >, const std::function< void ( const std::shared_ptr< Session > ) >& ) > m_authentication_handler;
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
ServiceImpl( const ServiceImpl& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
ServiceImpl& operator =( const ServiceImpl& value ) = delete;
|
||||
|
||||
//Properties
|
||||
};
|
||||
}
|
||||
}
|
||||
212
lib/restbed-4.8/source/corvusoft/restbed/detail/session_impl.cpp
Normal file
212
lib/restbed-4.8/source/corvusoft/restbed/detail/session_impl.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <regex>
|
||||
#include <utility>
|
||||
#include <ciso646>
|
||||
#include <stdexcept>
|
||||
#include <system_error>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/uri.hpp"
|
||||
#include "corvusoft/restbed/http.hpp"
|
||||
#include "corvusoft/restbed/string.hpp"
|
||||
#include "corvusoft/restbed/session.hpp"
|
||||
#include "corvusoft/restbed/request.hpp"
|
||||
#include "corvusoft/restbed/response.hpp"
|
||||
#include "corvusoft/restbed/resource.hpp"
|
||||
#include "corvusoft/restbed/settings.hpp"
|
||||
#include "corvusoft/restbed/context_value.hpp"
|
||||
#include "corvusoft/restbed/session_manager.hpp"
|
||||
#include "corvusoft/restbed/detail/socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/request_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/session_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/resource_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::map;
|
||||
using std::set;
|
||||
using std::regex;
|
||||
using std::smatch;
|
||||
using std::string;
|
||||
using std::getline;
|
||||
using std::istream;
|
||||
using std::function;
|
||||
using std::multimap;
|
||||
using std::make_pair;
|
||||
using std::exception;
|
||||
using std::to_string;
|
||||
using std::ssub_match;
|
||||
using std::shared_ptr;
|
||||
using std::error_code;
|
||||
using std::make_shared;
|
||||
using std::regex_match;
|
||||
using std::regex_error;
|
||||
using std::runtime_error;
|
||||
using std::placeholders::_1;
|
||||
using std::rethrow_exception;
|
||||
using std::current_exception;
|
||||
using std::chrono::milliseconds;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::SessionImpl;
|
||||
|
||||
//External Namespaces
|
||||
using asio::buffer;
|
||||
using asio::streambuf;
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
SessionImpl::SessionImpl( void ) : m_id( String::empty ),
|
||||
m_request( nullptr ),
|
||||
m_resource( nullptr ),
|
||||
m_settings( nullptr ),
|
||||
m_manager( nullptr ),
|
||||
m_web_socket_manager( nullptr ),
|
||||
m_headers( ),
|
||||
m_context( ),
|
||||
m_error_handler( nullptr ),
|
||||
m_keep_alive_callback( nullptr ),
|
||||
m_error_handler_invoked( false )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SessionImpl::~SessionImpl( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void SessionImpl::fetch_body( const size_t length, const shared_ptr< Session > session, const function< void ( const shared_ptr< Session >, const Bytes& ) >& callback ) const
|
||||
{
|
||||
const auto data_ptr = asio::buffer_cast< const Byte* >( session->m_pimpl->m_request->m_pimpl->m_buffer->data( ) );
|
||||
const auto data = Bytes( data_ptr, data_ptr + length );
|
||||
session->m_pimpl->m_request->m_pimpl->m_buffer->consume( length );
|
||||
|
||||
auto& body = m_request->m_pimpl->m_body;
|
||||
|
||||
if ( body.empty( ) )
|
||||
{
|
||||
body = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
body.insert( body.end( ), data.begin( ), data.end( ) );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
callback(session, data);
|
||||
}
|
||||
catch ( const int status_code )
|
||||
{
|
||||
const auto error_handler = session->m_pimpl->get_error_handler();
|
||||
error_handler( status_code, runtime_error( m_settings->get_status_message( status_code ) ), session );
|
||||
}
|
||||
catch ( const regex_error& re )
|
||||
{
|
||||
const auto error_handler = session->m_pimpl->get_error_handler();
|
||||
error_handler( 500, re, session );
|
||||
}
|
||||
catch ( const runtime_error& re )
|
||||
{
|
||||
const auto error_handler = session->m_pimpl->get_error_handler();
|
||||
error_handler( 400, re, session );
|
||||
}
|
||||
catch ( const exception& ex )
|
||||
{
|
||||
const auto error_handler = session->m_pimpl->get_error_handler();
|
||||
error_handler( 500, ex, session );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
auto cex = current_exception( );
|
||||
|
||||
if ( cex not_eq nullptr )
|
||||
{
|
||||
try
|
||||
{
|
||||
rethrow_exception( cex );
|
||||
}
|
||||
catch ( const exception& ex )
|
||||
{
|
||||
const auto error_handler = session->m_pimpl->get_error_handler();
|
||||
error_handler( 500, ex, session );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
const auto error_handler = session->m_pimpl->get_error_handler();
|
||||
error_handler( 500, runtime_error( "Internal Server Error" ), session );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto error_handler = session->m_pimpl->get_error_handler();
|
||||
error_handler( 500, runtime_error( "Internal Server Error" ), session );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SessionImpl::transmit( const Response& response, const function< void ( const error_code&, size_t ) >& callback ) const
|
||||
{
|
||||
auto hdrs = m_settings->get_default_headers( );
|
||||
|
||||
if ( m_resource not_eq nullptr )
|
||||
{
|
||||
const auto m_resource_headers = m_resource->m_pimpl->m_default_headers;
|
||||
hdrs.insert( m_resource_headers.begin( ), m_resource_headers.end( ) );
|
||||
}
|
||||
|
||||
hdrs.insert( m_headers.begin( ), m_headers.end( ) );
|
||||
|
||||
auto response_headers = response.get_headers( );
|
||||
hdrs.insert( response_headers.begin( ), response_headers.end( ) );
|
||||
|
||||
auto payload = make_shared< Response >( );
|
||||
payload->set_headers( hdrs );
|
||||
payload->set_body( response.get_body( ) );
|
||||
payload->set_version( response.get_version( ) );
|
||||
payload->set_protocol( response.get_protocol( ) );
|
||||
payload->set_status_code( response.get_status_code( ) );
|
||||
payload->set_status_message( response.get_status_message( ) );
|
||||
|
||||
if ( payload->get_status_message( ).empty( ) )
|
||||
{
|
||||
payload->set_status_message( m_settings->get_status_message( payload->get_status_code( ) ) );
|
||||
}
|
||||
|
||||
m_request->m_pimpl->m_socket->start_write( Http::to_bytes( payload ), callback );
|
||||
}
|
||||
|
||||
const function< void ( const int, const exception&, const shared_ptr< Session > ) > SessionImpl::get_error_handler( void )
|
||||
{
|
||||
if ( m_error_handler_invoked )
|
||||
{
|
||||
return [ ]( const int, const exception&, const shared_ptr< Session > ) { };
|
||||
}
|
||||
|
||||
m_error_handler_invoked = true;
|
||||
|
||||
auto error_handler = ( m_resource not_eq nullptr and m_resource->m_pimpl->m_error_handler not_eq nullptr ) ? m_resource->m_pimpl->m_error_handler : m_error_handler;
|
||||
|
||||
if ( error_handler == nullptr )
|
||||
{
|
||||
return [ ]( const int, const exception&, const shared_ptr< Session > session )
|
||||
{
|
||||
if ( session not_eq nullptr and session->is_open( ) )
|
||||
{
|
||||
session->close( );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return error_handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
125
lib/restbed-4.8/source/corvusoft/restbed/detail/session_impl.hpp
Normal file
125
lib/restbed-4.8/source/corvusoft/restbed/detail/session_impl.hpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <istream>
|
||||
#include <functional>
|
||||
#include <system_error>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/byte.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Session;
|
||||
class Request;
|
||||
class Response;
|
||||
class Resource;
|
||||
class Settings;
|
||||
class SessionManager;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
class WebSocketManagerImpl;
|
||||
|
||||
class SessionImpl
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
SessionImpl( void );
|
||||
|
||||
SessionImpl( const SessionImpl& original ) = delete;
|
||||
|
||||
virtual ~SessionImpl( void );
|
||||
|
||||
//Functionality
|
||||
void fetch_body( const std::size_t length, const std::shared_ptr< Session > session, const std::function< void ( const std::shared_ptr< Session >, const Bytes& ) >& callback ) const;
|
||||
|
||||
void transmit( const Response& response, const std::function< void ( const std::error_code&, std::size_t ) >& callback ) const;
|
||||
|
||||
//Getters
|
||||
const std::function< void ( const int, const std::exception&, const std::shared_ptr< Session > ) > get_error_handler( void );
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
SessionImpl& operator =( const SessionImpl& value ) = delete;
|
||||
|
||||
//Properties
|
||||
std::string m_id;
|
||||
|
||||
std::shared_ptr< const Request > m_request;
|
||||
|
||||
std::shared_ptr< const Resource > m_resource;
|
||||
|
||||
std::shared_ptr< const Settings > m_settings;
|
||||
|
||||
std::shared_ptr< SessionManager > m_manager;
|
||||
|
||||
std::shared_ptr< WebSocketManagerImpl > m_web_socket_manager;
|
||||
|
||||
std::multimap< std::string, std::string > m_headers;
|
||||
|
||||
std::map< std::string, const ContextValue > m_context;
|
||||
|
||||
std::function< void ( const int, const std::exception&, const std::shared_ptr< Session > ) > m_error_handler;
|
||||
|
||||
std::function< void ( const std::error_code& error, std::size_t length, const std::shared_ptr< Session > ) > m_keep_alive_callback;
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
bool m_error_handler_invoked;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class SSLSettings;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
struct SettingsImpl
|
||||
{
|
||||
uint16_t m_port = 80;
|
||||
|
||||
std::string m_root = "/";
|
||||
|
||||
bool m_reuse_address = true;
|
||||
|
||||
unsigned int m_worker_limit = 0;
|
||||
|
||||
unsigned int m_connection_limit = 128;
|
||||
|
||||
std::string m_bind_address = "";
|
||||
|
||||
bool m_case_insensitive_uris = true;
|
||||
|
||||
bool m_keep_alive = true;
|
||||
|
||||
uint32_t m_keep_alive_start = 900;
|
||||
|
||||
uint32_t m_keep_alive_interval = 900;
|
||||
|
||||
uint32_t m_keep_alive_cnt = 3;
|
||||
|
||||
std::map< std::string, std::string > m_properties { };
|
||||
|
||||
std::shared_ptr< const SSLSettings > m_ssl_settings = nullptr;
|
||||
|
||||
std::multimap< std::string, std::string > m_default_headers { };
|
||||
|
||||
std::chrono::milliseconds m_connection_timeout = std::chrono::milliseconds( 5000 );
|
||||
|
||||
std::map< int, std::string > m_status_messages
|
||||
{
|
||||
{ 100, "Continue" },
|
||||
{ 101, "Switching Protocols" },
|
||||
{ 102, "Processing" },
|
||||
{ 200, "OK" },
|
||||
{ 201, "Created" },
|
||||
{ 202, "Accepted" },
|
||||
{ 203, "Non-Authoritative Information" },
|
||||
{ 204, "No Content" },
|
||||
{ 205, "Reset Content" },
|
||||
{ 206, "Partial Content" },
|
||||
{ 207, "Multi-Status" },
|
||||
{ 208, "Already Reported" },
|
||||
{ 226, "IM Used" },
|
||||
{ 300, "Multiple Choices" },
|
||||
{ 301, "Moved Permanently" },
|
||||
{ 302, "Found" },
|
||||
{ 303, "See Other" },
|
||||
{ 304, "Not Modified" },
|
||||
{ 305, "Use Proxy" },
|
||||
{ 306, "Reserved" },
|
||||
{ 307, "Temporary Redirect" },
|
||||
{ 308, "Permanent Redirect" },
|
||||
{ 400, "Bad Request" },
|
||||
{ 401, "Unauthorized" },
|
||||
{ 402, "Payment Required" },
|
||||
{ 403, "Forbidden" },
|
||||
{ 404, "Not Found" },
|
||||
{ 405, "Method Not Allowed" },
|
||||
{ 406, "Not Acceptable" },
|
||||
{ 407, "Proxy Authentication Required" },
|
||||
{ 408, "Request Timeout" },
|
||||
{ 409, "Conflict" },
|
||||
{ 410, "Gone" },
|
||||
{ 411, "Length Required" },
|
||||
{ 412, "Precondition Failed" },
|
||||
{ 413, "Request Entity Too Large" },
|
||||
{ 414, "Request URI Too Long" },
|
||||
{ 415, "Unsupported Media Type" },
|
||||
{ 416, "Requested Range Not Satisfiable" },
|
||||
{ 417, "Expectation Failed" },
|
||||
{ 422, "Unprocessable Entity" },
|
||||
{ 423, "Locked" },
|
||||
{ 424, "Failed Dependency" },
|
||||
{ 426, "Upgrade Required" },
|
||||
{ 428, "Precondition Required" },
|
||||
{ 429, "Too Many Requests" },
|
||||
{ 431, "Request Header Fields Too Large" },
|
||||
{ 500, "Internal Server Error" },
|
||||
{ 501, "Not Implemented" },
|
||||
{ 502, "Bad Gateway" },
|
||||
{ 503, "Service Unavailable" },
|
||||
{ 504, "Gateway Timeout" },
|
||||
{ 505, "HTTP Version Not Supported" },
|
||||
{ 506, "Variant Also Negotiates" },
|
||||
{ 507, "Insufficient Storage" },
|
||||
{ 508, "Loop Detected" },
|
||||
{ 510, "Not Extended" },
|
||||
{ 511, "Network Authentication Required" }
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
728
lib/restbed-4.8/source/corvusoft/restbed/detail/socket_impl.cpp
Normal file
728
lib/restbed-4.8/source/corvusoft/restbed/detail/socket_impl.cpp
Normal file
@@ -0,0 +1,728 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <future>
|
||||
#include <ciso646>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/logger.hpp"
|
||||
#include "corvusoft/restbed/detail/socket_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
#include <asio/read.hpp>
|
||||
#include <asio/write.hpp>
|
||||
#include <asio/connect.hpp>
|
||||
#include <asio/read_until.hpp>
|
||||
|
||||
|
||||
//System Namespaces
|
||||
using std::get;
|
||||
using std::bind;
|
||||
using std::size_t;
|
||||
using std::string;
|
||||
using std::promise;
|
||||
using std::function;
|
||||
using std::to_string;
|
||||
using std::error_code;
|
||||
using std::shared_ptr;
|
||||
using std::make_shared;
|
||||
using std::runtime_error;
|
||||
using std::placeholders::_1;
|
||||
using std::chrono::milliseconds;
|
||||
using std::chrono::steady_clock;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::SocketImpl;
|
||||
|
||||
//External Namespaces
|
||||
using asio::ip::tcp;
|
||||
using asio::io_service;
|
||||
using asio::steady_timer;
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
using asio::ssl::stream;
|
||||
#endif
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
SocketImpl::SocketImpl( asio::io_context& context, const shared_ptr< tcp::socket >& socket, const shared_ptr< Logger >& logger ) : m_error_handler( nullptr ),
|
||||
m_is_open( socket->is_open( ) ),
|
||||
m_pending_writes( ),
|
||||
m_logger( logger ),
|
||||
m_timeout( 0 ),
|
||||
m_io_service( context ),
|
||||
m_timer( make_shared< asio::steady_timer >( m_io_service ) ),
|
||||
m_strand( make_shared< io_service::strand > ( m_io_service ) ),
|
||||
m_resolver( nullptr ),
|
||||
m_socket( socket )
|
||||
#ifdef BUILD_SSL
|
||||
, m_ssl_socket( nullptr )
|
||||
#endif
|
||||
{
|
||||
return;
|
||||
}
|
||||
#ifdef BUILD_SSL
|
||||
SocketImpl::SocketImpl( asio::io_context& context, const shared_ptr< asio::ssl::stream< tcp::socket > >& socket, const shared_ptr< Logger >& logger ) : m_error_handler( nullptr ),
|
||||
m_is_open( socket->lowest_layer( ).is_open( ) ),
|
||||
m_pending_writes( ),
|
||||
m_logger( logger ),
|
||||
m_timeout( 0 ),
|
||||
m_io_service( context ),
|
||||
m_timer( make_shared< asio::steady_timer >( m_io_service ) ),
|
||||
m_strand( make_shared< io_service::strand > ( m_io_service ) ),
|
||||
m_resolver( nullptr ),
|
||||
m_socket( nullptr ),
|
||||
m_ssl_socket( socket )
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
void SocketImpl::close( void )
|
||||
{
|
||||
m_is_open = false;
|
||||
|
||||
if ( m_timer not_eq nullptr )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
}
|
||||
|
||||
if ( m_socket not_eq nullptr )
|
||||
{
|
||||
m_socket->close( );
|
||||
}
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
|
||||
if ( m_ssl_socket not_eq nullptr )
|
||||
{
|
||||
m_ssl_socket->lowest_layer( ).close( );
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SocketImpl::is_open( void ) const
|
||||
{
|
||||
return m_is_open;
|
||||
}
|
||||
|
||||
bool SocketImpl::is_closed( void ) const
|
||||
{
|
||||
return not m_is_open;
|
||||
}
|
||||
|
||||
void SocketImpl::connect( const string& hostname, const uint16_t port, const function< void ( const error_code& ) >& callback )
|
||||
{
|
||||
m_resolver = make_shared< tcp::resolver >( m_io_service );
|
||||
tcp::resolver::query query( hostname, ::to_string( port ) );
|
||||
|
||||
m_resolver->async_resolve( query, [ this, callback ]( const error_code & error, tcp::resolver::iterator endpoint_iterator )
|
||||
{
|
||||
if ( not error )
|
||||
{
|
||||
#ifdef BUILD_SSL
|
||||
auto& socket = ( m_socket not_eq nullptr ) ? *m_socket : m_ssl_socket->lowest_layer( );
|
||||
#else
|
||||
auto& socket = *m_socket;
|
||||
#endif
|
||||
asio::async_connect( socket, endpoint_iterator, [ this, callback ]( const error_code & error, tcp::resolver::iterator )
|
||||
{
|
||||
#ifdef BUILD_SSL
|
||||
|
||||
if ( m_ssl_socket not_eq nullptr )
|
||||
{
|
||||
m_ssl_socket->handshake( asio::ssl::stream_base::client );
|
||||
}
|
||||
|
||||
#endif
|
||||
m_is_open = true;
|
||||
callback( error );
|
||||
} );
|
||||
}
|
||||
else
|
||||
{
|
||||
callback( error );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
void SocketImpl::sleep_for( const milliseconds& delay, const function< void ( const error_code& ) >& callback )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( delay );
|
||||
m_timer->async_wait( callback );
|
||||
}
|
||||
|
||||
void SocketImpl::start_write(const Bytes& data, const std::function< void ( const std::error_code&, std::size_t ) >& callback)
|
||||
{
|
||||
m_strand->post([this, data, callback] { write_helper(data, callback); });
|
||||
}
|
||||
|
||||
size_t SocketImpl::start_read(const shared_ptr< asio::streambuf >& data, const string& delimiter, error_code& error)
|
||||
{
|
||||
return read( data, delimiter,error );
|
||||
}
|
||||
|
||||
size_t SocketImpl::start_read(const shared_ptr< asio::streambuf >& data, const size_t length, error_code& error)
|
||||
{
|
||||
return read( data, length, error );
|
||||
}
|
||||
|
||||
void SocketImpl::start_read( const std::size_t length, const function< void ( const Bytes ) > success, const function< void ( const error_code ) > failure )
|
||||
{
|
||||
m_strand->post([this, length, success, failure] {
|
||||
read(length, success, failure);
|
||||
});
|
||||
}
|
||||
|
||||
void SocketImpl::start_read(const shared_ptr< asio::streambuf >& data, const size_t length, const function< void ( const error_code&, size_t ) >& callback)
|
||||
{
|
||||
m_strand->post([this, data, length, callback]
|
||||
{
|
||||
read(data, length, callback);
|
||||
});
|
||||
}
|
||||
|
||||
void SocketImpl::start_read(const shared_ptr< asio::streambuf >& data, const string& delimiter, const function< void ( const error_code&, size_t ) >& callback)
|
||||
{
|
||||
m_strand->post([this, data, delimiter, callback]
|
||||
{
|
||||
read(data, delimiter, callback);
|
||||
});
|
||||
}
|
||||
|
||||
string SocketImpl::get_local_endpoint( void )
|
||||
{
|
||||
error_code error;
|
||||
tcp::endpoint endpoint;
|
||||
#ifdef BUILD_SSL
|
||||
|
||||
if ( m_socket not_eq nullptr )
|
||||
{
|
||||
#endif
|
||||
endpoint = m_socket->local_endpoint( error );
|
||||
#ifdef BUILD_SSL
|
||||
}
|
||||
else
|
||||
{
|
||||
endpoint = m_ssl_socket->lowest_layer( ).local_endpoint( error );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
auto address = endpoint.address( );
|
||||
auto local = address.is_v4( ) ? address.to_string( ) + ":" : "[" + address.to_string( ) + "]:";
|
||||
local += ::to_string( endpoint.port( ) );
|
||||
|
||||
return local;
|
||||
}
|
||||
|
||||
string SocketImpl::get_remote_endpoint( void )
|
||||
{
|
||||
error_code error;
|
||||
tcp::endpoint endpoint;
|
||||
#ifdef BUILD_SSL
|
||||
|
||||
if ( m_socket not_eq nullptr )
|
||||
{
|
||||
#endif
|
||||
endpoint = m_socket->remote_endpoint( error );
|
||||
#ifdef BUILD_SSL
|
||||
}
|
||||
else
|
||||
{
|
||||
endpoint = m_ssl_socket->lowest_layer( ).remote_endpoint( error );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
auto address = endpoint.address( );
|
||||
auto remote = address.is_v4( ) ? address.to_string( ) + ":" : "[" + address.to_string( ) + "]:";
|
||||
remote += ::to_string( endpoint.port( ) );
|
||||
|
||||
return remote;
|
||||
}
|
||||
|
||||
void SocketImpl::set_timeout( const milliseconds& value )
|
||||
{
|
||||
m_timeout = value;
|
||||
}
|
||||
|
||||
void SocketImpl::set_keep_alive( const uint32_t start, const uint32_t interval, const uint32_t cnt)
|
||||
{
|
||||
(void) cnt;
|
||||
(void) start;
|
||||
(void) interval;
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
auto& socket = ( m_socket not_eq nullptr ) ? *m_socket : m_ssl_socket->lowest_layer( );
|
||||
#else
|
||||
auto& socket = *m_socket;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string val = "1";
|
||||
setsockopt(socket.native_handle(), SOL_SOCKET, SO_KEEPALIVE, val.c_str(), sizeof(val));
|
||||
|
||||
// TCP_KEEPIDLE and TCP_KEEPINTVL are available since Win 10 version 1709
|
||||
// TCP_KEEPCNT since Win 10 version 1703
|
||||
#ifdef TCP_KEEPIDLE
|
||||
std::string start_str = std::to_string(start);
|
||||
setsockopt(socket.native_handle(), IPPROTO_TCP, TCP_KEEPIDLE,
|
||||
start_str.c_str(), sizeof(start_str));
|
||||
#endif
|
||||
#ifdef TCP_KEEPINTVL
|
||||
std::string interval_str = std::to_string(interval);
|
||||
setsockopt(socket.native_handle(), IPPROTO_TCP, TCP_KEEPINTVL,
|
||||
interval_str.c_str(), sizeof(interval_str));
|
||||
#endif
|
||||
#ifdef TCP_KEEPCNT
|
||||
std::string cnt_str = std::to_string(cnt);
|
||||
setsockopt(socket.native_handle(), IPPROTO_TCP, TCP_KEEPCNT,
|
||||
cnt_str.c_str(), sizeof(cnt_str));
|
||||
#endif
|
||||
#else
|
||||
uint32_t val = 1;
|
||||
setsockopt(socket.native_handle(), SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(uint32_t));
|
||||
#ifdef __APPLE__
|
||||
setsockopt(socket.native_handle(), IPPROTO_TCP, TCP_KEEPALIVE, &start, sizeof(uint32_t));
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
setsockopt(socket.native_handle(), IPPROTO_TCP, SO_KEEPALIVE, &start, sizeof(uint32_t));
|
||||
#else
|
||||
// Linux based systems
|
||||
setsockopt(socket.native_handle(), SOL_TCP, TCP_KEEPIDLE, &start, sizeof(uint32_t));
|
||||
setsockopt(socket.native_handle(), SOL_TCP, TCP_KEEPINTVL, &interval, sizeof(uint32_t));
|
||||
setsockopt(socket.native_handle(), SOL_TCP, TCP_KEEPCNT, &cnt, sizeof(uint32_t));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
SocketImpl::SocketImpl( asio::io_context& context ) : m_error_handler( nullptr ),
|
||||
m_is_open( false ),
|
||||
m_pending_writes( ),
|
||||
m_logger( nullptr ),
|
||||
m_timeout( 0 ),
|
||||
m_io_service( context ),
|
||||
m_timer( make_shared< asio::steady_timer >( m_io_service ) ),
|
||||
m_strand( make_shared< io_service::strand > ( m_io_service ) ),
|
||||
m_resolver( nullptr ),
|
||||
m_socket( nullptr )
|
||||
#ifdef BUILD_SSL
|
||||
, m_ssl_socket( nullptr )
|
||||
#endif
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void SocketImpl::connection_timeout_handler( const shared_ptr< SocketImpl > socket, const error_code& error )
|
||||
{
|
||||
if ( error or socket == nullptr or socket->m_timer->expires_at( ) > steady_clock::now( ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
socket->close( );
|
||||
|
||||
if ( m_error_handler not_eq nullptr )
|
||||
{
|
||||
m_error_handler( 408, runtime_error( "The socket timed out waiting for the request." ), nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
void SocketImpl::write( void )
|
||||
{
|
||||
if(m_is_open)
|
||||
{
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( m_timeout );
|
||||
m_timer->async_wait( m_strand->wrap( bind( &SocketImpl::connection_timeout_handler, this, shared_from_this( ), _1 ) ) );
|
||||
#ifdef BUILD_SSL
|
||||
if ( m_socket not_eq nullptr )
|
||||
{
|
||||
#endif
|
||||
asio::async_write( *m_socket, asio::buffer( get<0>(m_pending_writes.front()).data( ), get<0>(m_pending_writes.front()).size( ) ), m_strand->wrap( [ this ]( const error_code & error, size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
auto callback = get<2>(m_pending_writes.front());
|
||||
auto & retries = get<1>(m_pending_writes.front());
|
||||
auto & buffer = get<0>(m_pending_writes.front());
|
||||
if(length < buffer.size() && retries < MAX_WRITE_RETRIES && error not_eq asio::error::operation_aborted)
|
||||
{
|
||||
++retries;
|
||||
buffer.erase(buffer.begin(),buffer.begin() + length);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pending_writes.pop();
|
||||
}
|
||||
if ( error not_eq asio::error::operation_aborted )
|
||||
{
|
||||
callback( error, length );
|
||||
}
|
||||
if(!m_pending_writes.empty())
|
||||
{
|
||||
write();
|
||||
}
|
||||
} ) );
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
}
|
||||
else
|
||||
{
|
||||
asio::async_write(*m_ssl_socket, asio::buffer( get<0>(m_pending_writes.front()).data( ), get<0>(m_pending_writes.front()).size( ) ), m_strand->wrap( [ this ]( const error_code & error, size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
auto callback = get<2>(m_pending_writes.front());
|
||||
auto & retries = get<1>(m_pending_writes.front());
|
||||
auto & buffer = get<0>(m_pending_writes.front());
|
||||
if(length < buffer.size() && retries < MAX_WRITE_RETRIES && error not_eq asio::error::operation_aborted)
|
||||
{
|
||||
++retries;
|
||||
buffer.erase(buffer.begin(),buffer.begin() + length);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pending_writes.pop();
|
||||
}
|
||||
if ( error not_eq asio::error::operation_aborted )
|
||||
{
|
||||
callback( error, length );
|
||||
}
|
||||
if(!m_pending_writes.empty())
|
||||
{
|
||||
write();
|
||||
}
|
||||
} ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
while(!m_pending_writes.empty())
|
||||
{
|
||||
m_pending_writes.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SocketImpl::write( const Bytes& data, const function< void ( const error_code&, size_t ) >& callback )
|
||||
{
|
||||
const auto buffer = make_shared< Bytes >( data );
|
||||
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( m_timeout );
|
||||
m_timer->async_wait( m_strand->wrap( bind( &SocketImpl::connection_timeout_handler, this, shared_from_this( ), _1 ) ) );
|
||||
#ifdef BUILD_SSL
|
||||
|
||||
if ( m_socket not_eq nullptr )
|
||||
{
|
||||
#endif
|
||||
asio::async_write( *m_socket, asio::buffer( buffer->data( ), buffer->size( ) ), m_strand->wrap( [ this, callback, buffer ]( const error_code & error, size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
if ( error not_eq asio::error::operation_aborted )
|
||||
{
|
||||
callback( error, length );
|
||||
}
|
||||
} ) );
|
||||
#ifdef BUILD_SSL
|
||||
}
|
||||
else
|
||||
{
|
||||
asio::async_write( *m_ssl_socket, asio::buffer( buffer->data( ), buffer->size( ) ), m_strand->wrap( [ this, callback, buffer ]( const error_code & error, size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
if ( error not_eq asio::error::operation_aborted )
|
||||
{
|
||||
callback( error, length );
|
||||
}
|
||||
} ) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SocketImpl::write_helper(const Bytes& data, const function< void ( const error_code&, size_t ) >& callback)
|
||||
{
|
||||
const uint8_t retries = 0;
|
||||
m_pending_writes.push(make_tuple(data, retries, callback));
|
||||
if(m_pending_writes.size() == 1)
|
||||
{
|
||||
write();
|
||||
}
|
||||
}
|
||||
|
||||
size_t SocketImpl::read( const shared_ptr< asio::streambuf >& data, const size_t length, error_code& error )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( m_timeout );
|
||||
m_timer->async_wait( m_strand->wrap( bind( &SocketImpl::connection_timeout_handler, this, shared_from_this( ), _1 ) ) );
|
||||
|
||||
size_t size = 0;
|
||||
auto finished = std::make_shared<bool>(false);
|
||||
auto sharedError = std::make_shared<error_code>();
|
||||
auto sharedSize = std::make_shared<size_t>(0);
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
|
||||
if ( m_socket not_eq nullptr )
|
||||
{
|
||||
#endif
|
||||
asio::async_read( *m_socket, *data, asio::transfer_at_least( length ),
|
||||
[ finished, sharedSize, sharedError ]( const error_code & error, size_t size ) {
|
||||
*sharedError = error;
|
||||
*sharedSize = size;
|
||||
*finished = true;
|
||||
});
|
||||
#ifdef BUILD_SSL
|
||||
}
|
||||
else
|
||||
{
|
||||
asio::async_read( *m_ssl_socket, *data, asio::transfer_at_least( length ),
|
||||
[ finished, sharedSize, sharedError ]( const error_code & error, size_t size ) {
|
||||
*sharedError = error;
|
||||
*sharedSize = size;
|
||||
*finished = true;
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
while (!*finished)
|
||||
m_io_service.run_one();
|
||||
error = *sharedError;
|
||||
size = *sharedSize;
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void SocketImpl::read( const std::size_t length, const function< void ( const Bytes ) > success, const function< void ( const error_code ) > failure )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( m_timeout );
|
||||
m_timer->async_wait( m_strand->wrap( bind( &SocketImpl::connection_timeout_handler, this, shared_from_this( ), _1 ) ) );
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
|
||||
if ( m_socket not_eq nullptr )
|
||||
{
|
||||
#endif
|
||||
auto data = make_shared< asio::streambuf >( );
|
||||
asio::async_read( *m_socket, *data, asio::transfer_exactly( length ), [ this, data, success, failure ]( const error_code code, const size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( code )
|
||||
{
|
||||
m_is_open = false;
|
||||
failure( code );
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto data_ptr = asio::buffer_cast< const Byte* >( data->data( ) );
|
||||
success( Bytes( data_ptr, data_ptr + length ) );
|
||||
}
|
||||
} );
|
||||
#ifdef BUILD_SSL
|
||||
}
|
||||
else
|
||||
{
|
||||
auto data = make_shared< asio::streambuf >( );
|
||||
asio::async_read( *m_ssl_socket, *data, asio::transfer_exactly( length ), [ this, data, success, failure ]( const error_code code, const size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( code )
|
||||
{
|
||||
m_is_open = false;
|
||||
failure( code );
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto data_ptr = asio::buffer_cast< const Byte* >( data->data( ) );
|
||||
success( Bytes( data_ptr, data_ptr + length ) );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void SocketImpl::read( const shared_ptr< asio::streambuf >& data, const size_t length, const function< void ( const error_code&, size_t ) >& callback )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( m_timeout );
|
||||
m_timer->async_wait( m_strand->wrap( bind( &SocketImpl::connection_timeout_handler, this, shared_from_this( ), _1 ) ) );
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
|
||||
if ( m_socket not_eq nullptr )
|
||||
{
|
||||
#endif
|
||||
asio::async_read( *m_socket, *data, asio::transfer_at_least( length ), m_strand->wrap( [ this, callback ]( const error_code & error, size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
if ( error not_eq asio::error::operation_aborted )
|
||||
{
|
||||
callback( error, length );
|
||||
}
|
||||
} ) );
|
||||
#ifdef BUILD_SSL
|
||||
}
|
||||
else
|
||||
{
|
||||
asio::async_read( *m_ssl_socket, *data, asio::transfer_at_least( length ), m_strand->wrap( [ this, callback ]( const error_code & error, size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
if ( error not_eq asio::error::operation_aborted )
|
||||
{
|
||||
callback( error, length );
|
||||
}
|
||||
} ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t SocketImpl::read( const shared_ptr< asio::streambuf >& data, const string& delimiter, error_code& error )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( m_timeout );
|
||||
m_timer->async_wait( bind( &SocketImpl::connection_timeout_handler, this, shared_from_this( ), _1 ) );
|
||||
|
||||
size_t length = 0;
|
||||
auto finished = std::make_shared<bool>(false);
|
||||
auto sharedError = std::make_shared<error_code>();
|
||||
auto sharedLength = std::make_shared<size_t>(0);
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
|
||||
if ( m_socket not_eq nullptr )
|
||||
{
|
||||
#endif
|
||||
asio::async_read_until( *m_socket, *data, delimiter,
|
||||
[ finished, sharedLength, sharedError ]( const error_code & error, size_t length ) {
|
||||
*sharedError = error;
|
||||
*sharedLength = length;
|
||||
*finished = true;
|
||||
});
|
||||
#ifdef BUILD_SSL
|
||||
}
|
||||
else
|
||||
{
|
||||
asio::async_read_until( *m_ssl_socket, *data, delimiter,
|
||||
[ finished, sharedLength, sharedError ]( const error_code & error, size_t length ) {
|
||||
*sharedError = error;
|
||||
*sharedLength = length;
|
||||
*finished = true;
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
while (!*finished)
|
||||
m_io_service.run_one();
|
||||
error = *sharedError;
|
||||
length = *sharedLength;
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
void SocketImpl::read( const shared_ptr< asio::streambuf >& data, const string& delimiter, const function< void ( const error_code&, size_t ) >& callback )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
m_timer->expires_from_now( m_timeout );
|
||||
m_timer->async_wait( m_strand->wrap( bind( &SocketImpl::connection_timeout_handler, this, shared_from_this( ), _1 ) ) );
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
|
||||
if ( m_socket not_eq nullptr )
|
||||
{
|
||||
#endif
|
||||
asio::async_read_until( *m_socket, *data, delimiter, m_strand->wrap( [ this, callback ]( const error_code & error, size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
if ( error not_eq asio::error::operation_aborted )
|
||||
{
|
||||
callback( error, length );
|
||||
}
|
||||
} ) );
|
||||
#ifdef BUILD_SSL
|
||||
}
|
||||
else
|
||||
{
|
||||
asio::async_read_until( *m_ssl_socket, *data, delimiter, m_strand->wrap( [ this, callback ]( const error_code & error, size_t length )
|
||||
{
|
||||
m_timer->cancel( );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
if ( error not_eq asio::error::operation_aborted )
|
||||
{
|
||||
callback( error, length );
|
||||
}
|
||||
} ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
178
lib/restbed-4.8/source/corvusoft/restbed/detail/socket_impl.hpp
Normal file
178
lib/restbed-4.8/source/corvusoft/restbed/detail/socket_impl.hpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <queue>
|
||||
#include <tuple>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <system_error>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/byte.hpp"
|
||||
|
||||
//External Includes
|
||||
#include <asio/ip/tcp.hpp>
|
||||
#include <asio/streambuf.hpp>
|
||||
#include <asio/steady_timer.hpp>
|
||||
#include <asio/io_service.hpp>
|
||||
#include <asio/io_service_strand.hpp>
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
#include <asio/ssl.hpp>
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Logger;
|
||||
class Session;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
class SocketImpl : public std::enable_shared_from_this<SocketImpl>
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
SocketImpl( asio::io_context& context, const std::shared_ptr< asio::ip::tcp::socket >& socket, const std::shared_ptr< Logger >& logger = nullptr );
|
||||
#ifdef BUILD_SSL
|
||||
SocketImpl( asio::io_context& context, const std::shared_ptr< asio::ssl::stream< asio::ip::tcp::socket > >& socket, const std::shared_ptr< Logger >& logger = nullptr );
|
||||
#endif
|
||||
~SocketImpl( void ) = default;
|
||||
|
||||
//Functionality
|
||||
virtual void close( void );
|
||||
|
||||
virtual bool is_open( void ) const;
|
||||
|
||||
virtual bool is_closed( void ) const;
|
||||
|
||||
virtual void connect( const std::string& hostname, const uint16_t port, const std::function< void ( const std::error_code& ) >& callback );
|
||||
|
||||
virtual void sleep_for( const std::chrono::milliseconds& delay, const std::function< void ( const std::error_code& ) >& callback );
|
||||
|
||||
virtual void start_write(const Bytes& data, const std::function< void ( const std::error_code&, std::size_t ) >& callback);
|
||||
|
||||
virtual size_t start_read( const std::shared_ptr< asio::streambuf >& data, const std::string& delimiter, std::error_code& error );
|
||||
|
||||
virtual size_t start_read( const std::shared_ptr< asio::streambuf >& data, const std::size_t length, std::error_code& error );
|
||||
|
||||
virtual void start_read(const std::size_t length, const std::function< void ( const Bytes ) > success, const std::function< void ( const std::error_code ) > failure );
|
||||
|
||||
virtual void start_read( const std::shared_ptr< asio::streambuf >& data, const std::size_t length, const std::function< void ( const std::error_code&, std::size_t ) >& callback );
|
||||
|
||||
virtual void start_read(const std::shared_ptr< asio::streambuf >& data, const std::string& delimiter, const std::function< void ( const std::error_code&, std::size_t ) >& callback );
|
||||
|
||||
//Getters
|
||||
virtual std::string get_local_endpoint( void );
|
||||
|
||||
virtual std::string get_remote_endpoint( void );
|
||||
|
||||
//Setters
|
||||
virtual void set_timeout( const std::chrono::milliseconds& value );
|
||||
|
||||
virtual void set_keep_alive( const uint32_t start, const uint32_t interval, const uint32_t cnt);
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
std::function< void ( const int, const std::exception&, const std::shared_ptr< Session > ) > m_error_handler;
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
SocketImpl( asio::io_context& context );
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
SocketImpl( const SocketImpl& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
void connection_timeout_handler( const std::shared_ptr< SocketImpl > socket, const std::error_code& error );
|
||||
|
||||
void write( void );
|
||||
|
||||
void write( const Bytes& data, const std::function< void ( const std::error_code&, std::size_t ) >& callback );
|
||||
|
||||
void write_helper( const Bytes& data, const std::function< void ( const std::error_code&, std::size_t ) >& callback );
|
||||
|
||||
size_t read( const std::shared_ptr< asio::streambuf >& data, const std::size_t length, std::error_code& error );
|
||||
|
||||
void read( const std::size_t length, const std::function< void ( const Bytes ) > success, const std::function< void ( const std::error_code ) > failure );
|
||||
|
||||
void read( const std::shared_ptr< asio::streambuf >& data, const std::size_t length, const std::function< void ( const std::error_code&, std::size_t ) >& callback );
|
||||
|
||||
size_t read( const std::shared_ptr< asio::streambuf >& data, const std::string& delimiter, std::error_code& error );
|
||||
|
||||
void read( const std::shared_ptr< asio::streambuf >& data, const std::string& delimiter, const std::function< void ( const std::error_code&, std::size_t ) >& callback );
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
SocketImpl& operator =( const SocketImpl& value ) = delete;
|
||||
|
||||
//Properties
|
||||
bool m_is_open;
|
||||
|
||||
const uint8_t MAX_WRITE_RETRIES = 5;
|
||||
|
||||
std::queue< std::tuple< Bytes, uint8_t, std::function< void ( const std::error_code&, std::size_t ) > > > m_pending_writes;
|
||||
|
||||
std::shared_ptr< Logger > m_logger;
|
||||
|
||||
std::chrono::milliseconds m_timeout;
|
||||
|
||||
asio::io_context &m_io_service;
|
||||
|
||||
std::shared_ptr< asio::steady_timer > m_timer;
|
||||
|
||||
std::shared_ptr< asio::io_service::strand > m_strand;
|
||||
|
||||
std::shared_ptr< asio::ip::tcp::resolver > m_resolver;
|
||||
|
||||
std::shared_ptr< asio::ip::tcp::socket > m_socket;
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
std::shared_ptr< asio::ssl::stream< asio::ip::tcp::socket > > m_ssl_socket;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
struct SSLSettingsImpl
|
||||
{
|
||||
uint16_t m_port = 443;
|
||||
|
||||
bool m_http_disabled = false;
|
||||
|
||||
bool m_sslv2_enabled = true;
|
||||
|
||||
bool m_sslv3_enabled = true;
|
||||
|
||||
bool m_tlsv1_enabled = true;
|
||||
|
||||
bool m_tlsv11_enabled = true;
|
||||
|
||||
bool m_tlsv12_enabled = true;
|
||||
|
||||
bool m_compression_enabled = true;
|
||||
|
||||
bool m_default_workarounds_enabled = true;
|
||||
|
||||
bool m_single_diffie_hellman_use_enabled = true;
|
||||
|
||||
std::string m_bind_address = "";
|
||||
|
||||
std::string m_passphrase = "";
|
||||
|
||||
std::string m_private_key = "";
|
||||
|
||||
std::string m_private_rsa_key = "";
|
||||
|
||||
std::string m_certificate = "";
|
||||
|
||||
std::string m_certificate_chain = "";
|
||||
|
||||
std::string m_certificate_authority_pool = "";
|
||||
|
||||
std::string m_temporary_diffie_hellman = "";
|
||||
};
|
||||
}
|
||||
}
|
||||
35
lib/restbed-4.8/source/corvusoft/restbed/detail/uri_impl.hpp
Normal file
35
lib/restbed-4.8/source/corvusoft/restbed/detail/uri_impl.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <string>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
struct UriImpl
|
||||
{
|
||||
std::string m_uri = "";
|
||||
|
||||
bool m_relative = false;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <ciso646>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/web_socket.hpp"
|
||||
#include "corvusoft/restbed/web_socket_message.hpp"
|
||||
#include "corvusoft/restbed/detail/socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/web_socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/web_socket_manager_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::bind;
|
||||
using std::string;
|
||||
using std::shared_ptr;
|
||||
using std::error_code;
|
||||
using std::placeholders::_1;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::SocketImpl;
|
||||
using restbed::detail::WebSocketImpl;
|
||||
using restbed::detail::WebSocketManagerImpl;
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
WebSocketImpl::WebSocketImpl( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WebSocketImpl::~WebSocketImpl( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void WebSocketImpl::log( const Logger::Level level, const string& message ) const
|
||||
{
|
||||
if ( m_logger not_eq nullptr )
|
||||
{
|
||||
try
|
||||
{
|
||||
m_logger->log( level, "%s", message.data( ) );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
fprintf( stderr, "Failed to create log entry: %s", message.data( ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketImpl::listen( const shared_ptr< WebSocket > socket )
|
||||
{
|
||||
m_socket->start_read( 2, bind( &WebSocketImpl::parse_flags, this, _1, socket ), [ this, socket ]( const error_code code )
|
||||
{
|
||||
if ( m_error_handler not_eq nullptr )
|
||||
{
|
||||
m_error_handler( socket, code );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
void WebSocketImpl::parse_flags( const Bytes data, const shared_ptr< WebSocket > socket )
|
||||
{
|
||||
auto message = m_manager->parse( data );
|
||||
|
||||
auto length = message->get_length( );
|
||||
|
||||
if ( length == 126 )
|
||||
{
|
||||
length = 2;
|
||||
}
|
||||
else if ( length == 127 )
|
||||
{
|
||||
length = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
length = 0;
|
||||
}
|
||||
|
||||
if ( message->get_mask_flag( ) == true )
|
||||
{
|
||||
length += 4;
|
||||
}
|
||||
|
||||
m_socket->start_read( length, bind( &WebSocketImpl::parse_length_and_mask, this, _1, data, socket ), [ this, socket ]( const error_code code )
|
||||
{
|
||||
if ( m_error_handler not_eq nullptr )
|
||||
{
|
||||
m_error_handler( socket, code );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
void WebSocketImpl::parse_payload( const Bytes data, Bytes packet, const shared_ptr< WebSocket > socket )
|
||||
{
|
||||
packet.insert( packet.end( ), data.begin( ), data.end( ) );
|
||||
auto message = m_manager->parse( packet );
|
||||
|
||||
if ( m_message_handler not_eq nullptr )
|
||||
{
|
||||
m_message_handler( socket, message );
|
||||
}
|
||||
|
||||
listen( socket );
|
||||
}
|
||||
|
||||
void WebSocketImpl::parse_length_and_mask( const Bytes data, Bytes packet, const shared_ptr< WebSocket > socket )
|
||||
{
|
||||
packet.insert( packet.end( ), data.begin( ), data.end( ) );
|
||||
auto message = m_manager->parse( packet );
|
||||
|
||||
auto length = message->get_extended_length( );
|
||||
|
||||
if ( length == 0 )
|
||||
{
|
||||
length = message->get_length( );
|
||||
}
|
||||
|
||||
m_socket->start_read( length, bind( &WebSocketImpl::parse_payload, this, _1, packet, socket ), [ this, socket ]( const error_code code )
|
||||
{
|
||||
if ( m_error_handler not_eq nullptr )
|
||||
{
|
||||
m_error_handler( socket, code );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/byte.hpp"
|
||||
#include "corvusoft/restbed/logger.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class WebSocket;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
class SocketImpl;
|
||||
class WebSocketManagerImpl;
|
||||
|
||||
class WebSocketImpl
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
WebSocketImpl( void );
|
||||
|
||||
virtual ~WebSocketImpl( void );
|
||||
|
||||
//Functionality
|
||||
void log( const Logger::Level level, const std::string& message ) const;
|
||||
|
||||
void listen( const std::shared_ptr< WebSocket > socket );
|
||||
|
||||
void parse_flags( const Bytes data, const std::shared_ptr< WebSocket > socket );
|
||||
|
||||
void parse_payload( const Bytes data, Bytes packet, const std::shared_ptr< WebSocket > socket );
|
||||
|
||||
void parse_length_and_mask( const Bytes data, Bytes packet, const std::shared_ptr< WebSocket > socket );
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
std::string m_key = "";
|
||||
|
||||
bool m_error_handler_invoked = false;
|
||||
|
||||
std::shared_ptr< Logger > m_logger = nullptr;
|
||||
|
||||
std::shared_ptr< SocketImpl > m_socket = nullptr;
|
||||
|
||||
std::shared_ptr< WebSocketManagerImpl > m_manager = nullptr;
|
||||
|
||||
std::function< void ( const std::shared_ptr< WebSocket > ) > m_open_handler = nullptr;
|
||||
|
||||
std::function< void ( const std::shared_ptr< WebSocket > ) > m_close_handler = nullptr;
|
||||
|
||||
std::function< void ( const std::shared_ptr< WebSocket >, const std::error_code ) > m_error_handler = nullptr;
|
||||
|
||||
std::function< void ( const std::shared_ptr< WebSocket >, const std::shared_ptr< WebSocketMessage > ) > m_message_handler = nullptr;
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
WebSocketImpl( const WebSocketImpl& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
WebSocketImpl& operator =( const WebSocketImpl& value ) = delete;
|
||||
|
||||
//Properties
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <ciso646>
|
||||
#include <system_error>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/logger.hpp"
|
||||
#include "corvusoft/restbed/session.hpp"
|
||||
#include "corvusoft/restbed/request.hpp"
|
||||
#include "corvusoft/restbed/web_socket.hpp"
|
||||
#include "corvusoft/restbed/web_socket_message.hpp"
|
||||
#include "corvusoft/restbed/detail/socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/request_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/session_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/web_socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/web_socket_manager_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::get;
|
||||
using std::tuple;
|
||||
using std::string;
|
||||
using std::mt19937;
|
||||
using std::function;
|
||||
using std::to_string;
|
||||
using std::shared_ptr;
|
||||
using std::error_code;
|
||||
using std::make_shared;
|
||||
using std::random_device;
|
||||
using std::placeholders::_1;
|
||||
using std::uniform_int_distribution;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::WebSocketManagerImpl;
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
WebSocketManagerImpl::WebSocketManagerImpl( void ) : m_logger( nullptr ),
|
||||
m_sockets( )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
shared_ptr< WebSocketMessage > WebSocketManagerImpl::parse( const Bytes& packet )
|
||||
{
|
||||
if ( packet.empty( ) )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Byte byte = packet[ 0 ];
|
||||
|
||||
auto message = make_shared< WebSocketMessage >( );
|
||||
message->set_final_frame_flag( ( byte & 0x80 ) ? true : false );
|
||||
message->set_reserved_flags( ( byte & 0x40 ) ? true : false,
|
||||
( byte & 0x20 ) ? true : false,
|
||||
( byte & 0x10 ) ? true : false );
|
||||
message->set_opcode( static_cast< WebSocketMessage::OpCode >( byte & 0x0F ) );
|
||||
|
||||
const auto packet_length = packet.size( );
|
||||
|
||||
if ( packet_length == 1 )
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
byte = packet[ 1 ];
|
||||
message->set_mask_flag( ( byte & 0x80 ) ? true : false );
|
||||
message->set_length( byte & 0x7F );
|
||||
|
||||
if ( packet_length == 2 )
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
size_t offset = 2;
|
||||
uint64_t length = message->get_length( );
|
||||
|
||||
if ( length == 126 )
|
||||
{
|
||||
if ( ( packet_length - ( offset + 1 ) ) <= 0 )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
length = packet[ offset++ ] << 8;
|
||||
length |= packet[ offset++ ] ;
|
||||
|
||||
message->set_extended_length( length );
|
||||
}
|
||||
else if ( length == 127 )
|
||||
{
|
||||
if ( ( packet_length - ( offset + 3 ) ) <= 0 )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
length |= packet[ offset++ ] << 24;
|
||||
length |= packet[ offset++ ] << 16;
|
||||
length |= packet[ offset++ ] << 8;
|
||||
length = packet[ offset++ ] ;
|
||||
|
||||
message->set_extended_length( length );
|
||||
}
|
||||
|
||||
if ( message->get_mask_flag( ) == true )
|
||||
{
|
||||
if ( ( packet_length - ( offset + 3 ) ) <= 0 )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t mask = packet[ offset++ ] << 24;
|
||||
mask |= packet[ offset++ ] << 16;
|
||||
mask |= packet[ offset++ ] << 8;
|
||||
mask |= packet[ offset++ ] ;
|
||||
|
||||
message->set_mask( mask );
|
||||
}
|
||||
|
||||
Bytes payload( packet.begin( ) + offset, packet.end( ) );
|
||||
|
||||
if ( message->get_mask_flag( ) == true )
|
||||
{
|
||||
auto masking_key = message->get_mask( );
|
||||
|
||||
Byte mask[ 4 ] = { };
|
||||
mask[ 0 ] = ( masking_key >> 24 ) & 0xFF;
|
||||
mask[ 1 ] = ( masking_key >> 16 ) & 0xFF;
|
||||
mask[ 2 ] = ( masking_key >> 8 ) & 0xFF;
|
||||
mask[ 3 ] = masking_key & 0xFF;
|
||||
|
||||
for ( size_t index = 0; index < payload.size( ); index++ )
|
||||
{
|
||||
payload[ index ] ^= mask[ index % 4 ];
|
||||
}
|
||||
}
|
||||
|
||||
message->set_data( payload );
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
Bytes WebSocketManagerImpl::compose( const shared_ptr< WebSocketMessage >& message )
|
||||
{
|
||||
Byte byte = 0x80;
|
||||
|
||||
if ( message->get_final_frame_flag( ) == false )
|
||||
{
|
||||
byte = 0x00;
|
||||
}
|
||||
|
||||
auto reserved_flags = message->get_reserved_flags( );
|
||||
|
||||
if ( get< 0 >( reserved_flags ) )
|
||||
{
|
||||
byte |= 0x40;
|
||||
}
|
||||
|
||||
if ( get< 1 >( reserved_flags ) )
|
||||
{
|
||||
byte |= 0x20;
|
||||
}
|
||||
|
||||
if ( get< 2 >( reserved_flags ) )
|
||||
{
|
||||
byte |= 0x10;
|
||||
}
|
||||
|
||||
byte |= ( message->get_opcode( ) & 0x0F );
|
||||
|
||||
Bytes frame = { byte };
|
||||
|
||||
auto length = message->get_length( );
|
||||
auto mask_flag = message->get_mask_flag( );
|
||||
|
||||
if ( length == 126 )
|
||||
{
|
||||
auto extended_length = message->get_extended_length( );
|
||||
frame.push_back( ( mask_flag ) ? 254 : 126 );
|
||||
frame.push_back( ( extended_length >> 8 ) & 0xFF );
|
||||
frame.push_back( extended_length & 0xFF );
|
||||
}
|
||||
else if ( length == 127 )
|
||||
{
|
||||
auto extended_length = message->get_extended_length( );
|
||||
frame.push_back( ( mask_flag ) ? 255 : 127 );
|
||||
frame.push_back( ( extended_length >> 56 ) & 0xFF );
|
||||
frame.push_back( ( extended_length >> 48 ) & 0xFF );
|
||||
frame.push_back( ( extended_length >> 40 ) & 0xFF );
|
||||
frame.push_back( ( extended_length >> 32 ) & 0xFF );
|
||||
frame.push_back( ( extended_length >> 24 ) & 0xFF );
|
||||
frame.push_back( ( extended_length >> 16 ) & 0xFF );
|
||||
frame.push_back( ( extended_length >> 8 ) & 0xFF );
|
||||
frame.push_back( extended_length & 0xFF );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mask_flag )
|
||||
{
|
||||
length |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
length &= ~0x80;
|
||||
}
|
||||
|
||||
frame.push_back( length );
|
||||
}
|
||||
|
||||
if ( mask_flag )
|
||||
{
|
||||
auto masking_key = message->get_mask( );
|
||||
|
||||
uint8_t mask[ 4 ] = { };
|
||||
mask[ 0 ] = masking_key & 0xFF;
|
||||
mask[ 1 ] = ( masking_key >> 8 ) & 0xFF;
|
||||
mask[ 2 ] = ( masking_key >> 16 ) & 0xFF;
|
||||
mask[ 3 ] = ( masking_key >> 24 ) & 0xFF;
|
||||
|
||||
frame.push_back( mask[ 3 ] );
|
||||
frame.push_back( mask[ 2 ] );
|
||||
frame.push_back( mask[ 1 ] );
|
||||
frame.push_back( mask[ 0 ] );
|
||||
|
||||
auto data = message->get_data( );
|
||||
|
||||
for ( size_t index = 0; index < data.size( ); index++ )
|
||||
{
|
||||
auto datum = data.at( index );
|
||||
datum ^= mask[ index % 4 ];
|
||||
frame.push_back( datum );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto data = message->get_data( );
|
||||
frame.insert( frame.end( ), data.begin( ), data.end( ) );
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
shared_ptr< WebSocket > WebSocketManagerImpl::create( const std::shared_ptr< Session >& session )
|
||||
{
|
||||
if ( session == nullptr )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static auto& charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
thread_local static mt19937 generator{ random_device{ }( ) };
|
||||
thread_local static uniform_int_distribution< string::size_type > pick( 0, sizeof( charset ) - 2 );
|
||||
|
||||
string key;
|
||||
auto length = 16;
|
||||
key.reserve( length );
|
||||
while( length-- ) key += charset[ pick( generator ) ];
|
||||
|
||||
auto socket = make_shared< WebSocket >( );
|
||||
socket->set_key( key );
|
||||
socket->set_logger( m_logger );
|
||||
socket->set_socket( session->m_pimpl->m_request->m_pimpl->m_socket );
|
||||
socket->m_pimpl->m_manager = shared_from_this( );
|
||||
|
||||
m_sockets.insert( make_pair( key, socket ) );
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
shared_ptr< WebSocket > WebSocketManagerImpl::read( const string& key )
|
||||
{
|
||||
auto socket = m_sockets.find( key );
|
||||
return ( socket not_eq m_sockets.end( ) ) ? socket->second : nullptr;
|
||||
}
|
||||
|
||||
shared_ptr< WebSocket > WebSocketManagerImpl::update( const shared_ptr< WebSocket >& socket )
|
||||
{
|
||||
return socket;
|
||||
}
|
||||
|
||||
void WebSocketManagerImpl::destroy( const shared_ptr< WebSocket >& socket )
|
||||
{
|
||||
if ( socket == nullptr )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_sockets.erase( socket->get_key( ) );
|
||||
}
|
||||
|
||||
shared_ptr< Logger > WebSocketManagerImpl::get_logger( void ) const
|
||||
{
|
||||
return m_logger;
|
||||
}
|
||||
|
||||
void WebSocketManagerImpl::set_logger( const shared_ptr< Logger >& value )
|
||||
{
|
||||
m_logger = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/byte.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Logger;
|
||||
class Session;
|
||||
class WebSocket;
|
||||
class WebSocketMessage;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
class SocketImpl;
|
||||
|
||||
class WebSocketManagerImpl : public std::enable_shared_from_this< WebSocketManagerImpl >
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
WebSocketManagerImpl( void );
|
||||
|
||||
~WebSocketManagerImpl( void ) = default;
|
||||
|
||||
//Functionality
|
||||
std::shared_ptr< WebSocketMessage > parse( const Bytes& packet );
|
||||
|
||||
Bytes compose( const std::shared_ptr< WebSocketMessage >& message );
|
||||
|
||||
std::shared_ptr< WebSocket > create( const std::shared_ptr< Session >& session );
|
||||
|
||||
std::shared_ptr< WebSocket > read( const std::string& key );
|
||||
|
||||
std::shared_ptr< WebSocket > update( const std::shared_ptr< WebSocket >& socket );
|
||||
|
||||
void destroy( const std::shared_ptr< WebSocket >& socket );
|
||||
|
||||
//Getters
|
||||
std::shared_ptr< Logger > get_logger( void ) const;
|
||||
|
||||
//Setters
|
||||
void set_logger( const std::shared_ptr< Logger >& value );
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
WebSocketManagerImpl( const WebSocketManagerImpl& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
WebSocketManagerImpl& operator =( const WebSocketManagerImpl& value ) = delete;
|
||||
|
||||
//Properties
|
||||
std::shared_ptr< Logger > m_logger;
|
||||
|
||||
std::map< std::string, std::shared_ptr< WebSocket > > m_sockets;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <cstdint>
|
||||
|
||||
//Project Includes
|
||||
#include <corvusoft/restbed/byte.hpp>
|
||||
#include <corvusoft/restbed/web_socket.hpp>
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
struct WebSocketMessageImpl
|
||||
{
|
||||
Bytes m_data = { };
|
||||
|
||||
std::uint32_t m_mask = 0;
|
||||
|
||||
std::uint8_t m_length = 0;
|
||||
|
||||
std::uint64_t m_extended_length = 0;
|
||||
|
||||
bool m_mask_flag = false;
|
||||
|
||||
bool m_final_frame_flag = true;
|
||||
|
||||
bool m_reserved_flag_one = false;
|
||||
|
||||
bool m_reserved_flag_two = false;
|
||||
|
||||
bool m_reserved_flag_three = false;
|
||||
|
||||
WebSocketMessage::OpCode m_opcode = WebSocketMessage::OpCode::BINARY_FRAME;
|
||||
};
|
||||
}
|
||||
}
|
||||
285
lib/restbed-4.8/source/corvusoft/restbed/http.cpp
Normal file
285
lib/restbed-4.8/source/corvusoft/restbed/http.cpp
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <ciso646>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <clocale>
|
||||
#include <stdexcept>
|
||||
#include <system_error>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/uri.hpp"
|
||||
#include "corvusoft/restbed/http.hpp"
|
||||
#include "corvusoft/restbed/string.hpp"
|
||||
#include "corvusoft/restbed/request.hpp"
|
||||
#include "corvusoft/restbed/response.hpp"
|
||||
#include "corvusoft/restbed/settings.hpp"
|
||||
#include "corvusoft/restbed/ssl_settings.hpp"
|
||||
#include "corvusoft/restbed/detail/http_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/request_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/response_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
#include <asio/error.hpp>
|
||||
#include <asio/buffer.hpp>
|
||||
|
||||
//System Namespaces
|
||||
using std::free;
|
||||
using std::bind;
|
||||
using std::string;
|
||||
using std::future;
|
||||
using std::function;
|
||||
using std::setlocale;
|
||||
using std::error_code;
|
||||
using std::shared_ptr;
|
||||
using std::make_shared;
|
||||
using std::runtime_error;
|
||||
using std::invalid_argument;
|
||||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::HttpImpl;
|
||||
using restbed::detail::SocketImpl;
|
||||
using restbed::detail::RequestImpl;
|
||||
using restbed::detail::ResponseImpl;
|
||||
|
||||
//External Namespaces
|
||||
using asio::buffer;
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
Bytes Http::to_bytes( const shared_ptr< Request >& value )
|
||||
{
|
||||
return HttpImpl::to_bytes( value );
|
||||
}
|
||||
|
||||
Bytes Http::to_bytes( const shared_ptr< Response >& value )
|
||||
{
|
||||
char* locale = nullptr;
|
||||
if (auto current_locale = setlocale( LC_NUMERIC, nullptr ) )
|
||||
{
|
||||
locale = strdup(current_locale);
|
||||
setlocale( LC_NUMERIC, "C" );
|
||||
}
|
||||
|
||||
auto data = String::format( "%s/%.1f %i %s\r\n",
|
||||
value->get_protocol( ).data( ),
|
||||
value->get_version( ),
|
||||
value->get_status_code( ),
|
||||
value->get_status_message( ).data( ) );
|
||||
|
||||
if (locale) {
|
||||
setlocale( LC_NUMERIC, locale );
|
||||
free( locale );
|
||||
}
|
||||
|
||||
auto headers = value->get_headers( );
|
||||
|
||||
if ( not headers.empty( ) )
|
||||
{
|
||||
data += String::join( headers, ": ", "\r\n" ) + "\r\n";
|
||||
}
|
||||
|
||||
data += "\r\n";
|
||||
|
||||
auto bytes = String::to_bytes( data );
|
||||
auto body = value->get_body( );
|
||||
|
||||
if ( not body.empty( ) )
|
||||
{
|
||||
bytes.insert( bytes.end( ), body.begin( ), body.end( ) );
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void Http::close( const shared_ptr< Request >& value )
|
||||
{
|
||||
if ( value not_eq nullptr and value->m_pimpl->m_socket not_eq nullptr )
|
||||
{
|
||||
value->m_pimpl->m_socket->close( );
|
||||
}
|
||||
}
|
||||
|
||||
bool Http::is_open( const shared_ptr< Request >& value )
|
||||
{
|
||||
if ( value not_eq nullptr and value->m_pimpl->m_socket not_eq nullptr )
|
||||
{
|
||||
return value->m_pimpl->m_socket->is_open( );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Http::is_closed( const shared_ptr< Request >& value )
|
||||
{
|
||||
return not is_open( value );
|
||||
}
|
||||
|
||||
const shared_ptr< Response > Http::sync( const shared_ptr< Request > request, const shared_ptr< const Settings >& settings )
|
||||
{
|
||||
auto response = Http::async( request, nullptr, settings );
|
||||
response.wait( );
|
||||
|
||||
return response.get( );
|
||||
}
|
||||
|
||||
future< shared_ptr< Response > > Http::async( const shared_ptr< Request > request, const function< void ( const shared_ptr< Request >, const shared_ptr< Response > ) >& callback, const shared_ptr< const Settings >& settings )
|
||||
{
|
||||
#ifndef BUILD_SSL
|
||||
|
||||
if ( settings->get_ssl_settings( ) not_eq nullptr )
|
||||
{
|
||||
throw runtime_error( "Not Implemented! Rebuild Restbed with SSL funcationality enabled." );
|
||||
}
|
||||
|
||||
#endif
|
||||
bool finished = true;
|
||||
auto completion_handler = callback;
|
||||
|
||||
if ( completion_handler == nullptr )
|
||||
{
|
||||
finished = false;
|
||||
completion_handler = [ &finished ]( const shared_ptr< Request >, const shared_ptr< Response > )
|
||||
{
|
||||
finished = true;
|
||||
};
|
||||
}
|
||||
|
||||
HttpImpl::socket_setup( request, settings );
|
||||
|
||||
request->m_pimpl->m_response = make_shared< Response >( );
|
||||
request->m_pimpl->m_response->m_pimpl->m_request = request.get( );
|
||||
|
||||
if ( request->m_pimpl->m_socket not_eq nullptr and request->m_pimpl->m_socket->is_closed( ) )
|
||||
{
|
||||
request->m_pimpl->m_socket->connect( request->get_host( ), request->get_port( ), bind( HttpImpl::request_handler, _1, request, completion_handler ) );
|
||||
}
|
||||
else if ( request->m_pimpl->m_socket not_eq nullptr )
|
||||
{
|
||||
request->m_pimpl->m_socket->start_write( Http::to_bytes( request ), bind( HttpImpl::write_handler, _1, _2, request, completion_handler ) );
|
||||
}
|
||||
|
||||
if ( finished )
|
||||
{
|
||||
return std::async( std::launch::async, [ ]( const shared_ptr< Request > request ) -> shared_ptr< Response >
|
||||
{
|
||||
request->m_pimpl->m_io_service->run( );
|
||||
return request->m_pimpl->m_response;
|
||||
}, request );
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
request->m_pimpl->m_io_service->run_one( );
|
||||
}
|
||||
while ( finished == false and not request->m_pimpl->m_io_service->stopped( ) );
|
||||
|
||||
std::promise< shared_ptr< Response > > result;
|
||||
result.set_value( request->m_pimpl->m_response );
|
||||
|
||||
return result.get_future( );
|
||||
}
|
||||
}
|
||||
|
||||
Bytes Http::fetch( const size_t length, const shared_ptr< Response >& response )
|
||||
{
|
||||
if ( response == nullptr )
|
||||
{
|
||||
throw invalid_argument( String::empty );
|
||||
}
|
||||
|
||||
auto request = response->m_pimpl->m_request;
|
||||
|
||||
if ( request == nullptr or request->m_pimpl->m_buffer == nullptr or request->m_pimpl->m_socket == nullptr )
|
||||
{
|
||||
throw invalid_argument( String::empty );
|
||||
}
|
||||
|
||||
Bytes data = { };
|
||||
|
||||
if ( length > request->m_pimpl->m_buffer->size( ) )
|
||||
{
|
||||
error_code error;
|
||||
const size_t size = length - request->m_pimpl->m_buffer->size( );
|
||||
|
||||
request->m_pimpl->m_socket->start_read( request->m_pimpl->m_buffer, size, error );
|
||||
|
||||
if ( error and error not_eq asio::error::eof )
|
||||
{
|
||||
throw runtime_error( String::format( "Socket receive failed: '%s'", error.message( ).data( ) ) );
|
||||
}
|
||||
|
||||
const auto data_ptr = asio::buffer_cast< const Byte* >( request->m_pimpl->m_buffer->data( ) );
|
||||
data = Bytes( data_ptr, data_ptr + length );
|
||||
request->m_pimpl->m_buffer->consume( length );
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto data_ptr = asio::buffer_cast< const Byte* >( request->m_pimpl->m_buffer->data( ) );
|
||||
data = Bytes( data_ptr, data_ptr + length );
|
||||
request->m_pimpl->m_buffer->consume( length );
|
||||
}
|
||||
|
||||
auto& body = response->m_pimpl->m_body;
|
||||
|
||||
if ( body.empty( ) )
|
||||
{
|
||||
body = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
body.insert( body.end( ), data.begin( ), data.end( ) );
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
Bytes Http::fetch( const string& delimiter, const shared_ptr< Response >& response )
|
||||
{
|
||||
if ( response == nullptr )
|
||||
{
|
||||
throw invalid_argument( String::empty );
|
||||
}
|
||||
|
||||
auto request = response->m_pimpl->m_request;
|
||||
|
||||
if ( request == nullptr or request->m_pimpl->m_buffer == nullptr or request->m_pimpl->m_socket == nullptr )
|
||||
{
|
||||
throw invalid_argument( String::empty );
|
||||
}
|
||||
|
||||
error_code error;
|
||||
const size_t size = request->m_pimpl->m_socket->start_read( request->m_pimpl->m_buffer, delimiter, error );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
throw runtime_error( String::format( "Socket receive failed: '%s'", error.message( ).data( ) ) );
|
||||
}
|
||||
|
||||
const auto data_ptr = asio::buffer_cast< const Byte* >( request->m_pimpl->m_buffer->data( ) );
|
||||
const Bytes data( data_ptr, data_ptr + size );
|
||||
request->m_pimpl->m_buffer->consume( size );
|
||||
|
||||
auto& body = response->m_pimpl->m_body;
|
||||
|
||||
if ( body.empty( ) )
|
||||
{
|
||||
body = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
body.insert( body.end( ), data.begin( ), data.end( ) );
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
119
lib/restbed-4.8/source/corvusoft/restbed/http.hpp
Normal file
119
lib/restbed-4.8/source/corvusoft/restbed/http.hpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
|
||||
//Project Includes
|
||||
#include <corvusoft/restbed/byte.hpp>
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define HTTP_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define HTTP_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define HTTP_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Request;
|
||||
class Response;
|
||||
class Settings;
|
||||
|
||||
class [[deprecated("HTTP client is deprecated; we will release a complimentary client framework at a future date.")]] HTTP_EXPORT Http
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
static Bytes to_bytes( const std::shared_ptr< Request >& value );
|
||||
|
||||
static Bytes to_bytes( const std::shared_ptr< Response >& value );
|
||||
|
||||
static void close( const std::shared_ptr< Request >& value );
|
||||
|
||||
static bool is_open( const std::shared_ptr< Request >& value );
|
||||
|
||||
static bool is_closed( const std::shared_ptr< Request >& value );
|
||||
|
||||
static const std::shared_ptr< Response > sync( const std::shared_ptr< Request > request, const std::shared_ptr< const Settings >& settings = std::make_shared< Settings >( ) );
|
||||
|
||||
static std::future< std::shared_ptr< Response > > async( const std::shared_ptr< Request > request, const std::function< void ( const std::shared_ptr< Request >, const std::shared_ptr< Response > ) >& callback, const std::shared_ptr< const Settings >& settings = std::make_shared< Settings >( ) );
|
||||
|
||||
static Bytes fetch( const std::size_t length, const std::shared_ptr< Response >& response );
|
||||
|
||||
static Bytes fetch( const std::string& delimiter, const std::shared_ptr< Response >& response );
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Http( void ) = delete;
|
||||
|
||||
virtual ~Http( void ) = delete;
|
||||
|
||||
Http( const Http& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
Http& operator =( const Http& value ) = delete;
|
||||
|
||||
//Properties
|
||||
};
|
||||
}
|
||||
116
lib/restbed-4.8/source/corvusoft/restbed/logger.hpp
Normal file
116
lib/restbed-4.8/source/corvusoft/restbed/logger.hpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(_WIN32)
|
||||
#undef ERROR
|
||||
#endif
|
||||
|
||||
//System Includes
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define LOGGER_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define LOGGER_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define LOGGER_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Settings;
|
||||
|
||||
class LOGGER_EXPORT Logger
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
enum Level : int
|
||||
{
|
||||
INFO = 0000,
|
||||
DEBUG = 1000,
|
||||
FATAL = 2000,
|
||||
ERROR = 3000,
|
||||
WARNING = 4000,
|
||||
SECURITY = 5000
|
||||
};
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
virtual void stop( void ) = 0;
|
||||
|
||||
virtual void start( const std::shared_ptr< const Settings >& settings ) = 0;
|
||||
|
||||
virtual void log( const Level level, const char* format, ... ) = 0;
|
||||
|
||||
virtual void log_if( bool expression, const Level level, const char* format, ... ) = 0;
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Logger( void ) = default;
|
||||
|
||||
explicit Logger( const Logger& original ) = default;
|
||||
|
||||
virtual ~Logger( void ) = default;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
Logger& operator =( const Logger& value ) = default;
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
};
|
||||
}
|
||||
296
lib/restbed-4.8/source/corvusoft/restbed/request.cpp
Normal file
296
lib/restbed-4.8/source/corvusoft/restbed/request.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <utility>
|
||||
#include <ciso646>
|
||||
#include <algorithm>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/uri.hpp"
|
||||
#include "corvusoft/restbed/string.hpp"
|
||||
#include "corvusoft/restbed/request.hpp"
|
||||
#include "corvusoft/restbed/response.hpp"
|
||||
#include "corvusoft/restbed/detail/socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/request_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/response_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::map;
|
||||
using std::pair;
|
||||
using std::stof;
|
||||
using std::stod;
|
||||
using std::string;
|
||||
using std::function;
|
||||
using std::multimap;
|
||||
using std::make_pair;
|
||||
using std::unique_ptr;
|
||||
using std::shared_ptr;
|
||||
using std::make_shared;
|
||||
using std::out_of_range;
|
||||
using std::invalid_argument;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::Common;
|
||||
using restbed::detail::RequestImpl;
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
Request::Request( void ) : m_pimpl( new detail::RequestImpl )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Request::Request( const Uri& value ) : m_pimpl( new detail::RequestImpl )
|
||||
{
|
||||
m_pimpl->m_uri = make_shared< Uri >( value );
|
||||
m_pimpl->m_path = value.get_path( );
|
||||
m_pimpl->m_port = value.get_port( );
|
||||
m_pimpl->m_host = value.get_authority( );
|
||||
m_pimpl->m_query_parameters = value.get_query_parameters( );
|
||||
m_pimpl->m_protocol = String::uppercase( value.get_scheme( ) );
|
||||
|
||||
if ( m_pimpl->m_path.empty( ) )
|
||||
{
|
||||
m_pimpl->m_path = "/";
|
||||
}
|
||||
|
||||
if ( m_pimpl->m_port == 0 )
|
||||
{
|
||||
m_pimpl->m_port = ( m_pimpl->m_protocol == "HTTPS" ) ? 443 : 80;
|
||||
}
|
||||
}
|
||||
|
||||
Request::~Request( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool Request::has_header( const string& name ) const
|
||||
{
|
||||
return Common::has_parameter( name, m_pimpl->m_headers );
|
||||
}
|
||||
|
||||
bool Request::has_path_parameter( const string& name ) const
|
||||
{
|
||||
return Common::has_parameter( name, m_pimpl->m_path_parameters );
|
||||
}
|
||||
|
||||
bool Request::has_query_parameter( const string& name ) const
|
||||
{
|
||||
return Common::has_parameter( name, m_pimpl->m_query_parameters );
|
||||
}
|
||||
|
||||
uint16_t Request::get_port( void ) const
|
||||
{
|
||||
return m_pimpl->m_port;
|
||||
}
|
||||
|
||||
double Request::get_version( void ) const
|
||||
{
|
||||
return m_pimpl->m_version;
|
||||
}
|
||||
|
||||
const Bytes& Request::get_body( void ) const
|
||||
{
|
||||
return m_pimpl->m_body;
|
||||
}
|
||||
|
||||
const shared_ptr< const Response > Request::get_response( void ) const
|
||||
{
|
||||
return m_pimpl->m_response;
|
||||
}
|
||||
|
||||
string Request::get_host( const function< string ( const string& ) >& transform ) const
|
||||
{
|
||||
return Common::transform( m_pimpl->m_host, transform );
|
||||
}
|
||||
|
||||
string Request::get_path( const function< string ( const string& ) >& transform ) const
|
||||
{
|
||||
return Common::transform( m_pimpl->m_path, transform );
|
||||
}
|
||||
|
||||
string Request::get_method( const function< string ( const string& ) >& transform ) const
|
||||
{
|
||||
return Common::transform( m_pimpl->m_method, transform );
|
||||
}
|
||||
|
||||
string Request::get_protocol( const function< string ( const string& ) >& transform ) const
|
||||
{
|
||||
return Common::transform( m_pimpl->m_protocol, transform );
|
||||
}
|
||||
|
||||
void Request::get_body( string& body, const function< string ( const Bytes& ) >& transform ) const
|
||||
{
|
||||
body = ( transform == nullptr ) ? String::to_string( m_pimpl->m_body ) : transform( m_pimpl->m_body );
|
||||
}
|
||||
|
||||
string Request::get_header( const string& name, const string& default_value ) const
|
||||
{
|
||||
if ( name.empty( ) )
|
||||
{
|
||||
return default_value;
|
||||
}
|
||||
|
||||
const auto headers = Common::get_parameters( name, m_pimpl->m_headers );
|
||||
return ( headers.empty( ) ) ? default_value : headers.begin( )->second;
|
||||
}
|
||||
|
||||
string Request::get_header( const string& name, const function< string ( const string& ) >& transform ) const
|
||||
{
|
||||
if ( name.empty( ) )
|
||||
{
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
const auto headers = Common::get_parameters( name, m_pimpl->m_headers );
|
||||
const auto value = ( headers.empty( ) ) ? String::empty : headers.begin( )->second;
|
||||
|
||||
return Common::transform( value, transform );
|
||||
}
|
||||
|
||||
multimap< string, string > Request::get_headers( const string& name ) const
|
||||
{
|
||||
return Common::get_parameters( name, m_pimpl->m_headers );
|
||||
}
|
||||
|
||||
string Request::get_query_parameter( const string& name, const string& default_value ) const
|
||||
{
|
||||
if ( name.empty( ) )
|
||||
{
|
||||
return default_value;
|
||||
}
|
||||
|
||||
const auto parameters = Common::get_parameters( name, m_pimpl->m_query_parameters );
|
||||
return ( parameters.empty( ) ) ? default_value : parameters.begin( )->second;
|
||||
}
|
||||
|
||||
string Request::get_query_parameter( const string& name, const function< string ( const string& ) >& transform ) const
|
||||
{
|
||||
if ( name.empty( ) )
|
||||
{
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
const auto parameters = Common::get_parameters( name, m_pimpl->m_query_parameters );
|
||||
const auto value = ( parameters.empty( ) ) ? String::empty : parameters.begin( )->second;
|
||||
|
||||
return Common::transform( value, transform );
|
||||
}
|
||||
|
||||
multimap< string, string > Request::get_query_parameters( const string& name ) const
|
||||
{
|
||||
return Common::get_parameters( name, m_pimpl->m_query_parameters );
|
||||
}
|
||||
|
||||
string Request::get_path_parameter( const string& name, const string& default_value ) const
|
||||
{
|
||||
if ( name.empty( ) )
|
||||
{
|
||||
return default_value;
|
||||
}
|
||||
|
||||
const auto parameters = Common::get_parameters( name, m_pimpl->m_path_parameters );
|
||||
return ( parameters.empty( ) ) ? default_value : parameters.begin( )->second;
|
||||
}
|
||||
|
||||
string Request::get_path_parameter( const string& name, const function< string ( const string& ) >& transform ) const
|
||||
{
|
||||
if ( name.empty( ) )
|
||||
{
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
const auto parameters = Common::get_parameters( name, m_pimpl->m_path_parameters );
|
||||
const auto value = ( parameters.empty( ) ) ? String::empty : parameters.begin( )->second;
|
||||
|
||||
return Common::transform( value, transform );
|
||||
}
|
||||
|
||||
map< string, string > Request::get_path_parameters( const string& name ) const
|
||||
{
|
||||
return Common::get_parameters( name, m_pimpl->m_path_parameters );
|
||||
}
|
||||
|
||||
void Request::set_body( const Bytes& value )
|
||||
{
|
||||
m_pimpl->m_body = value;
|
||||
}
|
||||
|
||||
void Request::set_body( const string& value )
|
||||
{
|
||||
m_pimpl->m_body = String::to_bytes( value );
|
||||
}
|
||||
|
||||
void Request::set_port( const uint16_t value )
|
||||
{
|
||||
if ( m_pimpl->m_socket not_eq nullptr )
|
||||
{
|
||||
m_pimpl->m_socket->close( );
|
||||
}
|
||||
|
||||
m_pimpl->m_port = value;
|
||||
}
|
||||
|
||||
void Request::set_version( const double value )
|
||||
{
|
||||
m_pimpl->m_version = value;
|
||||
}
|
||||
|
||||
void Request::set_path( const string& value )
|
||||
{
|
||||
m_pimpl->m_path = value;
|
||||
}
|
||||
|
||||
void Request::set_host( const string& value )
|
||||
{
|
||||
if ( m_pimpl->m_socket not_eq nullptr )
|
||||
{
|
||||
m_pimpl->m_socket->close( );
|
||||
}
|
||||
|
||||
m_pimpl->m_host = value;
|
||||
}
|
||||
|
||||
void Request::set_method( const string& value )
|
||||
{
|
||||
m_pimpl->m_method = value;
|
||||
}
|
||||
|
||||
void Request::set_protocol( const string& value )
|
||||
{
|
||||
m_pimpl->m_protocol = value;
|
||||
}
|
||||
|
||||
void Request::add_header( const string& name, const string& value )
|
||||
{
|
||||
m_pimpl->m_headers.insert( make_pair( name, value ) );
|
||||
}
|
||||
|
||||
void Request::set_header( const string& name, const string& value )
|
||||
{
|
||||
m_pimpl->m_headers.erase( name );
|
||||
m_pimpl->m_headers.insert( make_pair( name, value ) );
|
||||
}
|
||||
|
||||
void Request::set_headers( const multimap< string, string >& values )
|
||||
{
|
||||
m_pimpl->m_headers = values;
|
||||
}
|
||||
|
||||
void Request::set_query_parameter( const string& name, const string& value )
|
||||
{
|
||||
m_pimpl->m_query_parameters.insert( make_pair( name, value ) );
|
||||
}
|
||||
|
||||
void Request::set_query_parameters( const multimap< string, string >& values )
|
||||
{
|
||||
m_pimpl->m_query_parameters = values;
|
||||
}
|
||||
}
|
||||
207
lib/restbed-4.8/source/corvusoft/restbed/request.hpp
Normal file
207
lib/restbed-4.8/source/corvusoft/restbed/request.hpp
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
//Project Includes
|
||||
#include <corvusoft/restbed/byte.hpp>
|
||||
#include <corvusoft/restbed/common.hpp>
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define REQUEST_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define REQUEST_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define REQUEST_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Uri;
|
||||
class Http;
|
||||
class Session;
|
||||
class Response;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class HttpImpl;
|
||||
class SessionImpl;
|
||||
class ServiceImpl;
|
||||
struct RequestImpl;
|
||||
class WebSocketManagerImpl;
|
||||
}
|
||||
|
||||
class REQUEST_EXPORT Request
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Request( void );
|
||||
|
||||
Request( const Uri& value );
|
||||
|
||||
virtual ~Request( void );
|
||||
|
||||
//Functionality
|
||||
bool has_header( const std::string& name ) const;
|
||||
|
||||
bool has_path_parameter( const std::string& name ) const;
|
||||
|
||||
bool has_query_parameter( const std::string& name ) const;
|
||||
|
||||
//Getters
|
||||
uint16_t get_port( void ) const;
|
||||
|
||||
double get_version( void ) const;
|
||||
|
||||
const Bytes& get_body( void ) const;
|
||||
|
||||
const std::shared_ptr< const Response > get_response( void ) const;
|
||||
|
||||
std::string get_host( const std::function< std::string ( const std::string& ) >& transform = nullptr ) const;
|
||||
|
||||
std::string get_path( const std::function< std::string ( const std::string& ) >& transform = nullptr ) const;
|
||||
|
||||
std::string get_method( const std::function< std::string ( const std::string& ) >& transform = nullptr ) const;
|
||||
|
||||
std::string get_protocol( const std::function< std::string ( const std::string& ) >& transform = nullptr ) const;
|
||||
|
||||
void get_body( std::string& body, const std::function< std::string ( const Bytes& ) >& transform = nullptr ) const;
|
||||
|
||||
std::string get_header( const std::string& name, const std::string& default_value = "" ) const;
|
||||
|
||||
std::string get_header( const std::string& name, const std::function< std::string ( const std::string& ) >& transform ) const;
|
||||
|
||||
template <typename Type, std::enable_if_t< std::is_arithmetic< std::remove_reference_t< Type > >::value > * = nullptr> inline
|
||||
Type get_header( const std::string& name, const Type default_value ) const
|
||||
{
|
||||
return Common::parse_parameter( get_header( name ), default_value );
|
||||
}
|
||||
|
||||
std::multimap< std::string, std::string > get_headers( const std::string& name = "" ) const;
|
||||
|
||||
std::string get_query_parameter( const std::string& name, const std::string& default_value = "" ) const;
|
||||
|
||||
std::string get_query_parameter( const std::string& name, const std::function< std::string ( const std::string& ) >& transform ) const;
|
||||
|
||||
template <typename Type, std::enable_if_t< std::is_arithmetic< std::remove_reference_t< Type > >::value > * = nullptr> inline
|
||||
Type get_query_parameter( const std::string& name, const Type default_value ) const
|
||||
{
|
||||
return Common::parse_parameter( get_query_parameter( name ), default_value );
|
||||
}
|
||||
|
||||
std::multimap< std::string, std::string > get_query_parameters( const std::string& name = "" ) const;
|
||||
|
||||
std::string get_path_parameter( const std::string& name, const std::string& default_value = "" ) const;
|
||||
|
||||
std::string get_path_parameter( const std::string& name, const std::function< std::string ( const std::string& ) >& transform ) const;
|
||||
|
||||
template <typename Type, std::enable_if_t< std::is_arithmetic< std::remove_reference_t< Type > >::value > * = nullptr> inline
|
||||
Type get_path_parameter( const std::string& name, const Type default_value ) const
|
||||
{
|
||||
return Common::parse_parameter( get_path_parameter( name ), default_value );
|
||||
}
|
||||
|
||||
std::map< std::string, std::string > get_path_parameters( const std::string& name = "" ) const;
|
||||
|
||||
//Setters
|
||||
void set_body( const Bytes& value );
|
||||
|
||||
void set_body( const std::string& value );
|
||||
|
||||
void set_port( const uint16_t value );
|
||||
|
||||
void set_version( const double value );
|
||||
|
||||
void set_path( const std::string& value );
|
||||
|
||||
void set_host( const std::string& value );
|
||||
|
||||
void set_method( const std::string& value );
|
||||
|
||||
void set_protocol( const std::string& value );
|
||||
|
||||
void add_header( const std::string& name, const std::string& value );
|
||||
|
||||
void set_header( const std::string& name, const std::string& value );
|
||||
|
||||
void set_headers( const std::multimap< std::string, std::string >& values );
|
||||
|
||||
void set_query_parameter( const std::string& name, const std::string& value );
|
||||
|
||||
void set_query_parameters( const std::multimap< std::string, std::string >& values );
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
friend Http;
|
||||
friend Session;
|
||||
friend detail::HttpImpl;
|
||||
friend detail::SessionImpl;
|
||||
friend detail::ServiceImpl;
|
||||
friend detail::WebSocketManagerImpl;
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Request( const Request& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
Request& operator =( const Request& value ) = delete;
|
||||
|
||||
//Properties
|
||||
std::unique_ptr< detail::RequestImpl > m_pimpl;
|
||||
};
|
||||
}
|
||||
126
lib/restbed-4.8/source/corvusoft/restbed/resource.cpp
Normal file
126
lib/restbed-4.8/source/corvusoft/restbed/resource.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/rule.hpp"
|
||||
#include "corvusoft/restbed/session.hpp"
|
||||
#include "corvusoft/restbed/resource.hpp"
|
||||
#include "corvusoft/restbed/detail/resource_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::set;
|
||||
using std::string;
|
||||
using std::multimap;
|
||||
using std::function;
|
||||
using std::exception;
|
||||
using std::unique_ptr;
|
||||
using std::shared_ptr;
|
||||
using std::invalid_argument;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::ResourceImpl;
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
Resource::Resource( void ) : m_pimpl( new ResourceImpl )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Resource::~Resource( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void Resource::add_rule( const shared_ptr< Rule >& rule )
|
||||
{
|
||||
if ( rule not_eq nullptr )
|
||||
{
|
||||
m_pimpl->m_rules.push_back( rule );
|
||||
|
||||
stable_sort( m_pimpl->m_rules.begin( ), m_pimpl->m_rules.end( ), [ ]( const shared_ptr< const Rule >& lhs, const shared_ptr< const Rule >& rhs )
|
||||
{
|
||||
return lhs->get_priority( ) < rhs->get_priority( );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::add_rule( const shared_ptr< Rule >& rule, const int priority )
|
||||
{
|
||||
if ( rule not_eq nullptr )
|
||||
{
|
||||
rule->set_priority( priority );
|
||||
add_rule( rule );
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::set_path( const string& value )
|
||||
{
|
||||
m_pimpl->m_paths = { value };
|
||||
}
|
||||
|
||||
void Resource::set_paths( const set< string >& values )
|
||||
{
|
||||
m_pimpl->m_paths = values;
|
||||
}
|
||||
|
||||
void Resource::set_default_header( const string& name, const string& value )
|
||||
{
|
||||
m_pimpl->m_default_headers.insert( make_pair( name, value ) );
|
||||
}
|
||||
|
||||
void Resource::set_default_headers( const multimap< string, string >& values )
|
||||
{
|
||||
m_pimpl->m_default_headers = values;
|
||||
}
|
||||
|
||||
void Resource::set_failed_filter_validation_handler( const function< void ( const shared_ptr< Session > ) >& value )
|
||||
{
|
||||
m_pimpl->m_failed_filter_validation_handler = value;
|
||||
}
|
||||
|
||||
void Resource::set_error_handler( const function< void ( const int, const exception&, const shared_ptr< Session > ) >& value )
|
||||
{
|
||||
m_pimpl->m_error_handler = value;
|
||||
}
|
||||
|
||||
void Resource::set_authentication_handler( const function< void ( const shared_ptr< Session >, const function< void ( const shared_ptr< Session > ) >& ) >& value )
|
||||
{
|
||||
m_pimpl->m_authentication_handler = value;
|
||||
}
|
||||
|
||||
void Resource::set_method_handler( const string& method, const function< void ( const shared_ptr< Session > ) >& callback )
|
||||
{
|
||||
static const multimap< string, string > empty { };
|
||||
set_method_handler( method, empty, callback );
|
||||
}
|
||||
|
||||
void Resource::set_method_handler( const string& method, const multimap< string, string >& filters, const function< void ( const shared_ptr< Session > ) >& callback )
|
||||
{
|
||||
if ( method.empty( ) )
|
||||
{
|
||||
throw invalid_argument( "Attempt to set resource handler to an empty protocol method." );
|
||||
}
|
||||
|
||||
if ( callback not_eq nullptr )
|
||||
{
|
||||
m_pimpl->m_methods.insert( method );
|
||||
m_pimpl->m_method_handlers.insert( make_pair( method, make_pair( filters, callback ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
130
lib/restbed-4.8/source/corvusoft/restbed/resource.hpp
Normal file
130
lib/restbed-4.8/source/corvusoft/restbed/resource.hpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define RESOURCE_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define RESOURCE_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define RESOURCE_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Rule;
|
||||
class Session;
|
||||
class Service;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class SessionImpl;
|
||||
class ServiceImpl;
|
||||
struct ResourceImpl;
|
||||
}
|
||||
|
||||
class RESOURCE_EXPORT Resource
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Resource( void );
|
||||
|
||||
virtual ~Resource( void );
|
||||
|
||||
//Functionality
|
||||
void add_rule( const std::shared_ptr< Rule >& rule );
|
||||
|
||||
void add_rule( const std::shared_ptr< Rule >& rule, const int priority );
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
void set_path( const std::string& value );
|
||||
|
||||
void set_paths( const std::set< std::string >& values );
|
||||
|
||||
void set_default_header( const std::string& name, const std::string& value );
|
||||
|
||||
void set_default_headers( const std::multimap< std::string, std::string >& values );
|
||||
|
||||
void set_failed_filter_validation_handler( const std::function< void ( const std::shared_ptr< Session > ) >& value );
|
||||
|
||||
void set_error_handler( const std::function< void ( const int, const std::exception&, const std::shared_ptr< Session > ) >& value );
|
||||
|
||||
void set_authentication_handler( const std::function< void ( const std::shared_ptr< Session >, const std::function< void ( const std::shared_ptr< Session > ) >& ) >& value );
|
||||
|
||||
void set_method_handler( const std::string& method, const std::function< void ( const std::shared_ptr< Session > ) >& callback );
|
||||
|
||||
void set_method_handler( const std::string& method, const std::multimap< std::string, std::string >& filters, const std::function< void ( const std::shared_ptr< Session > ) >& callback );
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
friend Service;
|
||||
friend detail::ServiceImpl;
|
||||
friend detail::SessionImpl;
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Resource( const Resource& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
Resource& operator =( const Resource& value ) = delete;
|
||||
|
||||
//Properties
|
||||
std::unique_ptr< detail::ResourceImpl > m_pimpl;
|
||||
};
|
||||
}
|
||||
157
lib/restbed-4.8/source/corvusoft/restbed/response.cpp
Normal file
157
lib/restbed-4.8/source/corvusoft/restbed/response.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <utility>
|
||||
#include <ciso646>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/string.hpp"
|
||||
#include "corvusoft/restbed/request.hpp"
|
||||
#include "corvusoft/restbed/response.hpp"
|
||||
#include "corvusoft/restbed/detail/response_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::map;
|
||||
using std::pair;
|
||||
using std::string;
|
||||
using std::function;
|
||||
using std::multimap;
|
||||
using std::unique_ptr;
|
||||
using std::shared_ptr;
|
||||
using std::invalid_argument;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::Common;
|
||||
using restbed::Request;
|
||||
using restbed::detail::ResponseImpl;
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
Response::Response( void ) : m_pimpl( new ResponseImpl )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Response::~Response( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool Response::has_header( const string& name ) const
|
||||
{
|
||||
return Common::has_parameter( name, m_pimpl->m_headers );
|
||||
}
|
||||
|
||||
Bytes Response::get_body( void ) const
|
||||
{
|
||||
return m_pimpl->m_body;
|
||||
}
|
||||
|
||||
double Response::get_version( void ) const
|
||||
{
|
||||
return m_pimpl->m_version;
|
||||
}
|
||||
|
||||
int Response::get_status_code( void ) const
|
||||
{
|
||||
return m_pimpl->m_status_code;
|
||||
}
|
||||
|
||||
string Response::get_protocol( void ) const
|
||||
{
|
||||
return m_pimpl->m_protocol;
|
||||
}
|
||||
|
||||
string Response::get_status_message( void ) const
|
||||
{
|
||||
return m_pimpl->m_status_message;
|
||||
}
|
||||
|
||||
void Response::get_body( string& body, const function< string ( const Bytes& ) >& transform ) const
|
||||
{
|
||||
body = ( transform == nullptr ) ? string( m_pimpl->m_body.begin( ), m_pimpl->m_body.end( ) ) : transform( m_pimpl->m_body );
|
||||
}
|
||||
|
||||
string Response::get_header( const string& name, const string& default_value ) const
|
||||
{
|
||||
if ( name.empty( ) )
|
||||
{
|
||||
return default_value;
|
||||
}
|
||||
|
||||
const auto headers = Common::get_parameters( name, m_pimpl->m_headers );
|
||||
return ( headers.empty( ) ) ? default_value : headers.begin( )->second;
|
||||
}
|
||||
|
||||
string Response::get_header( const string& name, const function< string ( const string& ) >& transform ) const
|
||||
{
|
||||
if ( name.empty( ) )
|
||||
{
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
const auto headers = Common::get_parameters( name, m_pimpl->m_headers );
|
||||
const auto value = ( headers.empty( ) ) ? String::empty : headers.begin( )->second;
|
||||
|
||||
return Common::transform( value, transform );
|
||||
}
|
||||
|
||||
multimap< string, string > Response::get_headers( const string& name ) const
|
||||
{
|
||||
return Common::get_parameters( name, m_pimpl->m_headers );
|
||||
}
|
||||
|
||||
void Response::set_body( const Bytes& value )
|
||||
{
|
||||
m_pimpl->m_body = value;
|
||||
}
|
||||
|
||||
void Response::set_body( const string& value )
|
||||
{
|
||||
m_pimpl->m_body = String::to_bytes( value );
|
||||
}
|
||||
|
||||
void Response::set_version( const double value )
|
||||
{
|
||||
m_pimpl->m_version = value;
|
||||
}
|
||||
|
||||
void Response::set_status_code( const int value )
|
||||
{
|
||||
m_pimpl->m_status_code = value;
|
||||
}
|
||||
|
||||
void Response::set_protocol( const string& value )
|
||||
{
|
||||
m_pimpl->m_protocol = value;
|
||||
}
|
||||
|
||||
void Response::set_status_message( const string& value )
|
||||
{
|
||||
m_pimpl->m_status_message = value;
|
||||
}
|
||||
|
||||
void Response::add_header( const string& name, const string& value )
|
||||
{
|
||||
m_pimpl->m_headers.insert( make_pair( name, value ) );
|
||||
}
|
||||
|
||||
void Response::set_header( const string& name, const string& value )
|
||||
{
|
||||
m_pimpl->m_headers.erase( name );
|
||||
m_pimpl->m_headers.insert( make_pair( name, value ) );
|
||||
}
|
||||
|
||||
void Response::set_headers( const multimap< string, string >& values )
|
||||
{
|
||||
m_pimpl->m_headers = values;
|
||||
}
|
||||
}
|
||||
149
lib/restbed-4.8/source/corvusoft/restbed/response.hpp
Normal file
149
lib/restbed-4.8/source/corvusoft/restbed/response.hpp
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
//Project Includes
|
||||
#include <corvusoft/restbed/byte.hpp>
|
||||
#include <corvusoft/restbed/common.hpp>
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define RESPONSE_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define RESPONSE_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define RESPONSE_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Http;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct ResponseImpl;
|
||||
}
|
||||
|
||||
class RESPONSE_EXPORT Response
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Response( void );
|
||||
|
||||
virtual ~Response( void );
|
||||
|
||||
//Functionality
|
||||
bool has_header( const std::string& name ) const;
|
||||
|
||||
//Getters
|
||||
Bytes get_body( void ) const;
|
||||
|
||||
double get_version( void ) const;
|
||||
|
||||
int get_status_code( void ) const;
|
||||
|
||||
std::string get_protocol( void ) const;
|
||||
|
||||
std::string get_status_message( void ) const;
|
||||
|
||||
void get_body( std::string& body, const std::function< std::string ( const Bytes& ) >& transform = nullptr ) const;
|
||||
|
||||
template< typename Type, typename std::enable_if< std::is_arithmetic< Type >::value, Type >::type = 0 >
|
||||
Type get_header( const std::string& name, const Type default_value ) const
|
||||
{
|
||||
return Common::parse_parameter( get_header( name ), default_value );
|
||||
}
|
||||
|
||||
std::string get_header( const std::string& name, const std::string& default_value ) const;
|
||||
|
||||
std::string get_header( const std::string& name, const std::function< std::string ( const std::string& ) >& transform = nullptr ) const;
|
||||
|
||||
std::multimap< std::string, std::string > get_headers( const std::string& name = "" ) const;
|
||||
|
||||
//Setters
|
||||
void set_body( const Bytes& value );
|
||||
|
||||
void set_body( const std::string& value );
|
||||
|
||||
void set_version( const double value );
|
||||
|
||||
void set_status_code( const int value );
|
||||
|
||||
void set_protocol( const std::string& protocol );
|
||||
|
||||
void set_status_message( const std::string& value );
|
||||
|
||||
void add_header( const std::string& name, const std::string& value );
|
||||
|
||||
void set_header( const std::string& name, const std::string& value );
|
||||
|
||||
void set_headers( const std::multimap< std::string, std::string >& values );
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
friend Http;
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Response( const Response& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
Response& operator =( const Response& value ) = delete;
|
||||
|
||||
//Properties
|
||||
std::unique_ptr< detail::ResponseImpl > m_pimpl;
|
||||
};
|
||||
}
|
||||
48
lib/restbed-4.8/source/corvusoft/restbed/rule.cpp
Normal file
48
lib/restbed-4.8/source/corvusoft/restbed/rule.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/rule.hpp"
|
||||
#include "corvusoft/restbed/detail/rule_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::unique_ptr;
|
||||
using std::shared_ptr;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::RuleImpl;
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
bool Rule::condition( const shared_ptr< Session > )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int Rule::get_priority( void ) const
|
||||
{
|
||||
return m_pimpl->m_priority;
|
||||
}
|
||||
|
||||
void Rule::set_priority( const int value )
|
||||
{
|
||||
m_pimpl->m_priority = value;
|
||||
}
|
||||
|
||||
Rule::Rule( void ) : m_pimpl( new RuleImpl )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Rule::~Rule( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
106
lib/restbed-4.8/source/corvusoft/restbed/rule.hpp
Normal file
106
lib/restbed-4.8/source/corvusoft/restbed/rule.hpp
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define RULE_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define RULE_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define RULE_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Session;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct RuleImpl;
|
||||
}
|
||||
|
||||
class RULE_EXPORT Rule
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
virtual bool condition( const std::shared_ptr< Session > session );
|
||||
|
||||
virtual void action( const std::shared_ptr< Session > session, const std::function< void ( const std::shared_ptr< Session > ) >& callback ) = 0;
|
||||
|
||||
//Getters
|
||||
int get_priority( void ) const;
|
||||
|
||||
//Setters
|
||||
void set_priority( const int value );
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Rule( void );
|
||||
|
||||
virtual ~Rule( void );
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
explicit Rule( const Rule& ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
Rule& operator =( const Rule& ) = delete;
|
||||
|
||||
//Properties
|
||||
std::unique_ptr< detail::RuleImpl > m_pimpl;
|
||||
};
|
||||
}
|
||||
479
lib/restbed-4.8/source/corvusoft/restbed/service.cpp
Normal file
479
lib/restbed-4.8/source/corvusoft/restbed/service.cpp
Normal file
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
#include <ciso646>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/uri.hpp"
|
||||
#include "corvusoft/restbed/rule.hpp"
|
||||
#include "corvusoft/restbed/logger.hpp"
|
||||
#include "corvusoft/restbed/service.hpp"
|
||||
#include "corvusoft/restbed/session.hpp"
|
||||
#include "corvusoft/restbed/resource.hpp"
|
||||
#include "corvusoft/restbed/settings.hpp"
|
||||
#include "corvusoft/restbed/ssl_settings.hpp"
|
||||
#include "corvusoft/restbed/session_manager.hpp"
|
||||
#include "corvusoft/restbed/detail/service_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/resource_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/web_socket_manager_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
#include <asio/io_service.hpp>
|
||||
#include <asio/steady_timer.hpp>
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
#include <asio/ssl.hpp>
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
using std::map;
|
||||
using std::bind;
|
||||
using std::promise;
|
||||
using std::future;
|
||||
using std::future_status;
|
||||
using std::async;
|
||||
using std::launch;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::function;
|
||||
using std::exception;
|
||||
using std::to_string;
|
||||
using std::unique_ptr;
|
||||
using std::shared_ptr;
|
||||
using std::error_code;
|
||||
using std::make_shared;
|
||||
using std::stable_sort;
|
||||
using std::runtime_error;
|
||||
using std::chrono::seconds;
|
||||
using std::invalid_argument;
|
||||
using std::chrono::milliseconds;
|
||||
using std::chrono::steady_clock;
|
||||
using std::chrono::duration_cast;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::ServiceImpl;
|
||||
using restbed::detail::WebSocketManagerImpl;
|
||||
|
||||
//External Namespaces
|
||||
using asio::io_service;
|
||||
using asio::steady_timer;
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
Service::Service( void ) : m_pimpl( new ServiceImpl )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Service::~Service( void )
|
||||
{
|
||||
try
|
||||
{
|
||||
stop( );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
m_pimpl->log( Logger::WARNING, "Service failed graceful wind down." );
|
||||
}
|
||||
}
|
||||
|
||||
bool Service::is_up( void ) const
|
||||
{
|
||||
return m_pimpl->m_uptime not_eq steady_clock::time_point::min( );
|
||||
}
|
||||
|
||||
bool Service::is_down( void ) const
|
||||
{
|
||||
return not is_up( );
|
||||
}
|
||||
|
||||
void Service::stop( void )
|
||||
{
|
||||
m_pimpl->m_uptime = steady_clock::time_point::min( );
|
||||
|
||||
if ( m_pimpl->m_io_service not_eq nullptr )
|
||||
{
|
||||
m_pimpl->m_io_service->stop( );
|
||||
}
|
||||
|
||||
if ( m_pimpl->m_session_manager not_eq nullptr )
|
||||
{
|
||||
m_pimpl->m_session_manager->stop( );
|
||||
}
|
||||
|
||||
if ( m_pimpl->m_workers_stopped )
|
||||
{
|
||||
m_pimpl->m_workers_stopped->wait_for( seconds( 1 ) );
|
||||
m_pimpl->m_workers_stopped.reset( );
|
||||
}
|
||||
|
||||
if ( m_pimpl->m_logger not_eq nullptr )
|
||||
{
|
||||
m_pimpl->log( Logger::INFO, "Service halted." );
|
||||
m_pimpl->m_logger->stop( );
|
||||
}
|
||||
}
|
||||
|
||||
void Service::start( const shared_ptr< const Settings >& settings )
|
||||
{
|
||||
m_pimpl->setup_signal_handler( );
|
||||
|
||||
m_pimpl->m_settings = settings;
|
||||
|
||||
if ( m_pimpl->m_settings == nullptr )
|
||||
{
|
||||
m_pimpl->m_settings = make_shared< Settings >( );
|
||||
}
|
||||
|
||||
#ifdef BUILD_SSL
|
||||
m_pimpl->m_ssl_settings = m_pimpl->m_settings->get_ssl_settings( );
|
||||
#else
|
||||
|
||||
if ( m_pimpl->m_settings->get_ssl_settings( ) not_eq nullptr )
|
||||
{
|
||||
throw runtime_error( "Not Implemented! Rebuild Restbed with SSL functionality enabled." );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if ( m_pimpl->m_logger not_eq nullptr )
|
||||
{
|
||||
m_pimpl->m_logger->start( m_pimpl->m_settings );
|
||||
}
|
||||
|
||||
if ( m_pimpl->m_session_manager == nullptr )
|
||||
{
|
||||
m_pimpl->m_session_manager = make_shared< SessionManager >( );
|
||||
}
|
||||
|
||||
m_pimpl->m_session_manager->start( m_pimpl->m_settings );
|
||||
|
||||
m_pimpl->m_web_socket_manager = make_shared< WebSocketManagerImpl >( );
|
||||
|
||||
stable_sort( m_pimpl->m_rules.begin( ), m_pimpl->m_rules.end( ), [ ]( const shared_ptr< const Rule >& lhs, const shared_ptr< const Rule >& rhs )
|
||||
{
|
||||
return lhs->get_priority( ) < rhs->get_priority( );
|
||||
} );
|
||||
|
||||
#ifdef BUILD_IPC
|
||||
m_pimpl->ipc_start( );
|
||||
#endif
|
||||
m_pimpl->http_start( );
|
||||
#ifdef BUILD_SSL
|
||||
m_pimpl->https_start( );
|
||||
#endif
|
||||
for ( const auto& route : m_pimpl->m_resource_paths )
|
||||
{
|
||||
auto path = String::format( "/%s/%s", m_pimpl->m_settings->get_root( ).data( ), route.second.data( ) );
|
||||
path = String::replace( "//", "/", path );
|
||||
|
||||
m_pimpl->log( Logger::INFO, String::format( "Resource published on route '%s'.", path.data( ) ) );
|
||||
}
|
||||
|
||||
if ( m_pimpl->m_ready_handler not_eq nullptr )
|
||||
{
|
||||
m_pimpl->m_io_service->post( m_pimpl->m_ready_handler );
|
||||
}
|
||||
|
||||
m_pimpl->m_uptime = steady_clock::now( );
|
||||
unsigned int limit = m_pimpl->m_settings->get_worker_limit( );
|
||||
|
||||
if ( limit == 0 )
|
||||
{
|
||||
m_pimpl->m_io_service->run( );
|
||||
}
|
||||
else
|
||||
{
|
||||
promise<void> all_signalled;
|
||||
m_pimpl->m_workers_stopped = unique_ptr<future<void> >(new future<void>(all_signalled.get_future()));
|
||||
vector<future<void> > signals;
|
||||
for ( unsigned int count = 0; count < limit; count++ )
|
||||
{
|
||||
signals.push_back( async(launch::async, [ this ]( )
|
||||
{
|
||||
m_pimpl->m_io_service->run( );
|
||||
} ) );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
while (!signals.empty())
|
||||
{
|
||||
signals.erase(std::remove_if(signals.begin(), signals.end(),
|
||||
[](future<void>& signal) {
|
||||
return (signal.wait_for(milliseconds(5)) == future_status::ready) ?
|
||||
(signal.get(), true) : // this will throw if the worker thread ended with an exception
|
||||
false;
|
||||
}),
|
||||
signals.end());
|
||||
}
|
||||
all_signalled.set_value();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
m_pimpl->m_io_service->stop( );
|
||||
all_signalled.set_value();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Service::restart( const shared_ptr< const Settings >& settings )
|
||||
{
|
||||
try
|
||||
{
|
||||
stop( );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
m_pimpl->log( Logger::WARNING, "Service failed graceful reboot." );
|
||||
}
|
||||
|
||||
start( settings );
|
||||
}
|
||||
|
||||
void Service::add_rule( const shared_ptr< Rule >& rule )
|
||||
{
|
||||
if ( is_up( ) )
|
||||
{
|
||||
throw runtime_error( "Runtime modifications of the service are prohibited." );
|
||||
}
|
||||
|
||||
if ( rule not_eq nullptr )
|
||||
{
|
||||
m_pimpl->m_rules.push_back( rule );
|
||||
}
|
||||
}
|
||||
|
||||
void Service::add_rule( const shared_ptr< Rule >& rule, const int priority )
|
||||
{
|
||||
if ( is_up( ) )
|
||||
{
|
||||
throw runtime_error( "Runtime modifications of the service are prohibited." );
|
||||
}
|
||||
|
||||
if ( rule not_eq nullptr )
|
||||
{
|
||||
rule->set_priority( priority );
|
||||
m_pimpl->m_rules.push_back( rule );
|
||||
}
|
||||
}
|
||||
|
||||
void Service::publish( const shared_ptr< const Resource >& resource )
|
||||
{
|
||||
if ( is_up( ) )
|
||||
{
|
||||
throw runtime_error( "Runtime modifications of the service are prohibited." );
|
||||
}
|
||||
|
||||
if ( resource == nullptr )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto paths = resource->m_pimpl->m_paths;
|
||||
|
||||
if ( not m_pimpl->has_unique_paths( paths ) )
|
||||
{
|
||||
throw invalid_argument( "Resource would pollute namespace. Please ensure all published resources have unique paths." );
|
||||
}
|
||||
|
||||
for ( auto& path : paths )
|
||||
{
|
||||
const string sanitised_path = m_pimpl->sanitise_path( path );
|
||||
|
||||
m_pimpl->m_resource_paths[ sanitised_path ] = path;
|
||||
m_pimpl->m_resource_routes[ sanitised_path ] = resource;
|
||||
}
|
||||
|
||||
const auto& methods = resource->m_pimpl->m_methods;
|
||||
m_pimpl->m_supported_methods.insert( methods.begin( ), methods.end( ) );
|
||||
}
|
||||
|
||||
void Service::suppress( const shared_ptr< const Resource >& resource )
|
||||
{
|
||||
if ( is_up( ) )
|
||||
{
|
||||
throw runtime_error( "Runtime modifications of the service are prohibited." );
|
||||
}
|
||||
|
||||
if ( resource == nullptr )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for ( const auto& path : resource->m_pimpl->m_paths )
|
||||
{
|
||||
if ( m_pimpl->m_resource_routes.erase( path ) )
|
||||
{
|
||||
m_pimpl->log( Logger::INFO, String::format( "Suppressed resource route '%s'.", path.data( ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pimpl->log( Logger::WARNING, String::format( "Failed to suppress resource route '%s'; Not Found!", path.data( ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Service::schedule( const function< void ( void ) >& task, const milliseconds& interval )
|
||||
{
|
||||
if ( task == nullptr )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( interval == milliseconds::zero( ) )
|
||||
{
|
||||
m_pimpl->m_io_service->post( task );
|
||||
return;
|
||||
}
|
||||
|
||||
auto timer = make_shared< steady_timer >( *m_pimpl->m_io_service );
|
||||
timer->expires_from_now( interval );
|
||||
timer->async_wait( [ this, task, interval, timer ]( const error_code& )
|
||||
{
|
||||
task( );
|
||||
schedule( task, interval );
|
||||
} );
|
||||
}
|
||||
|
||||
const seconds Service::get_uptime( void ) const
|
||||
{
|
||||
if ( is_down( ) )
|
||||
{
|
||||
return seconds( 0 );
|
||||
}
|
||||
|
||||
return duration_cast< seconds >( steady_clock::now( ) - m_pimpl->m_uptime );
|
||||
}
|
||||
|
||||
const shared_ptr< const Uri > Service::get_http_uri( void ) const
|
||||
{
|
||||
return m_pimpl->get_http_uri( );
|
||||
}
|
||||
|
||||
const shared_ptr< const Uri > Service::get_https_uri( void ) const
|
||||
{
|
||||
return m_pimpl->get_https_uri( );
|
||||
}
|
||||
|
||||
void Service::set_logger( const shared_ptr< Logger >& value )
|
||||
{
|
||||
if ( is_up( ) )
|
||||
{
|
||||
throw runtime_error( "Runtime modifications of the service are prohibited." );
|
||||
}
|
||||
|
||||
m_pimpl->m_logger = value;
|
||||
}
|
||||
|
||||
void Service::set_session_manager( const shared_ptr< SessionManager >& value )
|
||||
{
|
||||
if ( is_up( ) )
|
||||
{
|
||||
throw runtime_error( "Runtime modifications of the service are prohibited." );
|
||||
}
|
||||
|
||||
m_pimpl->m_session_manager = value;
|
||||
}
|
||||
|
||||
void Service::set_ready_handler( const function< void ( Service& ) >& value )
|
||||
{
|
||||
if ( is_up( ) )
|
||||
{
|
||||
throw runtime_error( "Runtime modifications of the service are prohibited." );
|
||||
}
|
||||
|
||||
if ( value not_eq nullptr )
|
||||
{
|
||||
m_pimpl->m_ready_handler = bind( value, std::ref( *this ) );
|
||||
}
|
||||
}
|
||||
|
||||
void Service::set_signal_handler( const int signal, const function< void ( const int ) >& value )
|
||||
{
|
||||
if ( is_up( ) )
|
||||
{
|
||||
throw runtime_error( "Runtime modifications of the service are prohibited." );
|
||||
}
|
||||
|
||||
if ( value not_eq nullptr )
|
||||
{
|
||||
m_pimpl->m_signal_handlers[ signal ] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void Service::set_not_found_handler( const function< void ( const shared_ptr< Session > ) >& value )
|
||||
{
|
||||
if ( is_up( ) )
|
||||
{
|
||||
throw runtime_error( "Runtime modifications of the service are prohibited." );
|
||||
}
|
||||
|
||||
m_pimpl->m_not_found_handler = value;
|
||||
}
|
||||
|
||||
void Service::set_method_not_allowed_handler( const function< void ( const shared_ptr< Session > ) >& value )
|
||||
{
|
||||
if ( is_up( ) )
|
||||
{
|
||||
throw runtime_error( "Runtime modifications of the service are prohibited." );
|
||||
}
|
||||
|
||||
m_pimpl->m_method_not_allowed_handler = value;
|
||||
}
|
||||
|
||||
void Service::set_method_not_implemented_handler( const function< void ( const shared_ptr< Session > ) >& value )
|
||||
{
|
||||
if ( is_up( ) )
|
||||
{
|
||||
throw runtime_error( "Runtime modifications of the service are prohibited." );
|
||||
}
|
||||
|
||||
m_pimpl->m_method_not_implemented_handler = value;
|
||||
}
|
||||
|
||||
void Service::set_failed_filter_validation_handler( const function< void ( const shared_ptr< Session > ) >& value )
|
||||
{
|
||||
if ( is_up( ) )
|
||||
{
|
||||
throw runtime_error( "Runtime modifications of the service are prohibited." );
|
||||
}
|
||||
|
||||
m_pimpl->m_failed_filter_validation_handler = value;
|
||||
}
|
||||
|
||||
void Service::set_error_handler( const function< void ( const int, const exception&, const shared_ptr< Session > ) >& value )
|
||||
{
|
||||
if ( is_up( ) )
|
||||
{
|
||||
throw runtime_error( "Runtime modifications of the service are prohibited." );
|
||||
}
|
||||
|
||||
if ( value == nullptr )
|
||||
{
|
||||
m_pimpl->m_error_handler = ServiceImpl::default_error_handler;
|
||||
}
|
||||
|
||||
m_pimpl->m_error_handler = value;
|
||||
}
|
||||
|
||||
void Service::set_authentication_handler( const function< void ( const shared_ptr< Session >, const function< void ( const shared_ptr< Session > ) >& ) >& value )
|
||||
{
|
||||
if ( is_up( ) )
|
||||
{
|
||||
throw runtime_error( "Runtime modifications of the service are prohibited." );
|
||||
}
|
||||
|
||||
m_pimpl->m_authentication_handler = value;
|
||||
}
|
||||
}
|
||||
154
lib/restbed-4.8/source/corvusoft/restbed/service.hpp
Normal file
154
lib/restbed-4.8/source/corvusoft/restbed/service.hpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define SERVICE_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define SERVICE_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define SERVICE_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Uri;
|
||||
class Rule;
|
||||
class Logger;
|
||||
class Session;
|
||||
class Resource;
|
||||
class Settings;
|
||||
class SessionManager;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class ServiceImpl;
|
||||
}
|
||||
|
||||
class SERVICE_EXPORT Service
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Service( void );
|
||||
|
||||
virtual ~Service( void );
|
||||
|
||||
//Functionality
|
||||
bool is_up( void ) const;
|
||||
|
||||
bool is_down( void ) const;
|
||||
|
||||
void stop( void );
|
||||
|
||||
void start( const std::shared_ptr< const Settings >& settings = nullptr );
|
||||
|
||||
void restart( const std::shared_ptr< const Settings >& settings = nullptr );
|
||||
|
||||
void add_rule( const std::shared_ptr< Rule >& rule );
|
||||
|
||||
void add_rule( const std::shared_ptr< Rule >& rule, const int priority );
|
||||
|
||||
void publish( const std::shared_ptr< const Resource >& resource );
|
||||
|
||||
void suppress( const std::shared_ptr< const Resource >& resource );
|
||||
|
||||
void schedule( const std::function< void ( void ) >& task, const std::chrono::milliseconds& interval = std::chrono::milliseconds::zero( ) );
|
||||
|
||||
//Getters
|
||||
const std::chrono::seconds get_uptime( void ) const;
|
||||
|
||||
const std::shared_ptr< const Uri > get_http_uri( void ) const;
|
||||
|
||||
const std::shared_ptr< const Uri > get_https_uri( void ) const;
|
||||
|
||||
//Setters
|
||||
void set_logger( const std::shared_ptr< Logger >& value );
|
||||
|
||||
void set_session_manager( const std::shared_ptr< SessionManager >& value );
|
||||
|
||||
void set_ready_handler( const std::function< void ( Service& ) >& value );
|
||||
|
||||
void set_signal_handler( const int signal, const std::function< void ( const int ) >& value );
|
||||
|
||||
void set_not_found_handler( const std::function< void ( const std::shared_ptr< Session > ) >& value );
|
||||
|
||||
void set_method_not_allowed_handler( const std::function< void ( const std::shared_ptr< Session > ) >& value );
|
||||
|
||||
void set_method_not_implemented_handler( const std::function< void ( const std::shared_ptr< Session > ) >& value );
|
||||
|
||||
void set_failed_filter_validation_handler( const std::function< void ( const std::shared_ptr< Session > ) >& value );
|
||||
|
||||
void set_error_handler( const std::function< void ( const int, const std::exception&, const std::shared_ptr< Session > ) >& value );
|
||||
|
||||
void set_authentication_handler( const std::function< void ( const std::shared_ptr< Session >, const std::function< void ( const std::shared_ptr< Session > ) >& ) >& value );
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Service( const Service& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
Service& operator =( const Service& value ) = delete;
|
||||
|
||||
//Properties
|
||||
std::unique_ptr< detail::ServiceImpl > m_pimpl;
|
||||
};
|
||||
}
|
||||
476
lib/restbed-4.8/source/corvusoft/restbed/session.cpp
Normal file
476
lib/restbed-4.8/source/corvusoft/restbed/session.cpp
Normal file
@@ -0,0 +1,476 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <ciso646>
|
||||
#include <system_error>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/session.hpp"
|
||||
#include "corvusoft/restbed/request.hpp"
|
||||
#include "corvusoft/restbed/response.hpp"
|
||||
#include "corvusoft/restbed/web_socket.hpp"
|
||||
#include "corvusoft/restbed/context_value.hpp"
|
||||
#include "corvusoft/restbed/session_manager.hpp"
|
||||
#include "corvusoft/restbed/detail/socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/request_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/session_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/web_socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/web_socket_manager_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
#include <asio/buffer.hpp>
|
||||
|
||||
//System Namespaces
|
||||
using std::set;
|
||||
using std::string;
|
||||
using std::function;
|
||||
using std::multimap;
|
||||
using std::error_code;
|
||||
using std::unique_ptr;
|
||||
using std::shared_ptr;
|
||||
using std::make_shared;
|
||||
using std::runtime_error;
|
||||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
using std::invalid_argument;
|
||||
using std::chrono::milliseconds;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::SessionImpl;
|
||||
|
||||
//External Namespaces
|
||||
using asio::buffer;
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
static Bytes empty_body = { };
|
||||
static multimap< string, string > empty_headers = { };
|
||||
|
||||
Session::Session( const string& id ) : m_pimpl( new SessionImpl )
|
||||
{
|
||||
m_pimpl->m_id = id;
|
||||
}
|
||||
|
||||
bool Session::has( const string& name ) const
|
||||
{
|
||||
return m_pimpl->m_context.find( name ) not_eq m_pimpl->m_context.end( );
|
||||
}
|
||||
|
||||
void Session::erase( const string& name )
|
||||
{
|
||||
if ( name.empty( ) )
|
||||
{
|
||||
m_pimpl->m_context.clear( );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pimpl->m_context.erase( name );
|
||||
}
|
||||
}
|
||||
|
||||
const set< string > Session::keys( void ) const
|
||||
{
|
||||
std::set< string > keys;
|
||||
|
||||
for ( const auto& value : m_pimpl->m_context )
|
||||
{
|
||||
keys.insert( value.first );
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
bool Session::is_open( void ) const
|
||||
{
|
||||
return m_pimpl->m_request not_eq nullptr and
|
||||
m_pimpl->m_request->m_pimpl->m_socket not_eq nullptr and
|
||||
m_pimpl->m_request->m_pimpl->m_socket->is_open( );
|
||||
}
|
||||
|
||||
bool Session::is_closed( void ) const
|
||||
{
|
||||
return not is_open( );
|
||||
}
|
||||
|
||||
void Session::close( const Bytes& body )
|
||||
{
|
||||
auto session = shared_from_this( );
|
||||
|
||||
if ( is_closed( ) )
|
||||
{
|
||||
const auto error_handler = m_pimpl->get_error_handler( );
|
||||
return error_handler( 500, runtime_error( "Close failed: session already closed." ), session );
|
||||
}
|
||||
|
||||
m_pimpl->m_request->m_pimpl->m_socket->start_write( body, [ this, session ]( const error_code & error, size_t )
|
||||
{
|
||||
if ( error )
|
||||
{
|
||||
const auto message = String::format( "Close failed: %s", error.message( ).data( ) );
|
||||
const auto error_handler = m_pimpl->get_error_handler( );
|
||||
return error_handler( 500, runtime_error( message ), session );
|
||||
}
|
||||
|
||||
m_pimpl->m_manager->save( session, [ this, session ]( const shared_ptr< Session > )
|
||||
{
|
||||
m_pimpl->m_request->m_pimpl->m_socket->close( );
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
void Session::close( const Response& response )
|
||||
{
|
||||
auto session = shared_from_this( );
|
||||
|
||||
if ( is_closed( ) )
|
||||
{
|
||||
const auto error_handler = m_pimpl->get_error_handler( );
|
||||
return error_handler( 500, runtime_error( "Close failed: session already closed." ), session );
|
||||
}
|
||||
|
||||
m_pimpl->transmit( response, [ this, session ]( const error_code & error, size_t )
|
||||
{
|
||||
if ( error )
|
||||
{
|
||||
const auto message = String::format( "Close failed: %s", error.message( ).data( ) );
|
||||
const auto error_handler = m_pimpl->get_error_handler( );
|
||||
return error_handler( 500, runtime_error( message ), session );
|
||||
}
|
||||
|
||||
m_pimpl->m_manager->save( session, [ this ]( const shared_ptr< Session > )
|
||||
{
|
||||
m_pimpl->m_request->m_pimpl->m_socket->close( );
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
void Session::close( const string& body )
|
||||
{
|
||||
close( String::to_bytes( body ) );
|
||||
}
|
||||
|
||||
void Session::close( const int status, const Bytes& body )
|
||||
{
|
||||
close( status, body, empty_headers );
|
||||
}
|
||||
|
||||
void Session::close( const int status, const string& body )
|
||||
{
|
||||
close( status, String::to_bytes( body ), empty_headers );
|
||||
}
|
||||
|
||||
void Session::close( const int status, const multimap< string, string >& headers )
|
||||
{
|
||||
close( status, empty_body, headers );
|
||||
}
|
||||
|
||||
void Session::close( const int status, const string& body, const multimap< string, string >& headers )
|
||||
{
|
||||
close( status, String::to_bytes( body ), headers );
|
||||
}
|
||||
|
||||
void Session::close( const int status, const Bytes& body, const multimap< string, string >& headers )
|
||||
{
|
||||
Response response;
|
||||
response.set_body( body );
|
||||
response.set_headers( headers );
|
||||
response.set_status_code( status );
|
||||
|
||||
close( response );
|
||||
}
|
||||
|
||||
void Session::yield( const Bytes& body, const function< void ( const shared_ptr< Session > ) >& callback )
|
||||
{
|
||||
auto session = shared_from_this( );
|
||||
|
||||
if ( is_closed( ) )
|
||||
{
|
||||
const auto error_handler = m_pimpl->get_error_handler( );
|
||||
return error_handler( 500, runtime_error( "Yield failed: session already closed." ), session );
|
||||
}
|
||||
|
||||
m_pimpl->m_request->m_pimpl->m_socket->start_write( body, [ this, session, callback ]( const error_code & error, size_t )
|
||||
{
|
||||
if ( error )
|
||||
{
|
||||
const auto message = String::format( "Yield failed: %s", error.message( ).data( ) );
|
||||
const auto error_handler = m_pimpl->get_error_handler( );
|
||||
return error_handler( 500, runtime_error( message ), session );
|
||||
}
|
||||
|
||||
if ( callback not_eq nullptr )
|
||||
{
|
||||
callback( session );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
void Session::yield( const string& body, const function< void ( const shared_ptr< Session > ) >& callback )
|
||||
{
|
||||
yield( String::to_bytes( body ), callback );
|
||||
}
|
||||
|
||||
void Session::yield( const Response& response, const function< void ( const shared_ptr< Session > ) >& callback )
|
||||
{
|
||||
auto session = shared_from_this( );
|
||||
|
||||
if ( is_closed( ) )
|
||||
{
|
||||
const auto error_handler = m_pimpl->get_error_handler( );
|
||||
return error_handler( 500, runtime_error( "Yield failed: session already closed." ), session );
|
||||
}
|
||||
|
||||
m_pimpl->transmit( response, [ this, session, callback ]( const error_code & error, size_t )
|
||||
{
|
||||
if ( error )
|
||||
{
|
||||
const auto message = String::format( "Yield failed: %s", error.message( ).data( ) );
|
||||
const auto error_handler = m_pimpl->get_error_handler( );
|
||||
return error_handler( 500, runtime_error( message ), session );
|
||||
}
|
||||
|
||||
if ( callback == nullptr )
|
||||
{
|
||||
m_pimpl->m_request->m_pimpl->m_socket->start_read( m_pimpl->m_request->m_pimpl->m_buffer, "\r\n\r\n", [ this, session ]( const error_code & error, const size_t length )
|
||||
{
|
||||
m_pimpl->m_keep_alive_callback( error, length, session );
|
||||
} );
|
||||
}
|
||||
else
|
||||
{
|
||||
callback( session );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
void Session::yield( const int status, const Bytes& body, const function< void ( const shared_ptr< Session > ) >& callback )
|
||||
{
|
||||
yield( status, body, empty_headers, callback );
|
||||
}
|
||||
|
||||
void Session::yield( const int status, const string& body, const function< void ( const shared_ptr< Session > ) >& callback )
|
||||
{
|
||||
yield( status, String::to_bytes( body ), empty_headers, callback );
|
||||
}
|
||||
|
||||
void Session::yield( const int status, const multimap< string, string >& headers, const function< void ( const shared_ptr< Session > ) >& callback )
|
||||
{
|
||||
yield( status, empty_body, headers, callback );
|
||||
}
|
||||
|
||||
void Session::yield( const int status, const string& body, const multimap< string, string >& headers, const function< void ( const shared_ptr< Session > ) >& callback )
|
||||
{
|
||||
yield( status, String::to_bytes( body ), headers, callback );
|
||||
}
|
||||
|
||||
void Session::yield( const int status, const Bytes& body, const multimap< string, string >& headers, const function< void ( const shared_ptr< Session > ) >& callback )
|
||||
{
|
||||
Response response;
|
||||
response.set_body( body );
|
||||
response.set_headers( headers );
|
||||
response.set_status_code( status );
|
||||
|
||||
yield( response, callback );
|
||||
}
|
||||
|
||||
void Session::fetch( const size_t length, const function< void ( const shared_ptr< Session >, const Bytes& ) >& callback )
|
||||
{
|
||||
auto session = shared_from_this( );
|
||||
|
||||
if ( is_closed( ) )
|
||||
{
|
||||
const auto error_handler = m_pimpl->get_error_handler( );
|
||||
return error_handler( 500, runtime_error( "Fetch failed: session already closed." ), session );
|
||||
}
|
||||
|
||||
if ( length > m_pimpl->m_request->m_pimpl->m_buffer->size( ) )
|
||||
{
|
||||
size_t size = length - m_pimpl->m_request->m_pimpl->m_buffer->size( );
|
||||
|
||||
m_pimpl->m_request->m_pimpl->m_socket->start_read( m_pimpl->m_request->m_pimpl->m_buffer, size, [ this, session, length, callback ]( const error_code & error, size_t )
|
||||
{
|
||||
if ( error )
|
||||
{
|
||||
const auto message = String::format( "Fetch failed: %s", error.message( ).data( ) );
|
||||
const auto error_handler = m_pimpl->get_error_handler( );
|
||||
return error_handler( 500, runtime_error( message ), session );
|
||||
}
|
||||
|
||||
m_pimpl->fetch_body( length, session, callback );
|
||||
} );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pimpl->fetch_body( length, session, callback );
|
||||
}
|
||||
}
|
||||
|
||||
void Session::fetch( const string& delimiter, const function< void ( const shared_ptr< Session >, const Bytes& ) >& callback )
|
||||
{
|
||||
auto session = shared_from_this( );
|
||||
|
||||
if ( is_closed( ) )
|
||||
{
|
||||
const auto error_handler = m_pimpl->get_error_handler( );
|
||||
return error_handler( 500, runtime_error( "Fetch failed: session already closed." ), session );
|
||||
}
|
||||
|
||||
m_pimpl->m_request->m_pimpl->m_socket->start_read( m_pimpl->m_request->m_pimpl->m_buffer, delimiter, [ this, session, callback ]( const error_code & error, size_t length )
|
||||
{
|
||||
if ( error )
|
||||
{
|
||||
const auto message = String::format( "Fetch failed: %s", error.message( ).data( ) );
|
||||
const auto error_handler = m_pimpl->get_error_handler( );
|
||||
return error_handler( 500, runtime_error( message ), session );
|
||||
}
|
||||
|
||||
m_pimpl->fetch_body( length, session, callback );
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
void Session::upgrade( const int status, const function< void ( const shared_ptr< WebSocket > ) >& callback )
|
||||
{
|
||||
upgrade( status, empty_body, empty_headers, callback );
|
||||
}
|
||||
|
||||
void Session::upgrade( const int status, const Bytes& body, const function< void ( const shared_ptr< WebSocket > ) >& callback )
|
||||
{
|
||||
upgrade( status, body, empty_headers, callback );
|
||||
}
|
||||
|
||||
void Session::upgrade( const int status, const string& body, const function< void ( const shared_ptr< WebSocket > ) >& callback )
|
||||
{
|
||||
upgrade( status, String::to_bytes( body ), empty_headers, callback );
|
||||
}
|
||||
|
||||
void Session::upgrade( const int status, const multimap< string, string >& headers, const function< void ( const shared_ptr< WebSocket > ) >& callback )
|
||||
{
|
||||
upgrade( status, empty_body, headers, callback );
|
||||
}
|
||||
|
||||
void Session::upgrade( const int status, const Bytes& body, const multimap< string, string >& headers, const function< void ( const shared_ptr< WebSocket > ) >& callback )
|
||||
{
|
||||
auto socket = m_pimpl->m_web_socket_manager->create( shared_from_this( ) );
|
||||
yield( status, body, headers, bind( callback, socket ) );
|
||||
}
|
||||
|
||||
void Session::upgrade( const int status, const string& body, const multimap< string, string >& headers, const function< void ( const shared_ptr< WebSocket > ) >& callback )
|
||||
{
|
||||
upgrade( status, String::to_bytes( body ), headers, callback );
|
||||
}
|
||||
|
||||
void Session::sleep_for( const milliseconds& delay, const function< void ( const shared_ptr< Session > ) >& callback )
|
||||
{
|
||||
auto session = shared_from_this( );
|
||||
|
||||
if ( is_closed( ) )
|
||||
{
|
||||
const auto error_handler = m_pimpl->get_error_handler( );
|
||||
return error_handler( 500, runtime_error( "Sleep failed: session already closed." ), session );
|
||||
}
|
||||
|
||||
m_pimpl->m_request->m_pimpl->m_socket->sleep_for( delay, [ session, callback, this ]( const error_code & error )
|
||||
{
|
||||
if ( error )
|
||||
{
|
||||
const auto message = String::format( "Wait failed: %s", error.message( ).data( ) );
|
||||
const auto error_handler = m_pimpl->get_error_handler( );
|
||||
return error_handler( 500, runtime_error( message ), session );
|
||||
}
|
||||
|
||||
if ( callback not_eq nullptr )
|
||||
{
|
||||
callback( session );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
const string& Session::get_id( void ) const
|
||||
{
|
||||
return m_pimpl->m_id;
|
||||
}
|
||||
|
||||
const string Session::get_origin( void ) const
|
||||
{
|
||||
if ( m_pimpl->m_request == nullptr or m_pimpl->m_request->m_pimpl->m_socket == nullptr )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return m_pimpl->m_request->m_pimpl->m_socket->get_remote_endpoint( );
|
||||
}
|
||||
|
||||
const string Session::get_destination( void ) const
|
||||
{
|
||||
if ( m_pimpl->m_request == nullptr or m_pimpl->m_request->m_pimpl->m_socket == nullptr )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return m_pimpl->m_request->m_pimpl->m_socket->get_local_endpoint( );
|
||||
}
|
||||
|
||||
const shared_ptr< const Request > Session::get_request( void ) const
|
||||
{
|
||||
return m_pimpl->m_request;
|
||||
}
|
||||
|
||||
const shared_ptr< const Resource > Session::get_resource( void ) const
|
||||
{
|
||||
return m_pimpl->m_resource;
|
||||
}
|
||||
|
||||
const multimap< string, string >& Session::get_headers( void ) const
|
||||
{
|
||||
return m_pimpl->m_headers;
|
||||
}
|
||||
|
||||
const ContextValue& Session::get( const string& name ) const
|
||||
{
|
||||
return m_pimpl->m_context.at( name );
|
||||
}
|
||||
|
||||
const ContextValue& Session::get( const string& name, const ContextValue& default_value ) const
|
||||
{
|
||||
if ( has( name ) )
|
||||
{
|
||||
return m_pimpl->m_context.at( name );
|
||||
}
|
||||
|
||||
return default_value;
|
||||
}
|
||||
|
||||
void Session::set_id( const string& value )
|
||||
{
|
||||
m_pimpl->m_id = value;
|
||||
}
|
||||
|
||||
void Session::set( const string& name, const ContextValue& value )
|
||||
{
|
||||
if ( has( name ) )
|
||||
{
|
||||
m_pimpl->m_context.erase( name );
|
||||
}
|
||||
|
||||
m_pimpl->m_context.insert( make_pair( name, value ) );
|
||||
}
|
||||
|
||||
void Session::add_header( const string& name, const string& value )
|
||||
{
|
||||
m_pimpl->m_headers.insert( make_pair( name, value ) );
|
||||
}
|
||||
|
||||
void Session::set_header( const string& name, const string& value )
|
||||
{
|
||||
m_pimpl->m_headers.erase( name );
|
||||
m_pimpl->m_headers.insert( make_pair( name, value ) );
|
||||
}
|
||||
|
||||
void Session::set_headers( const multimap< string, string >& values )
|
||||
{
|
||||
m_pimpl->m_headers = values;
|
||||
}
|
||||
}
|
||||
202
lib/restbed-4.8/source/corvusoft/restbed/session.hpp
Normal file
202
lib/restbed-4.8/source/corvusoft/restbed/session.hpp
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
//Project Includes
|
||||
#include <corvusoft/restbed/byte.hpp>
|
||||
#include <corvusoft/restbed/string.hpp>
|
||||
#include <corvusoft/restbed/context_value.hpp>
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define SESSION_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define SESSION_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define SESSION_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Request;
|
||||
class Session;
|
||||
class Response;
|
||||
class Resource;
|
||||
class WebSocket;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class SessionImpl;
|
||||
class ServiceImpl;
|
||||
class WebSocketManagerImpl;
|
||||
}
|
||||
|
||||
class SESSION_EXPORT Session : public std::enable_shared_from_this< Session >
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
explicit Session( const std::string& id );
|
||||
|
||||
~Session( void ) = default;
|
||||
|
||||
//Functionality
|
||||
bool has( const std::string& name ) const;
|
||||
|
||||
void erase( const std::string& name = "" );
|
||||
|
||||
const std::set< std::string > keys( void ) const;
|
||||
|
||||
bool is_open( void ) const;
|
||||
|
||||
bool is_closed( void ) const;
|
||||
|
||||
void close( const Bytes& body );
|
||||
|
||||
void close( const Response& response );
|
||||
|
||||
void close( const std::string& body = "" );
|
||||
|
||||
void close( const int status, const Bytes& body );
|
||||
|
||||
void close( const int status, const std::string& body = "" );
|
||||
|
||||
void close( const int status, const std::multimap< std::string, std::string >& headers );
|
||||
|
||||
void close( const int status, const std::string& body, const std::multimap< std::string, std::string >& headers );
|
||||
|
||||
void close( const int status, const Bytes& body, const std::multimap< std::string, std::string >& headers );
|
||||
|
||||
void yield( const Bytes& data, const std::function< void ( const std::shared_ptr< Session > ) >& callback = nullptr );
|
||||
|
||||
void yield( const std::string& data, const std::function< void ( const std::shared_ptr< Session > ) >& callback = nullptr );
|
||||
|
||||
void yield( const Response& response, const std::function< void ( const std::shared_ptr< Session > ) >& callback = nullptr );
|
||||
|
||||
void yield( const int status, const std::string& body, const std::function< void ( const std::shared_ptr< Session > ) >& callback = nullptr );
|
||||
|
||||
void yield( const int status, const Bytes& body = { }, const std::function< void ( const std::shared_ptr< Session > ) >& callback = nullptr );
|
||||
|
||||
void yield( const int status, const std::multimap< std::string, std::string >& headers, const std::function< void ( const std::shared_ptr< Session > ) >& callback = nullptr );
|
||||
|
||||
void yield( const int status, const Bytes& body, const std::multimap< std::string, std::string >& headers, const std::function< void ( const std::shared_ptr< Session > ) >& callback = nullptr );
|
||||
|
||||
void yield( const int status, const std::string& body, const std::multimap< std::string, std::string >& headers, const std::function< void ( const std::shared_ptr< Session > ) >& callback = nullptr );
|
||||
|
||||
void fetch( const std::size_t length, const std::function< void ( const std::shared_ptr< Session >, const Bytes& ) >& callback );
|
||||
|
||||
void fetch( const std::string& delimiter, const std::function< void ( const std::shared_ptr< Session >, const Bytes& ) >& callback );
|
||||
|
||||
void upgrade( const int status, const std::function< void ( const std::shared_ptr< WebSocket > ) >& callback );
|
||||
|
||||
void upgrade( const int status, const Bytes& body, const std::function< void ( const std::shared_ptr< WebSocket > ) >& callback );
|
||||
|
||||
void upgrade( const int status, const std::string& body, const std::function< void ( const std::shared_ptr< WebSocket > ) >& callback );
|
||||
|
||||
void upgrade( const int status, const std::multimap< std::string, std::string >& headers, const std::function< void ( const std::shared_ptr< WebSocket > ) >& callback );
|
||||
|
||||
void upgrade( const int status, const Bytes& body, const std::multimap< std::string, std::string >& headers, const std::function< void ( const std::shared_ptr< WebSocket > ) >& callback );
|
||||
|
||||
void upgrade( const int status, const std::string& body, const std::multimap< std::string, std::string >& headers, const std::function< void ( const std::shared_ptr< WebSocket > ) >& callback );
|
||||
|
||||
void sleep_for( const std::chrono::milliseconds& delay, const std::function< void ( const std::shared_ptr< Session > ) >& callback );
|
||||
|
||||
//Getters
|
||||
const std::string& get_id( void ) const;
|
||||
|
||||
const std::string get_origin( void ) const;
|
||||
|
||||
const std::string get_destination( void ) const;
|
||||
|
||||
const std::shared_ptr< const Request > get_request( void ) const;
|
||||
|
||||
const std::shared_ptr< const Resource > get_resource( void ) const;
|
||||
|
||||
const std::multimap< std::string, std::string >& get_headers( void ) const;
|
||||
|
||||
const ContextValue& get( const std::string& name ) const;
|
||||
|
||||
const ContextValue& get( const std::string& name, const ContextValue& default_value ) const;
|
||||
|
||||
//Setters
|
||||
void set_id( const std::string& value );
|
||||
|
||||
void set( const std::string& name, const ContextValue& value );
|
||||
|
||||
void add_header( const std::string& name, const std::string& value );
|
||||
|
||||
void set_header( const std::string& name, const std::string& value );
|
||||
|
||||
void set_headers( const std::multimap< std::string, std::string >& values );
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
friend detail::ServiceImpl;
|
||||
friend detail::SessionImpl;
|
||||
friend detail::WebSocketManagerImpl;
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Session( void ) = delete;
|
||||
|
||||
Session( const Session& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
Session& operator =( const Session& value ) = delete;
|
||||
|
||||
//Properties
|
||||
std::shared_ptr< detail::SessionImpl > m_pimpl;
|
||||
};
|
||||
}
|
||||
63
lib/restbed-4.8/source/corvusoft/restbed/session_manager.cpp
Normal file
63
lib/restbed-4.8/source/corvusoft/restbed/session_manager.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <ciso646>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/string.hpp"
|
||||
#include "corvusoft/restbed/session.hpp"
|
||||
#include "corvusoft/restbed/settings.hpp"
|
||||
#include "corvusoft/restbed/session_manager.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::string;
|
||||
using std::function;
|
||||
using std::to_string;
|
||||
using std::shared_ptr;
|
||||
using std::make_shared;
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
SessionManager::SessionManager( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SessionManager::~SessionManager( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void SessionManager::stop( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void SessionManager::start( const shared_ptr< const Settings >& )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void SessionManager::create( const function< void ( const shared_ptr< Session > ) >& callback )
|
||||
{
|
||||
callback( make_shared< Session >( String::empty ) );
|
||||
}
|
||||
|
||||
void SessionManager::load( const shared_ptr< Session > session, const function< void ( const shared_ptr< Session > ) >& callback )
|
||||
{
|
||||
callback( session );
|
||||
}
|
||||
|
||||
void SessionManager::save( const shared_ptr< Session > session, const function< void ( const shared_ptr< Session > ) >& callback )
|
||||
{
|
||||
callback( session );
|
||||
}
|
||||
}
|
||||
110
lib/restbed-4.8/source/corvusoft/restbed/session_manager.hpp
Normal file
110
lib/restbed-4.8/source/corvusoft/restbed/session_manager.hpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define SESSION_MANAGER_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define SESSION_MANAGER_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define SESSION_MANAGER_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Session;
|
||||
class Settings;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct SessionManagerImpl;
|
||||
}
|
||||
|
||||
class SESSION_MANAGER_EXPORT SessionManager
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
SessionManager( void );
|
||||
|
||||
virtual ~SessionManager( void );
|
||||
|
||||
//Functionality
|
||||
virtual void stop( void );
|
||||
|
||||
virtual void start( const std::shared_ptr< const Settings >& settings );
|
||||
|
||||
virtual void create( const std::function< void ( const std::shared_ptr< Session > ) >& callback );
|
||||
|
||||
virtual void load( const std::shared_ptr< Session > session, const std::function< void ( const std::shared_ptr< Session > ) >& callback );
|
||||
|
||||
virtual void save( const std::shared_ptr< Session > session, const std::function< void ( const std::shared_ptr< Session > ) >& callback );
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
SessionManager( const SessionManager& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
SessionManager& operator =( const SessionManager& value ) = delete;
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
};
|
||||
}
|
||||
230
lib/restbed-4.8/source/corvusoft/restbed/settings.cpp
Normal file
230
lib/restbed-4.8/source/corvusoft/restbed/settings.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/settings.hpp"
|
||||
#include "corvusoft/restbed/detail/settings_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::map;
|
||||
using std::string;
|
||||
using std::multimap;
|
||||
using std::make_pair;
|
||||
using std::unique_ptr;
|
||||
using std::shared_ptr;
|
||||
using std::chrono::seconds;
|
||||
using std::chrono::milliseconds;
|
||||
using std::chrono::duration_cast;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::SettingsImpl;
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
Settings::Settings( void ) : m_pimpl( new SettingsImpl )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Settings::~Settings( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t Settings::get_port( void ) const
|
||||
{
|
||||
return m_pimpl->m_port;
|
||||
}
|
||||
|
||||
string Settings::get_root( void ) const
|
||||
{
|
||||
return m_pimpl->m_root;
|
||||
}
|
||||
|
||||
bool Settings::get_reuse_address( void ) const
|
||||
{
|
||||
return m_pimpl->m_reuse_address;
|
||||
}
|
||||
|
||||
unsigned int Settings::get_worker_limit( void ) const
|
||||
{
|
||||
return m_pimpl->m_worker_limit;
|
||||
}
|
||||
|
||||
unsigned int Settings::get_connection_limit( void ) const
|
||||
{
|
||||
return m_pimpl->m_connection_limit;
|
||||
}
|
||||
|
||||
string Settings::get_bind_address( void ) const
|
||||
{
|
||||
return m_pimpl->m_bind_address;
|
||||
}
|
||||
|
||||
bool Settings::get_case_insensitive_uris( void ) const
|
||||
{
|
||||
return m_pimpl->m_case_insensitive_uris;
|
||||
}
|
||||
|
||||
milliseconds Settings::get_connection_timeout( void ) const
|
||||
{
|
||||
return m_pimpl->m_connection_timeout;
|
||||
}
|
||||
|
||||
bool Settings::get_keep_alive( void ) const
|
||||
{
|
||||
return m_pimpl->m_keep_alive;
|
||||
}
|
||||
|
||||
uint32_t Settings::get_keep_alive_start( void ) const
|
||||
{
|
||||
return m_pimpl->m_keep_alive_start;
|
||||
}
|
||||
|
||||
uint32_t Settings::get_keep_alive_interval( void ) const
|
||||
{
|
||||
return m_pimpl->m_keep_alive_interval;
|
||||
}
|
||||
|
||||
uint32_t Settings::get_keep_alive_cnt( void ) const
|
||||
{
|
||||
return m_pimpl->m_keep_alive_cnt;
|
||||
}
|
||||
|
||||
string Settings::get_status_message( const int code ) const
|
||||
{
|
||||
return ( m_pimpl->m_status_messages.count( code ) ) ? m_pimpl->m_status_messages.at( code ) : "No Appropriate Status Message Found";
|
||||
}
|
||||
|
||||
map< int, string > Settings::get_status_messages( void ) const
|
||||
{
|
||||
return m_pimpl->m_status_messages;
|
||||
}
|
||||
|
||||
string Settings::get_property( const string& name ) const
|
||||
{
|
||||
return ( m_pimpl->m_properties.count( name ) ) ? m_pimpl->m_properties.at( name ) : "";
|
||||
}
|
||||
|
||||
map< string, string > Settings::get_properties( void ) const
|
||||
{
|
||||
return m_pimpl->m_properties;
|
||||
}
|
||||
|
||||
shared_ptr< const SSLSettings > Settings::get_ssl_settings( void ) const
|
||||
{
|
||||
return m_pimpl->m_ssl_settings;
|
||||
}
|
||||
|
||||
multimap< string, string > Settings::get_default_headers( void ) const
|
||||
{
|
||||
return m_pimpl->m_default_headers;
|
||||
}
|
||||
|
||||
void Settings::set_port( const uint16_t value )
|
||||
{
|
||||
m_pimpl->m_port = value;
|
||||
}
|
||||
|
||||
void Settings::set_root( const string& value )
|
||||
{
|
||||
m_pimpl->m_root = value;
|
||||
}
|
||||
|
||||
void Settings::set_reuse_address( const bool value )
|
||||
{
|
||||
m_pimpl->m_reuse_address = value;
|
||||
}
|
||||
|
||||
void Settings::set_worker_limit( const unsigned int value )
|
||||
{
|
||||
m_pimpl->m_worker_limit = value;
|
||||
}
|
||||
|
||||
void Settings::set_connection_limit( const unsigned int value )
|
||||
{
|
||||
m_pimpl->m_connection_limit = value;
|
||||
}
|
||||
|
||||
void Settings::set_bind_address( const string& value )
|
||||
{
|
||||
m_pimpl->m_bind_address = value;
|
||||
}
|
||||
|
||||
void Settings::set_case_insensitive_uris( const bool value )
|
||||
{
|
||||
m_pimpl->m_case_insensitive_uris = value;
|
||||
}
|
||||
|
||||
void Settings::set_connection_timeout( const seconds& value )
|
||||
{
|
||||
m_pimpl->m_connection_timeout = duration_cast< milliseconds >( value );
|
||||
}
|
||||
|
||||
void Settings::set_connection_timeout( const milliseconds& value )
|
||||
{
|
||||
m_pimpl->m_connection_timeout = value;
|
||||
}
|
||||
|
||||
void Settings::set_keep_alive( bool value )
|
||||
{
|
||||
m_pimpl->m_keep_alive = value;
|
||||
}
|
||||
|
||||
void Settings::set_keep_alive_start( const uint32_t value )
|
||||
{
|
||||
m_pimpl->m_keep_alive_start = value;
|
||||
}
|
||||
|
||||
void Settings::set_keep_alive_interval( const uint32_t value )
|
||||
{
|
||||
m_pimpl->m_keep_alive_interval = value;
|
||||
}
|
||||
|
||||
void Settings::set_keep_alive_cnt( const uint32_t value )
|
||||
{
|
||||
m_pimpl->m_keep_alive_cnt = value;
|
||||
}
|
||||
|
||||
void Settings::set_status_message( const int code, const string& message )
|
||||
{
|
||||
m_pimpl->m_status_messages[ code ] = message;
|
||||
}
|
||||
|
||||
void Settings::set_status_messages( const map< int, string >& values )
|
||||
{
|
||||
m_pimpl->m_status_messages = values;
|
||||
}
|
||||
|
||||
void Settings::set_property( const string& name, const string& value )
|
||||
{
|
||||
m_pimpl->m_properties[ name ] = value;
|
||||
}
|
||||
|
||||
void Settings::set_properties( const map< string, string >& values )
|
||||
{
|
||||
m_pimpl->m_properties = values;
|
||||
}
|
||||
|
||||
void Settings::set_ssl_settings( const shared_ptr< const SSLSettings >& values )
|
||||
{
|
||||
m_pimpl->m_ssl_settings = values;
|
||||
}
|
||||
|
||||
void Settings::set_default_header( const string& name, const string& value )
|
||||
{
|
||||
m_pimpl->m_default_headers.insert( make_pair( name, value ) );
|
||||
}
|
||||
|
||||
void Settings::set_default_headers( const multimap< string, string >& values )
|
||||
{
|
||||
m_pimpl->m_default_headers = values;
|
||||
}
|
||||
}
|
||||
178
lib/restbed-4.8/source/corvusoft/restbed/settings.hpp
Normal file
178
lib/restbed-4.8/source/corvusoft/restbed/settings.hpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define SETTINGS_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define SETTINGS_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define SETTINGS_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class SSLSettings;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct SettingsImpl;
|
||||
}
|
||||
|
||||
class SETTINGS_EXPORT Settings
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Settings( void );
|
||||
|
||||
virtual ~Settings( void );
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
uint16_t get_port( void ) const;
|
||||
|
||||
std::string get_root( void ) const;
|
||||
|
||||
bool get_reuse_address( void ) const;
|
||||
|
||||
unsigned int get_worker_limit( void ) const;
|
||||
|
||||
unsigned int get_connection_limit( void ) const;
|
||||
|
||||
std::string get_bind_address( void ) const;
|
||||
|
||||
bool get_case_insensitive_uris( void ) const;
|
||||
|
||||
std::chrono::milliseconds get_connection_timeout( void ) const;
|
||||
|
||||
bool get_keep_alive( void ) const;
|
||||
|
||||
uint32_t get_keep_alive_start( void ) const;
|
||||
|
||||
uint32_t get_keep_alive_interval( void ) const;
|
||||
|
||||
uint32_t get_keep_alive_cnt( void ) const;
|
||||
|
||||
std::string get_status_message( const int code ) const;
|
||||
|
||||
std::map< int, std::string > get_status_messages( void ) const;
|
||||
|
||||
std::string get_property( const std::string& name ) const;
|
||||
|
||||
std::map< std::string, std::string > get_properties( void ) const;
|
||||
|
||||
std::shared_ptr< const SSLSettings > get_ssl_settings( void ) const;
|
||||
|
||||
std::multimap< std::string, std::string > get_default_headers( void ) const;
|
||||
|
||||
//Setters
|
||||
void set_port( const uint16_t value );
|
||||
|
||||
void set_root( const std::string& value );
|
||||
|
||||
void set_reuse_address( const bool value );
|
||||
|
||||
void set_worker_limit( const unsigned int value );
|
||||
|
||||
void set_connection_limit( const unsigned int value );
|
||||
|
||||
void set_bind_address( const std::string& value );
|
||||
|
||||
void set_case_insensitive_uris( const bool value );
|
||||
|
||||
void set_connection_timeout( const std::chrono::seconds& value );
|
||||
|
||||
void set_connection_timeout( const std::chrono::milliseconds& value );
|
||||
|
||||
void set_keep_alive( bool value );
|
||||
|
||||
void set_keep_alive_start( const uint32_t value );
|
||||
|
||||
void set_keep_alive_interval( const uint32_t value );
|
||||
|
||||
void set_keep_alive_cnt( const uint32_t value );
|
||||
|
||||
void set_status_message( const int code, const std::string& message );
|
||||
|
||||
void set_status_messages( const std::map< int, std::string >& values );
|
||||
|
||||
void set_property( const std::string& name, const std::string& value );
|
||||
|
||||
void set_properties( const std::map< std::string, std::string >& values );
|
||||
|
||||
void set_ssl_settings( const std::shared_ptr< const SSLSettings >& value );
|
||||
|
||||
void set_default_header( const std::string& name, const std::string& value );
|
||||
|
||||
void set_default_headers( const std::multimap< std::string, std::string >& values );
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Settings( const Settings& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
Settings& operator =( const Settings& value ) = delete;
|
||||
|
||||
//Properties
|
||||
std::unique_ptr< detail::SettingsImpl > m_pimpl;
|
||||
};
|
||||
}
|
||||
215
lib/restbed-4.8/source/corvusoft/restbed/ssl_settings.cpp
Normal file
215
lib/restbed-4.8/source/corvusoft/restbed/ssl_settings.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/uri.hpp"
|
||||
#include "corvusoft/restbed/string.hpp"
|
||||
#include "corvusoft/restbed/ssl_settings.hpp"
|
||||
#include "corvusoft/restbed/detail/ssl_settings_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::string;
|
||||
using std::unique_ptr;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::SSLSettingsImpl;
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
SSLSettings::SSLSettings( void ) : m_pimpl( new SSLSettingsImpl )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SSLSettings::~SSLSettings( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool SSLSettings::has_disabled_http( void ) const
|
||||
{
|
||||
return m_pimpl->m_http_disabled;
|
||||
}
|
||||
|
||||
bool SSLSettings::has_enabled_sslv2( void ) const
|
||||
{
|
||||
return m_pimpl->m_sslv2_enabled;
|
||||
}
|
||||
|
||||
bool SSLSettings::has_enabled_sslv3( void ) const
|
||||
{
|
||||
return m_pimpl->m_sslv3_enabled;
|
||||
}
|
||||
|
||||
bool SSLSettings::has_enabled_tlsv1( void ) const
|
||||
{
|
||||
return m_pimpl->m_tlsv1_enabled;
|
||||
}
|
||||
|
||||
bool SSLSettings::has_enabled_tlsv11( void ) const
|
||||
{
|
||||
return m_pimpl->m_tlsv11_enabled;
|
||||
}
|
||||
|
||||
bool SSLSettings::has_enabled_tlsv12( void ) const
|
||||
{
|
||||
return m_pimpl->m_tlsv12_enabled;
|
||||
}
|
||||
|
||||
bool SSLSettings::has_enabled_compression( void ) const
|
||||
{
|
||||
return m_pimpl->m_compression_enabled;
|
||||
}
|
||||
|
||||
bool SSLSettings::has_enabled_default_workarounds( void ) const
|
||||
{
|
||||
return m_pimpl->m_default_workarounds_enabled;
|
||||
}
|
||||
|
||||
bool SSLSettings::has_enabled_single_diffie_hellman_use( void ) const
|
||||
{
|
||||
return m_pimpl->m_single_diffie_hellman_use_enabled;
|
||||
}
|
||||
|
||||
uint16_t SSLSettings::get_port( void ) const
|
||||
{
|
||||
return m_pimpl->m_port;
|
||||
}
|
||||
|
||||
string SSLSettings::get_bind_address( void ) const
|
||||
{
|
||||
return m_pimpl->m_bind_address;
|
||||
}
|
||||
|
||||
string SSLSettings::get_certificate( void ) const
|
||||
{
|
||||
return m_pimpl->m_certificate;
|
||||
}
|
||||
|
||||
string SSLSettings::get_passphrase( void ) const
|
||||
{
|
||||
return m_pimpl->m_passphrase;
|
||||
}
|
||||
|
||||
string SSLSettings::get_private_key( void ) const
|
||||
{
|
||||
return m_pimpl->m_private_key;
|
||||
}
|
||||
|
||||
string SSLSettings::get_private_rsa_key( void ) const
|
||||
{
|
||||
return m_pimpl->m_private_rsa_key;
|
||||
}
|
||||
|
||||
string SSLSettings::get_certificate_chain( void ) const
|
||||
{
|
||||
return m_pimpl->m_certificate_chain;
|
||||
}
|
||||
|
||||
string SSLSettings::get_temporary_diffie_hellman( void ) const
|
||||
{
|
||||
return m_pimpl->m_temporary_diffie_hellman;
|
||||
}
|
||||
|
||||
string SSLSettings::get_certificate_authority_pool( void ) const
|
||||
{
|
||||
return m_pimpl->m_certificate_authority_pool;
|
||||
}
|
||||
|
||||
void SSLSettings::set_port( const uint16_t value )
|
||||
{
|
||||
m_pimpl->m_port = value;
|
||||
}
|
||||
|
||||
void SSLSettings::set_bind_address( const string& value )
|
||||
{
|
||||
m_pimpl->m_bind_address = value;
|
||||
}
|
||||
|
||||
void SSLSettings::set_http_disabled( const bool value )
|
||||
{
|
||||
m_pimpl->m_http_disabled = value;
|
||||
}
|
||||
|
||||
void SSLSettings::set_sslv2_enabled( const bool value )
|
||||
{
|
||||
m_pimpl->m_sslv2_enabled = value;
|
||||
}
|
||||
|
||||
void SSLSettings::set_sslv3_enabled( const bool value )
|
||||
{
|
||||
m_pimpl->m_sslv3_enabled = value;
|
||||
}
|
||||
|
||||
void SSLSettings::set_tlsv1_enabled( const bool value )
|
||||
{
|
||||
m_pimpl->m_tlsv1_enabled = value;
|
||||
}
|
||||
|
||||
void SSLSettings::set_tlsv11_enabled( const bool value )
|
||||
{
|
||||
m_pimpl->m_tlsv11_enabled = value;
|
||||
}
|
||||
|
||||
void SSLSettings::set_tlsv12_enabled( const bool value )
|
||||
{
|
||||
m_pimpl->m_tlsv12_enabled = value;
|
||||
}
|
||||
|
||||
void SSLSettings::set_compression_enabled( const bool value )
|
||||
{
|
||||
m_pimpl->m_compression_enabled = value;
|
||||
}
|
||||
|
||||
void SSLSettings::set_default_workarounds_enabled( const bool value )
|
||||
{
|
||||
m_pimpl->m_default_workarounds_enabled = value;
|
||||
}
|
||||
|
||||
void SSLSettings::set_single_diffie_hellman_use_enabled( const bool value )
|
||||
{
|
||||
m_pimpl->m_single_diffie_hellman_use_enabled = value;
|
||||
}
|
||||
|
||||
void SSLSettings::set_certificate( const Uri& value )
|
||||
{
|
||||
m_pimpl->m_certificate = Uri::decode( String::remove( "file://", value.to_string( ), String::CASE_INSENSITIVE ) );
|
||||
}
|
||||
|
||||
void SSLSettings::set_certificate_chain( const Uri& value )
|
||||
{
|
||||
m_pimpl->m_certificate_chain = Uri::decode( String::remove( "file://", value.to_string( ), String::CASE_INSENSITIVE ) );
|
||||
}
|
||||
|
||||
void SSLSettings::set_certificate_authority_pool( const Uri& value )
|
||||
{
|
||||
m_pimpl->m_certificate_authority_pool = Uri::decode( String::remove( "file://", value.to_string( ), String::CASE_INSENSITIVE ) );
|
||||
}
|
||||
|
||||
void SSLSettings::set_passphrase( const string& value )
|
||||
{
|
||||
m_pimpl->m_passphrase = value;
|
||||
}
|
||||
|
||||
void SSLSettings::set_private_key( const Uri& value )
|
||||
{
|
||||
m_pimpl->m_private_key = Uri::decode( String::remove( "file://", value.to_string( ), String::CASE_INSENSITIVE ) );
|
||||
}
|
||||
|
||||
void SSLSettings::set_private_rsa_key( const Uri& value )
|
||||
{
|
||||
m_pimpl->m_private_rsa_key = Uri::decode( String::remove( "file://", value.to_string( ), String::CASE_INSENSITIVE ) );
|
||||
}
|
||||
|
||||
void SSLSettings::set_temporary_diffie_hellman( const Uri& value )
|
||||
{
|
||||
m_pimpl->m_temporary_diffie_hellman = Uri::decode( String::remove( "file://", value.to_string( ), String::CASE_INSENSITIVE ) );
|
||||
}
|
||||
}
|
||||
171
lib/restbed-4.8/source/corvusoft/restbed/ssl_settings.hpp
Normal file
171
lib/restbed-4.8/source/corvusoft/restbed/ssl_settings.hpp
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define SSL_SETTINGS_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define SSL_SETTINGS_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define SSL_SETTINGS_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Uri;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct SSLSettingsImpl;
|
||||
}
|
||||
|
||||
class SSL_SETTINGS_EXPORT SSLSettings
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
SSLSettings( void );
|
||||
|
||||
virtual ~SSLSettings( void );
|
||||
|
||||
//Functionality
|
||||
bool has_disabled_http( void ) const;
|
||||
|
||||
bool has_enabled_sslv2( void ) const;
|
||||
|
||||
bool has_enabled_sslv3( void ) const;
|
||||
|
||||
bool has_enabled_tlsv1( void ) const;
|
||||
|
||||
bool has_enabled_tlsv11( void ) const;
|
||||
|
||||
bool has_enabled_tlsv12( void ) const;
|
||||
|
||||
bool has_enabled_compression( void ) const;
|
||||
|
||||
bool has_enabled_default_workarounds( void ) const;
|
||||
|
||||
bool has_enabled_single_diffie_hellman_use( void ) const;
|
||||
|
||||
//Getters
|
||||
uint16_t get_port( void ) const;
|
||||
|
||||
std::string get_bind_address( void ) const;
|
||||
|
||||
std::string get_certificate( void ) const;
|
||||
|
||||
std::string get_passphrase( void ) const;
|
||||
|
||||
std::string get_private_key( void ) const;
|
||||
|
||||
std::string get_private_rsa_key( void ) const;
|
||||
|
||||
std::string get_certificate_chain( void ) const;
|
||||
|
||||
std::string get_temporary_diffie_hellman( void ) const;
|
||||
|
||||
std::string get_certificate_authority_pool( void ) const;
|
||||
|
||||
//Setters
|
||||
void set_port( const uint16_t value );
|
||||
|
||||
void set_bind_address( const std::string& value );
|
||||
|
||||
void set_http_disabled( const bool value );
|
||||
|
||||
void set_sslv2_enabled( const bool value );
|
||||
|
||||
void set_sslv3_enabled( const bool value );
|
||||
|
||||
void set_tlsv1_enabled( const bool value );
|
||||
|
||||
void set_tlsv11_enabled( const bool value );
|
||||
|
||||
void set_tlsv12_enabled( const bool value );
|
||||
|
||||
void set_compression_enabled( const bool value );
|
||||
|
||||
void set_default_workarounds_enabled( const bool value );
|
||||
|
||||
void set_single_diffie_hellman_use_enabled( const bool value );
|
||||
|
||||
void set_certificate( const Uri& value );
|
||||
|
||||
void set_certificate_chain( const Uri& value );
|
||||
|
||||
void set_certificate_authority_pool( const Uri& value );
|
||||
|
||||
void set_passphrase( const std::string& value );
|
||||
|
||||
void set_private_key( const Uri& value );
|
||||
|
||||
void set_private_rsa_key( const Uri& value );
|
||||
|
||||
void set_temporary_diffie_hellman( const Uri& value );
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
SSLSettings( const SSLSettings& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
SSLSettings& operator =( const SSLSettings& value ) = delete;
|
||||
|
||||
//Properties
|
||||
std::unique_ptr< detail::SSLSettingsImpl > m_pimpl;
|
||||
};
|
||||
}
|
||||
84
lib/restbed-4.8/source/corvusoft/restbed/status_code.hpp
Normal file
84
lib/restbed-4.8/source/corvusoft/restbed/status_code.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
|
||||
//Project Includes
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
enum : int
|
||||
{
|
||||
CONTINUE = 100,
|
||||
SWITCHING_PROTOCOLS = 101,
|
||||
PROCESSING = 102,
|
||||
OK = 200,
|
||||
CREATED = 201,
|
||||
ACCEPTED = 202,
|
||||
NON_AUTHORITATIVE_INFORMATION = 203,
|
||||
NO_CONTENT = 204,
|
||||
RESET_CONTENT = 205,
|
||||
PARTIAL_CONTENT = 206,
|
||||
MULTI_STATUS = 207,
|
||||
ALREADY_REPORTED = 208,
|
||||
IM_USED = 226,
|
||||
MULTIPLE_CHOICES = 300,
|
||||
MOVED_PERMANENTLY = 301,
|
||||
FOUND = 302,
|
||||
SEE_OTHER = 303,
|
||||
NOT_MODIFIED = 304,
|
||||
USE_PROXY = 305,
|
||||
RESERVED = 306,
|
||||
TEMPORARY_REDIRECT = 307,
|
||||
PERMANENT_REDIRECT = 308,
|
||||
BAD_REQUEST = 400,
|
||||
UNAUTHORIZED = 401,
|
||||
PAYMENT_REQUIRED = 402,
|
||||
FORBIDDEN = 403,
|
||||
NOT_FOUND = 404,
|
||||
METHOD_NOT_ALLOWED = 405,
|
||||
NOT_ACCEPTABLE = 406,
|
||||
PROXY_AUTHENTICATION_REQUIRED = 407,
|
||||
REQUEST_TIMEOUT = 408,
|
||||
CONFLICT = 409,
|
||||
GONE = 410,
|
||||
LENGTH_REQUIRED = 411,
|
||||
PRECONDITION_FAILED = 412,
|
||||
REQUEST_ENTITY_TOO_LARGE = 413,
|
||||
REQUEST_URI_TOO_LONG = 414,
|
||||
UNSUPPORTED_MEDIA_TYPE = 415,
|
||||
REQUESTED_RANGE_NOT_SATISFIABLE = 416,
|
||||
EXPECTATION_FAILED = 417,
|
||||
UNPROCESSABLE_ENTITY = 422,
|
||||
LOCKED = 423,
|
||||
FAILED_DEPENDENCY = 424,
|
||||
UPGRADE_REQUIRED = 426,
|
||||
PRECONDITION_REQUIRED = 428,
|
||||
TOO_MANY_REQUESTS = 429,
|
||||
REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
|
||||
INTERNAL_SERVER_ERROR = 500,
|
||||
NOT_IMPLEMENTED = 501,
|
||||
BAD_GATEWAY = 502,
|
||||
SERVICE_UNAVAILABLE = 503,
|
||||
GATEWAY_TIMEOUT = 504,
|
||||
HTTP_VERSION_NOT_SUPPORTED = 505,
|
||||
VARIANT_ALSO_NEGOTIATES = 506,
|
||||
INSUFFICIENT_STORAGE = 507,
|
||||
LOOP_DETECTED = 508,
|
||||
NOT_EXTENDED = 510,
|
||||
NETWORK_AUTHENTICATION_REQUIRED = 511
|
||||
};
|
||||
}
|
||||
178
lib/restbed-4.8/source/corvusoft/restbed/string.cpp
Normal file
178
lib/restbed-4.8/source/corvusoft/restbed/string.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <regex>
|
||||
#include <memory>
|
||||
#include <ciso646>
|
||||
#include <algorithm>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/string.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::regex;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::smatch;
|
||||
using std::multimap;
|
||||
using std::transform;
|
||||
using std::unique_ptr;
|
||||
using std::regex_match;
|
||||
using std::regex_replace;
|
||||
using std::regex_constants::icase;
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
const string String::empty = "";
|
||||
|
||||
Bytes String::to_bytes( const string& value )
|
||||
{
|
||||
return Bytes( value.begin( ), value.end( ) );
|
||||
}
|
||||
|
||||
string String::to_string( const Bytes& value )
|
||||
{
|
||||
return string( value.begin( ), value.end( ) );
|
||||
}
|
||||
|
||||
string String::lowercase( const string& value )
|
||||
{
|
||||
string result = "";
|
||||
transform( value.begin( ), value.end( ), back_inserter( result ), [ ]( const char value ) { return static_cast< char >( tolower( value ) ); } );
|
||||
return result;
|
||||
}
|
||||
|
||||
string String::uppercase( const string& value )
|
||||
{
|
||||
string result = "";
|
||||
transform( value.begin( ), value.end( ), back_inserter( result ), [ ]( const char value ) { return static_cast< char >( toupper( value ) ); } );
|
||||
return result;
|
||||
}
|
||||
|
||||
string String::format( const char* format, ... )
|
||||
{
|
||||
va_list arguments;
|
||||
va_start( arguments, format );
|
||||
|
||||
string formatted = "";
|
||||
string::size_type length = FORMAT_BUFFER_INITIAL_LENGTH;
|
||||
string::size_type required_length = String::format( formatted, length, format, arguments );
|
||||
|
||||
va_end( arguments );
|
||||
|
||||
if ( required_length > length )
|
||||
{
|
||||
va_start( arguments, format );
|
||||
String::format( formatted, required_length, format, arguments );
|
||||
va_end( arguments );
|
||||
}
|
||||
|
||||
return formatted;
|
||||
}
|
||||
|
||||
vector< string > String::split( const string& value, const char delimiter )
|
||||
{
|
||||
vector< string > tokens;
|
||||
string::size_type start = 0;
|
||||
string::size_type end = 0;
|
||||
|
||||
while ( ( end = value.find( delimiter, start ) ) not_eq string::npos )
|
||||
{
|
||||
const auto text = value.substr( start, end - start );
|
||||
|
||||
if ( not text.empty( ) )
|
||||
{
|
||||
tokens.push_back( text );
|
||||
}
|
||||
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
const auto token = value.substr( start );
|
||||
|
||||
if ( not token.empty( ) )
|
||||
{
|
||||
tokens.push_back( token );
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
string String::join( const multimap< string, string >& values, const string& pair_delimiter, const string& delimiter )
|
||||
{
|
||||
string result = "";
|
||||
|
||||
for ( auto value : values )
|
||||
{
|
||||
result += value.first + pair_delimiter + value.second + delimiter;
|
||||
}
|
||||
|
||||
if ( not result.empty( ) )
|
||||
{
|
||||
const size_t position = result.find_last_not_of( delimiter );
|
||||
|
||||
if ( string::npos not_eq position )
|
||||
{
|
||||
result = result.substr( 0, position + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
string String::remove( const string& target, const string& value, const Option option )
|
||||
{
|
||||
return replace( target, "", value, option );
|
||||
}
|
||||
|
||||
string String::replace( const string& target, const string& substitute, const string& value, const Option option )
|
||||
{
|
||||
if ( target.empty( ) )
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
static const regex escape( "([.^$|()\\[\\]{}*+?\\\\])" );
|
||||
const auto expression = regex_replace( target, escape, "\\$1" );
|
||||
auto pattern = regex( expression );
|
||||
|
||||
if ( option & String::Option::CASE_INSENSITIVE )
|
||||
{
|
||||
pattern.assign( expression, icase );
|
||||
}
|
||||
|
||||
smatch match;
|
||||
string result = value;
|
||||
|
||||
while ( regex_search( result, match, pattern ) )
|
||||
{
|
||||
result = regex_replace( result, pattern, substitute );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
string::size_type String::format( string& output, const string::size_type length, const char* format, va_list arguments )
|
||||
{
|
||||
unique_ptr< char[ ] > formatted( new char[ length + 1 ] );
|
||||
|
||||
int required_length = vsnprintf( formatted.get( ), length + 1, format, arguments );
|
||||
|
||||
if ( required_length == -1 )
|
||||
{
|
||||
required_length = 0;
|
||||
}
|
||||
|
||||
output = formatted.get( );
|
||||
|
||||
return required_length;
|
||||
}
|
||||
}
|
||||
124
lib/restbed-4.8/source/corvusoft/restbed/string.hpp
Normal file
124
lib/restbed-4.8/source/corvusoft/restbed/string.hpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdarg>
|
||||
|
||||
//Project Includes
|
||||
#include <corvusoft/restbed/byte.hpp>
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define STRING_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define STRING_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define STRING_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
class STRING_EXPORT String
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
enum Option : int
|
||||
{
|
||||
CASE_SENSITIVE = 0,
|
||||
CASE_INSENSITIVE = 1
|
||||
};
|
||||
|
||||
static const size_t FORMAT_BUFFER_INITIAL_LENGTH = 2048;
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
static Bytes to_bytes( const std::string& value );
|
||||
|
||||
static std::string to_string( const Bytes& value );
|
||||
|
||||
static std::string lowercase( const std::string& value );
|
||||
|
||||
static std::string uppercase( const std::string& value );
|
||||
|
||||
static std::string format( const char* format, ... );
|
||||
|
||||
static std::vector< std::string > split( const std::string& text, const char delimiter );
|
||||
|
||||
static std::string join( const std::multimap< std::string, std::string >& values, const std::string& pair_delimiter, const std::string& delimiter );
|
||||
|
||||
static std::string remove( const std::string& needle, const std::string& haystack, const Option option = CASE_SENSITIVE );
|
||||
|
||||
static std::string replace( const std::string& target, const std::string& substitute, const std::string& value, const Option option = CASE_SENSITIVE );
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
static const std::string empty;
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
String( void ) = delete;
|
||||
|
||||
String( const String& original ) = delete;
|
||||
|
||||
virtual ~String( void ) = delete;
|
||||
|
||||
//Functionality
|
||||
static std::string::size_type format( std::string& output, const std::string::size_type length, const char* format, va_list arguments );
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
String& operator =( const String& value ) = delete;
|
||||
|
||||
//Properties
|
||||
};
|
||||
}
|
||||
402
lib/restbed-4.8/source/corvusoft/restbed/uri.cpp
Normal file
402
lib/restbed-4.8/source/corvusoft/restbed/uri.cpp
Normal file
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <regex>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <ciso646>
|
||||
#include <winsock2.h>
|
||||
#pragma comment( lib, "Ws2_32.lib" )
|
||||
#else
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/uri.hpp"
|
||||
#include "corvusoft/restbed/string.hpp"
|
||||
#include "corvusoft/restbed/detail/uri_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::stoi;
|
||||
using std::regex;
|
||||
using std::smatch;
|
||||
using std::strtol;
|
||||
using std::string;
|
||||
using std::multimap;
|
||||
using std::snprintf;
|
||||
using std::to_string;
|
||||
using std::unique_ptr;
|
||||
using std::runtime_error;
|
||||
using std::invalid_argument;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::UriImpl;
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
Uri::Uri( const string& value, bool relative ) : m_pimpl( new UriImpl )
|
||||
{
|
||||
if ( not is_valid( value ) )
|
||||
{
|
||||
throw invalid_argument( "Argument is not a valid URI: " + value );
|
||||
}
|
||||
|
||||
m_pimpl->m_uri = value;
|
||||
m_pimpl->m_relative = relative;
|
||||
}
|
||||
|
||||
Uri::Uri( const Uri& original ) : m_pimpl( new UriImpl( *original.m_pimpl ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Uri::~Uri( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool Uri::is_relative( void ) const
|
||||
{
|
||||
return m_pimpl->m_relative;
|
||||
}
|
||||
|
||||
bool Uri::is_absolute( void ) const
|
||||
{
|
||||
return not m_pimpl->m_relative;
|
||||
}
|
||||
|
||||
string Uri::to_string( void ) const
|
||||
{
|
||||
return m_pimpl->m_uri;
|
||||
}
|
||||
|
||||
bool Uri::is_valid( const string& value )
|
||||
{
|
||||
static const regex pattern( "^[a-zA-Z][a-zA-Z0-9+\\-.]*://(([a-zA-Z0-9\\-._~%!$&'()*+,;=]+)(:([a-zA-Z0-9\\-._~%!$&'()*+,;=]+))?@)?([a-zA-Z0-9\\-._~%!$&'()*+,;=:\\[\\]]*(:[0-9]+)?)?[a-zA-Z0-9\\-._~%!$&'()*+,;=:@/]+(\\?[a-zA-Z0-9\\-._~%!$&'()*+,;=:@/]*)?(#[a-zA-Z0-9\\-._~%!$&'()*+,;=:@/?]*)?$" );
|
||||
|
||||
return regex_match( value, pattern );
|
||||
}
|
||||
|
||||
Uri Uri::parse( const string& value )
|
||||
{
|
||||
return Uri( value );
|
||||
}
|
||||
|
||||
string Uri::decode( const Bytes& value )
|
||||
{
|
||||
return decode( string( value.begin( ), value.end( ) ) );
|
||||
}
|
||||
|
||||
string Uri::decode( const string& value )
|
||||
{
|
||||
static const char hex_to_dec[256] =
|
||||
{
|
||||
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
||||
/* 0 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 1 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 2 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 3 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1,
|
||||
|
||||
/* 4 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 5 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 6 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 7 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
|
||||
/* 8 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 9 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* A */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* B */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
|
||||
/* C */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* D */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* E */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* F */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
|
||||
};
|
||||
|
||||
if( value.size( ) < 3 ) {
|
||||
return value;
|
||||
}
|
||||
|
||||
string::size_type valuesize = value.size( );
|
||||
|
||||
string result;
|
||||
result.reserve( valuesize );
|
||||
|
||||
char c1 = 0;
|
||||
char c2 = 0;
|
||||
unsigned char cindex = 0;
|
||||
|
||||
string::size_type index = 0;
|
||||
for ( ; index < ( valuesize - 2 ); index++ )
|
||||
{
|
||||
if ( value[index] == '%' )
|
||||
{
|
||||
cindex = value[ index + 1 ];
|
||||
c1 = hex_to_dec[ cindex ];
|
||||
|
||||
cindex = value[ index + 2 ];
|
||||
c2 = hex_to_dec[ cindex ];
|
||||
if ( c1 != -1 && c2 != -1 )
|
||||
{
|
||||
result.push_back( ( c1 << 4 ) + c2 );
|
||||
index += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
result.push_back( value[ index ] );
|
||||
}
|
||||
|
||||
for ( ; index < valuesize; index++ )
|
||||
{
|
||||
result.push_back( value[ index ] );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
string Uri::decode_parameter( const string& value )
|
||||
{
|
||||
return decode( String::replace( "+", " ", value ) );
|
||||
}
|
||||
|
||||
string Uri::encode( const Bytes& value )
|
||||
{
|
||||
const bool unsafe_carachters[256] =
|
||||
{
|
||||
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
||||
/* 0 */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
|
||||
/* 1 */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
|
||||
/* 2 */ 1,0,1,1, 1,1,1,0, 0,0,0,1, 1,0,0,1,
|
||||
/* 3 */ 0,0,0,0, 0,0,0,0, 0,0,1,1, 1,1,1,1,
|
||||
/* 4 */ 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
||||
/* 5 */ 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,1,0,
|
||||
/* 6 */ 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
||||
/* 7 */ 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,0,1,
|
||||
/* 8 */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
|
||||
/* 9 */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
|
||||
/* A */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
|
||||
/* B */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
|
||||
/* C */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
|
||||
/* D */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
|
||||
/* E */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
|
||||
/* F */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1
|
||||
};
|
||||
static const char dec_to_hex[] = "0123456789ABCDEF";
|
||||
|
||||
string encoded;
|
||||
encoded.reserve( value.size() );
|
||||
|
||||
for ( Byte character : value )
|
||||
{
|
||||
if ( unsafe_carachters[ character ] )
|
||||
{
|
||||
encoded.push_back( '%' );
|
||||
encoded.push_back( dec_to_hex[ character >> 4 ] );
|
||||
encoded.push_back( dec_to_hex[ character & 0x0F ]);
|
||||
}
|
||||
else
|
||||
{
|
||||
encoded.push_back( character );
|
||||
}
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
string Uri::encode( const string& value )
|
||||
{
|
||||
return encode( Bytes( value.begin( ), value.end( ) ) );
|
||||
}
|
||||
|
||||
string Uri::encode_parameter( const string& value )
|
||||
{
|
||||
return encode( value );
|
||||
}
|
||||
|
||||
uint16_t Uri::get_port( void ) const
|
||||
{
|
||||
smatch match;
|
||||
string port = String::empty;
|
||||
static const regex pattern( "^[a-zA-Z][a-zA-Z0-9+\\-.]*://(([a-zA-Z0-9\\-._~%!$&'()*+,;=]+)(:([a-zA-Z0-9\\-._~%!$&'()*+,;=]+))?@)?([a-zA-Z0-9\\-._~%]+|\\[[a-zA-Z0-9\\-._~%!$&'()*+,;=:]+\\]):([0-9]+)" );
|
||||
|
||||
if ( regex_search( m_pimpl->m_uri, match, pattern ) )
|
||||
{
|
||||
port = match[ 6 ];
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto scheme = get_scheme( );
|
||||
|
||||
if ( not scheme.empty( ) )
|
||||
{
|
||||
const struct servent* entry = getservbyname( scheme.data( ), nullptr );
|
||||
|
||||
if ( entry not_eq nullptr )
|
||||
{
|
||||
port = ::to_string( ntohs( entry->s_port ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( port.empty( ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast< uint16_t >( stoi( port ) );
|
||||
}
|
||||
|
||||
string Uri::get_path( void ) const
|
||||
{
|
||||
static const regex pattern( "^([a-zA-Z][a-zA-Z0-9+\\-.]*://([^/?#]+)?)?([a-zA-Z0-9\\-._~%!$&'()*+,;=:@/]*)" );
|
||||
|
||||
smatch match;
|
||||
|
||||
if ( regex_search( m_pimpl->m_uri, match, pattern ) )
|
||||
{
|
||||
return ( is_absolute( ) ) ? match[ 3 ] : string( match[ 2 ] ) + string( match[ 3 ] );
|
||||
}
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
string Uri::get_query( void ) const
|
||||
{
|
||||
smatch match;
|
||||
static const regex pattern( "^[^?#]+\\?([^#]+)" );
|
||||
|
||||
if ( regex_search( m_pimpl->m_uri, match, pattern ) )
|
||||
{
|
||||
return match[ 1 ];
|
||||
}
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
string Uri::get_scheme( void ) const
|
||||
{
|
||||
smatch match;
|
||||
static const regex pattern( "^([a-zA-Z][a-zA-Z0-9+\\-.]*):" );
|
||||
|
||||
if ( regex_search( m_pimpl->m_uri, match, pattern ) )
|
||||
{
|
||||
return match[ 1 ];
|
||||
}
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
string Uri::get_fragment( void ) const
|
||||
{
|
||||
smatch match;
|
||||
static const regex pattern( "#(.+)" );
|
||||
|
||||
if ( regex_search( m_pimpl->m_uri, match, pattern ) )
|
||||
{
|
||||
return match[ 1 ];
|
||||
}
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
string Uri::get_username( void ) const
|
||||
{
|
||||
smatch match;
|
||||
static const regex pattern( "^[a-zA-Z0-9+\\-.]+://([a-zA-Z0-9\\-._~%!$&'()*+,;=]+)(:([a-zA-Z0-9\\-._~%!$&'()*+,;=]+))?@" );
|
||||
|
||||
if ( regex_search( m_pimpl->m_uri, match, pattern ) )
|
||||
{
|
||||
return match[ 1 ];
|
||||
}
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
string Uri::get_password( void ) const
|
||||
{
|
||||
smatch match;
|
||||
static const regex pattern( "^[a-zA-Z0-9+\\-.]+://([a-zA-Z0-9\\-._~%!$&'()*+,;=]+):([a-zA-Z0-9\\-._~%!$&'()*+,;=]+)@" );
|
||||
|
||||
if ( regex_search( m_pimpl->m_uri, match, pattern ) )
|
||||
{
|
||||
return match[ 2 ];
|
||||
}
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
|
||||
string Uri::get_authority( void ) const
|
||||
{
|
||||
string authority = String::empty;
|
||||
if ( is_relative( ) ) return authority;
|
||||
|
||||
smatch match;
|
||||
static const regex pattern( "^[a-zA-Z][a-zA-Z0-9+\\-.]*://(([a-zA-Z0-9\\-._~%!$&'()*+,;=]+)(:([a-zA-Z0-9\\-._~%!$&'()*+,;=]+))?@)?([a-zA-Z0-9\\-._~%]+|\\[[a-zA-Z0-9\\-._~%!$&'()*+,;=:]+\\])" );
|
||||
if ( regex_search( m_pimpl->m_uri, match, pattern ) ) authority = match[ 5 ];
|
||||
else return authority;
|
||||
|
||||
if ( authority.front( ) == '[' ) authority.erase( 0, 1 );
|
||||
if ( authority.back( ) == ']' ) authority.erase( authority.length( ) - 1, 1 );
|
||||
return authority;
|
||||
}
|
||||
|
||||
multimap< string, string > Uri::get_query_parameters( void ) const
|
||||
{
|
||||
multimap< string, string > parameters;
|
||||
|
||||
auto query = String::split( get_query( ), '&' );
|
||||
|
||||
for ( auto parameter : query )
|
||||
{
|
||||
auto index = parameter.find_first_of( '=' );
|
||||
auto name = decode_parameter( parameter.substr( 0, index ) );
|
||||
auto value = (index not_eq string::npos) ? decode_parameter( parameter.substr( index + 1, parameter.length( ) ) ) : "";
|
||||
|
||||
parameters.insert( make_pair( name, value ) );
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
Uri& Uri::operator =( const Uri& rhs )
|
||||
{
|
||||
m_pimpl->m_uri = rhs.m_pimpl->m_uri;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Uri::operator <( const Uri& rhs ) const
|
||||
{
|
||||
return m_pimpl->m_uri < rhs.m_pimpl->m_uri;
|
||||
}
|
||||
|
||||
bool Uri::operator >( const Uri& rhs ) const
|
||||
{
|
||||
return m_pimpl->m_uri > rhs.m_pimpl->m_uri;
|
||||
}
|
||||
|
||||
bool Uri::operator ==( const Uri& rhs ) const
|
||||
{
|
||||
return m_pimpl->m_uri == rhs.m_pimpl->m_uri;
|
||||
}
|
||||
|
||||
bool Uri::operator !=( const Uri& rhs ) const
|
||||
{
|
||||
return m_pimpl->m_uri not_eq rhs.m_pimpl->m_uri;
|
||||
}
|
||||
|
||||
Uri::Uri( void ) : m_pimpl( new UriImpl )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
152
lib/restbed-4.8/source/corvusoft/restbed/uri.hpp
Normal file
152
lib/restbed-4.8/source/corvusoft/restbed/uri.hpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
//Project Includes
|
||||
#include <corvusoft/restbed/byte.hpp>
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define URI_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define URI_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define URI_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
namespace detail
|
||||
{
|
||||
struct UriImpl;
|
||||
}
|
||||
|
||||
class URI_EXPORT Uri
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
static const bool Relative = true;
|
||||
static const bool Absolute = false;
|
||||
|
||||
//Constructors
|
||||
explicit Uri( const std::string& value, bool relative = false );
|
||||
|
||||
Uri( const Uri& original );
|
||||
|
||||
virtual ~Uri( void );
|
||||
|
||||
//Functionality
|
||||
bool is_relative( void ) const;
|
||||
|
||||
bool is_absolute( void ) const;
|
||||
|
||||
std::string to_string( void ) const;
|
||||
|
||||
static bool is_valid( const std::string& value );
|
||||
|
||||
static Uri parse( const std::string& value );
|
||||
|
||||
static std::string decode( const Bytes& value );
|
||||
|
||||
static std::string decode( const std::string& value );
|
||||
|
||||
static std::string decode_parameter( const std::string& value );
|
||||
|
||||
static std::string encode( const Bytes& value );
|
||||
|
||||
static std::string encode( const std::string& value );
|
||||
|
||||
static std::string encode_parameter( const std::string& value );
|
||||
|
||||
//Getters
|
||||
uint16_t get_port( void ) const;
|
||||
|
||||
std::string get_path( void ) const;
|
||||
|
||||
std::string get_query( void ) const;
|
||||
|
||||
std::string get_scheme( void ) const;
|
||||
|
||||
std::string get_fragment( void ) const;
|
||||
|
||||
std::string get_username( void ) const;
|
||||
|
||||
std::string get_password( void ) const;
|
||||
|
||||
std::string get_authority( void ) const;
|
||||
|
||||
std::multimap< std::string, std::string > get_query_parameters( void ) const;
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
Uri& operator =( const Uri& rhs );
|
||||
|
||||
bool operator <( const Uri& rhs ) const;
|
||||
|
||||
bool operator >( const Uri& rhs ) const;
|
||||
|
||||
bool operator ==( const Uri& rhs ) const;
|
||||
|
||||
bool operator !=( const Uri& rhs ) const;
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
Uri( void );
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
std::unique_ptr< detail::UriImpl > m_pimpl;
|
||||
};
|
||||
}
|
||||
209
lib/restbed-4.8/source/corvusoft/restbed/web_socket.cpp
Normal file
209
lib/restbed-4.8/source/corvusoft/restbed/web_socket.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
#include <ciso646>
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/string.hpp"
|
||||
#include "corvusoft/restbed/web_socket.hpp"
|
||||
#include "corvusoft/restbed/detail/socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/web_socket_impl.hpp"
|
||||
#include "corvusoft/restbed/detail/web_socket_manager_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::ref;
|
||||
using std::bind;
|
||||
using std::string;
|
||||
using std::function;
|
||||
using std::error_code;
|
||||
using std::shared_ptr;
|
||||
using std::make_shared;
|
||||
using std::placeholders::_1;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::SocketImpl;
|
||||
using restbed::detail::WebSocketImpl;
|
||||
using restbed::detail::WebSocketManagerImpl;
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
WebSocket::WebSocket( void ) : m_pimpl( new WebSocketImpl )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WebSocket::~WebSocket( void )
|
||||
{
|
||||
try
|
||||
{
|
||||
close( );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
m_pimpl->log( Logger::WARNING, "Service failed graceful wind down." );
|
||||
}
|
||||
}
|
||||
|
||||
bool WebSocket::is_open( void ) const
|
||||
{
|
||||
return m_pimpl->m_socket not_eq nullptr and m_pimpl->m_socket->is_open( );
|
||||
}
|
||||
|
||||
bool WebSocket::is_closed( void ) const
|
||||
{
|
||||
return m_pimpl->m_socket not_eq nullptr and m_pimpl->m_socket->is_closed( );
|
||||
}
|
||||
|
||||
void WebSocket::close( void )
|
||||
{
|
||||
auto socket = shared_from_this( );
|
||||
|
||||
if ( m_pimpl->m_close_handler not_eq nullptr )
|
||||
{
|
||||
m_pimpl->m_close_handler( socket );
|
||||
}
|
||||
|
||||
m_pimpl->m_manager->destroy( socket );
|
||||
m_pimpl->m_socket->close( );
|
||||
}
|
||||
|
||||
void WebSocket::send( const Bytes& body, const function< void ( const shared_ptr< WebSocket > ) > callback )
|
||||
{
|
||||
send( make_shared< WebSocketMessage >( WebSocketMessage::BINARY_FRAME, body ), callback );
|
||||
}
|
||||
|
||||
void WebSocket::send( const string& body, const function< void ( const shared_ptr< WebSocket > ) > callback )
|
||||
{
|
||||
send( make_shared< WebSocketMessage >( WebSocketMessage::TEXT_FRAME, body ), callback );
|
||||
}
|
||||
|
||||
void WebSocket::send( const WebSocketMessage::OpCode opcode, const function< void ( const shared_ptr< WebSocket > ) > callback )
|
||||
{
|
||||
send( make_shared< WebSocketMessage >( opcode ), callback );
|
||||
}
|
||||
|
||||
void WebSocket::send( const shared_ptr< WebSocketMessage > message, const function< void ( const shared_ptr< WebSocket > ) > callback )
|
||||
{
|
||||
const auto data = m_pimpl->m_manager->compose( message );
|
||||
|
||||
m_pimpl->m_socket->start_write( data, [ this, callback ]( const error_code & code, size_t )
|
||||
{
|
||||
if ( code )
|
||||
{
|
||||
if ( m_pimpl->m_error_handler not_eq nullptr )
|
||||
{
|
||||
m_pimpl->m_error_handler( shared_from_this( ), code );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( callback not_eq nullptr )
|
||||
{
|
||||
callback( shared_from_this( ) );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
string WebSocket::get_key( void ) const
|
||||
{
|
||||
return m_pimpl->m_key;
|
||||
}
|
||||
|
||||
shared_ptr< Logger > WebSocket::get_logger( void ) const
|
||||
{
|
||||
return m_pimpl->m_logger;
|
||||
}
|
||||
|
||||
shared_ptr< SocketImpl > WebSocket::get_socket( void ) const
|
||||
{
|
||||
return m_pimpl->m_socket;
|
||||
}
|
||||
|
||||
function< void ( const shared_ptr< WebSocket > ) > WebSocket::get_open_handler( void ) const
|
||||
{
|
||||
return m_pimpl->m_open_handler;
|
||||
}
|
||||
|
||||
function< void ( const shared_ptr< WebSocket > ) > WebSocket::get_close_handler( void ) const
|
||||
{
|
||||
return m_pimpl->m_close_handler;
|
||||
}
|
||||
|
||||
function< void ( const shared_ptr< WebSocket >, const error_code ) > WebSocket::get_error_handler( void ) const
|
||||
{
|
||||
return m_pimpl->m_error_handler;
|
||||
}
|
||||
|
||||
function< void ( const shared_ptr< WebSocket >, const shared_ptr< WebSocketMessage > ) > WebSocket::get_message_handler( void ) const
|
||||
{
|
||||
return m_pimpl->m_message_handler;
|
||||
}
|
||||
|
||||
void WebSocket::set_key( const string& value )
|
||||
{
|
||||
m_pimpl->m_key = value;
|
||||
}
|
||||
|
||||
void WebSocket::set_logger( const shared_ptr< Logger >& value )
|
||||
{
|
||||
m_pimpl->m_logger = value;
|
||||
}
|
||||
|
||||
void WebSocket::set_socket( const shared_ptr< SocketImpl >& value )
|
||||
{
|
||||
m_pimpl->m_socket = value;
|
||||
}
|
||||
|
||||
void WebSocket::set_open_handler( const function< void ( const shared_ptr< WebSocket > ) >& value )
|
||||
{
|
||||
m_pimpl->m_open_handler = value;
|
||||
}
|
||||
|
||||
void WebSocket::set_close_handler( const function< void ( const shared_ptr< WebSocket > ) >& value )
|
||||
{
|
||||
if ( value == nullptr )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_pimpl->m_close_handler = [ value, this ]( const shared_ptr< WebSocket >& socket )
|
||||
{
|
||||
value( socket );
|
||||
m_pimpl->m_manager->destroy( socket );
|
||||
};
|
||||
}
|
||||
|
||||
void WebSocket::set_error_handler( const function< void ( const shared_ptr< WebSocket >, const error_code ) >& value )
|
||||
{
|
||||
if ( value == nullptr )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_pimpl->m_error_handler = [ value, this ]( const shared_ptr< WebSocket > socket, const error_code code )
|
||||
{
|
||||
if ( m_pimpl->m_error_handler_invoked == false )
|
||||
{
|
||||
value( socket, code );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void WebSocket::set_message_handler( const function< void ( const shared_ptr< WebSocket >, const shared_ptr< WebSocketMessage > ) >& value )
|
||||
{
|
||||
if ( value == nullptr )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_pimpl->m_message_handler = value;
|
||||
m_pimpl->listen( shared_from_this( ) );
|
||||
}
|
||||
}
|
||||
148
lib/restbed-4.8/source/corvusoft/restbed/web_socket.hpp
Normal file
148
lib/restbed-4.8/source/corvusoft/restbed/web_socket.hpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <system_error>
|
||||
|
||||
//Project Includes
|
||||
#include <corvusoft/restbed/web_socket_message.hpp>
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define WEB_SOCKET_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define WEB_SOCKET_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define WEB_SOCKET_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
class Logger;
|
||||
class Session;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class SocketImpl;
|
||||
class WebSocketImpl;
|
||||
class WebSocketManagerImpl;
|
||||
}
|
||||
|
||||
class WEB_SOCKET_EXPORT WebSocket : public std::enable_shared_from_this< WebSocket >
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
WebSocket( void );
|
||||
|
||||
~WebSocket( void );
|
||||
|
||||
//Functionality
|
||||
bool is_open( void ) const;
|
||||
|
||||
bool is_closed( void ) const;
|
||||
|
||||
void close( void );
|
||||
|
||||
void send( const Bytes& body, const std::function< void ( const std::shared_ptr< WebSocket > ) > callback = nullptr );
|
||||
|
||||
void send( const std::string& body, const std::function< void ( const std::shared_ptr< WebSocket > ) > callback = nullptr );
|
||||
|
||||
void send( const WebSocketMessage::OpCode opcode, const std::function< void ( const std::shared_ptr< WebSocket > ) > callback = nullptr );
|
||||
|
||||
void send( const std::shared_ptr< WebSocketMessage > message, const std::function< void ( const std::shared_ptr< WebSocket > ) > callback = nullptr );
|
||||
|
||||
//Getters
|
||||
std::string get_key( void ) const;
|
||||
|
||||
std::shared_ptr< Logger > get_logger( void ) const;
|
||||
|
||||
std::shared_ptr< detail::SocketImpl > get_socket( void ) const;
|
||||
|
||||
std::function< void ( const std::shared_ptr< WebSocket > ) > get_open_handler( void ) const;
|
||||
|
||||
std::function< void ( const std::shared_ptr< WebSocket > ) > get_close_handler( void ) const;
|
||||
|
||||
std::function< void ( const std::shared_ptr< WebSocket >, const std::error_code ) > get_error_handler( void ) const;
|
||||
|
||||
std::function< void ( const std::shared_ptr< WebSocket >, const std::shared_ptr< WebSocketMessage > ) > get_message_handler( void ) const;
|
||||
|
||||
//Setters
|
||||
void set_key( const std::string& value );
|
||||
|
||||
void set_logger( const std::shared_ptr< Logger >& value );
|
||||
|
||||
void set_socket( const std::shared_ptr< detail::SocketImpl >& value );
|
||||
|
||||
void set_open_handler( const std::function< void ( const std::shared_ptr< WebSocket > ) >& value );
|
||||
|
||||
void set_close_handler( const std::function< void ( const std::shared_ptr< WebSocket > ) >& value );
|
||||
|
||||
void set_error_handler( const std::function< void ( const std::shared_ptr< WebSocket >, const std::error_code ) >& value );
|
||||
|
||||
void set_message_handler( const std::function< void ( const std::shared_ptr< WebSocket >, const std::shared_ptr< WebSocketMessage > ) >& value );
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
friend Session;
|
||||
friend detail::WebSocketManagerImpl;
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
WebSocket( const WebSocket& original ) = delete;
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
WebSocket& operator =( const WebSocket& value ) = delete;
|
||||
|
||||
//Properties
|
||||
std::unique_ptr< detail::WebSocketImpl > m_pimpl;
|
||||
};
|
||||
}
|
||||
167
lib/restbed-4.8/source/corvusoft/restbed/web_socket_message.cpp
Normal file
167
lib/restbed-4.8/source/corvusoft/restbed/web_socket_message.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
//System Includes
|
||||
|
||||
//Project Includes
|
||||
#include "corvusoft/restbed/string.hpp"
|
||||
#include "corvusoft/restbed/web_socket_message.hpp"
|
||||
#include "corvusoft/restbed/detail/web_socket_message_impl.hpp"
|
||||
|
||||
//External Includes
|
||||
|
||||
//System Namespaces
|
||||
using std::tuple;
|
||||
using std::string;
|
||||
using std::uint8_t;
|
||||
using std::uint32_t;
|
||||
using std::uint64_t;
|
||||
using std::shared_ptr;
|
||||
using std::make_tuple;
|
||||
|
||||
//Project Namespaces
|
||||
using restbed::detail::WebSocketMessageImpl;
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
WebSocketMessage::WebSocketMessage( void ) : m_pimpl( new WebSocketMessageImpl )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WebSocketMessage::WebSocketMessage( const WebSocketMessage& original ) : m_pimpl( new WebSocketMessageImpl )
|
||||
{
|
||||
*m_pimpl = *original.m_pimpl;
|
||||
}
|
||||
|
||||
WebSocketMessage::WebSocketMessage( const WebSocketMessage::OpCode code, const Bytes& data ) : WebSocketMessage( code, data, 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WebSocketMessage::WebSocketMessage( const WebSocketMessage::OpCode code, const string& data ) : WebSocketMessage( code, data, 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WebSocketMessage::WebSocketMessage( const WebSocketMessage::OpCode code, const Bytes& data, const uint32_t mask ) : m_pimpl( new WebSocketMessageImpl )
|
||||
{
|
||||
m_pimpl->m_data = data;
|
||||
m_pimpl->m_mask = mask;
|
||||
m_pimpl->m_opcode = code;
|
||||
m_pimpl->m_mask_flag = ( mask == 0 ) ? false : true;
|
||||
|
||||
const auto length = data.size( );
|
||||
|
||||
if ( length <= 125 )
|
||||
{
|
||||
m_pimpl->m_length = static_cast< uint8_t >( length );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pimpl->m_extended_length = length;
|
||||
m_pimpl->m_length = ( length < 65535 ) ? 126 : 127;
|
||||
}
|
||||
}
|
||||
|
||||
WebSocketMessage::WebSocketMessage( const WebSocketMessage::OpCode code, const string& data, const uint32_t mask ) : WebSocketMessage( code, String::to_bytes( data ), mask )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WebSocketMessage::~WebSocketMessage( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Bytes WebSocketMessage::get_data( void ) const
|
||||
{
|
||||
return m_pimpl->m_data;
|
||||
}
|
||||
|
||||
WebSocketMessage::OpCode WebSocketMessage::get_opcode( void ) const
|
||||
{
|
||||
return m_pimpl->m_opcode;
|
||||
}
|
||||
|
||||
uint32_t WebSocketMessage::get_mask( void ) const
|
||||
{
|
||||
return m_pimpl->m_mask;
|
||||
}
|
||||
|
||||
uint8_t WebSocketMessage::get_length( void ) const
|
||||
{
|
||||
return m_pimpl->m_length;
|
||||
}
|
||||
|
||||
uint64_t WebSocketMessage::get_extended_length( void ) const
|
||||
{
|
||||
return m_pimpl->m_extended_length;
|
||||
}
|
||||
|
||||
bool WebSocketMessage::get_mask_flag( void ) const
|
||||
{
|
||||
return m_pimpl->m_mask_flag;
|
||||
}
|
||||
|
||||
bool WebSocketMessage::get_final_frame_flag( void ) const
|
||||
{
|
||||
return m_pimpl->m_final_frame_flag;
|
||||
}
|
||||
|
||||
tuple< bool, bool, bool > WebSocketMessage::get_reserved_flags( void ) const
|
||||
{
|
||||
return make_tuple( m_pimpl->m_reserved_flag_one, m_pimpl->m_reserved_flag_two, m_pimpl->m_reserved_flag_three );
|
||||
}
|
||||
|
||||
void WebSocketMessage::set_data( const Bytes& value )
|
||||
{
|
||||
m_pimpl->m_data = value;
|
||||
}
|
||||
|
||||
void WebSocketMessage::set_data( const string& value )
|
||||
{
|
||||
m_pimpl->m_data = String::to_bytes( value );
|
||||
}
|
||||
|
||||
void WebSocketMessage::set_opcode( const WebSocketMessage::OpCode value )
|
||||
{
|
||||
m_pimpl->m_opcode = value;
|
||||
}
|
||||
|
||||
void WebSocketMessage::set_mask( const uint32_t value )
|
||||
{
|
||||
m_pimpl->m_mask = value;
|
||||
m_pimpl->m_mask_flag = ( value == 0 ) ? false : true;
|
||||
}
|
||||
|
||||
void WebSocketMessage::set_length( const uint8_t value )
|
||||
{
|
||||
m_pimpl->m_length = value;
|
||||
}
|
||||
|
||||
void WebSocketMessage::set_extended_length( const uint64_t value )
|
||||
{
|
||||
m_pimpl->m_extended_length = value;
|
||||
}
|
||||
|
||||
void WebSocketMessage::set_mask_flag( const bool value )
|
||||
{
|
||||
m_pimpl->m_mask_flag = value;
|
||||
}
|
||||
|
||||
void WebSocketMessage::set_final_frame_flag( const bool value )
|
||||
{
|
||||
m_pimpl->m_final_frame_flag = value;
|
||||
}
|
||||
|
||||
void WebSocketMessage::set_reserved_flags( const bool rsv1, const bool rsv2, const bool rsv3 )
|
||||
{
|
||||
m_pimpl->m_reserved_flag_one = rsv1;
|
||||
m_pimpl->m_reserved_flag_two = rsv2;
|
||||
m_pimpl->m_reserved_flag_three = rsv3;
|
||||
}
|
||||
}
|
||||
155
lib/restbed-4.8/source/corvusoft/restbed/web_socket_message.hpp
Normal file
155
lib/restbed-4.8/source/corvusoft/restbed/web_socket_message.hpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2013-2020, Corvusoft Ltd, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//System Includes
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <system_error>
|
||||
|
||||
//Project Includes
|
||||
#include <corvusoft/restbed/byte.hpp>
|
||||
|
||||
//External Includes
|
||||
|
||||
//Windows DLL Exports
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||
#ifdef WIN_DLL_EXPORT
|
||||
#define WEB_SOCKET_MESSAGE_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define WEB_SOCKET_MESSAGE_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define WEB_SOCKET_MESSAGE_EXPORT
|
||||
#endif
|
||||
|
||||
//System Namespaces
|
||||
|
||||
//Project Namespaces
|
||||
|
||||
//External Namespaces
|
||||
|
||||
namespace restbed
|
||||
{
|
||||
//Forward Declarations
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct WebSocketMessageImpl;
|
||||
}
|
||||
|
||||
class WEB_SOCKET_MESSAGE_EXPORT WebSocketMessage
|
||||
{
|
||||
public:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
enum OpCode : uint8_t
|
||||
{
|
||||
CONTINUATION_FRAME = 0x00,
|
||||
TEXT_FRAME = 0x01,
|
||||
BINARY_FRAME = 0x02,
|
||||
CONNECTION_CLOSE_FRAME = 0x08,
|
||||
PING_FRAME = 0x09,
|
||||
PONG_FRAME = 0x0A
|
||||
};
|
||||
|
||||
//Constructors
|
||||
WebSocketMessage( void );
|
||||
|
||||
WebSocketMessage( const WebSocketMessage& original );
|
||||
|
||||
WebSocketMessage( const OpCode code, const Bytes& data = { } );
|
||||
|
||||
WebSocketMessage( const OpCode code, const std::string& data );
|
||||
|
||||
WebSocketMessage( const OpCode code, const Bytes& data, const std::uint32_t mask );
|
||||
|
||||
WebSocketMessage( const OpCode code, const std::string& data, const std::uint32_t mask );
|
||||
|
||||
virtual ~WebSocketMessage( void );
|
||||
|
||||
//Functionality
|
||||
Bytes to_bytes( void ) const;
|
||||
|
||||
//Getters
|
||||
Bytes get_data( void ) const;
|
||||
|
||||
OpCode get_opcode( void ) const;
|
||||
|
||||
std::uint32_t get_mask( void ) const;
|
||||
|
||||
std::uint8_t get_length( void ) const;
|
||||
|
||||
std::uint64_t get_extended_length( void ) const;
|
||||
|
||||
bool get_mask_flag( void ) const;
|
||||
|
||||
bool get_final_frame_flag( void ) const;
|
||||
|
||||
std::tuple< bool, bool, bool > get_reserved_flags( void ) const;
|
||||
|
||||
//Setters
|
||||
void set_data( const Bytes& value );
|
||||
|
||||
void set_data( const std::string& value );
|
||||
|
||||
void set_opcode( const OpCode value );
|
||||
|
||||
void set_mask( const std::uint32_t value );
|
||||
|
||||
void set_length( const std::uint8_t value );
|
||||
|
||||
void set_extended_length( const std::uint64_t value );
|
||||
|
||||
void set_mask_flag( const bool value );
|
||||
|
||||
void set_final_frame_flag( const bool value );
|
||||
|
||||
void set_reserved_flags( const bool rsv1, const bool rsv2, const bool rsv3 );
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
protected:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
|
||||
//Properties
|
||||
|
||||
private:
|
||||
//Friends
|
||||
|
||||
//Definitions
|
||||
|
||||
//Constructors
|
||||
|
||||
//Functionality
|
||||
|
||||
//Getters
|
||||
|
||||
//Setters
|
||||
|
||||
//Operators
|
||||
WebSocketMessage& operator =( const WebSocketMessage& value ) = delete;
|
||||
|
||||
//Properties
|
||||
std::unique_ptr< detail::WebSocketMessageImpl > m_pimpl;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user