mirror of
https://github.com/boostorg/beast.git
synced 2025-08-01 05:44:38 +02:00
Add server-framework SSL HTTP and WebSocket ports
This commit is contained in:
@@ -8,6 +8,7 @@ Version 61:
|
|||||||
* Tidy up names in error categories
|
* Tidy up names in error categories
|
||||||
* Flush the output stream in the example
|
* Flush the output stream in the example
|
||||||
* Clean close in Secure WebSocket client
|
* Clean close in Secure WebSocket client
|
||||||
|
* Add server-framework SSL HTTP and WebSocket ports
|
||||||
|
|
||||||
API Changes:
|
API Changes:
|
||||||
|
|
||||||
|
@@ -70,6 +70,13 @@ endif()
|
|||||||
|
|
||||||
find_package(OpenSSL)
|
find_package(OpenSSL)
|
||||||
|
|
||||||
|
if (OPENSSL_FOUND)
|
||||||
|
add_definitions (-DBEAST_USE_OPENSSL=1)
|
||||||
|
else()
|
||||||
|
add_definitions (-DBEAST_USE_OPENSSL=0)
|
||||||
|
message("OpenSSL not found.")
|
||||||
|
endif()
|
||||||
|
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -182,9 +189,7 @@ add_subdirectory (test)
|
|||||||
|
|
||||||
add_subdirectory (example)
|
add_subdirectory (example)
|
||||||
|
|
||||||
if (NOT OPENSSL_FOUND)
|
if (OPENSSL_FOUND)
|
||||||
message("OpenSSL not found. Not building SSL tests and examples")
|
|
||||||
else()
|
|
||||||
add_subdirectory (example/ssl-http-client)
|
add_subdirectory (example/ssl-http-client)
|
||||||
add_subdirectory (example/ssl-websocket-client)
|
add_subdirectory (example/ssl-websocket-client)
|
||||||
add_subdirectory (test/websocket/ssl)
|
add_subdirectory (test/websocket/ssl)
|
||||||
|
@@ -113,14 +113,18 @@ for writing their own servers. It serves both HTTP and WebSocket.
|
|||||||
* [repo_file example/server-framework/http_async_port.hpp]
|
* [repo_file example/server-framework/http_async_port.hpp]
|
||||||
* [repo_file example/server-framework/http_base.hpp]
|
* [repo_file example/server-framework/http_base.hpp]
|
||||||
* [repo_file example/server-framework/http_sync_port.hpp]
|
* [repo_file example/server-framework/http_sync_port.hpp]
|
||||||
|
* [repo_file example/server-framework/https_ports.hpp]
|
||||||
* [repo_file example/server-framework/main.cpp]
|
* [repo_file example/server-framework/main.cpp]
|
||||||
* [repo_file example/server-framework/rfc7231.hpp]
|
* [repo_file example/server-framework/rfc7231.hpp]
|
||||||
* [repo_file example/server-framework/server.hpp]
|
* [repo_file example/server-framework/server.hpp]
|
||||||
* [repo_file example/server-framework/service_list.hpp]
|
* [repo_file example/server-framework/service_list.hpp]
|
||||||
|
* [repo_file example/server-framework/ssl_certificate.hpp]
|
||||||
|
* [repo_file example/server-framework/ssl_stream.hpp]
|
||||||
* [repo_file example/server-framework/write_msg.hpp]
|
* [repo_file example/server-framework/write_msg.hpp]
|
||||||
* [repo_file example/server-framework/ws_async_port.hpp]
|
* [repo_file example/server-framework/ws_async_port.hpp]
|
||||||
* [repo_file example/server-framework/ws_sync_port.hpp]
|
* [repo_file example/server-framework/ws_sync_port.hpp]
|
||||||
* [repo_file example/server-framework/ws_upgrade_service.hpp]
|
* [repo_file example/server-framework/ws_upgrade_service.hpp]
|
||||||
|
* [repo_file example/server-framework/wss_ports.hpp]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
@@ -4,6 +4,10 @@ GroupSources(include/beast beast)
|
|||||||
|
|
||||||
GroupSources(example/server-framework "/")
|
GroupSources(example/server-framework "/")
|
||||||
|
|
||||||
|
if (OPENSSL_FOUND)
|
||||||
|
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable (server-framework
|
add_executable (server-framework
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
${SERVER_INCLUDES}
|
${SERVER_INCLUDES}
|
||||||
@@ -15,3 +19,7 @@ target_link_libraries(
|
|||||||
Beast
|
Beast
|
||||||
${Boost_PROGRAM_OPTIONS_LIBRARY}
|
${Boost_PROGRAM_OPTIONS_LIBRARY}
|
||||||
${Boost_FILESYSTEM_LIBRARY})
|
${Boost_FILESYSTEM_LIBRARY})
|
||||||
|
|
||||||
|
if (OPENSSL_FOUND)
|
||||||
|
target_link_libraries(server-framework ${OPENSSL_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
@@ -118,7 +118,7 @@ make_queued_http_write(
|
|||||||
@tparam Services The list of services this connection will support.
|
@tparam Services The list of services this connection will support.
|
||||||
*/
|
*/
|
||||||
template<class Derived, class... Services>
|
template<class Derived, class... Services>
|
||||||
class async_http_con : public http_base
|
class async_http_con_base : public http_base
|
||||||
{
|
{
|
||||||
// This function lets us access members of the derived class
|
// This function lets us access members of the derived class
|
||||||
Derived&
|
Derived&
|
||||||
@@ -161,7 +161,7 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
async_http_con(
|
async_http_con_base(
|
||||||
beast::string_view server_name,
|
beast::string_view server_name,
|
||||||
std::ostream& log,
|
std::ostream& log,
|
||||||
service_list<Services...> const& services,
|
service_list<Services...> const& services,
|
||||||
@@ -180,15 +180,36 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by the port after creating the object
|
|
||||||
void
|
void
|
||||||
run()
|
run()
|
||||||
{
|
{
|
||||||
// Start reading the header for the first request.
|
// Give the derived class a chance to do stuff
|
||||||
//
|
//
|
||||||
|
impl().do_handshake();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void
|
||||||
|
do_run()
|
||||||
|
{
|
||||||
do_read_header();
|
do_read_header();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called when a failure occurs
|
||||||
|
//
|
||||||
|
void
|
||||||
|
fail(std::string what, error_code ec)
|
||||||
|
{
|
||||||
|
// Don't log operation aborted since those happen normally.
|
||||||
|
//
|
||||||
|
if(ec && ec != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
log_ <<
|
||||||
|
"[#" << id_ << " " << ep_ << "] " <<
|
||||||
|
what << ": " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Perform an asynchronous read for the next request header
|
// Perform an asynchronous read for the next request header
|
||||||
//
|
//
|
||||||
@@ -214,7 +235,7 @@ private:
|
|||||||
buffer_,
|
buffer_,
|
||||||
*parser_,
|
*parser_,
|
||||||
strand_.wrap(std::bind(
|
strand_.wrap(std::bind(
|
||||||
&async_http_con::on_read_header,
|
&async_http_con_base::on_read_header,
|
||||||
impl().shared_from_this(),
|
impl().shared_from_this(),
|
||||||
std::placeholders::_1)));
|
std::placeholders::_1)));
|
||||||
}
|
}
|
||||||
@@ -228,12 +249,12 @@ private:
|
|||||||
struct send_lambda
|
struct send_lambda
|
||||||
{
|
{
|
||||||
// holds "this"
|
// holds "this"
|
||||||
async_http_con& self_;
|
async_http_con_base& self_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// capture "this"
|
// capture "this"
|
||||||
explicit
|
explicit
|
||||||
send_lambda(async_http_con& self)
|
send_lambda(async_http_con_base& self)
|
||||||
: self_(self)
|
: self_(self)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -251,9 +272,17 @@ private:
|
|||||||
void
|
void
|
||||||
on_read_header(error_code ec)
|
on_read_header(error_code ec)
|
||||||
{
|
{
|
||||||
|
// This happens when the other end closes gracefully
|
||||||
|
//
|
||||||
|
if(ec == beast::http::error::end_of_stream)
|
||||||
|
{
|
||||||
|
// VFALCO what about the write queue?
|
||||||
|
return impl().do_shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
// On failure we just return, the shared_ptr that is bound
|
// On failure we just return, the shared_ptr that is bound
|
||||||
// into the completion will go out of scope and eventually
|
// into the completion will go out of scope and eventually
|
||||||
// we will get destroyed.
|
// this will get destroyed.
|
||||||
//
|
//
|
||||||
if(ec)
|
if(ec)
|
||||||
return fail("on_read", ec);
|
return fail("on_read", ec);
|
||||||
@@ -281,7 +310,7 @@ private:
|
|||||||
buffer_,
|
buffer_,
|
||||||
*parser_,
|
*parser_,
|
||||||
strand_.wrap(std::bind(
|
strand_.wrap(std::bind(
|
||||||
&async_http_con::on_read,
|
&async_http_con_base::on_read,
|
||||||
impl().shared_from_this(),
|
impl().shared_from_this(),
|
||||||
std::placeholders::_1)));
|
std::placeholders::_1)));
|
||||||
}
|
}
|
||||||
@@ -290,6 +319,13 @@ private:
|
|||||||
void
|
void
|
||||||
on_read(error_code ec)
|
on_read(error_code ec)
|
||||||
{
|
{
|
||||||
|
// Shouldn't be getting end_of_stream here;
|
||||||
|
// that would mean that we got an incomplete
|
||||||
|
// message, counting as an error.
|
||||||
|
//
|
||||||
|
if(ec)
|
||||||
|
return fail("on_read", ec);
|
||||||
|
|
||||||
// Grab a reference to the request again
|
// Grab a reference to the request again
|
||||||
auto& req = parser_->get();
|
auto& req = parser_->get();
|
||||||
|
|
||||||
@@ -298,10 +334,10 @@ private:
|
|||||||
//
|
//
|
||||||
send_lambda send{*this};
|
send_lambda send{*this};
|
||||||
|
|
||||||
// Give each services a chance to handle the request
|
// Give each service a chance to handle the request
|
||||||
//
|
//
|
||||||
if(! services_.respond(
|
if(! services_.respond(
|
||||||
impl().stream(),
|
std::move(impl().stream()),
|
||||||
ep_,
|
ep_,
|
||||||
std::move(req),
|
std::move(req),
|
||||||
send))
|
send))
|
||||||
@@ -319,7 +355,7 @@ private:
|
|||||||
if(! impl().stream().lowest_layer().is_open())
|
if(! impl().stream().lowest_layer().is_open())
|
||||||
{
|
{
|
||||||
// They took ownership so just return and
|
// They took ownership so just return and
|
||||||
// let this async_http_con object get destroyed.
|
// let this async_http_con_base object get destroyed.
|
||||||
//
|
//
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -357,7 +393,7 @@ private:
|
|||||||
impl().stream(),
|
impl().stream(),
|
||||||
std::move(res),
|
std::move(res),
|
||||||
strand_.wrap(std::bind(
|
strand_.wrap(std::bind(
|
||||||
&async_http_con::on_write,
|
&async_http_con_base::on_write,
|
||||||
impl().shared_from_this(),
|
impl().shared_from_this(),
|
||||||
std::placeholders::_1)));
|
std::placeholders::_1)));
|
||||||
}
|
}
|
||||||
@@ -369,7 +405,7 @@ private:
|
|||||||
impl().stream(),
|
impl().stream(),
|
||||||
std::move(res),
|
std::move(res),
|
||||||
strand_.wrap(std::bind(
|
strand_.wrap(std::bind(
|
||||||
&async_http_con::on_write,
|
&async_http_con_base::on_write,
|
||||||
impl().shared_from_this(),
|
impl().shared_from_this(),
|
||||||
std::placeholders::_1))));
|
std::placeholders::_1))));
|
||||||
}
|
}
|
||||||
@@ -381,6 +417,14 @@ private:
|
|||||||
// Make sure our state is what we think it is
|
// Make sure our state is what we think it is
|
||||||
BOOST_ASSERT(writing_);
|
BOOST_ASSERT(writing_);
|
||||||
|
|
||||||
|
// This happens when we send an HTTP message
|
||||||
|
// whose semantics indicate that the connection
|
||||||
|
// should be closed afterwards. For example if
|
||||||
|
// we send a Connection: close.
|
||||||
|
//
|
||||||
|
if(ec == beast::http::error::end_of_stream)
|
||||||
|
return impl().do_shutdown();
|
||||||
|
|
||||||
// On failure just log and return
|
// On failure just log and return
|
||||||
if(ec)
|
if(ec)
|
||||||
return fail("on_write", ec);
|
return fail("on_write", ec);
|
||||||
@@ -403,23 +447,6 @@ private:
|
|||||||
// Delete the item since we used it
|
// Delete the item since we used it
|
||||||
queue_.erase(queue_.begin());
|
queue_.erase(queue_.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when a failure occurs
|
|
||||||
//
|
|
||||||
void
|
|
||||||
fail(std::string what, error_code ec)
|
|
||||||
{
|
|
||||||
// Don't log end of stream or operation aborted
|
|
||||||
// since those happen under normal circumstances.
|
|
||||||
//
|
|
||||||
if( ec != beast::http::error::end_of_stream &&
|
|
||||||
ec != boost::asio::error::operation_aborted)
|
|
||||||
{
|
|
||||||
log_ <<
|
|
||||||
"[#" << id_ << " " << ep_ << "] " <<
|
|
||||||
what << ": " << ec.message() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -428,7 +455,7 @@ private:
|
|||||||
// uses a plain TCP/IP socket (no encryption) as the stream.
|
// uses a plain TCP/IP socket (no encryption) as the stream.
|
||||||
//
|
//
|
||||||
template<class... Services>
|
template<class... Services>
|
||||||
class async_http_con_plain
|
class async_http_con
|
||||||
|
|
||||||
// Note that we give this object the enable_shared_from_this, and have
|
// Note that we give this object the enable_shared_from_this, and have
|
||||||
// the base class call impl().shared_from_this(). The reason we do that
|
// the base class call impl().shared_from_this(). The reason we do that
|
||||||
@@ -436,7 +463,7 @@ class async_http_con_plain
|
|||||||
// derived class (this class) use its members in calls to std::bind,
|
// derived class (this class) use its members in calls to std::bind,
|
||||||
// without an ugly call to `dynamic_downcast` or other nonsense.
|
// without an ugly call to `dynamic_downcast` or other nonsense.
|
||||||
//
|
//
|
||||||
: public std::enable_shared_from_this<async_http_con_plain<Services...>>
|
: public std::enable_shared_from_this<async_http_con<Services...>>
|
||||||
|
|
||||||
// We want the socket to be created before the base class so we use
|
// We want the socket to be created before the base class so we use
|
||||||
// the "base from member" idiom which Boost provides as a class.
|
// the "base from member" idiom which Boost provides as a class.
|
||||||
@@ -445,17 +472,17 @@ class async_http_con_plain
|
|||||||
|
|
||||||
// Declare this base last now that everything else got set up first.
|
// Declare this base last now that everything else got set up first.
|
||||||
//
|
//
|
||||||
, public async_http_con<async_http_con_plain<Services...>, Services...>
|
, public async_http_con_base<async_http_con<Services...>, Services...>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Construct the plain connection.
|
// Construct the plain connection.
|
||||||
//
|
//
|
||||||
template<class... Args>
|
template<class... Args>
|
||||||
async_http_con_plain(
|
async_http_con(
|
||||||
socket_type&& sock,
|
socket_type&& sock,
|
||||||
Args&&... args)
|
Args&&... args)
|
||||||
: base_from_member<socket_type>(std::move(sock))
|
: base_from_member<socket_type>(std::move(sock))
|
||||||
, async_http_con<async_http_con_plain<Services...>, Services...>(
|
, async_http_con_base<async_http_con<Services...>, Services...>(
|
||||||
std::forward<Args>(args)...)
|
std::forward<Args>(args)...)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -469,6 +496,31 @@ public:
|
|||||||
{
|
{
|
||||||
return this->member;
|
return this->member;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Base class needs to be a friend to call our private members
|
||||||
|
friend class async_http_con_base<async_http_con<Services...>, Services...>;
|
||||||
|
|
||||||
|
// This is called by the base before running the main loop.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
do_handshake()
|
||||||
|
{
|
||||||
|
// Run the main loop right away
|
||||||
|
//
|
||||||
|
this->do_run();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is called when the other end closes the connection gracefully.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
do_shutdown()
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
stream().shutdown(socket_type::shutdown_both, ec);
|
||||||
|
if(ec)
|
||||||
|
return this->fail("shutdown", ec);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -539,7 +591,7 @@ public:
|
|||||||
// Create a plain http connection object
|
// Create a plain http connection object
|
||||||
// and transfer ownership of the socket.
|
// and transfer ownership of the socket.
|
||||||
//
|
//
|
||||||
std::make_shared<async_http_con_plain<Services...>>(
|
std::make_shared<async_http_con<Services...>>(
|
||||||
std::move(sock),
|
std::move(sock),
|
||||||
"http_async_port",
|
"http_async_port",
|
||||||
log_,
|
log_,
|
||||||
|
@@ -42,7 +42,7 @@ namespace framework {
|
|||||||
@tparam Services The list of services this connection will support.
|
@tparam Services The list of services this connection will support.
|
||||||
*/
|
*/
|
||||||
template<class Derived, class... Services>
|
template<class Derived, class... Services>
|
||||||
class sync_http_con
|
class sync_http_con_base
|
||||||
: public http_base
|
: public http_base
|
||||||
{
|
{
|
||||||
// This function lets us access members of the derived class
|
// This function lets us access members of the derived class
|
||||||
@@ -71,7 +71,7 @@ class sync_http_con
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
sync_http_con(
|
sync_http_con_base(
|
||||||
beast::string_view server_name,
|
beast::string_view server_name,
|
||||||
std::ostream& log,
|
std::ostream& log,
|
||||||
service_list<Services...> const& services,
|
service_list<Services...> const& services,
|
||||||
@@ -90,19 +90,36 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is called to start the connection after
|
||||||
|
// it is accepted.
|
||||||
|
//
|
||||||
void
|
void
|
||||||
run()
|
run()
|
||||||
{
|
{
|
||||||
// Bind a shared pointer into the lambda for the
|
// Bind a shared pointer into the lambda for the
|
||||||
// thread, so the sync_http_con is destroyed after
|
// thread, so the sync_http_con_base is destroyed after
|
||||||
// the thread function exits.
|
// the thread function exits.
|
||||||
//
|
//
|
||||||
std::thread{
|
std::thread{
|
||||||
&sync_http_con::do_run,
|
&sync_http_con_base::do_run,
|
||||||
impl().shared_from_this()
|
impl().shared_from_this()
|
||||||
}.detach();
|
}.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Called when a failure occurs
|
||||||
|
//
|
||||||
|
void
|
||||||
|
fail(std::string what, error_code ec)
|
||||||
|
{
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
log_ <<
|
||||||
|
"[#" << id_ << " " << ep_ << "] " <<
|
||||||
|
what << ": " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// This lambda is passed to the service list to handle
|
// This lambda is passed to the service list to handle
|
||||||
// the case of sending request objects of varying types.
|
// the case of sending request objects of varying types.
|
||||||
@@ -113,7 +130,7 @@ private:
|
|||||||
struct send_lambda
|
struct send_lambda
|
||||||
{
|
{
|
||||||
// holds "this"
|
// holds "this"
|
||||||
sync_http_con& self_;
|
sync_http_con_base& self_;
|
||||||
|
|
||||||
// holds the captured error code
|
// holds the captured error code
|
||||||
error_code& ec_;
|
error_code& ec_;
|
||||||
@@ -123,7 +140,7 @@ private:
|
|||||||
//
|
//
|
||||||
// Capture "this" and "ec"
|
// Capture "this" and "ec"
|
||||||
//
|
//
|
||||||
send_lambda(sync_http_con& self, error_code& ec)
|
send_lambda(sync_http_con_base& self, error_code& ec)
|
||||||
: self_(self)
|
: self_(self)
|
||||||
, ec_(ec)
|
, ec_(ec)
|
||||||
{
|
{
|
||||||
@@ -146,6 +163,16 @@ private:
|
|||||||
void
|
void
|
||||||
do_run()
|
do_run()
|
||||||
{
|
{
|
||||||
|
error_code ec;
|
||||||
|
|
||||||
|
// Give the derived class a chance to do stuff before we
|
||||||
|
// enter the main loop. This is for SSL connections really.
|
||||||
|
//
|
||||||
|
impl().do_handshake(ec);
|
||||||
|
|
||||||
|
if(ec)
|
||||||
|
return fail("handshake", ec);
|
||||||
|
|
||||||
// The main connection loop, we alternate between
|
// The main connection loop, we alternate between
|
||||||
// reading a request and sending a response. On
|
// reading a request and sending a response. On
|
||||||
// error we log and return, which destroys the thread
|
// error we log and return, which destroys the thread
|
||||||
@@ -153,8 +180,6 @@ private:
|
|||||||
//
|
//
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
error_code ec;
|
|
||||||
|
|
||||||
// Arguments passed to the parser constructor are
|
// Arguments passed to the parser constructor are
|
||||||
// forwarded to the message object. A single argument
|
// forwarded to the message object. A single argument
|
||||||
// is forwarded to the body constructor.
|
// is forwarded to the body constructor.
|
||||||
@@ -167,8 +192,20 @@ private:
|
|||||||
// Read the header first
|
// Read the header first
|
||||||
beast::http::read_header(impl().stream(), buffer_, parser, ec);
|
beast::http::read_header(impl().stream(), buffer_, parser, ec);
|
||||||
|
|
||||||
|
// This happens when the other end closes gracefully
|
||||||
|
//
|
||||||
|
if(ec == beast::http::error::end_of_stream)
|
||||||
|
{
|
||||||
|
// Give the derived class a chance to do stuff
|
||||||
|
impl().do_shutdown(ec);
|
||||||
|
if(ec)
|
||||||
|
return fail("shutdown", ec);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any other error and we fail the connection
|
||||||
if(ec)
|
if(ec)
|
||||||
return fail("on_read", ec);
|
return fail("read_header", ec);
|
||||||
|
|
||||||
send_lambda send{*this, ec};
|
send_lambda send{*this, ec};
|
||||||
|
|
||||||
@@ -182,58 +219,105 @@ private:
|
|||||||
// so send the appropriate response synchronously.
|
// so send the appropriate response synchronously.
|
||||||
//
|
//
|
||||||
send(this->continue_100(req));
|
send(this->continue_100(req));
|
||||||
|
|
||||||
|
// This happens when we send an HTTP message
|
||||||
|
// whose semantics indicate that the connection
|
||||||
|
// should be closed afterwards. For example if
|
||||||
|
// we send a Connection: close.
|
||||||
|
//
|
||||||
|
if(ec == beast::http::error::end_of_stream)
|
||||||
|
{
|
||||||
|
// Give the derived class a chance to do stuff
|
||||||
|
impl().do_shutdown(ec);
|
||||||
|
if(ec)
|
||||||
|
return fail("shutdown", ec);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Have to check the error every time we call the lambda
|
||||||
|
//
|
||||||
|
if(ec)
|
||||||
|
return fail("write", ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the rest of the message, if any.
|
// Read the rest of the message, if any.
|
||||||
//
|
//
|
||||||
beast::http::read(impl().stream(), buffer_, parser, ec);
|
beast::http::read(impl().stream(), buffer_, parser, ec);
|
||||||
|
|
||||||
// Give each services a chance to handle the request
|
// Shouldn't be getting end_of_stream here;
|
||||||
|
// that would mean that we got an incomplete
|
||||||
|
// message, counting as an error.
|
||||||
|
//
|
||||||
|
if(ec)
|
||||||
|
return fail("read", ec);
|
||||||
|
|
||||||
|
// Give each service a chance to handle the request
|
||||||
//
|
//
|
||||||
if(! services_.respond(
|
if(! services_.respond(
|
||||||
impl().stream(),
|
std::move(impl().stream()),
|
||||||
ep_,
|
ep_,
|
||||||
std::move(req),
|
std::move(req),
|
||||||
send))
|
send))
|
||||||
{
|
{
|
||||||
// No service handled the request,
|
// No service handled the request,
|
||||||
// send a Bad Request result to the client.
|
// send a Bad Request result to the client.
|
||||||
//
|
//
|
||||||
send(this->bad_request(req));
|
send(this->bad_request(req));
|
||||||
|
|
||||||
|
// This happens when we send an HTTP message
|
||||||
|
// whose semantics indicate that the connection
|
||||||
|
// should be closed afterwards. For example if
|
||||||
|
// we send a Connection: close.
|
||||||
|
//
|
||||||
|
if(ec == beast::http::error::end_of_stream)
|
||||||
|
{
|
||||||
|
// Give the derived class a chance to do stuff
|
||||||
|
impl().do_shutdown(ec);
|
||||||
|
if(ec)
|
||||||
|
return fail("shutdown", ec);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Have to check the error every time we call the lambda
|
||||||
|
//
|
||||||
|
if(ec)
|
||||||
|
return fail("write", ec);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// This happens when we send an HTTP message
|
||||||
|
// whose semantics indicate that the connection
|
||||||
|
// should be closed afterwards. For example if
|
||||||
|
// we send a Connection: close.
|
||||||
|
//
|
||||||
|
if(ec == beast::http::error::end_of_stream)
|
||||||
|
{
|
||||||
|
// Give the derived class a chance to do stuff
|
||||||
|
impl().do_shutdown(ec);
|
||||||
|
if(ec)
|
||||||
|
return fail("shutdown", ec);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Have to check the error every time we call the lambda
|
||||||
|
//
|
||||||
|
if(ec)
|
||||||
|
return fail("write", ec);
|
||||||
|
|
||||||
// See if the service that handled the
|
// See if the service that handled the
|
||||||
// response took ownership of the stream.
|
// response took ownership of the stream.
|
||||||
if(! impl().stream().is_open())
|
if(! impl().stream().lowest_layer().is_open())
|
||||||
{
|
{
|
||||||
// They took ownership so just return and
|
// They took ownership so just return and
|
||||||
// let this sync_http_con object get destroyed.
|
// let this sync_http_con_base object get destroyed.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ec)
|
|
||||||
return fail("on_write", ec);
|
|
||||||
|
|
||||||
// Theres no pipelining possible in a synchronous server
|
// Theres no pipelining possible in a synchronous server
|
||||||
// because we can't do reads and writes at the same time.
|
// because we can't do reads and writes at the same time.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when a failure occurs
|
|
||||||
//
|
|
||||||
void
|
|
||||||
fail(std::string what, error_code ec)
|
|
||||||
{
|
|
||||||
if( ec != beast::http::error::end_of_stream &&
|
|
||||||
ec != boost::asio::error::operation_aborted)
|
|
||||||
{
|
|
||||||
log_ <<
|
|
||||||
"[#" << id_ << " " << ep_ << "] " <<
|
|
||||||
what << ": " << ec.message() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -242,12 +326,12 @@ private:
|
|||||||
// uses a plain TCP/IP socket (no encryption) as the stream.
|
// uses a plain TCP/IP socket (no encryption) as the stream.
|
||||||
//
|
//
|
||||||
template<class... Services>
|
template<class... Services>
|
||||||
class sync_http_con_plain
|
class sync_http_con
|
||||||
|
|
||||||
// Note that we give this object the `enable_shared_from_this`, and have
|
// Note that we give this object the `enable_shared_from_this`, and have
|
||||||
// the base class call `impl().shared_from_this()` when needed.
|
// the base class call `impl().shared_from_this()` when needed.
|
||||||
//
|
//
|
||||||
: public std::enable_shared_from_this<sync_http_con_plain<Services...>>
|
: public std::enable_shared_from_this<sync_http_con<Services...>>
|
||||||
|
|
||||||
// We want the socket to be created before the base class so we use
|
// We want the socket to be created before the base class so we use
|
||||||
// the "base from member" idiom which Boost provides as a class.
|
// the "base from member" idiom which Boost provides as a class.
|
||||||
@@ -256,17 +340,17 @@ class sync_http_con_plain
|
|||||||
|
|
||||||
// Declare this base last now that everything else got set up first.
|
// Declare this base last now that everything else got set up first.
|
||||||
//
|
//
|
||||||
, public sync_http_con<sync_http_con_plain<Services...>, Services...>
|
, public sync_http_con_base<sync_http_con<Services...>, Services...>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Construct the plain connection.
|
// Construct the plain connection.
|
||||||
//
|
//
|
||||||
template<class... Args>
|
template<class... Args>
|
||||||
sync_http_con_plain(
|
sync_http_con(
|
||||||
socket_type&& sock,
|
socket_type&& sock,
|
||||||
Args&&... args)
|
Args&&... args)
|
||||||
: base_from_member<socket_type>(std::move(sock))
|
: base_from_member<socket_type>(std::move(sock))
|
||||||
, sync_http_con<sync_http_con_plain<Services...>, Services...>(
|
, sync_http_con_base<sync_http_con<Services...>, Services...>(
|
||||||
std::forward<Args>(args)...)
|
std::forward<Args>(args)...)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -281,6 +365,29 @@ public:
|
|||||||
{
|
{
|
||||||
return this->member;
|
return this->member;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Base class needs to be a friend to call our private members
|
||||||
|
friend class sync_http_con_base<sync_http_con<Services...>, Services...>;
|
||||||
|
|
||||||
|
// This is called by the base before running the main loop.
|
||||||
|
// There's nothing to do for a plain connection.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
do_handshake(error_code& ec)
|
||||||
|
{
|
||||||
|
// This is required by the specifications for error_code
|
||||||
|
//
|
||||||
|
ec = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is called when the other end closes the connection gracefully.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
do_shutdown(error_code& ec)
|
||||||
|
{
|
||||||
|
stream().shutdown(socket_type::shutdown_both, ec);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -345,7 +452,7 @@ public:
|
|||||||
// Create a plain http connection object
|
// Create a plain http connection object
|
||||||
// and transfer ownership of the socket.
|
// and transfer ownership of the socket.
|
||||||
//
|
//
|
||||||
std::make_shared<sync_http_con_plain<Services...>>(
|
std::make_shared<sync_http_con<Services...>>(
|
||||||
std::move(sock),
|
std::move(sock),
|
||||||
"http_sync_port",
|
"http_sync_port",
|
||||||
log_,
|
log_,
|
||||||
|
368
example/server-framework/https_ports.hpp
Normal file
368
example/server-framework/https_ports.hpp
Normal file
@@ -0,0 +1,368 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BEAST_EXAMPLE_SERVER_HTTPS_PORTS_HPP
|
||||||
|
#define BEAST_EXAMPLE_SERVER_HTTPS_PORTS_HPP
|
||||||
|
|
||||||
|
#include "http_sync_port.hpp"
|
||||||
|
#include "http_async_port.hpp"
|
||||||
|
#include "ssl_stream.hpp"
|
||||||
|
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
|
|
||||||
|
namespace framework {
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// This class represents a synchronous HTTP connection which
|
||||||
|
// uses an OpenSSL socket as the stream.
|
||||||
|
//
|
||||||
|
template<class... Services>
|
||||||
|
class sync_https_con
|
||||||
|
|
||||||
|
// Note that we give this object the enable_shared_from_this, and have
|
||||||
|
// the base class call impl().shared_from_this(). The reason we do that
|
||||||
|
// is so that the shared_ptr has the correct type. This lets the
|
||||||
|
// derived class (this class) use its members in calls to std::bind,
|
||||||
|
// without an ugly call to `dynamic_downcast` or other nonsense.
|
||||||
|
//
|
||||||
|
: public std::enable_shared_from_this<sync_https_con<Services...>>
|
||||||
|
|
||||||
|
// We want the socket to be created before the base class so we use
|
||||||
|
// the "base from member" idiom which Boost provides as a class.
|
||||||
|
//
|
||||||
|
, public base_from_member<ssl_stream<socket_type>>
|
||||||
|
|
||||||
|
// Declare this base last now that everything else got set up first.
|
||||||
|
//
|
||||||
|
, public sync_http_con_base<sync_https_con<Services...>, Services...>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Construct the plain connection.
|
||||||
|
//
|
||||||
|
template<class... Args>
|
||||||
|
sync_https_con(
|
||||||
|
socket_type&& sock,
|
||||||
|
boost::asio::ssl::context& ctx,
|
||||||
|
Args&&... args)
|
||||||
|
: base_from_member<ssl_stream<socket_type>>(std::move(sock), ctx)
|
||||||
|
, sync_http_con_base<sync_https_con<Services...>, Services...>(
|
||||||
|
std::forward<Args>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the stream.
|
||||||
|
// The base class calls this to obtain the object to
|
||||||
|
// use for reading and writing HTTP messages.
|
||||||
|
//
|
||||||
|
ssl_stream<socket_type>&
|
||||||
|
stream()
|
||||||
|
{
|
||||||
|
return this->member;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class sync_http_con_base<sync_https_con<Services...>, Services...>;
|
||||||
|
|
||||||
|
// This is called by the base before running the main loop.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
do_handshake(error_code& ec)
|
||||||
|
{
|
||||||
|
// Perform the SSL handshake
|
||||||
|
//
|
||||||
|
stream().handshake(boost::asio::ssl::stream_base::server, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is called when the other end closes the connection gracefully.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
do_shutdown(error_code& ec)
|
||||||
|
{
|
||||||
|
// Note that this is an SSL shutdown
|
||||||
|
//
|
||||||
|
stream().shutdown(ec);
|
||||||
|
if(ec)
|
||||||
|
return this->fail("shutdown", ec);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// This class represents an asynchronous HTTP connection which
|
||||||
|
// uses an OpenSSL socket as the stream.
|
||||||
|
//
|
||||||
|
template<class... Services>
|
||||||
|
class async_https_con
|
||||||
|
|
||||||
|
// Note that we give this object the enable_shared_from_this, and have
|
||||||
|
// the base class call impl().shared_from_this(). The reason we do that
|
||||||
|
// is so that the shared_ptr has the correct type. This lets the
|
||||||
|
// derived class (this class) use its members in calls to std::bind,
|
||||||
|
// without an ugly call to `dynamic_downcast` or other nonsense.
|
||||||
|
//
|
||||||
|
: public std::enable_shared_from_this<async_https_con<Services...>>
|
||||||
|
|
||||||
|
// We want the socket to be created before the base class so we use
|
||||||
|
// the "base from member" idiom which Boost provides as a class.
|
||||||
|
//
|
||||||
|
, public base_from_member<ssl_stream<socket_type>>
|
||||||
|
|
||||||
|
// Declare this base last now that everything else got set up first.
|
||||||
|
//
|
||||||
|
, public async_http_con_base<async_https_con<Services...>, Services...>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Construct the plain connection.
|
||||||
|
//
|
||||||
|
template<class... Args>
|
||||||
|
async_https_con(
|
||||||
|
socket_type&& sock,
|
||||||
|
boost::asio::ssl::context& ctx,
|
||||||
|
Args&&... args)
|
||||||
|
: base_from_member<ssl_stream<socket_type>>(std::move(sock), ctx)
|
||||||
|
, async_http_con_base<async_https_con<Services...>, Services...>(
|
||||||
|
std::forward<Args>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the stream.
|
||||||
|
// The base class calls this to obtain the object to
|
||||||
|
// use for reading and writing HTTP messages.
|
||||||
|
//
|
||||||
|
ssl_stream<socket_type>&
|
||||||
|
stream()
|
||||||
|
{
|
||||||
|
return this->member;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class async_http_con_base<async_https_con<Services...>, Services...>;
|
||||||
|
|
||||||
|
// Called by the base class before starting the main loop.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
do_handshake()
|
||||||
|
{
|
||||||
|
// This is SSL so perform the handshake
|
||||||
|
//
|
||||||
|
stream().async_handshake(
|
||||||
|
boost::asio::ssl::stream_base::server,
|
||||||
|
this->strand_.wrap(std::bind(
|
||||||
|
&async_https_con::on_handshake,
|
||||||
|
this->shared_from_this(),
|
||||||
|
std::placeholders::_1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when the SSL handshake completes
|
||||||
|
void
|
||||||
|
on_handshake(error_code ec)
|
||||||
|
{
|
||||||
|
if(ec)
|
||||||
|
return this->fail("on_handshake", ec);
|
||||||
|
|
||||||
|
// No error so run the main loop
|
||||||
|
this->do_run();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when the end of stream is reached
|
||||||
|
void
|
||||||
|
do_shutdown()
|
||||||
|
{
|
||||||
|
// This is an SSL shutdown
|
||||||
|
//
|
||||||
|
stream().async_shutdown(
|
||||||
|
this->strand_.wrap(std::bind(
|
||||||
|
&async_https_con::on_shutdown,
|
||||||
|
this->shared_from_this(),
|
||||||
|
std::placeholders::_1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when the SSL shutdown completes
|
||||||
|
void
|
||||||
|
on_shutdown(error_code ec)
|
||||||
|
{
|
||||||
|
if(ec)
|
||||||
|
return this->fail("on_shutdown", ec);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/* A synchronous HTTPS port handler
|
||||||
|
|
||||||
|
This type meets the requirements of @b PortHandler. It supports
|
||||||
|
variable list of HTTP services in its template parameter list,
|
||||||
|
and provides a synchronous connection implementation to service
|
||||||
|
*/
|
||||||
|
template<class... Services>
|
||||||
|
class https_sync_port
|
||||||
|
{
|
||||||
|
// Reference to the server instance that made us
|
||||||
|
server& instance_;
|
||||||
|
|
||||||
|
// The stream to log to
|
||||||
|
std::ostream& log_;
|
||||||
|
|
||||||
|
// The list of services connections created from this port will support
|
||||||
|
service_list<Services...> services_;
|
||||||
|
|
||||||
|
// The SSL context containing the server's credentials
|
||||||
|
boost::asio::ssl::context& ctx_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
|
||||||
|
@param instance The server instance which owns this port
|
||||||
|
|
||||||
|
@param log The stream to use for logging
|
||||||
|
|
||||||
|
@param ctx The SSL context holding the SSL certificates to use
|
||||||
|
*/
|
||||||
|
https_sync_port(
|
||||||
|
server& instance,
|
||||||
|
std::ostream& log,
|
||||||
|
boost::asio::ssl::context& ctx)
|
||||||
|
: instance_(instance)
|
||||||
|
, log_(log)
|
||||||
|
, ctx_(ctx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Initialize a service
|
||||||
|
|
||||||
|
Every service in the list must be initialized exactly once.
|
||||||
|
|
||||||
|
@param args Optional arguments forwarded to the service
|
||||||
|
constructor.
|
||||||
|
|
||||||
|
@tparam Index The 0-based index of the service to initialize.
|
||||||
|
|
||||||
|
@return A reference to the service list. This permits
|
||||||
|
calls to be chained in a single expression.
|
||||||
|
*/
|
||||||
|
template<std::size_t Index, class... Args>
|
||||||
|
void
|
||||||
|
init(error_code& ec, Args&&... args)
|
||||||
|
{
|
||||||
|
services_.template init<Index>(
|
||||||
|
ec,
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Called by the server to provide ownership of the socket for a new connection
|
||||||
|
|
||||||
|
@param sock The socket whose ownership is to be transferred
|
||||||
|
|
||||||
|
@ep The remote endpoint
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
on_accept(socket_type&& sock, endpoint_type ep)
|
||||||
|
{
|
||||||
|
// Create an HTTPS connection object
|
||||||
|
// and transfer ownership of the socket.
|
||||||
|
//
|
||||||
|
std::make_shared<sync_https_con<Services...>>(
|
||||||
|
std::move(sock),
|
||||||
|
ctx_,
|
||||||
|
"https_sync_port",
|
||||||
|
log_,
|
||||||
|
services_,
|
||||||
|
instance_.next_id(),
|
||||||
|
ep
|
||||||
|
)->run();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/* An asynchronous HTTPS port handler
|
||||||
|
|
||||||
|
This type meets the requirements of @b PortHandler. It supports
|
||||||
|
variable list of HTTP services in its template parameter list,
|
||||||
|
and provides a synchronous connection implementation to service
|
||||||
|
*/
|
||||||
|
template<class... Services>
|
||||||
|
class https_async_port
|
||||||
|
{
|
||||||
|
// Reference to the server instance that made us
|
||||||
|
server& instance_;
|
||||||
|
|
||||||
|
// The stream to log to
|
||||||
|
std::ostream& log_;
|
||||||
|
|
||||||
|
// The list of services connections created from this port will support
|
||||||
|
service_list<Services...> services_;
|
||||||
|
|
||||||
|
// The SSL context containing the server's credentials
|
||||||
|
boost::asio::ssl::context& ctx_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
|
||||||
|
@param instance The server instance which owns this port
|
||||||
|
|
||||||
|
@param log The stream to use for logging
|
||||||
|
*/
|
||||||
|
https_async_port(
|
||||||
|
server& instance,
|
||||||
|
std::ostream& log,
|
||||||
|
boost::asio::ssl::context& ctx)
|
||||||
|
: instance_(instance)
|
||||||
|
, log_(log)
|
||||||
|
, ctx_(ctx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Initialize a service
|
||||||
|
|
||||||
|
Every service in the list must be initialized exactly once.
|
||||||
|
|
||||||
|
@param args Optional arguments forwarded to the service
|
||||||
|
constructor.
|
||||||
|
|
||||||
|
@tparam Index The 0-based index of the service to initialize.
|
||||||
|
|
||||||
|
@return A reference to the service list. This permits
|
||||||
|
calls to be chained in a single expression.
|
||||||
|
*/
|
||||||
|
template<std::size_t Index, class... Args>
|
||||||
|
void
|
||||||
|
init(error_code& ec, Args&&... args)
|
||||||
|
{
|
||||||
|
services_.template init<Index>(
|
||||||
|
ec,
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Called by the server to provide ownership of the socket for a new connection
|
||||||
|
|
||||||
|
@param sock The socket whose ownership is to be transferred
|
||||||
|
|
||||||
|
@ep The remote endpoint
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
on_accept(socket_type&& sock, endpoint_type ep)
|
||||||
|
{
|
||||||
|
// Create an HTTPS connection object
|
||||||
|
// and transfer ownership of the socket.
|
||||||
|
//
|
||||||
|
std::make_shared<async_https_con<Services...>>(
|
||||||
|
std::move(sock),
|
||||||
|
ctx_,
|
||||||
|
"https_async_port",
|
||||||
|
log_,
|
||||||
|
services_,
|
||||||
|
instance_.next_id(),
|
||||||
|
ep
|
||||||
|
)->run();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // framework
|
||||||
|
|
||||||
|
#endif
|
@@ -12,6 +12,12 @@
|
|||||||
#include "ws_async_port.hpp"
|
#include "ws_async_port.hpp"
|
||||||
#include "ws_sync_port.hpp"
|
#include "ws_sync_port.hpp"
|
||||||
|
|
||||||
|
#if BEAST_USE_OPENSSL
|
||||||
|
#include "https_ports.hpp"
|
||||||
|
#include "wss_ports.hpp"
|
||||||
|
#include "ssl_certificate.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "file_service.hpp"
|
#include "file_service.hpp"
|
||||||
#include "ws_upgrade_service.hpp"
|
#include "ws_upgrade_service.hpp"
|
||||||
|
|
||||||
@@ -133,6 +139,13 @@ main(
|
|||||||
// Create our server instance with the specified number of threads
|
// Create our server instance with the specified number of threads
|
||||||
server instance{threads};
|
server instance{threads};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Asynchronous WebSocket HTTP
|
||||||
|
//
|
||||||
|
// port port + 1
|
||||||
|
//
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
{
|
{
|
||||||
// Install an asynchronous WebSocket echo port handler
|
// Install an asynchronous WebSocket echo port handler
|
||||||
//
|
//
|
||||||
@@ -185,6 +198,13 @@ main(
|
|||||||
return fail("http_async_port/file_service", ec);
|
return fail("http_async_port/file_service", ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Synchronous WebSocket HTTP
|
||||||
|
//
|
||||||
|
// port + 2 port + 3
|
||||||
|
//
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
{
|
{
|
||||||
// Install a synchronous WebSocket echo port handler
|
// Install a synchronous WebSocket echo port handler
|
||||||
//
|
//
|
||||||
@@ -238,5 +258,138 @@ main(
|
|||||||
return fail("http_sync_port/file_service", ec);
|
return fail("http_sync_port/file_service", ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// If OpenSSL is available then install some SSL-enabled ports
|
||||||
|
//
|
||||||
|
|
||||||
|
#if BEAST_USE_OPENSSL
|
||||||
|
|
||||||
|
ssl_certificate cert;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Asynchronous Secure WebSocket HTTPS
|
||||||
|
//
|
||||||
|
// port + 4 port + 5
|
||||||
|
//
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
// Install an asynchronous Secure WebSocket echo port handler
|
||||||
|
//
|
||||||
|
auto wsp = instance.make_port<wss_async_port>(
|
||||||
|
ec,
|
||||||
|
endpoint_type{addr,
|
||||||
|
static_cast<unsigned short>(port + 4)},
|
||||||
|
instance,
|
||||||
|
std::cout,
|
||||||
|
cert.get(),
|
||||||
|
set_ws_options{pmd}
|
||||||
|
);
|
||||||
|
|
||||||
|
if(ec)
|
||||||
|
return fail("ws_async_port", ec);
|
||||||
|
|
||||||
|
// Install an asynchronous HTTPS port handler
|
||||||
|
//
|
||||||
|
auto sp = instance.make_port<https_async_port<
|
||||||
|
ws_upgrade_service<wss_async_port>,
|
||||||
|
file_service
|
||||||
|
>>(
|
||||||
|
ec,
|
||||||
|
endpoint_type{addr,
|
||||||
|
static_cast<unsigned short>(port + 5)},
|
||||||
|
instance,
|
||||||
|
std::cout,
|
||||||
|
cert.get());
|
||||||
|
|
||||||
|
if(ec)
|
||||||
|
return fail("https_async_port", ec);
|
||||||
|
|
||||||
|
// Set up the ws_upgrade_service. We will route upgrade
|
||||||
|
// requests to the websocket port handler created earlier.
|
||||||
|
//
|
||||||
|
sp->template init<0>(
|
||||||
|
ec,
|
||||||
|
wsp // The websocket port handler
|
||||||
|
);
|
||||||
|
|
||||||
|
if(ec)
|
||||||
|
return fail("https_async_port/ws_upgrade_service", ec);
|
||||||
|
|
||||||
|
// Set up the file_service to point to the root path.
|
||||||
|
//
|
||||||
|
sp->template init<1>(
|
||||||
|
ec,
|
||||||
|
root, // The root path
|
||||||
|
"https_async_port" // The value for the Server field
|
||||||
|
);
|
||||||
|
|
||||||
|
if(ec)
|
||||||
|
return fail("https_async_port/file_service", ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Synchronous Secure WebSocket HTTPS
|
||||||
|
//
|
||||||
|
// port + 6 port + 7
|
||||||
|
//
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
// Install a synchronous Secure WebSocket echo port handler
|
||||||
|
//
|
||||||
|
auto wsp = instance.make_port<wss_sync_port>(
|
||||||
|
ec,
|
||||||
|
endpoint_type{addr,
|
||||||
|
static_cast<unsigned short>(port + 6)},
|
||||||
|
instance,
|
||||||
|
std::cout,
|
||||||
|
cert.get(),
|
||||||
|
set_ws_options{pmd});
|
||||||
|
|
||||||
|
if(ec)
|
||||||
|
return fail("wss_sync_port", ec);
|
||||||
|
|
||||||
|
// Install a synchronous HTTPS port handler
|
||||||
|
//
|
||||||
|
auto sp = instance.make_port<https_sync_port<
|
||||||
|
ws_upgrade_service<wss_sync_port>,
|
||||||
|
file_service
|
||||||
|
>>(
|
||||||
|
ec,
|
||||||
|
endpoint_type{addr,
|
||||||
|
static_cast<unsigned short>(port + 7)},
|
||||||
|
instance,
|
||||||
|
std::cout,
|
||||||
|
cert.get());
|
||||||
|
|
||||||
|
if(ec)
|
||||||
|
return fail("https_sync_port", ec);
|
||||||
|
|
||||||
|
// Set up the ws_upgrade_service. We will route upgrade
|
||||||
|
// requests to the websocket port handler created earlier.
|
||||||
|
//
|
||||||
|
sp->template init<0>(
|
||||||
|
ec,
|
||||||
|
wsp // The websocket port handler
|
||||||
|
);
|
||||||
|
|
||||||
|
if(ec)
|
||||||
|
return fail("http_sync_port/ws_upgrade_service", ec);
|
||||||
|
|
||||||
|
// Set up the file_service to point to the root path.
|
||||||
|
//
|
||||||
|
sp->template init<1>(
|
||||||
|
ec,
|
||||||
|
root,
|
||||||
|
"https_sync_port"
|
||||||
|
);
|
||||||
|
|
||||||
|
if(ec)
|
||||||
|
return fail("https_sync_port/file_service", ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
sig_wait();
|
sig_wait();
|
||||||
}
|
}
|
||||||
|
146
example/server-framework/ssl_certificate.hpp
Normal file
146
example/server-framework/ssl_certificate.hpp
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BEAST_EXAMPLE_SERVER_SSL_CERTIFICATE_HPP
|
||||||
|
#define BEAST_EXAMPLE_SERVER_SSL_CERTIFICATE_HPP
|
||||||
|
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/asio/ssl/context.hpp>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace framework {
|
||||||
|
|
||||||
|
// This sets up the self-signed certificate that the server
|
||||||
|
// uses for its encrypted connections
|
||||||
|
|
||||||
|
class ssl_certificate
|
||||||
|
{
|
||||||
|
// The template argument is gratuitous, to
|
||||||
|
// make the definition header-only without
|
||||||
|
// also making it inline.
|
||||||
|
//
|
||||||
|
template<class = void>
|
||||||
|
void
|
||||||
|
construct();
|
||||||
|
|
||||||
|
boost::asio::ssl::context ctx_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ssl_certificate()
|
||||||
|
: ctx_(boost::asio::ssl::context::sslv23)
|
||||||
|
{
|
||||||
|
construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::asio::ssl::context&
|
||||||
|
get()
|
||||||
|
{
|
||||||
|
return ctx_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class>
|
||||||
|
void
|
||||||
|
ssl_certificate::construct()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
The certificate was generated from CMD.EXE on Windows 10 using:
|
||||||
|
|
||||||
|
winpty openssl dhparam -out dh.pem 2048
|
||||||
|
winpty openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 10000 -out cert.pem -subj "//C=US\ST=CA\L=Los Angeles\O=Beast\CN=www.example.com"
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::string const cert =
|
||||||
|
"-----BEGIN CERTIFICATE-----\n"
|
||||||
|
"MIIDaDCCAlCgAwIBAgIJAO8vBu8i8exWMA0GCSqGSIb3DQEBCwUAMEkxCzAJBgNV\n"
|
||||||
|
"BAYTAlVTMQswCQYDVQQIDAJDQTEtMCsGA1UEBwwkTG9zIEFuZ2VsZXNPPUJlYXN0\n"
|
||||||
|
"Q049d3d3LmV4YW1wbGUuY29tMB4XDTE3MDUwMzE4MzkxMloXDTQ0MDkxODE4Mzkx\n"
|
||||||
|
"MlowSTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMS0wKwYDVQQHDCRMb3MgQW5n\n"
|
||||||
|
"ZWxlc089QmVhc3RDTj13d3cuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUA\n"
|
||||||
|
"A4IBDwAwggEKAoIBAQDJ7BRKFO8fqmsEXw8v9YOVXyrQVsVbjSSGEs4Vzs4cJgcF\n"
|
||||||
|
"xqGitbnLIrOgiJpRAPLy5MNcAXE1strVGfdEf7xMYSZ/4wOrxUyVw/Ltgsft8m7b\n"
|
||||||
|
"Fu8TsCzO6XrxpnVtWk506YZ7ToTa5UjHfBi2+pWTxbpN12UhiZNUcrRsqTFW+6fO\n"
|
||||||
|
"9d7xm5wlaZG8cMdg0cO1bhkz45JSl3wWKIES7t3EfKePZbNlQ5hPy7Pd5JTmdGBp\n"
|
||||||
|
"yY8anC8u4LPbmgW0/U31PH0rRVfGcBbZsAoQw5Tc5dnb6N2GEIbq3ehSfdDHGnrv\n"
|
||||||
|
"enu2tOK9Qx6GEzXh3sekZkxcgh+NlIxCNxu//Dk9AgMBAAGjUzBRMB0GA1UdDgQW\n"
|
||||||
|
"BBTZh0N9Ne1OD7GBGJYz4PNESHuXezAfBgNVHSMEGDAWgBTZh0N9Ne1OD7GBGJYz\n"
|
||||||
|
"4PNESHuXezAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCmTJVT\n"
|
||||||
|
"LH5Cru1vXtzb3N9dyolcVH82xFVwPewArchgq+CEkajOU9bnzCqvhM4CryBb4cUs\n"
|
||||||
|
"gqXWp85hAh55uBOqXb2yyESEleMCJEiVTwm/m26FdONvEGptsiCmF5Gxi0YRtn8N\n"
|
||||||
|
"V+KhrQaAyLrLdPYI7TrwAOisq2I1cD0mt+xgwuv/654Rl3IhOMx+fKWKJ9qLAiaE\n"
|
||||||
|
"fQyshjlPP9mYVxWOxqctUdQ8UnsUKKGEUcVrA08i1OAnVKlPFjKBvk+r7jpsTPcr\n"
|
||||||
|
"9pWXTO9JrYMML7d+XRSZA1n3856OqZDX4403+9FnXCvfcLZLLKTBvwwFgEFGpzjK\n"
|
||||||
|
"UEVbkhd5qstF6qWK\n"
|
||||||
|
"-----END CERTIFICATE-----\n";
|
||||||
|
|
||||||
|
std::string const key =
|
||||||
|
"-----BEGIN PRIVATE KEY-----\n"
|
||||||
|
"MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJ7BRKFO8fqmsE\n"
|
||||||
|
"Xw8v9YOVXyrQVsVbjSSGEs4Vzs4cJgcFxqGitbnLIrOgiJpRAPLy5MNcAXE1strV\n"
|
||||||
|
"GfdEf7xMYSZ/4wOrxUyVw/Ltgsft8m7bFu8TsCzO6XrxpnVtWk506YZ7ToTa5UjH\n"
|
||||||
|
"fBi2+pWTxbpN12UhiZNUcrRsqTFW+6fO9d7xm5wlaZG8cMdg0cO1bhkz45JSl3wW\n"
|
||||||
|
"KIES7t3EfKePZbNlQ5hPy7Pd5JTmdGBpyY8anC8u4LPbmgW0/U31PH0rRVfGcBbZ\n"
|
||||||
|
"sAoQw5Tc5dnb6N2GEIbq3ehSfdDHGnrvenu2tOK9Qx6GEzXh3sekZkxcgh+NlIxC\n"
|
||||||
|
"Nxu//Dk9AgMBAAECggEBAK1gV8uETg4SdfE67f9v/5uyK0DYQH1ro4C7hNiUycTB\n"
|
||||||
|
"oiYDd6YOA4m4MiQVJuuGtRR5+IR3eI1zFRMFSJs4UqYChNwqQGys7CVsKpplQOW+\n"
|
||||||
|
"1BCqkH2HN/Ix5662Dv3mHJemLCKUON77IJKoq0/xuZ04mc9csykox6grFWB3pjXY\n"
|
||||||
|
"OEn9U8pt5KNldWfpfAZ7xu9WfyvthGXlhfwKEetOuHfAQv7FF6s25UIEU6Hmnwp9\n"
|
||||||
|
"VmYp2twfMGdztz/gfFjKOGxf92RG+FMSkyAPq/vhyB7oQWxa+vdBn6BSdsfn27Qs\n"
|
||||||
|
"bTvXrGe4FYcbuw4WkAKTljZX7TUegkXiwFoSps0jegECgYEA7o5AcRTZVUmmSs8W\n"
|
||||||
|
"PUHn89UEuDAMFVk7grG1bg8exLQSpugCykcqXt1WNrqB7x6nB+dbVANWNhSmhgCg\n"
|
||||||
|
"VrV941vbx8ketqZ9YInSbGPWIU/tss3r8Yx2Ct3mQpvpGC6iGHzEc/NHJP8Efvh/\n"
|
||||||
|
"CcUWmLjLGJYYeP5oNu5cncC3fXUCgYEA2LANATm0A6sFVGe3sSLO9un1brA4zlZE\n"
|
||||||
|
"Hjd3KOZnMPt73B426qUOcw5B2wIS8GJsUES0P94pKg83oyzmoUV9vJpJLjHA4qmL\n"
|
||||||
|
"CDAd6CjAmE5ea4dFdZwDDS8F9FntJMdPQJA9vq+JaeS+k7ds3+7oiNe+RUIHR1Sz\n"
|
||||||
|
"VEAKh3Xw66kCgYB7KO/2Mchesu5qku2tZJhHF4QfP5cNcos511uO3bmJ3ln+16uR\n"
|
||||||
|
"GRqz7Vu0V6f7dvzPJM/O2QYqV5D9f9dHzN2YgvU9+QSlUeFK9PyxPv3vJt/WP1//\n"
|
||||||
|
"zf+nbpaRbwLxnCnNsKSQJFpnrE166/pSZfFbmZQpNlyeIuJU8czZGQTifQKBgHXe\n"
|
||||||
|
"/pQGEZhVNab+bHwdFTxXdDzr+1qyrodJYLaM7uFES9InVXQ6qSuJO+WosSi2QXlA\n"
|
||||||
|
"hlSfwwCwGnHXAPYFWSp5Owm34tbpp0mi8wHQ+UNgjhgsE2qwnTBUvgZ3zHpPORtD\n"
|
||||||
|
"23KZBkTmO40bIEyIJ1IZGdWO32q79nkEBTY+v/lRAoGBAI1rbouFYPBrTYQ9kcjt\n"
|
||||||
|
"1yfu4JF5MvO9JrHQ9tOwkqDmNCWx9xWXbgydsn/eFtuUMULWsG3lNjfst/Esb8ch\n"
|
||||||
|
"k5cZd6pdJZa4/vhEwrYYSuEjMCnRb0lUsm7TsHxQrUd6Fi/mUuFU/haC0o0chLq7\n"
|
||||||
|
"pVOUFq5mW8p0zbtfHbjkgxyF\n"
|
||||||
|
"-----END PRIVATE KEY-----\n";
|
||||||
|
|
||||||
|
std::string const dh =
|
||||||
|
"-----BEGIN DH PARAMETERS-----\n"
|
||||||
|
"MIIBCAKCAQEArzQc5mpm0Fs8yahDeySj31JZlwEphUdZ9StM2D8+Fo7TMduGtSi+\n"
|
||||||
|
"/HRWVwHcTFAgrxVdm+dl474mOUqqaz4MpzIb6+6OVfWHbQJmXPepZKyu4LgUPvY/\n"
|
||||||
|
"4q3/iDMjIS0fLOu/bLuObwU5ccZmDgfhmz1GanRlTQOiYRty3FiOATWZBRh6uv4u\n"
|
||||||
|
"tff4A9Bm3V9tLx9S6djq31w31Gl7OQhryodW28kc16t9TvO1BzcV3HjRPwpe701X\n"
|
||||||
|
"oEEZdnZWANkkpR/m/pfgdmGPU66S2sXMHgsliViQWpDCYeehrvFRHEdR9NV+XJfC\n"
|
||||||
|
"QMUk26jPTIVTLfXmmwU0u8vUkpR7LQKkwwIBAg==\n"
|
||||||
|
"-----END DH PARAMETERS-----\n";
|
||||||
|
|
||||||
|
ctx_.set_password_callback(
|
||||||
|
[](std::size_t size,
|
||||||
|
boost::asio::ssl::context_base::password_purpose)
|
||||||
|
{
|
||||||
|
return "test";
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx_.set_options(
|
||||||
|
boost::asio::ssl::context::default_workarounds |
|
||||||
|
boost::asio::ssl::context::no_sslv2 |
|
||||||
|
boost::asio::ssl::context::single_dh_use);
|
||||||
|
|
||||||
|
ctx_.use_certificate_chain(
|
||||||
|
boost::asio::buffer(cert.data(), cert.size()));
|
||||||
|
|
||||||
|
ctx_.use_private_key(
|
||||||
|
boost::asio::buffer(key.data(), key.size()),
|
||||||
|
boost::asio::ssl::context::file_format::pem);
|
||||||
|
|
||||||
|
ctx_.use_tmp_dh(
|
||||||
|
boost::asio::buffer(dh.data(), dh.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // framework
|
||||||
|
|
||||||
|
#endif
|
@@ -8,24 +8,40 @@
|
|||||||
#ifndef BEAST_EXAMPLE_SERVER_SSL_STREAM_HPP
|
#ifndef BEAST_EXAMPLE_SERVER_SSL_STREAM_HPP
|
||||||
#define BEAST_EXAMPLE_SERVER_SSL_STREAM_HPP
|
#define BEAST_EXAMPLE_SERVER_SSL_STREAM_HPP
|
||||||
|
|
||||||
|
// This include is necessary to work with `ssl::stream` and `beast::websocket::stream`
|
||||||
|
#include <beast/websocket/ssl.hpp>
|
||||||
|
|
||||||
#include <boost/asio/ip/tcp.hpp>
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
#include <boost/asio/ssl/stream.hpp>
|
#include <boost/asio/ssl/stream.hpp>
|
||||||
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace beast {
|
/** C++11 enabled SSL socket wrapper
|
||||||
|
|
||||||
/** Movable SSL socket wrapper
|
|
||||||
|
|
||||||
This wrapper provides an interface identical to `boost::asio::ssl::stream`,
|
This wrapper provides an interface identical to `boost::asio::ssl::stream`,
|
||||||
which is additionally move constructible and move assignable.
|
with the following additional properties:
|
||||||
|
|
||||||
|
@li Satisfies @b MoveConstructible
|
||||||
|
|
||||||
|
@li Satisfies @b MoveAssignable
|
||||||
|
|
||||||
|
@li Constructible from a moved socket.
|
||||||
*/
|
*/
|
||||||
template<class NextLayer>
|
template<class NextLayer>
|
||||||
class ssl_stream
|
class ssl_stream
|
||||||
: public boost::asio::ssl::stream_base
|
: public boost::asio::ssl::stream_base
|
||||||
{
|
{
|
||||||
|
// only works for boost::asio::ip::tcp::socket
|
||||||
|
// for now because of the move limitations
|
||||||
|
static_assert(std::is_same<NextLayer, boost::asio::ip::tcp::socket>::value,
|
||||||
|
"NextLayer requirements not met");
|
||||||
|
|
||||||
using stream_type = boost::asio::ssl::stream<NextLayer>;
|
using stream_type = boost::asio::ssl::stream<NextLayer>;
|
||||||
|
|
||||||
std::unique_ptr<stream_type> p_;
|
std::unique_ptr<stream_type> p_;
|
||||||
|
boost::asio::ssl::context* ctx_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// The native handle type of the SSL stream.
|
/// The native handle type of the SSL stream.
|
||||||
@@ -43,15 +59,30 @@ public:
|
|||||||
/// The type of the lowest layer.
|
/// The type of the lowest layer.
|
||||||
using lowest_layer_type = typename stream_type::lowest_layer_type;
|
using lowest_layer_type = typename stream_type::lowest_layer_type;
|
||||||
|
|
||||||
ssl_stream(ssl_stream&&) = default;
|
ssl_stream(boost::asio::ip::tcp::socket&& sock, boost::asio::ssl::context& ctx)
|
||||||
ssl_stream(ssl_stream const&) = delete;
|
: p_(new stream_type{sock.get_io_service(), ctx})
|
||||||
ssl_stream& operator=(ssl_stream&&) = default;
|
, ctx_(&ctx)
|
||||||
ssl_stream& operator=(ssl_stream const&) = delete;
|
|
||||||
|
|
||||||
template<class... Args>
|
|
||||||
ssl_stream(Args&&... args)
|
|
||||||
: p_(new stream_type{std::forward<Args>(args)...)
|
|
||||||
{
|
{
|
||||||
|
p_->next_layer() = std::move(sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl_stream(ssl_stream&& other)
|
||||||
|
: p_(new stream_type(other.get_io_service(), *other.ctx_))
|
||||||
|
, ctx_(other.ctx_)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
swap(p_, other.p_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl_stream& operator=(ssl_stream&& other)
|
||||||
|
{
|
||||||
|
std::unique_ptr<stream_type> p(
|
||||||
|
new stream_type{other.get_io_service(), other.ctx_});
|
||||||
|
using std::swap;
|
||||||
|
swap(p_, p);
|
||||||
|
swap(p_, other.p_);
|
||||||
|
ctx_ = other.ctx_;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::asio::io_service&
|
boost::asio::io_service&
|
||||||
@@ -184,7 +215,7 @@ public:
|
|||||||
BOOST_ASIO_MOVE_ARG(BufferedHandshakeHandler) handler)
|
BOOST_ASIO_MOVE_ARG(BufferedHandshakeHandler) handler)
|
||||||
{
|
{
|
||||||
return p_->async_handshake(type, buffers,
|
return p_->async_handshake(type, buffers,
|
||||||
BOOST_ASIO__MOVE_CAST(BufferedHandshakeHandler)(handler));
|
BOOST_ASIO_MOVE_CAST(BufferedHandshakeHandler)(handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -251,14 +282,53 @@ public:
|
|||||||
template<class MutableBufferSequence, class ReadHandler>
|
template<class MutableBufferSequence, class ReadHandler>
|
||||||
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
|
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
|
||||||
void(boost::system::error_code, std::size_t))
|
void(boost::system::error_code, std::size_t))
|
||||||
async_read_some(MutableBufferSequence& buffers,
|
async_read_some(MutableBufferSequence const& buffers,
|
||||||
BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
|
BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
|
||||||
{
|
{
|
||||||
return p_->async_read_some(buffers,
|
return p_->async_read_some(buffers,
|
||||||
BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
|
BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class SyncStream>
|
||||||
|
friend
|
||||||
|
void
|
||||||
|
teardown(beast::websocket::teardown_tag,
|
||||||
|
ssl_stream<SyncStream>& stream,
|
||||||
|
boost::system::error_code& ec);
|
||||||
|
|
||||||
|
template<class AsyncStream, class TeardownHandler>
|
||||||
|
friend
|
||||||
|
void
|
||||||
|
async_teardown(beast::websocket::teardown_tag,
|
||||||
|
ssl_stream<AsyncStream>& stream, TeardownHandler&& handler);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // beast
|
// These hooks are used to inform beast::websocket::stream on
|
||||||
|
// how to tear down the connection as part of the WebSocket
|
||||||
|
// protocol specifications
|
||||||
|
|
||||||
#endif
|
template<class SyncStream>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
teardown(beast::websocket::teardown_tag,
|
||||||
|
ssl_stream<SyncStream>& stream,
|
||||||
|
boost::system::error_code& ec)
|
||||||
|
{
|
||||||
|
// Just forward it to the wrapped ssl::stream
|
||||||
|
using beast::websocket::teardown;
|
||||||
|
teardown(beast::websocket::teardown_tag{}, *stream.p_, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class AsyncStream, class TeardownHandler>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
async_teardown(beast::websocket::teardown_tag,
|
||||||
|
ssl_stream<AsyncStream>& stream, TeardownHandler&& handler)
|
||||||
|
{
|
||||||
|
// Just forward it to the wrapped ssl::stream
|
||||||
|
using beast::websocket::async_teardown;
|
||||||
|
async_teardown(beast::websocket::teardown_tag{},
|
||||||
|
*stream.p_, std::forward<TeardownHandler>(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@@ -23,7 +23,7 @@ namespace framework {
|
|||||||
//
|
//
|
||||||
//
|
//
|
||||||
template<class Derived>
|
template<class Derived>
|
||||||
class async_ws_con
|
class async_ws_con_base
|
||||||
{
|
{
|
||||||
// This function lets us access members of the derived class
|
// This function lets us access members of the derived class
|
||||||
Derived&
|
Derived&
|
||||||
@@ -58,7 +58,7 @@ protected:
|
|||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
template<class Callback>
|
template<class Callback>
|
||||||
async_ws_con(
|
async_ws_con_base(
|
||||||
beast::string_view server_name,
|
beast::string_view server_name,
|
||||||
std::ostream& log,
|
std::ostream& log,
|
||||||
std::size_t id,
|
std::size_t id,
|
||||||
@@ -72,9 +72,9 @@ public:
|
|||||||
// Limit of 1MB on messages
|
// Limit of 1MB on messages
|
||||||
, buffer_(1024 * 1024)
|
, buffer_(1024 * 1024)
|
||||||
|
|
||||||
, strand_(impl().ws().get_io_service())
|
, strand_(impl().stream().get_io_service())
|
||||||
{
|
{
|
||||||
cb(impl().ws());
|
cb(impl().stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the connection
|
// Run the connection
|
||||||
@@ -82,18 +82,7 @@ public:
|
|||||||
void
|
void
|
||||||
run()
|
run()
|
||||||
{
|
{
|
||||||
// Read the WebSocket upgrade request and attempt
|
impl().do_handshake();
|
||||||
// to send back the response.
|
|
||||||
//
|
|
||||||
impl().ws().async_accept_ex(
|
|
||||||
[&](beast::websocket::response_type& res)
|
|
||||||
{
|
|
||||||
res.set(beast::http::field::server, server_name_);
|
|
||||||
},
|
|
||||||
strand_.wrap(std::bind(
|
|
||||||
&async_ws_con::on_accept,
|
|
||||||
impl().shared_from_this(),
|
|
||||||
std::placeholders::_1)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the connection.
|
// Run the connection.
|
||||||
@@ -109,17 +98,47 @@ public:
|
|||||||
// the request by parameter, instead of reading
|
// the request by parameter, instead of reading
|
||||||
// it from the network.
|
// it from the network.
|
||||||
//
|
//
|
||||||
impl().ws().async_accept_ex(req,
|
impl().stream().async_accept_ex(req,
|
||||||
[&](beast::websocket::response_type& res)
|
[&](beast::websocket::response_type& res)
|
||||||
{
|
{
|
||||||
res.set(beast::http::field::server, server_name_);
|
res.set(beast::http::field::server, server_name_);
|
||||||
},
|
},
|
||||||
strand_.wrap(std::bind(
|
strand_.wrap(std::bind(
|
||||||
&async_ws_con::on_accept,
|
&async_ws_con_base::on_accept,
|
||||||
impl().shared_from_this(),
|
impl().shared_from_this(),
|
||||||
std::placeholders::_1)));
|
std::placeholders::_1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Performs the WebSocket handshake
|
||||||
|
void
|
||||||
|
do_accept()
|
||||||
|
{
|
||||||
|
// Read the WebSocket upgrade request and attempt
|
||||||
|
// to send back the response.
|
||||||
|
//
|
||||||
|
impl().stream().async_accept_ex(
|
||||||
|
[&](beast::websocket::response_type& res)
|
||||||
|
{
|
||||||
|
res.set(beast::http::field::server, server_name_);
|
||||||
|
},
|
||||||
|
strand_.wrap(std::bind(
|
||||||
|
&async_ws_con_base::on_accept,
|
||||||
|
impl().shared_from_this(),
|
||||||
|
std::placeholders::_1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This helper reports failures
|
||||||
|
//
|
||||||
|
void
|
||||||
|
fail(std::string what, error_code ec)
|
||||||
|
{
|
||||||
|
if(ec != beast::websocket::error::closed)
|
||||||
|
log_ <<
|
||||||
|
"[#" << id_ << " " << ep_ << "] " <<
|
||||||
|
what << ": " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Called when accept_ex completes
|
// Called when accept_ex completes
|
||||||
//
|
//
|
||||||
@@ -136,10 +155,10 @@ private:
|
|||||||
void
|
void
|
||||||
do_read()
|
do_read()
|
||||||
{
|
{
|
||||||
impl().ws().async_read(
|
impl().stream().async_read(
|
||||||
buffer_,
|
buffer_,
|
||||||
strand_.wrap(std::bind(
|
strand_.wrap(std::bind(
|
||||||
&async_ws_con::on_read,
|
&async_ws_con_base::on_read,
|
||||||
impl().shared_from_this(),
|
impl().shared_from_this(),
|
||||||
std::placeholders::_1)));
|
std::placeholders::_1)));
|
||||||
}
|
}
|
||||||
@@ -155,14 +174,14 @@ private:
|
|||||||
// Set the outgoing message type. We will use
|
// Set the outgoing message type. We will use
|
||||||
// the same setting as the message we just read.
|
// the same setting as the message we just read.
|
||||||
//
|
//
|
||||||
impl().ws().binary(impl().ws().got_binary());
|
impl().stream().binary(impl().stream().got_binary());
|
||||||
|
|
||||||
// Now echo back the message
|
// Now echo back the message
|
||||||
//
|
//
|
||||||
impl().ws().async_write(
|
impl().stream().async_write(
|
||||||
buffer_.data(),
|
buffer_.data(),
|
||||||
strand_.wrap(std::bind(
|
strand_.wrap(std::bind(
|
||||||
&async_ws_con::on_write,
|
&async_ws_con_base::on_write,
|
||||||
impl().shared_from_this(),
|
impl().shared_from_this(),
|
||||||
std::placeholders::_1)));
|
std::placeholders::_1)));
|
||||||
}
|
}
|
||||||
@@ -184,17 +203,6 @@ private:
|
|||||||
//
|
//
|
||||||
do_read();
|
do_read();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This helper reports failures
|
|
||||||
//
|
|
||||||
void
|
|
||||||
fail(std::string what, error_code ec)
|
|
||||||
{
|
|
||||||
if(ec != beast::websocket::error::closed)
|
|
||||||
log_ <<
|
|
||||||
"[#" << id_ << " " << ep_ << "] " <<
|
|
||||||
what << ": " << ec.message() << std::endl;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -202,12 +210,12 @@ private:
|
|||||||
// This class represents an asynchronous WebSocket connection
|
// This class represents an asynchronous WebSocket connection
|
||||||
// which uses a plain TCP/IP socket (no encryption) as the stream.
|
// which uses a plain TCP/IP socket (no encryption) as the stream.
|
||||||
//
|
//
|
||||||
class async_ws_con_plain
|
class async_ws_con
|
||||||
|
|
||||||
// Note that we give this object the `enable_shared_from_this`, and have
|
// Note that we give this object the `enable_shared_from_this`, and have
|
||||||
// the base class call `impl().shared_from_this()` when needed.
|
// the base class call `impl().shared_from_this()` when needed.
|
||||||
//
|
//
|
||||||
: public std::enable_shared_from_this<async_ws_con_plain>
|
: public std::enable_shared_from_this<async_ws_con>
|
||||||
|
|
||||||
// We want the socket to be created before the base class so we use
|
// We want the socket to be created before the base class so we use
|
||||||
// the "base from member" idiom which Boost provides as a class.
|
// the "base from member" idiom which Boost provides as a class.
|
||||||
@@ -216,18 +224,18 @@ class async_ws_con_plain
|
|||||||
|
|
||||||
// Declare this base last now that everything else got set up first.
|
// Declare this base last now that everything else got set up first.
|
||||||
//
|
//
|
||||||
, public async_ws_con<async_ws_con_plain>
|
, public async_ws_con_base<async_ws_con>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Construct the plain connection.
|
// Construct the plain connection.
|
||||||
//
|
//
|
||||||
template<class... Args>
|
template<class... Args>
|
||||||
explicit
|
explicit
|
||||||
async_ws_con_plain(
|
async_ws_con(
|
||||||
socket_type&& sock,
|
socket_type&& sock,
|
||||||
Args&&... args)
|
Args&&... args)
|
||||||
: base_from_member<beast::websocket::stream<socket_type>>(std::move(sock))
|
: base_from_member<beast::websocket::stream<socket_type>>(std::move(sock))
|
||||||
, async_ws_con<async_ws_con_plain>(std::forward<Args>(args)...)
|
, async_ws_con_base<async_ws_con>(std::forward<Args>(args)...)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,10 +244,20 @@ public:
|
|||||||
// The base class calls this to obtain the websocket stream object.
|
// The base class calls this to obtain the websocket stream object.
|
||||||
//
|
//
|
||||||
beast::websocket::stream<socket_type>&
|
beast::websocket::stream<socket_type>&
|
||||||
ws()
|
stream()
|
||||||
{
|
{
|
||||||
return this->member;
|
return this->member;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Base class needs to be a friend to call our private members
|
||||||
|
friend async_ws_con_base<async_ws_con>;
|
||||||
|
|
||||||
|
void
|
||||||
|
do_handshake()
|
||||||
|
{
|
||||||
|
do_accept();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -304,7 +322,7 @@ public:
|
|||||||
socket_type&& sock,
|
socket_type&& sock,
|
||||||
endpoint_type ep)
|
endpoint_type ep)
|
||||||
{
|
{
|
||||||
std::make_shared<async_ws_con_plain>(
|
std::make_shared<async_ws_con>(
|
||||||
std::move(sock),
|
std::move(sock),
|
||||||
"ws_async_port",
|
"ws_async_port",
|
||||||
log_,
|
log_,
|
||||||
@@ -332,7 +350,7 @@ public:
|
|||||||
endpoint_type ep,
|
endpoint_type ep,
|
||||||
beast::http::request<Body, Fields>&& req)
|
beast::http::request<Body, Fields>&& req)
|
||||||
{
|
{
|
||||||
std::make_shared<async_ws_con_plain>(
|
std::make_shared<async_ws_con>(
|
||||||
std::move(sock),
|
std::move(sock),
|
||||||
"ws_async_port",
|
"ws_async_port",
|
||||||
log_,
|
log_,
|
||||||
|
@@ -30,7 +30,7 @@ namespace framework {
|
|||||||
for plain and SSL stream objects.
|
for plain and SSL stream objects.
|
||||||
*/
|
*/
|
||||||
template<class Derived>
|
template<class Derived>
|
||||||
class sync_ws_con
|
class sync_ws_con_base
|
||||||
{
|
{
|
||||||
// This function lets us access members of the derived class
|
// This function lets us access members of the derived class
|
||||||
Derived&
|
Derived&
|
||||||
@@ -56,7 +56,7 @@ class sync_ws_con
|
|||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
template<class Callback>
|
template<class Callback>
|
||||||
sync_ws_con(
|
sync_ws_con_base(
|
||||||
beast::string_view server_name,
|
beast::string_view server_name,
|
||||||
std::ostream& log,
|
std::ostream& log,
|
||||||
std::size_t id,
|
std::size_t id,
|
||||||
@@ -67,22 +67,23 @@ public:
|
|||||||
, id_(id)
|
, id_(id)
|
||||||
, ep_(ep)
|
, ep_(ep)
|
||||||
{
|
{
|
||||||
cb(impl().ws());
|
cb(impl().stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the connection.
|
// Run the connection. This is called for the case
|
||||||
|
// where we have not received the upgrade request yet.
|
||||||
//
|
//
|
||||||
void
|
void
|
||||||
run()
|
run()
|
||||||
{
|
{
|
||||||
// We run the do_accept function in its own thread,
|
// We run the do_run function in its own thread,
|
||||||
// and bind a shared pointer to the connection object
|
// and bind a shared pointer to the connection object
|
||||||
// into the function. The last reference to the shared
|
// into the function. The last reference to the shared
|
||||||
// pointer will go away when the thread exits, thus
|
// pointer will go away when the thread exits, thus
|
||||||
// destroying the connection object.
|
// destroying the connection object.
|
||||||
//
|
//
|
||||||
std::thread{
|
std::thread{
|
||||||
&sync_ws_con::do_accept,
|
&sync_ws_con_base::do_accept,
|
||||||
impl().shared_from_this()
|
impl().shared_from_this()
|
||||||
}.detach();
|
}.detach();
|
||||||
}
|
}
|
||||||
@@ -106,7 +107,58 @@ public:
|
|||||||
}}.detach();
|
}}.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Called when a failure occurs
|
||||||
|
//
|
||||||
|
void
|
||||||
|
fail(std::string what, error_code ec)
|
||||||
|
{
|
||||||
|
// Don't report the "closed" error since that
|
||||||
|
// happens under normal circumstances.
|
||||||
|
//
|
||||||
|
if(ec && ec != beast::websocket::error::closed)
|
||||||
|
{
|
||||||
|
log_ <<
|
||||||
|
"[#" << id_ << " " << ep_ << "] " <<
|
||||||
|
what << ": " << ec.message() << std::endl;
|
||||||
|
log_.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// This function performs the WebSocket handshake
|
||||||
|
// and runs the main loop upon success.
|
||||||
|
void
|
||||||
|
do_accept()
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
|
||||||
|
// Give the derived class a chance to do stuff before we
|
||||||
|
// enter the main loop. This is for SSL connections really.
|
||||||
|
//
|
||||||
|
impl().do_handshake(ec);
|
||||||
|
|
||||||
|
if(ec)
|
||||||
|
return fail("handshake", ec);
|
||||||
|
|
||||||
|
// Read the WebSocket upgrade request and attempt
|
||||||
|
// to send back the response.
|
||||||
|
//
|
||||||
|
impl().stream().accept_ex(
|
||||||
|
[&](beast::websocket::response_type& res)
|
||||||
|
{
|
||||||
|
res.insert(beast::http::field::server, server_name_);
|
||||||
|
},
|
||||||
|
ec);
|
||||||
|
|
||||||
|
if(ec)
|
||||||
|
return fail("accept", ec);
|
||||||
|
|
||||||
|
// Run the connection
|
||||||
|
//
|
||||||
|
do_run();
|
||||||
|
}
|
||||||
|
|
||||||
// This is the lambda used when launching a connection from
|
// This is the lambda used when launching a connection from
|
||||||
// an already-received request. In C++14 we could simply use
|
// an already-received request. In C++14 we could simply use
|
||||||
// a lambda capture but this example requires only C++11 so
|
// a lambda capture but this example requires only C++11 so
|
||||||
@@ -116,7 +168,7 @@ private:
|
|||||||
template<class Body, class Fields>
|
template<class Body, class Fields>
|
||||||
class lambda
|
class lambda
|
||||||
{
|
{
|
||||||
std::shared_ptr<sync_ws_con> self_;
|
std::shared_ptr<sync_ws_con_base> self_;
|
||||||
beast::http::request<Body, Fields> req_;
|
beast::http::request<Body, Fields> req_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -125,7 +177,7 @@ private:
|
|||||||
// This is the equivalent of the capture section of the lambda.
|
// This is the equivalent of the capture section of the lambda.
|
||||||
//
|
//
|
||||||
lambda(
|
lambda(
|
||||||
std::shared_ptr<sync_ws_con> self,
|
std::shared_ptr<sync_ws_con_base> self,
|
||||||
beast::http::request<Body, Fields>&& req)
|
beast::http::request<Body, Fields>&& req)
|
||||||
: self_(std::move(self))
|
: self_(std::move(self))
|
||||||
, req_(std::move(req))
|
, req_(std::move(req))
|
||||||
@@ -151,7 +203,7 @@ private:
|
|||||||
// the request by parameter, instead of reading
|
// the request by parameter, instead of reading
|
||||||
// it from the network.
|
// it from the network.
|
||||||
//
|
//
|
||||||
self_->impl().ws().accept_ex(req,
|
self_->impl().stream().accept_ex(req,
|
||||||
[&](beast::websocket::response_type& res)
|
[&](beast::websocket::response_type& res)
|
||||||
{
|
{
|
||||||
res.insert(beast::http::field::server, self_->server_name_);
|
res.insert(beast::http::field::server, self_->server_name_);
|
||||||
@@ -159,55 +211,18 @@ private:
|
|||||||
ec);
|
ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the connection
|
if(ec)
|
||||||
//
|
return self_->fail("accept", ec);
|
||||||
self_->do_run(ec);
|
|
||||||
|
self_->do_run();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
do_accept()
|
do_run()
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec;
|
||||||
|
|
||||||
// Read the WebSocket upgrade request and attempt
|
|
||||||
// to send back the response.
|
|
||||||
//
|
|
||||||
impl().ws().accept_ex(
|
|
||||||
[&](beast::websocket::response_type& res)
|
|
||||||
{
|
|
||||||
res.insert(beast::http::field::server, server_name_);
|
|
||||||
},
|
|
||||||
ec);
|
|
||||||
|
|
||||||
// Run the connection
|
|
||||||
//
|
|
||||||
do_run(ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
do_run(error_code ec)
|
|
||||||
{
|
|
||||||
// Helper lambda to report a failure
|
|
||||||
//
|
|
||||||
auto const fail =
|
|
||||||
[&](std::string const& what, error_code ev)
|
|
||||||
{
|
|
||||||
if(ev != beast::websocket::error::closed)
|
|
||||||
log_ <<
|
|
||||||
"[#" << id_ << " " << ep_ << "] " <<
|
|
||||||
what << ": " << ev.message() << std::endl;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check for an error upon entry. This will
|
|
||||||
// come from one of the two calls to accept()
|
|
||||||
//
|
|
||||||
if(ec)
|
|
||||||
{
|
|
||||||
fail("accept", ec);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop, reading messages and echoing them back.
|
// Loop, reading messages and echoing them back.
|
||||||
//
|
//
|
||||||
for(;;)
|
for(;;)
|
||||||
@@ -219,7 +234,7 @@ private:
|
|||||||
|
|
||||||
// Read the message
|
// Read the message
|
||||||
//
|
//
|
||||||
impl().ws().read(buffer, ec);
|
impl().stream().read(buffer, ec);
|
||||||
|
|
||||||
if(ec)
|
if(ec)
|
||||||
return fail("read", ec);
|
return fail("read", ec);
|
||||||
@@ -227,11 +242,11 @@ private:
|
|||||||
// Set the outgoing message type. We will use
|
// Set the outgoing message type. We will use
|
||||||
// the same setting as the message we just read.
|
// the same setting as the message we just read.
|
||||||
//
|
//
|
||||||
impl().ws().binary(impl().ws().got_binary());
|
impl().stream().binary(impl().stream().got_binary());
|
||||||
|
|
||||||
// Now echo back the message
|
// Now echo back the message
|
||||||
//
|
//
|
||||||
impl().ws().write(buffer.data(), ec);
|
impl().stream().write(buffer.data(), ec);
|
||||||
|
|
||||||
if(ec)
|
if(ec)
|
||||||
return fail("write", ec);
|
return fail("write", ec);
|
||||||
@@ -244,12 +259,12 @@ private:
|
|||||||
// This class represents a synchronous WebSocket connection
|
// This class represents a synchronous WebSocket connection
|
||||||
// which uses a plain TCP/IP socket (no encryption) as the stream.
|
// which uses a plain TCP/IP socket (no encryption) as the stream.
|
||||||
//
|
//
|
||||||
class sync_ws_con_plain
|
class sync_ws_con
|
||||||
|
|
||||||
// Note that we give this object the `enable_shared_from_this`, and have
|
// Note that we give this object the `enable_shared_from_this`, and have
|
||||||
// the base class call `impl().shared_from_this()` when needed.
|
// the base class call `impl().shared_from_this()` when needed.
|
||||||
//
|
//
|
||||||
: public std::enable_shared_from_this<sync_ws_con_plain>
|
: public std::enable_shared_from_this<sync_ws_con>
|
||||||
|
|
||||||
// We want the socket to be created before the base class so we use
|
// We want the socket to be created before the base class so we use
|
||||||
// the "base from member" idiom which Boost provides as a class.
|
// the "base from member" idiom which Boost provides as a class.
|
||||||
@@ -258,18 +273,18 @@ class sync_ws_con_plain
|
|||||||
|
|
||||||
// Declare this base last now that everything else got set up first.
|
// Declare this base last now that everything else got set up first.
|
||||||
//
|
//
|
||||||
, public sync_ws_con<sync_ws_con_plain>
|
, public sync_ws_con_base<sync_ws_con>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Construct the plain connection.
|
// Construct the plain connection.
|
||||||
//
|
//
|
||||||
template<class... Args>
|
template<class... Args>
|
||||||
explicit
|
explicit
|
||||||
sync_ws_con_plain(
|
sync_ws_con(
|
||||||
socket_type&& sock,
|
socket_type&& sock,
|
||||||
Args&&... args)
|
Args&&... args)
|
||||||
: base_from_member<beast::websocket::stream<socket_type>>(std::move(sock))
|
: base_from_member<beast::websocket::stream<socket_type>>(std::move(sock))
|
||||||
, sync_ws_con<sync_ws_con_plain>(std::forward<Args>(args)...)
|
, sync_ws_con_base<sync_ws_con>(std::forward<Args>(args)...)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,10 +293,25 @@ public:
|
|||||||
// The base class calls this to obtain the websocket stream object.
|
// The base class calls this to obtain the websocket stream object.
|
||||||
//
|
//
|
||||||
beast::websocket::stream<socket_type>&
|
beast::websocket::stream<socket_type>&
|
||||||
ws()
|
stream()
|
||||||
{
|
{
|
||||||
return this->member;
|
return this->member;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Base class needs to be a friend to call our private members
|
||||||
|
friend class sync_ws_con_base<sync_ws_con>;
|
||||||
|
|
||||||
|
// This is called by the base before running the main loop.
|
||||||
|
// There's nothing to do for a plain connection.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
do_handshake(error_code& ec)
|
||||||
|
{
|
||||||
|
// This is required by the specifications for error_code
|
||||||
|
//
|
||||||
|
ec = {};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -346,7 +376,7 @@ public:
|
|||||||
{
|
{
|
||||||
// Create our connection object and run it
|
// Create our connection object and run it
|
||||||
//
|
//
|
||||||
std::make_shared<sync_ws_con_plain>(
|
std::make_shared<sync_ws_con>(
|
||||||
std::move(sock),
|
std::move(sock),
|
||||||
"ws_sync_port",
|
"ws_sync_port",
|
||||||
log_,
|
log_,
|
||||||
@@ -377,7 +407,7 @@ public:
|
|||||||
// Create the connection object and run it,
|
// Create the connection object and run it,
|
||||||
// transferring ownershop of the ugprade request.
|
// transferring ownershop of the ugprade request.
|
||||||
//
|
//
|
||||||
std::make_shared<sync_ws_con_plain>(
|
std::make_shared<sync_ws_con>(
|
||||||
std::move(sock),
|
std::move(sock),
|
||||||
"ws_sync_port",
|
"ws_sync_port",
|
||||||
log_,
|
log_,
|
||||||
|
414
example/server-framework/wss_ports.hpp
Normal file
414
example/server-framework/wss_ports.hpp
Normal file
@@ -0,0 +1,414 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BEAST_EXAMPLE_SERVER_WSS_PORTS_HPP
|
||||||
|
#define BEAST_EXAMPLE_SERVER_WSS_PORTS_HPP
|
||||||
|
|
||||||
|
#include "ws_sync_port.hpp"
|
||||||
|
#include "ws_async_port.hpp"
|
||||||
|
#include "ssl_stream.hpp"
|
||||||
|
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
|
||||||
|
namespace framework {
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// This class represents a synchronous Secure WebSocket connection
|
||||||
|
//
|
||||||
|
class sync_wss_con
|
||||||
|
|
||||||
|
// Note that we give this object the `enable_shared_from_this`, and have
|
||||||
|
// the base class call `impl().shared_from_this()` when needed.
|
||||||
|
//
|
||||||
|
: public std::enable_shared_from_this<sync_wss_con>
|
||||||
|
|
||||||
|
// We want the socket to be created before the base class so we use
|
||||||
|
// the "base from member" idiom which Boost provides as a class.
|
||||||
|
//
|
||||||
|
, public base_from_member<beast::websocket::stream<ssl_stream<socket_type>>>
|
||||||
|
|
||||||
|
// Declare this base last now that everything else got set up first.
|
||||||
|
//
|
||||||
|
, public sync_ws_con_base<sync_wss_con>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Construct the plain connection.
|
||||||
|
//
|
||||||
|
template<class... Args>
|
||||||
|
explicit
|
||||||
|
sync_wss_con(
|
||||||
|
socket_type&& sock,
|
||||||
|
boost::asio::ssl::context& ctx,
|
||||||
|
Args&&... args)
|
||||||
|
: base_from_member<beast::websocket::stream<ssl_stream<socket_type>>>(std::move(sock), ctx)
|
||||||
|
, sync_ws_con_base<sync_wss_con>(std::forward<Args>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the connection from an existing, handshaked SSL stream
|
||||||
|
//
|
||||||
|
template<class... Args>
|
||||||
|
sync_wss_con(
|
||||||
|
ssl_stream<socket_type>&& stream,
|
||||||
|
Args&&... args)
|
||||||
|
: base_from_member<beast::websocket::stream<ssl_stream<socket_type>>>(std::move(stream))
|
||||||
|
, sync_ws_con_base<sync_wss_con>(std::forward<Args>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the stream.
|
||||||
|
//
|
||||||
|
// The base class calls this to obtain the websocket stream object.
|
||||||
|
//
|
||||||
|
beast::websocket::stream<ssl_stream<socket_type>>&
|
||||||
|
stream()
|
||||||
|
{
|
||||||
|
return this->member;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class sync_ws_con_base<sync_wss_con>;
|
||||||
|
|
||||||
|
// This is called by the base before running the main loop.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
do_handshake(error_code& ec)
|
||||||
|
{
|
||||||
|
// Perform the SSL handshake
|
||||||
|
//
|
||||||
|
// We use next_layer() to get at the underlying ssl_stream
|
||||||
|
//
|
||||||
|
stream().next_layer().handshake(boost::asio::ssl::stream_base::server, ec);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// This class represents an asynchronous Secure WebSocket
|
||||||
|
// connection which uses an OpenSSL socket as the stream.
|
||||||
|
//
|
||||||
|
class async_wss_con
|
||||||
|
|
||||||
|
// Note that we give this object the enable_shared_from_this, and have
|
||||||
|
// the base class call impl().shared_from_this(). The reason we do that
|
||||||
|
// is so that the shared_ptr has the correct type. This lets the
|
||||||
|
// derived class (this class) use its members in calls to std::bind,
|
||||||
|
// without an ugly call to `dynamic_downcast` or other nonsense.
|
||||||
|
//
|
||||||
|
: public std::enable_shared_from_this<async_wss_con>
|
||||||
|
|
||||||
|
// We want the socket to be created before the base class so we use
|
||||||
|
// the "base from member" idiom which Boost provides as a class.
|
||||||
|
//
|
||||||
|
, public base_from_member<beast::websocket::stream<ssl_stream<socket_type>>>
|
||||||
|
|
||||||
|
// Declare this base last now that everything else got set up first.
|
||||||
|
//
|
||||||
|
, public async_ws_con_base<async_wss_con>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Construct the connection.
|
||||||
|
//
|
||||||
|
template<class... Args>
|
||||||
|
async_wss_con(
|
||||||
|
socket_type&& sock,
|
||||||
|
boost::asio::ssl::context& ctx,
|
||||||
|
Args&&... args)
|
||||||
|
: base_from_member<beast::websocket::stream<ssl_stream<socket_type>>>(std::move(sock), ctx)
|
||||||
|
, async_ws_con_base<async_wss_con>(std::forward<Args>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the connection from an existing, handshaked SSL stream
|
||||||
|
//
|
||||||
|
template<class... Args>
|
||||||
|
async_wss_con(
|
||||||
|
ssl_stream<socket_type>&& stream,
|
||||||
|
Args&&... args)
|
||||||
|
: base_from_member<beast::websocket::stream<ssl_stream<socket_type>>>(std::move(stream))
|
||||||
|
, async_ws_con_base<async_wss_con>(std::forward<Args>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the stream.
|
||||||
|
// The base class calls this to obtain the object to
|
||||||
|
// use for reading and writing HTTP messages.
|
||||||
|
//
|
||||||
|
beast::websocket::stream<ssl_stream<socket_type>>&
|
||||||
|
stream()
|
||||||
|
{
|
||||||
|
return this->member;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class async_ws_con_base<async_wss_con>;
|
||||||
|
|
||||||
|
// Called by the port to start the connection
|
||||||
|
// after creating the object
|
||||||
|
//
|
||||||
|
void
|
||||||
|
do_handshake()
|
||||||
|
{
|
||||||
|
// This is SSL so perform the handshake first
|
||||||
|
//
|
||||||
|
stream().next_layer().async_handshake(
|
||||||
|
boost::asio::ssl::stream_base::server,
|
||||||
|
this->strand_.wrap(std::bind(
|
||||||
|
&async_wss_con::on_handshake,
|
||||||
|
this->shared_from_this(),
|
||||||
|
std::placeholders::_1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when the SSL handshake completes
|
||||||
|
void
|
||||||
|
on_handshake(error_code ec)
|
||||||
|
{
|
||||||
|
if(ec)
|
||||||
|
return this->fail("on_handshake", ec);
|
||||||
|
|
||||||
|
// Move on to accepting the WebSocket handshake
|
||||||
|
//
|
||||||
|
this->do_accept();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** A synchronous Secure WebSocket @b PortHandler which implements echo.
|
||||||
|
|
||||||
|
This is a port handler which accepts Secure WebSocket upgrade
|
||||||
|
HTTP requests and implements the echo protocol. All received
|
||||||
|
WebSocket messages will be echoed back to the remote host.
|
||||||
|
*/
|
||||||
|
class wss_sync_port
|
||||||
|
{
|
||||||
|
// VFALCO We use boost::function to work around a compiler
|
||||||
|
// crash with gcc and clang using libstdc++
|
||||||
|
|
||||||
|
// The types of the on_stream callback
|
||||||
|
using on_new_stream_cb1 = boost::function<
|
||||||
|
void(beast::websocket::stream<socket_type>&)>;
|
||||||
|
using on_new_stream_cb2 = boost::function<
|
||||||
|
void(beast::websocket::stream<ssl_stream<socket_type>>&)>;
|
||||||
|
|
||||||
|
server& instance_;
|
||||||
|
std::ostream& log_;
|
||||||
|
boost::asio::ssl::context& ctx_;
|
||||||
|
on_new_stream_cb1 cb1_;
|
||||||
|
on_new_stream_cb2 cb2_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
|
||||||
|
@param instance The server instance which owns this port
|
||||||
|
|
||||||
|
@param log The stream to use for logging
|
||||||
|
|
||||||
|
@param ctx The SSL context holding the SSL certificates to use
|
||||||
|
|
||||||
|
@param cb A callback which will be invoked for every new
|
||||||
|
WebSocket connection. This provides an opportunity to change
|
||||||
|
the settings on the stream before it is used. The callback
|
||||||
|
should have this equivalent signature:
|
||||||
|
@code
|
||||||
|
template<class NextLayer>
|
||||||
|
void callback(beast::websocket::stream<NextLayer>&);
|
||||||
|
@endcode
|
||||||
|
In C++14 this can be accomplished with a generic lambda. In
|
||||||
|
C++11 it will be necessary to write out a lambda manually,
|
||||||
|
with a templated operator().
|
||||||
|
*/
|
||||||
|
template<class Callback>
|
||||||
|
wss_sync_port(
|
||||||
|
server& instance,
|
||||||
|
std::ostream& log,
|
||||||
|
boost::asio::ssl::context& ctx,
|
||||||
|
Callback const& cb)
|
||||||
|
: instance_(instance)
|
||||||
|
, log_(log)
|
||||||
|
, ctx_(ctx)
|
||||||
|
, cb1_(cb)
|
||||||
|
, cb2_(cb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Accept a TCP/IP connection.
|
||||||
|
|
||||||
|
This function is called when the server has accepted an
|
||||||
|
incoming connection.
|
||||||
|
|
||||||
|
@param sock The connected socket.
|
||||||
|
|
||||||
|
@param ep The endpoint of the remote host.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
on_accept(socket_type&& sock, endpoint_type ep)
|
||||||
|
{
|
||||||
|
// Create our connection object and run it
|
||||||
|
//
|
||||||
|
std::make_shared<sync_wss_con>(
|
||||||
|
std::move(sock),
|
||||||
|
ctx_,
|
||||||
|
"wss_sync_port",
|
||||||
|
log_,
|
||||||
|
instance_.next_id(),
|
||||||
|
ep,
|
||||||
|
cb2_
|
||||||
|
)->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Accept a WebSocket upgrade request.
|
||||||
|
|
||||||
|
This is used to accept a connection that has already
|
||||||
|
delivered the handshake.
|
||||||
|
|
||||||
|
@param stream The stream corresponding to the connection.
|
||||||
|
|
||||||
|
@param ep The remote endpoint.
|
||||||
|
|
||||||
|
@param req The upgrade request.
|
||||||
|
*/
|
||||||
|
template<class Body, class Fields>
|
||||||
|
void
|
||||||
|
accept(
|
||||||
|
ssl_stream<socket_type>&& stream,
|
||||||
|
endpoint_type ep,
|
||||||
|
beast::http::request<Body, Fields>&& req)
|
||||||
|
{
|
||||||
|
// Create the connection object and run it,
|
||||||
|
// transferring ownershop of the ugprade request.
|
||||||
|
//
|
||||||
|
std::make_shared<sync_wss_con>(
|
||||||
|
std::move(stream),
|
||||||
|
"wss_sync_port",
|
||||||
|
log_,
|
||||||
|
instance_.next_id(),
|
||||||
|
ep,
|
||||||
|
cb2_
|
||||||
|
)->run(std::move(req));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** An asynchronous WebSocket @b PortHandler which implements echo.
|
||||||
|
|
||||||
|
This is a port handler which accepts WebSocket upgrade HTTP
|
||||||
|
requests and implements the echo protocol. All received
|
||||||
|
WebSocket messages will be echoed back to the remote host.
|
||||||
|
*/
|
||||||
|
class wss_async_port
|
||||||
|
{
|
||||||
|
// VFALCO We use boost::function to work around a compiler
|
||||||
|
// crash with gcc and clang using libstdc++
|
||||||
|
|
||||||
|
// The types of the on_stream callback
|
||||||
|
using on_new_stream_cb1 = boost::function<
|
||||||
|
void(beast::websocket::stream<socket_type>&)>;
|
||||||
|
using on_new_stream_cb2 = boost::function<
|
||||||
|
void(beast::websocket::stream<ssl_stream<socket_type>>&)>;
|
||||||
|
|
||||||
|
server& instance_;
|
||||||
|
std::ostream& log_;
|
||||||
|
boost::asio::ssl::context& ctx_;
|
||||||
|
on_new_stream_cb1 cb1_;
|
||||||
|
on_new_stream_cb2 cb2_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
|
||||||
|
@param instance The server instance which owns this port
|
||||||
|
|
||||||
|
@param log The stream to use for logging
|
||||||
|
|
||||||
|
@param ctx The SSL context holding the SSL certificates to use
|
||||||
|
|
||||||
|
@param cb A callback which will be invoked for every new
|
||||||
|
WebSocket connection. This provides an opportunity to change
|
||||||
|
the settings on the stream before it is used. The callback
|
||||||
|
should have this equivalent signature:
|
||||||
|
@code
|
||||||
|
template<class NextLayer>
|
||||||
|
void callback(beast::websocket::stream<NextLayer>&);
|
||||||
|
@endcode
|
||||||
|
In C++14 this can be accomplished with a generic lambda. In
|
||||||
|
C++11 it will be necessary to write out a lambda manually,
|
||||||
|
with a templated operator().
|
||||||
|
*/
|
||||||
|
template<class Callback>
|
||||||
|
wss_async_port(
|
||||||
|
server& instance,
|
||||||
|
std::ostream& log,
|
||||||
|
boost::asio::ssl::context& ctx,
|
||||||
|
Callback const& cb)
|
||||||
|
: instance_(instance)
|
||||||
|
, log_(log)
|
||||||
|
, ctx_(ctx)
|
||||||
|
, cb1_(cb)
|
||||||
|
, cb2_(cb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Accept a TCP/IP connection.
|
||||||
|
|
||||||
|
This function is called when the server has accepted an
|
||||||
|
incoming connection.
|
||||||
|
|
||||||
|
@param sock The connected socket.
|
||||||
|
|
||||||
|
@param ep The endpoint of the remote host.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
on_accept(
|
||||||
|
socket_type&& sock,
|
||||||
|
endpoint_type ep)
|
||||||
|
{
|
||||||
|
std::make_shared<async_wss_con>(
|
||||||
|
std::move(sock),
|
||||||
|
ctx_,
|
||||||
|
"wss_async_port",
|
||||||
|
log_,
|
||||||
|
instance_.next_id(),
|
||||||
|
ep,
|
||||||
|
cb2_
|
||||||
|
)->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Accept a WebSocket upgrade request.
|
||||||
|
|
||||||
|
This is used to accept a connection that has already
|
||||||
|
delivered the handshake.
|
||||||
|
|
||||||
|
@param stream The stream corresponding to the connection.
|
||||||
|
|
||||||
|
@param ep The remote endpoint.
|
||||||
|
|
||||||
|
@param req The upgrade request.
|
||||||
|
*/
|
||||||
|
template<class Body, class Fields>
|
||||||
|
void
|
||||||
|
accept(
|
||||||
|
ssl_stream<socket_type>&& stream,
|
||||||
|
endpoint_type ep,
|
||||||
|
beast::http::request<Body, Fields>&& req)
|
||||||
|
{
|
||||||
|
std::make_shared<async_wss_con>(
|
||||||
|
std::move(stream),
|
||||||
|
"wss_async_port",
|
||||||
|
log_,
|
||||||
|
instance_.next_id(),
|
||||||
|
ep,
|
||||||
|
cb2_
|
||||||
|
)->run(std::move(req));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // framework
|
||||||
|
|
||||||
|
#endif
|
@@ -5,6 +5,16 @@ GroupSources(include/beast beast)
|
|||||||
|
|
||||||
GroupSources(test/server "/")
|
GroupSources(test/server "/")
|
||||||
|
|
||||||
|
if (OPENSSL_FOUND)
|
||||||
|
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||||
|
set(SSL_SOURCES
|
||||||
|
https_ports.cpp
|
||||||
|
ssl_stream.cpp
|
||||||
|
)
|
||||||
|
else ()
|
||||||
|
set(SSL_SOURCES "")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable (server-test
|
add_executable (server-test
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
${SERVER_INCLUDES}
|
${SERVER_INCLUDES}
|
||||||
@@ -14,15 +24,22 @@ add_executable (server-test
|
|||||||
http_async_port.cpp
|
http_async_port.cpp
|
||||||
http_base.cpp
|
http_base.cpp
|
||||||
http_sync_port.cpp
|
http_sync_port.cpp
|
||||||
|
https_ports.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
rfc7231.cpp
|
rfc7231.cpp
|
||||||
server.cpp
|
server.cpp
|
||||||
service_list.cpp
|
service_list.cpp
|
||||||
|
ssl_certificate
|
||||||
write_msg.cpp
|
write_msg.cpp
|
||||||
ws_async_port.cpp
|
ws_async_port.cpp
|
||||||
ws_sync_port.cpp
|
ws_sync_port.cpp
|
||||||
ws_upgrade_service.cpp
|
ws_upgrade_service.cpp
|
||||||
|
wss_ports.cpp
|
||||||
|
${SSL_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(server-test Beast)
|
target_link_libraries(server-test Beast)
|
||||||
|
|
||||||
|
if (OPENSSL_FOUND)
|
||||||
|
target_link_libraries(server-test ${OPENSSL_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
@@ -20,4 +20,7 @@ exe server-test :
|
|||||||
ws_async_port.cpp
|
ws_async_port.cpp
|
||||||
ws_sync_port.cpp
|
ws_sync_port.cpp
|
||||||
ws_upgrade_service.cpp
|
ws_upgrade_service.cpp
|
||||||
|
#https_ports.cpp
|
||||||
|
#ssl_certificate.cpp
|
||||||
|
#ssl_stream.cpp
|
||||||
;
|
;
|
||||||
|
13
test/server/https_ports.cpp
Normal file
13
test/server/https_ports.cpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
|
||||||
|
#if BEAST_USE_OPENSSL
|
||||||
|
|
||||||
|
// Test that header file is self-contained.
|
||||||
|
#include "../../example/server-framework/https_ports.hpp"
|
||||||
|
|
||||||
|
#endif
|
13
test/server/ssl_certificate.cpp
Normal file
13
test/server/ssl_certificate.cpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
|
||||||
|
#if BEAST_USE_OPENSSL
|
||||||
|
|
||||||
|
// Test that header file is self-contained.
|
||||||
|
#include "../../example/server-framework/ssl_certificate.hpp"
|
||||||
|
|
||||||
|
#endif
|
13
test/server/ssl_stream.cpp
Normal file
13
test/server/ssl_stream.cpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
|
||||||
|
#if BEAST_USE_OPENSSL
|
||||||
|
|
||||||
|
// Test that header file is self-contained.
|
||||||
|
#include "../../example/server-framework/ssl_stream.hpp"
|
||||||
|
|
||||||
|
#endif
|
13
test/server/wss_ports.cpp
Normal file
13
test/server/wss_ports.cpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
|
||||||
|
#if BEAST_USE_OPENSSL
|
||||||
|
|
||||||
|
// Test that header file is self-contained.
|
||||||
|
#include "../../example/server-framework/wss_ports.hpp"
|
||||||
|
|
||||||
|
#endif
|
Reference in New Issue
Block a user