mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 21:07:26 +02:00
Add multi_port to server-framework
This commit is contained in:
@ -11,6 +11,7 @@ Version 61:
|
||||
* Add server-framework SSL HTTP and WebSocket ports
|
||||
* Fix shadowing warnings
|
||||
* Tidy up http-crawl example
|
||||
* Add multi_port to server-framework
|
||||
|
||||
API Changes:
|
||||
|
||||
|
@ -75,10 +75,10 @@
|
||||
[def __static_buffer__ [link beast.ref.beast__static_buffer `static_buffer`]]
|
||||
[def __static_buffer_n__ [link beast.ref.beast__static_buffer_n `static_buffer_n`]]
|
||||
|
||||
[import ../example/doc/core_examples.hpp]
|
||||
[import ../example/doc/http_examples.hpp]
|
||||
[import ../example/echo-op/echo_op.cpp]
|
||||
[import ../example/http-client/http_client.cpp]
|
||||
[import ../example/server-framework/detect_ssl.hpp]
|
||||
[import ../example/server-framework/file_body.hpp]
|
||||
[import ../example/websocket-client/websocket_client.cpp]
|
||||
|
||||
|
@ -107,6 +107,7 @@ This is a complete program and framework of classes implementing
|
||||
a general purpose server that users may copy to use as the basis
|
||||
for writing their own servers. It serves both HTTP and WebSocket.
|
||||
|
||||
* [repo_file example/server-framework/detect_ssl.hpp]
|
||||
* [repo_file example/server-framework/file_body.hpp]
|
||||
* [repo_file example/server-framework/file_service.hpp]
|
||||
* [repo_file example/server-framework/framework.hpp]
|
||||
@ -115,6 +116,7 @@ for writing their own servers. It serves both HTTP and WebSocket.
|
||||
* [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/multi_port.hpp]
|
||||
* [repo_file example/server-framework/rfc7231.hpp]
|
||||
* [repo_file example/server-framework/server.hpp]
|
||||
* [repo_file example/server-framework/service_list.hpp]
|
||||
|
@ -18,23 +18,23 @@ Here is the declaration for a function to detect the SSL client handshake.
|
||||
The input to the function is simply a buffer sequence, no stream. This
|
||||
allows the detection algorithm to be used elsewhere.
|
||||
|
||||
[example_core_detect_tls_1]
|
||||
[example_core_detect_ssl_1]
|
||||
|
||||
The implementation checks the buffer for the presence of the SSL
|
||||
Handshake message octet sequence and returns an apporopriate value:
|
||||
|
||||
[example_core_detect_tls_2]
|
||||
[example_core_detect_ssl_2]
|
||||
|
||||
Now we define a stream operation. We start with the simple,
|
||||
synchronous version which takes the stream and buffer as input:
|
||||
|
||||
[example_core_detect_tls_3]
|
||||
[example_core_detect_ssl_3]
|
||||
|
||||
The synchronous algorithm is the model for building the asynchronous
|
||||
operation which has more boilerplate. First, we declare the asynchronous
|
||||
initiation function:
|
||||
|
||||
[example_core_detect_tls_4]
|
||||
[example_core_detect_ssl_4]
|
||||
|
||||
The implementation of the initiation function is straightforward
|
||||
and contains mostly boilerplate. It is to construct the return
|
||||
@ -43,13 +43,13 @@ then create the composed operation and launch it. The actual
|
||||
code for interacting with the stream is in the composed operation,
|
||||
which is written as a separate class.
|
||||
|
||||
[example_core_detect_tls_5]
|
||||
[example_core_detect_ssl_5]
|
||||
|
||||
Now we will declare our composed operation. There is a considerable
|
||||
amount of necessary boilerplate to get this right, but the result
|
||||
is worth the effort.
|
||||
|
||||
[example_core_detect_tls_6]
|
||||
[example_core_detect_ssl_6]
|
||||
|
||||
The boilerplate is all done, and now we need to implemnt the function
|
||||
call operator that turns this composed operation a completion handler
|
||||
@ -59,6 +59,9 @@ is a transformation of the synchronous version of `detect_ssl` above,
|
||||
but with the inversion of flow that characterizes code written in the
|
||||
callback style:
|
||||
|
||||
[example_core_detect_tls_7]
|
||||
[example_core_detect_ssl_7]
|
||||
|
||||
This SSL detector is used by the server framework in the example
|
||||
directory.
|
||||
|
||||
[endsect]
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
@ -62,7 +62,7 @@ ports created in the example program, and the HTTP services contained by
|
||||
the HTTP ports:
|
||||
|
||||
<img width="880" height = "344" alt = "ServerFramework"
|
||||
src="https://raw.githubusercontent.com/vinniefalco/Beast/server/doc/images/server.png">
|
||||
src="https://raw.githubusercontent.com/vinniefalco/Beast/master/doc/images/server.png">
|
||||
|
||||
## PortHandler Requirements
|
||||
```C++
|
||||
|
@ -5,22 +5,19 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_EXAMPLE_SERVER_DETECT_SSL_HPP
|
||||
#define BEAST_EXAMPLE_SERVER_DETECT_SSL_HPP
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
/* This file contains the functions and classes found in the documentation
|
||||
|
||||
They are compiled and run as part of the unit tests, so you can copy
|
||||
the code and use it in your own projects as a starting point for
|
||||
building a network application.
|
||||
*/
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Example: Detect TLS/SSL
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//[example_core_detect_tls_1
|
||||
//[example_core_detect_ssl_1
|
||||
|
||||
#include <beast.hpp>
|
||||
#include <boost/logic/tribool.hpp>
|
||||
@ -55,7 +52,7 @@ is_ssl_handshake(ConstBufferSequence const& buffers);
|
||||
|
||||
using namespace beast;
|
||||
|
||||
//[example_core_detect_tls_2
|
||||
//[example_core_detect_ssl_2
|
||||
|
||||
template<
|
||||
class ConstBufferSequence>
|
||||
@ -94,7 +91,7 @@ is_ssl_handshake(
|
||||
|
||||
//]
|
||||
|
||||
//[example_core_detect_tls_3
|
||||
//[example_core_detect_ssl_3
|
||||
|
||||
/** Detect a TLS/SSL handshake on a stream.
|
||||
|
||||
@ -176,7 +173,7 @@ detect_ssl(
|
||||
|
||||
//]
|
||||
|
||||
//[example_core_detect_tls_4
|
||||
//[example_core_detect_ssl_4
|
||||
|
||||
/** Detect a TLS/SSL handshake asynchronously on a stream.
|
||||
|
||||
@ -234,7 +231,7 @@ async_detect_ssl(
|
||||
|
||||
//]
|
||||
|
||||
//[example_core_detect_tls_5
|
||||
//[example_core_detect_ssl_5
|
||||
|
||||
// This is the composed operation.
|
||||
template<
|
||||
@ -292,7 +289,7 @@ async_detect_ssl(
|
||||
|
||||
//]
|
||||
|
||||
//[example_core_detect_tls_6
|
||||
//[example_core_detect_ssl_6
|
||||
|
||||
// Read from a stream to invoke is_tls_handshake asynchronously
|
||||
//
|
||||
@ -389,7 +386,7 @@ public:
|
||||
|
||||
//]
|
||||
|
||||
//[example_core_detect_tls_7
|
||||
//[example_core_detect_ssl_7
|
||||
|
||||
// detect_ssl_op is callable with the signature
|
||||
// void(error_code, bytes_transferred),
|
||||
@ -481,4 +478,4 @@ operator()(beast::error_code ec, std::size_t bytes_transferred)
|
||||
|
||||
//]
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
#endif
|
@ -15,7 +15,9 @@
|
||||
#include <beast/http/empty_body.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/string_body.hpp>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace framework {
|
||||
@ -47,8 +49,8 @@ public:
|
||||
*/
|
||||
explicit
|
||||
file_service(
|
||||
boost::filesystem::path const& root,
|
||||
beast::string_view server)
|
||||
boost::filesystem::path const& root,
|
||||
beast::string_view server)
|
||||
: root_(root)
|
||||
, server_(server)
|
||||
{
|
||||
@ -70,10 +72,33 @@ public:
|
||||
ec = {};
|
||||
}
|
||||
|
||||
/** Process a request.
|
||||
/** Try to handle a file request.
|
||||
|
||||
@param stream The stream belonging to the connection.
|
||||
Ownership is not transferred.
|
||||
|
||||
@note This is needed for to meet the requirements for @b Service
|
||||
@param ep The remote endpoint of the connection
|
||||
corresponding to the stream.
|
||||
|
||||
@param req The request message to attempt handling.
|
||||
Ownership is not transferred.
|
||||
|
||||
@param send The function to invoke with the response.
|
||||
The function will have this equivalent signature:
|
||||
|
||||
@code
|
||||
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
send(response<Body, Fields>&&);
|
||||
|
||||
@endcode
|
||||
|
||||
In C++14 this can be expressed using a generic lambda. In
|
||||
C++11 it will require a template member function of an invocable
|
||||
object.
|
||||
|
||||
@return `true` if the request was handled by the service.
|
||||
*/
|
||||
template<
|
||||
class Stream,
|
||||
@ -86,7 +111,7 @@ public:
|
||||
beast::http::request<Body, Fields>&& req,
|
||||
Send const& send) const
|
||||
{
|
||||
// Check the method and take action
|
||||
// Determine our action based on the method
|
||||
switch(req.method())
|
||||
{
|
||||
case beast::http::verb::get:
|
||||
@ -190,7 +215,8 @@ private:
|
||||
//
|
||||
template<class Body, class Fields>
|
||||
beast::http::response<beast::http::string_body>
|
||||
not_found(beast::http::request<Body, Fields> const& req,
|
||||
not_found(
|
||||
beast::http::request<Body, Fields> const& req,
|
||||
boost::filesystem::path const& rel_path) const
|
||||
{
|
||||
beast::http::response<beast::http::string_body> res;
|
||||
@ -207,7 +233,8 @@ private:
|
||||
//
|
||||
template<class Body, class Fields>
|
||||
beast::http::response<file_body>
|
||||
get(beast::http::request<Body, Fields> const& req,
|
||||
get(
|
||||
beast::http::request<Body, Fields> const& req,
|
||||
boost::filesystem::path const& full_path) const
|
||||
{
|
||||
beast::http::response<file_body> res;
|
||||
@ -224,7 +251,8 @@ private:
|
||||
//
|
||||
template<class Body, class Fields>
|
||||
beast::http::response<beast::http::empty_body>
|
||||
head(beast::http::request<Body, Fields> const& req,
|
||||
head(
|
||||
beast::http::request<Body, Fields> const& req,
|
||||
boost::filesystem::path const& full_path) const
|
||||
{
|
||||
beast::http::response<beast::http::empty_body> res;
|
||||
|
@ -31,6 +31,9 @@ namespace framework {
|
||||
//
|
||||
struct queued_http_write
|
||||
{
|
||||
// Destructor must be virtual since we delete a
|
||||
// derived class through a pointer to the base!
|
||||
//
|
||||
virtual ~queued_http_write() = default;
|
||||
|
||||
// When invoked, performs the write operation.
|
||||
@ -49,8 +52,13 @@ template<
|
||||
class Handler>
|
||||
class queued_http_write_impl : public queued_http_write
|
||||
{
|
||||
// The stream to write to
|
||||
Stream& stream_;
|
||||
|
||||
// The message to send, which we acquire by move or copy
|
||||
beast::http::message<isRequest, Body, Fields> msg_;
|
||||
|
||||
// The handler to invoke when the send completes.
|
||||
Handler handler_;
|
||||
|
||||
public:
|
||||
@ -69,7 +77,13 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// Writes the stored message
|
||||
// Writes the stored message.
|
||||
//
|
||||
// The caller must make sure this invocation represents
|
||||
// a continuation of an asynchronous operation which is
|
||||
// already in the right context. For example, already
|
||||
// running on the associated strand.
|
||||
//
|
||||
void
|
||||
invoke() override
|
||||
{
|
||||
@ -120,6 +134,7 @@ make_queued_http_write(
|
||||
template<class Derived, class... Services>
|
||||
class async_http_con_base : public http_base
|
||||
{
|
||||
protected:
|
||||
// This function lets us access members of the derived class
|
||||
Derived&
|
||||
impl()
|
||||
@ -153,7 +168,6 @@ class async_http_con_base : public http_base
|
||||
// Indicates if we have a write active.
|
||||
bool writing_ = false;
|
||||
|
||||
protected:
|
||||
// The strand makes sure that our data is
|
||||
// accessed from only one thread at a time.
|
||||
//
|
||||
@ -172,17 +186,40 @@ public:
|
||||
, services_(services)
|
||||
, id_(id)
|
||||
, ep_(ep)
|
||||
|
||||
// The buffer has a limit of 8192, otherwise
|
||||
// the server is vulnerable to a buffer attack.
|
||||
//
|
||||
, buffer_(8192)
|
||||
|
||||
, strand_(impl().stream().get_io_service())
|
||||
{
|
||||
}
|
||||
|
||||
// Called to start the object after the listener accepts
|
||||
// an incoming connection, when no bytes have been read yet.
|
||||
//
|
||||
void
|
||||
run()
|
||||
{
|
||||
// Just call run with an empty buffer
|
||||
run(boost::asio::null_buffers{});
|
||||
}
|
||||
|
||||
// Called to start the object after the
|
||||
// listener accepts an incoming connection.
|
||||
//
|
||||
template<class ConstBufferSequence>
|
||||
void
|
||||
run(ConstBufferSequence const& buffers)
|
||||
{
|
||||
// Copy the data into the buffer for performing
|
||||
// HTTP reads, so that the bytes get used.
|
||||
//
|
||||
buffer_.commit(boost::asio::buffer_copy(
|
||||
buffer_.prepare(boost::asio::buffer_size(buffers)),
|
||||
buffers));
|
||||
|
||||
// Give the derived class a chance to do stuff
|
||||
//
|
||||
impl().do_handshake();
|
||||
@ -210,7 +247,6 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Perform an asynchronous read for the next request header
|
||||
//
|
||||
void
|
||||
@ -457,25 +493,28 @@ private:
|
||||
template<class... Services>
|
||||
class async_http_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.
|
||||
// Give this object the enable_shared_from_this, and have
|
||||
// the base class call impl().shared_from_this(). The reason
|
||||
// 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_http_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.
|
||||
// The stream should be created before the base class so
|
||||
// use the "base from member" idiom.
|
||||
//
|
||||
, public base_from_member<socket_type>
|
||||
|
||||
// Declare this base last now that everything else got set up first.
|
||||
// Constructs last, destroys first
|
||||
//
|
||||
, public async_http_con_base<async_http_con<Services...>, Services...>
|
||||
{
|
||||
public:
|
||||
// Construct the plain connection.
|
||||
// Constructor
|
||||
//
|
||||
// Additional arguments are forwarded to the base class
|
||||
//
|
||||
template<class... Args>
|
||||
async_http_con(
|
||||
@ -488,8 +527,11 @@ public:
|
||||
}
|
||||
|
||||
// Returns the stream.
|
||||
// The base class calls this to obtain the object to
|
||||
// use for reading and writing HTTP messages.
|
||||
//
|
||||
// The base class calls this to obtain the object to use for
|
||||
// reading and writing HTTP messages. This allows the same base
|
||||
// class to work with different return types for `stream()` such
|
||||
// as a `boost::asio::ip::tcp::socket&` or a `boost::asio::ssl::stream&`
|
||||
//
|
||||
socket_type&
|
||||
stream()
|
||||
@ -597,8 +639,7 @@ public:
|
||||
log_,
|
||||
services_,
|
||||
instance_.next_id(),
|
||||
ep
|
||||
)->run();
|
||||
ep)->run();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -328,22 +328,28 @@ private:
|
||||
template<class... Services>
|
||||
class sync_http_con
|
||||
|
||||
// Note that we give this object the `enable_shared_from_this`, and have
|
||||
// the base class call `impl().shared_from_this()` when needed.
|
||||
// Give this object the enable_shared_from_this, and have
|
||||
// the base class call impl().shared_from_this(). The reason
|
||||
// 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_http_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.
|
||||
// The stream should be created before the base class so
|
||||
// use the "base from member" idiom.
|
||||
//
|
||||
, public base_from_member<socket_type>
|
||||
|
||||
// Declare this base last now that everything else got set up first.
|
||||
// Constructs last, destroys first
|
||||
//
|
||||
, public sync_http_con_base<sync_http_con<Services...>, Services...>
|
||||
{
|
||||
public:
|
||||
// Construct the plain connection.
|
||||
// Constructor
|
||||
//
|
||||
// Additional arguments are forwarded to the base class
|
||||
//
|
||||
template<class... Args>
|
||||
sync_http_con(
|
||||
@ -357,8 +363,10 @@ public:
|
||||
|
||||
// Returns the stream.
|
||||
//
|
||||
// The base class calls this to obtain the object to
|
||||
// use for reading and writing HTTP messages.
|
||||
// The base class calls this to obtain the object to use for
|
||||
// reading and writing HTTP messages. This allows the same base
|
||||
// class to work with different return types for `stream()` such
|
||||
// as a `boost::asio::ip::tcp::socket&` or a `boost::asio::ssl::stream&`
|
||||
//
|
||||
socket_type&
|
||||
stream()
|
||||
@ -458,8 +466,7 @@ public:
|
||||
log_,
|
||||
services_,
|
||||
instance_.next_id(),
|
||||
ep
|
||||
)->run();
|
||||
ep)->run();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -24,25 +24,28 @@ namespace framework {
|
||||
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.
|
||||
// Give this object the enable_shared_from_this, and have
|
||||
// the base class call impl().shared_from_this(). The reason
|
||||
// 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.
|
||||
// The stream should be created before the base class so
|
||||
// use the "base from member" idiom.
|
||||
//
|
||||
, public base_from_member<ssl_stream<socket_type>>
|
||||
|
||||
// Declare this base last now that everything else got set up first.
|
||||
// Constructs last, destroys first
|
||||
//
|
||||
, public sync_http_con_base<sync_https_con<Services...>, Services...>
|
||||
{
|
||||
public:
|
||||
// Construct the plain connection.
|
||||
// Constructor
|
||||
//
|
||||
// Additional arguments are forwarded to the base class
|
||||
//
|
||||
template<class... Args>
|
||||
sync_https_con(
|
||||
@ -56,8 +59,11 @@ public:
|
||||
}
|
||||
|
||||
// Returns the stream.
|
||||
// The base class calls this to obtain the object to
|
||||
// use for reading and writing HTTP messages.
|
||||
//
|
||||
// The base class calls this to obtain the object to use for
|
||||
// reading and writing HTTP messages. This allows the same base
|
||||
// class to work with different return types for `stream()` such
|
||||
// as a `boost::asio::ip::tcp::socket&` or a `boost::asio::ssl::stream&`
|
||||
//
|
||||
ssl_stream<socket_type>&
|
||||
stream()
|
||||
@ -99,25 +105,28 @@ private:
|
||||
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.
|
||||
// Give this object the enable_shared_from_this, and have
|
||||
// the base class call impl().shared_from_this(). The reason
|
||||
// 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.
|
||||
// The stream should be created before the base class so
|
||||
// use the "base from member" idiom.
|
||||
//
|
||||
, public base_from_member<ssl_stream<socket_type>>
|
||||
|
||||
// Declare this base last now that everything else got set up first.
|
||||
// Constructs last, destroys first
|
||||
//
|
||||
, public async_http_con_base<async_https_con<Services...>, Services...>
|
||||
{
|
||||
public:
|
||||
// Construct the plain connection.
|
||||
// Constructor
|
||||
//
|
||||
// Additional arguments are forwarded to the base class
|
||||
//
|
||||
template<class... Args>
|
||||
async_https_con(
|
||||
@ -131,8 +140,11 @@ public:
|
||||
}
|
||||
|
||||
// Returns the stream.
|
||||
// The base class calls this to obtain the object to
|
||||
// use for reading and writing HTTP messages.
|
||||
//
|
||||
// The base class calls this to obtain the object to use for
|
||||
// reading and writing HTTP messages. This allows the same base
|
||||
// class to work with different return types for `stream()` such
|
||||
// as a `boost::asio::ip::tcp::socket&` or a `boost::asio::ssl::stream&`
|
||||
//
|
||||
ssl_stream<socket_type>&
|
||||
stream()
|
||||
@ -140,6 +152,37 @@ public:
|
||||
return this->member;
|
||||
}
|
||||
|
||||
// Called by the multi-port after reading some
|
||||
// bytes from the stream and detecting SSL.
|
||||
//
|
||||
template<class ConstBufferSequence>
|
||||
void
|
||||
handshake(ConstBufferSequence const& buffers)
|
||||
{
|
||||
// Copy the caller's bytes into the buffer we
|
||||
// use for reading HTTP messages, otherwise
|
||||
// the memory pointed to by buffers will go out
|
||||
// of scope.
|
||||
//
|
||||
this->buffer_.commit(
|
||||
boost::asio::buffer_copy(
|
||||
this->buffer_.prepare(boost::asio::buffer_size(buffers)),
|
||||
buffers));
|
||||
|
||||
// Perform SSL handshake. We use the "buffered"
|
||||
// overload which lets us pass those extra bytes.
|
||||
//
|
||||
stream().async_handshake(
|
||||
boost::asio::ssl::stream_base::server,
|
||||
buffers,
|
||||
this->strand_.wrap(
|
||||
std::bind(
|
||||
&async_https_con::on_buffered_handshake,
|
||||
this->shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
private:
|
||||
friend class async_http_con_base<async_https_con<Services...>, Services...>;
|
||||
|
||||
@ -152,10 +195,11 @@ private:
|
||||
//
|
||||
stream().async_handshake(
|
||||
boost::asio::ssl::stream_base::server,
|
||||
this->strand_.wrap(std::bind(
|
||||
this->strand_.wrap(
|
||||
std::bind(
|
||||
&async_https_con::on_handshake,
|
||||
this->shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
this->shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
// Called when the SSL handshake completes
|
||||
@ -169,6 +213,20 @@ private:
|
||||
this->do_run();
|
||||
}
|
||||
|
||||
// Called when the buffered SSL handshake completes
|
||||
void
|
||||
on_buffered_handshake(error_code ec, std::size_t bytes_transferred)
|
||||
{
|
||||
if(ec)
|
||||
return this->fail("on_handshake", ec);
|
||||
|
||||
// Consume what was read but leave the rest
|
||||
this->buffer_.consume(bytes_transferred);
|
||||
|
||||
// No error so run the main loop
|
||||
this->do_run();
|
||||
}
|
||||
|
||||
// Called when the end of stream is reached
|
||||
void
|
||||
do_shutdown()
|
||||
@ -176,10 +234,11 @@ private:
|
||||
// This is an SSL shutdown
|
||||
//
|
||||
stream().async_shutdown(
|
||||
this->strand_.wrap(std::bind(
|
||||
&async_https_con::on_shutdown,
|
||||
this->strand_.wrap(
|
||||
std::bind(
|
||||
&async_https_con::on_shutdown,
|
||||
this->shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
// Called when the SSL shutdown completes
|
||||
@ -273,8 +332,7 @@ public:
|
||||
log_,
|
||||
services_,
|
||||
instance_.next_id(),
|
||||
ep
|
||||
)->run();
|
||||
ep)->run();
|
||||
}
|
||||
};
|
||||
|
||||
@ -348,7 +406,7 @@ public:
|
||||
void
|
||||
on_accept(socket_type&& sock, endpoint_type ep)
|
||||
{
|
||||
// Create an HTTPS connection object
|
||||
// Create an SSL connection object
|
||||
// and transfer ownership of the socket.
|
||||
//
|
||||
std::make_shared<async_https_con<Services...>>(
|
||||
@ -358,8 +416,7 @@ public:
|
||||
log_,
|
||||
services_,
|
||||
instance_.next_id(),
|
||||
ep
|
||||
)->run();
|
||||
ep)->run();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#if BEAST_USE_OPENSSL
|
||||
#include "https_ports.hpp"
|
||||
#include "multi_port.hpp"
|
||||
#include "wss_ports.hpp"
|
||||
#include "ssl_certificate.hpp"
|
||||
#endif
|
||||
@ -79,11 +80,11 @@ main(
|
||||
int ac,
|
||||
char const* av[])
|
||||
{
|
||||
// Helper for reporting failures
|
||||
//
|
||||
using namespace framework;
|
||||
using namespace beast::http;
|
||||
|
||||
// Helper for reporting failures
|
||||
//
|
||||
auto const fail =
|
||||
[&](
|
||||
std::string const& what,
|
||||
@ -141,17 +142,75 @@ main(
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Asynchronous WebSocket HTTP
|
||||
// Synchronous WebSocket HTTP
|
||||
//
|
||||
// port port + 1
|
||||
// port + 0 port + 1
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
{
|
||||
// Install an asynchronous WebSocket echo port handler
|
||||
// Create a WebSocket port
|
||||
//
|
||||
auto wsp = instance.make_port<ws_sync_port>(
|
||||
ec,
|
||||
endpoint_type{addr,static_cast<unsigned short>(port + 0)},
|
||||
instance,
|
||||
std::cout,
|
||||
set_ws_options{pmd});
|
||||
|
||||
if(ec)
|
||||
return fail("ws_sync_port", ec);
|
||||
|
||||
// Create an HTTP port
|
||||
//
|
||||
auto sp = instance.make_port<http_sync_port<
|
||||
ws_upgrade_service<ws_sync_port>,
|
||||
file_service
|
||||
>>(
|
||||
ec,
|
||||
endpoint_type{addr,static_cast<unsigned short>(port + 1)},
|
||||
instance,
|
||||
std::cout);
|
||||
|
||||
if(ec)
|
||||
return fail("http_sync_port", ec);
|
||||
|
||||
// Init the ws_upgrade_service to
|
||||
// forward upgrades to the WebSocket port.
|
||||
//
|
||||
sp->template init<0>(
|
||||
ec,
|
||||
*wsp // The WebSocket port handler
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("http_sync_port/ws_upgrade_service", ec);
|
||||
|
||||
// Init the file_service to point to the root path.
|
||||
//
|
||||
sp->template init<1>(
|
||||
ec,
|
||||
root, // The root path
|
||||
"http_sync_port" // The value for the Server field
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("http_sync_port/file_service", ec);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Asynchronous WebSocket HTTP
|
||||
//
|
||||
// port + 2 port + 3
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
{
|
||||
// Create a WebSocket port
|
||||
//
|
||||
auto wsp = instance.make_port<ws_async_port>(
|
||||
ec,
|
||||
endpoint_type{addr, port},
|
||||
endpoint_type{addr,
|
||||
static_cast<unsigned short>(port + 2)},
|
||||
instance,
|
||||
std::cout,
|
||||
set_ws_options{pmd}
|
||||
@ -160,106 +219,47 @@ main(
|
||||
if(ec)
|
||||
return fail("ws_async_port", ec);
|
||||
|
||||
// Install an asynchronous HTTP port handler
|
||||
// Create an HTTP port
|
||||
//
|
||||
auto sp = instance.make_port<http_async_port<
|
||||
ws_upgrade_service<ws_async_port>,
|
||||
file_service
|
||||
>>(
|
||||
ec,
|
||||
endpoint_type{addr,
|
||||
static_cast<unsigned short>(port + 1)},
|
||||
instance,
|
||||
std::cout);
|
||||
|
||||
if(ec)
|
||||
return fail("http_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("http_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
|
||||
"http_async_port" // The value for the Server field
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("http_async_port/file_service", ec);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Synchronous WebSocket HTTP
|
||||
//
|
||||
// port + 2 port + 3
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
{
|
||||
// Install a synchronous WebSocket echo port handler
|
||||
//
|
||||
auto wsp = instance.make_port<ws_sync_port>(
|
||||
ec,
|
||||
endpoint_type{addr,
|
||||
static_cast<unsigned short>(port + 2)},
|
||||
instance,
|
||||
std::cout,
|
||||
set_ws_options{pmd});
|
||||
|
||||
if(ec)
|
||||
return fail("ws_sync_port", ec);
|
||||
|
||||
|
||||
// Install a synchronous HTTP port handler
|
||||
//
|
||||
auto sp = instance.make_port<http_sync_port<
|
||||
ws_upgrade_service<ws_sync_port>,
|
||||
file_service
|
||||
>>(
|
||||
ec,
|
||||
endpoint_type{addr,
|
||||
static_cast<unsigned short>(port + 3)},
|
||||
instance,
|
||||
std::cout);
|
||||
|
||||
if(ec)
|
||||
return fail("http_sync_port", ec);
|
||||
return fail("http_async_port", ec);
|
||||
|
||||
// Set up the ws_upgrade_service. We will route upgrade
|
||||
// requests to the websocket port handler created earlier.
|
||||
// Init the ws_upgrade_service to
|
||||
// forward upgrades to the WebSocket port.
|
||||
//
|
||||
sp->template init<0>(
|
||||
ec,
|
||||
wsp
|
||||
*wsp // The websocket port handler
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("http_sync_port/ws_upgrade_service", ec);
|
||||
return fail("http_async_port/ws_upgrade_service", ec);
|
||||
|
||||
// Set up the file_service to point to the root path.
|
||||
// Init the file_service to point to the root path.
|
||||
//
|
||||
sp->template init<1>(
|
||||
ec,
|
||||
root,
|
||||
"http_sync_port"
|
||||
root, // The root path
|
||||
"http_async_port" // The value for the Server field
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("http_sync_port/file_service", ec);
|
||||
return fail("http_async_port/file_service", ec);
|
||||
}
|
||||
|
||||
//
|
||||
// If OpenSSL is available then install some SSL-enabled ports
|
||||
// The next section supports encrypted connections and requires
|
||||
// an installed and configured OpenSSL as part of the build.
|
||||
//
|
||||
|
||||
#if BEAST_USE_OPENSSL
|
||||
@ -268,31 +268,30 @@ main(
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Asynchronous Secure WebSocket HTTPS
|
||||
// Synchronous Secure WebSocket HTTPS
|
||||
//
|
||||
// port + 4 port + 5
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
{
|
||||
// Install an asynchronous Secure WebSocket echo port handler
|
||||
// Create a WebSocket port
|
||||
//
|
||||
auto wsp = instance.make_port<wss_async_port>(
|
||||
auto wsp = instance.make_port<wss_sync_port>(
|
||||
ec,
|
||||
endpoint_type{addr,
|
||||
static_cast<unsigned short>(port + 4)},
|
||||
instance,
|
||||
std::cout,
|
||||
cert.get(),
|
||||
set_ws_options{pmd}
|
||||
);
|
||||
set_ws_options{pmd});
|
||||
|
||||
if(ec)
|
||||
return fail("ws_async_port", ec);
|
||||
return fail("wss_sync_port", ec);
|
||||
|
||||
// Install an asynchronous HTTPS port handler
|
||||
// Create an HTTP port
|
||||
//
|
||||
auto sp = instance.make_port<https_async_port<
|
||||
ws_upgrade_service<wss_async_port>,
|
||||
auto sp = instance.make_port<https_sync_port<
|
||||
ws_upgrade_service<wss_sync_port>,
|
||||
file_service
|
||||
>>(
|
||||
ec,
|
||||
@ -303,20 +302,82 @@ main(
|
||||
cert.get());
|
||||
|
||||
if(ec)
|
||||
return fail("https_async_port", 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.
|
||||
// Init the ws_upgrade_service to
|
||||
// forward upgrades to the WebSocket port.
|
||||
//
|
||||
sp->template init<0>(
|
||||
ec,
|
||||
wsp // The websocket port handler
|
||||
*wsp // The websocket port handler
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("http_sync_port/ws_upgrade_service", ec);
|
||||
|
||||
// Init the file_service to point to the root path.
|
||||
//
|
||||
sp->template init<1>(
|
||||
ec,
|
||||
root, // The root path
|
||||
"http_sync_port" // The value for the Server field
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("https_sync_port/file_service", ec);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Asynchronous Secure WebSocket HTTPS
|
||||
//
|
||||
// port + 6 port + 7
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
{
|
||||
// Create a WebSocket port
|
||||
//
|
||||
auto wsp = instance.make_port<wss_async_port>(
|
||||
ec,
|
||||
endpoint_type{addr,
|
||||
static_cast<unsigned short>(port + 6)},
|
||||
instance,
|
||||
std::cout,
|
||||
cert.get(),
|
||||
set_ws_options{pmd}
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("ws_async_port", ec);
|
||||
|
||||
// Create an HTTP port
|
||||
//
|
||||
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 + 7)},
|
||||
instance,
|
||||
std::cout,
|
||||
cert.get());
|
||||
|
||||
if(ec)
|
||||
return fail("https_async_port", ec);
|
||||
|
||||
// Init the ws_upgrade_service to
|
||||
// forward upgrades to the WebSocket port.
|
||||
//
|
||||
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.
|
||||
// Init the file_service to point to the root path.
|
||||
//
|
||||
sp->template init<1>(
|
||||
ec,
|
||||
@ -330,63 +391,53 @@ main(
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Synchronous Secure WebSocket HTTPS
|
||||
// Multi-Port HTTP, WebSockets,
|
||||
// HTTPS Secure WebSockets
|
||||
//
|
||||
// port + 6 port + 7
|
||||
// Asynchronous, all on the same port!
|
||||
//
|
||||
// port + 8
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
{
|
||||
// Install a synchronous Secure WebSocket echo port handler
|
||||
// Create a multi_port
|
||||
//
|
||||
auto wsp = instance.make_port<wss_sync_port>(
|
||||
auto sp = instance.make_port<multi_port<
|
||||
ws_upgrade_service<multi_port_base>,
|
||||
file_service
|
||||
>>(
|
||||
ec,
|
||||
endpoint_type{addr,
|
||||
static_cast<unsigned short>(port + 6)},
|
||||
static_cast<unsigned short>(port + 8)},
|
||||
instance,
|
||||
std::cout,
|
||||
cert.get(),
|
||||
set_ws_options{pmd});
|
||||
|
||||
if(ec)
|
||||
return fail("wss_sync_port", ec);
|
||||
return fail("multi_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.
|
||||
// Init the ws_upgrade_service to forward requests to the multi_port.
|
||||
//
|
||||
sp->template init<0>(
|
||||
ec,
|
||||
wsp // The websocket port handler
|
||||
*sp // The websocket port handler
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("http_sync_port/ws_upgrade_service", ec);
|
||||
return fail("multi_port/ws_upgrade_service", ec);
|
||||
|
||||
// Set up the file_service to point to the root path.
|
||||
// Init the ws_upgrade_service to
|
||||
// forward upgrades to the Multi port.
|
||||
//
|
||||
sp->template init<1>(
|
||||
ec,
|
||||
root,
|
||||
"https_sync_port"
|
||||
root, // The root path
|
||||
"multi_port" // The value for the Server field
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("https_sync_port/file_service", ec);
|
||||
return fail("multi_port/file_service", ec);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
398
example/server-framework/multi_port.hpp
Normal file
398
example/server-framework/multi_port.hpp
Normal file
@ -0,0 +1,398 @@
|
||||
//
|
||||
// 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_MULTI_PORT_HPP
|
||||
#define BEAST_EXAMPLE_SERVER_MULTI_PORT_HPP
|
||||
|
||||
#include "detect_ssl.hpp"
|
||||
#include "ws_async_port.hpp"
|
||||
#include "http_async_port.hpp"
|
||||
#include "https_ports.hpp"
|
||||
#include "wss_ports.hpp"
|
||||
|
||||
#include <beast/core.hpp>
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
namespace framework {
|
||||
|
||||
// A connection that detects an opening SSL handshake
|
||||
//
|
||||
// If the SSL handshake is detected, then an HTTPS connection object
|
||||
// is move constructed from this object. Otherwise, this object continues
|
||||
// as a normal unencrypted HTTP connection. If the underlying port has
|
||||
// the ws_upgrade_service configured, the connection may be optionally
|
||||
// be upgraded to WebSocket by the client.
|
||||
//
|
||||
template<class... Services>
|
||||
class multi_con
|
||||
|
||||
// Give this object the enable_shared_from_this, and have
|
||||
// the base class call impl().shared_from_this(). The reason
|
||||
// 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<multi_con<Services...>>
|
||||
|
||||
// The stream should be created before the base class so
|
||||
// use the "base from member" idiom.
|
||||
//
|
||||
, public base_from_member<socket_type>
|
||||
|
||||
// Constructs last, destroys first
|
||||
//
|
||||
, public async_http_con_base<multi_con<Services...>, Services...>
|
||||
{
|
||||
// Context to use if we get an SSL handshake
|
||||
boost::asio::ssl::context& ctx_;
|
||||
|
||||
// Holds the data we read during ssl detection
|
||||
beast::static_buffer_n<6> buffer_;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
//
|
||||
// Additional arguments are simply forwarded to the base class
|
||||
//
|
||||
template<class... Args>
|
||||
multi_con(
|
||||
socket_type&& sock,
|
||||
boost::asio::ssl::context& ctx,
|
||||
Args&&... args)
|
||||
: base_from_member<socket_type>(std::move(sock))
|
||||
, async_http_con_base<multi_con<Services...>, Services...>(std::forward<Args>(args)...)
|
||||
, ctx_(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
// Returns the stream.
|
||||
//
|
||||
// The base class calls this to obtain the object to use for
|
||||
// reading and writing HTTP messages. This allows the same base
|
||||
// class to work with different return types for `stream()` such
|
||||
// as a `boost::asio::ip::tcp::socket&` or a `boost::asio::ssl::stream&`
|
||||
//
|
||||
socket_type&
|
||||
stream()
|
||||
{
|
||||
return this->member;
|
||||
}
|
||||
|
||||
// Called by the port to launch the connection in detect mode
|
||||
void
|
||||
detect()
|
||||
{
|
||||
// The detect function operates asynchronously by reading
|
||||
// in some data from the stream to figure out if its an SSL
|
||||
// handshake. When it completes, it informs us of the result
|
||||
// and also stores the bytes it read in the buffer.
|
||||
//
|
||||
async_detect_ssl(
|
||||
stream(),
|
||||
buffer_,
|
||||
this->strand_.wrap(
|
||||
std::bind(
|
||||
&multi_con::on_detect,
|
||||
this->shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
private:
|
||||
// Base class needs to be a friend to call our private members
|
||||
friend class async_http_con_base<multi_con<Services...>, Services...>;
|
||||
|
||||
// Called when the handshake detection is complete
|
||||
//
|
||||
void
|
||||
on_detect(
|
||||
error_code ec,
|
||||
boost::tribool result)
|
||||
{
|
||||
// Report failures if any
|
||||
if(ec)
|
||||
return this->fail("on_detect", ec);
|
||||
|
||||
// Was an SSL handshake detected?
|
||||
if(result)
|
||||
{
|
||||
// Yes, get the remote endpoint since it is
|
||||
// needed to construct the new connection.
|
||||
//
|
||||
endpoint_type ep = stream().remote_endpoint(ec);
|
||||
if(ec)
|
||||
return this->fail("remote_endpoint", ec);
|
||||
|
||||
// Now launch our new connection object
|
||||
//
|
||||
std::make_shared<async_https_con<Services...>>(
|
||||
std::move(stream()),
|
||||
ctx_,
|
||||
"multi_port",
|
||||
this->log_,
|
||||
this->services_,
|
||||
this->id_,
|
||||
ep
|
||||
)->handshake(buffer_.data());
|
||||
|
||||
// When we return the last shared pointer to this
|
||||
// object will go away and `*this` will be destroyed.
|
||||
//
|
||||
return;
|
||||
}
|
||||
|
||||
// No SSL handshake, so start the HTTP connection normally.
|
||||
//
|
||||
// Since we read some bytes from the connection that might
|
||||
// contain an HTTP request, we pass the buffer holding those
|
||||
// bytes to the base class so it can use them.
|
||||
//
|
||||
this->run(buffer_.data());
|
||||
}
|
||||
|
||||
// This is called by the base before running the main loop.
|
||||
//
|
||||
void
|
||||
do_handshake()
|
||||
{
|
||||
// Just run the main loop right away.
|
||||
//
|
||||
this->do_run();
|
||||
}
|
||||
|
||||
// This is called when the other end closes the connection gracefully.
|
||||
//
|
||||
void
|
||||
do_shutdown()
|
||||
{
|
||||
// Attempt a clean TCP/IP shutdown
|
||||
//
|
||||
error_code ec;
|
||||
stream().shutdown(
|
||||
socket_type::shutdown_both,
|
||||
ec);
|
||||
|
||||
// Report failure if any
|
||||
//
|
||||
if(ec)
|
||||
return this->fail("shutdown", ec);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/* An asynchronous HTTP and WebSocket port handler, plain or SSL
|
||||
|
||||
This type meets the requirements of @b PortHandler. It supports a
|
||||
variable list of HTTP services in its template parameter list,
|
||||
and provides a synchronous connection implementation to service.
|
||||
|
||||
The port will automatically detect OpenSSL handshakes and establish
|
||||
encrypted connections, otherwise will use a plain unencrypted
|
||||
connection. This all happens through the same port.
|
||||
|
||||
In addition this port can process WebSocket upgrade requests by
|
||||
launching them as a new asynchronous WebSocket connection using
|
||||
either plain or OpenSSL transport.
|
||||
|
||||
This class is split up into two parts, the multi_port_base,
|
||||
and the multi_port, to avoid a recursive type reference when
|
||||
we name the type of the ws_upgrade_service.
|
||||
*/
|
||||
class multi_port_base
|
||||
{
|
||||
protected:
|
||||
// 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>>&)>;
|
||||
|
||||
// Reference to the server instance that made us
|
||||
server& instance_;
|
||||
|
||||
// The stream to log to
|
||||
std::ostream& log_;
|
||||
|
||||
// The context holds the SSL certificates the server uses
|
||||
boost::asio::ssl::context& ctx_;
|
||||
|
||||
// Called for each new websocket stream
|
||||
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>
|
||||
multi_port_base(
|
||||
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 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
|
||||
on_upgrade(
|
||||
socket_type&& sock,
|
||||
endpoint_type ep,
|
||||
beast::http::request<Body, Fields>&& req)
|
||||
{
|
||||
// Create the connection and call the version of
|
||||
// run that takes the request since we have it already
|
||||
//
|
||||
std::make_shared<async_ws_con>(
|
||||
std::move(sock),
|
||||
"multi_port",
|
||||
log_,
|
||||
instance_.next_id(),
|
||||
ep,
|
||||
cb1_
|
||||
)->run(std::move(req));
|
||||
}
|
||||
|
||||
/** 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
|
||||
on_upgrade(
|
||||
ssl_stream<socket_type>&& stream,
|
||||
endpoint_type ep,
|
||||
beast::http::request<Body, Fields>&& req)
|
||||
{
|
||||
std::make_shared<async_wss_con>(
|
||||
std::move(stream),
|
||||
"multi_port",
|
||||
log_,
|
||||
instance_.next_id(),
|
||||
ep,
|
||||
cb2_
|
||||
)->run(std::move(req));
|
||||
}
|
||||
};
|
||||
|
||||
/* An asynchronous HTTP and WebSocket port handler, plain or SSL
|
||||
|
||||
This class is the other half of multi_port_base. It gets the
|
||||
Services... variadic type list and owns the service list.
|
||||
*/
|
||||
template<class... Services>
|
||||
class multi_port : public multi_port_base
|
||||
{
|
||||
// The list of services connections created from this port will support
|
||||
service_list<Services...> services_;
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
|
||||
All arguments are forwarded to the multi_port_base constructor.
|
||||
*/
|
||||
template<class... Args>
|
||||
multi_port(Args&&... args)
|
||||
: multi_port_base(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
/** 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 a plain http connection object by transferring
|
||||
// ownership of the socket, then launch it to perform
|
||||
// the SSL handshake detection.
|
||||
//
|
||||
std::make_shared<multi_con<Services...>>(
|
||||
std::move(sock),
|
||||
ctx_,
|
||||
"multi_port",
|
||||
log_,
|
||||
services_,
|
||||
instance_.next_id(),
|
||||
ep
|
||||
)->detect();
|
||||
}
|
||||
};
|
||||
|
||||
} // framework
|
||||
|
||||
#endif
|
@ -90,7 +90,7 @@ public:
|
||||
to the stream.
|
||||
|
||||
@param req The request message to attempt handling. A service
|
||||
which handles the request may optionally take ownershop of the
|
||||
which handles the request may optionally take ownership of the
|
||||
message.
|
||||
|
||||
@param send The function to invoke with the response. The function
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#include <beast/core/multi_buffer.hpp>
|
||||
#include <beast/websocket/stream.hpp>
|
||||
#include <functional>
|
||||
#include <boost/function.hpp>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
|
||||
@ -212,22 +212,28 @@ private:
|
||||
//
|
||||
class async_ws_con
|
||||
|
||||
// Note that we give this object the `enable_shared_from_this`, and have
|
||||
// the base class call `impl().shared_from_this()` when needed.
|
||||
// Give this object the enable_shared_from_this, and have
|
||||
// the base class call impl().shared_from_this(). The reason
|
||||
// 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_ws_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.
|
||||
// The stream should be created before the base class so
|
||||
// use the "base from member" idiom.
|
||||
//
|
||||
, public base_from_member<beast::websocket::stream<socket_type>>
|
||||
|
||||
// Declare this base last now that everything else got set up first.
|
||||
// Constructs last, destroys first
|
||||
//
|
||||
, public async_ws_con_base<async_ws_con>
|
||||
{
|
||||
public:
|
||||
// Construct the plain connection.
|
||||
// Constructor
|
||||
//
|
||||
// Additional arguments are forwarded to the base class
|
||||
//
|
||||
template<class... Args>
|
||||
explicit
|
||||
@ -241,7 +247,10 @@ public:
|
||||
|
||||
// Returns the stream.
|
||||
//
|
||||
// The base class calls this to obtain the websocket stream object.
|
||||
// The base class calls this to obtain the object to use for
|
||||
// reading and writing HTTP messages. This allows the same base
|
||||
// class to work with different return types for `stream()` such
|
||||
// as a `boost::asio::ip::tcp::socket&` or a `boost::asio::ssl::stream&`
|
||||
//
|
||||
beast::websocket::stream<socket_type>&
|
||||
stream()
|
||||
@ -270,9 +279,10 @@ private:
|
||||
*/
|
||||
class ws_async_port
|
||||
{
|
||||
// The type of the on_stream callback
|
||||
using on_new_stream_cb = std::function<
|
||||
void(beast::websocket::stream<socket_type>&)>;
|
||||
// The type of the on_new_stream callback
|
||||
//
|
||||
using on_new_stream_cb =
|
||||
boost::function<void(beast::websocket::stream<socket_type>&)>;
|
||||
|
||||
server& instance_;
|
||||
std::ostream& log_;
|
||||
@ -328,8 +338,7 @@ public:
|
||||
log_,
|
||||
instance_.next_id(),
|
||||
ep,
|
||||
cb_
|
||||
)->run();
|
||||
cb_)->run();
|
||||
}
|
||||
|
||||
/** Accept a WebSocket upgrade request.
|
||||
@ -345,7 +354,7 @@ public:
|
||||
*/
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
accept(
|
||||
on_upgrade(
|
||||
socket_type&& sock,
|
||||
endpoint_type ep,
|
||||
beast::http::request<Body, Fields>&& req)
|
||||
@ -356,8 +365,7 @@ public:
|
||||
log_,
|
||||
instance_.next_id(),
|
||||
ep,
|
||||
cb_
|
||||
)->run(std::move(req));
|
||||
cb_)->run(std::move(req));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#include <beast/core/multi_buffer.hpp>
|
||||
#include <beast/websocket.hpp>
|
||||
#include <functional>
|
||||
#include <boost/function.hpp>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <thread>
|
||||
@ -21,8 +21,8 @@ namespace framework {
|
||||
|
||||
/** A synchronous WebSocket connection.
|
||||
|
||||
This base class implements a WebSocket connection object
|
||||
using synchronous calls.
|
||||
This base class implements a WebSocket connection object using
|
||||
synchronous calls over an unencrypted connection.
|
||||
|
||||
It uses the Curiously Recurring Template pattern (CRTP) where
|
||||
we refer to the derived class in order to access the stream object
|
||||
@ -55,6 +55,9 @@ class sync_ws_con_base
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
//
|
||||
// Additional arguments are forwarded to the base class
|
||||
//
|
||||
template<class Callback>
|
||||
sync_ws_con_base(
|
||||
beast::string_view server_name,
|
||||
@ -261,17 +264,21 @@ private:
|
||||
//
|
||||
class sync_ws_con
|
||||
|
||||
// Note that we give this object the `enable_shared_from_this`, and have
|
||||
// the base class call `impl().shared_from_this()` when needed.
|
||||
// Give this object the enable_shared_from_this, and have
|
||||
// the base class call impl().shared_from_this(). The reason
|
||||
// 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_ws_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.
|
||||
// The stream should be created before the base class so
|
||||
// use the "base from member" idiom.
|
||||
//
|
||||
, public base_from_member<beast::websocket::stream<socket_type>>
|
||||
|
||||
// Declare this base last now that everything else got set up first.
|
||||
// Constructs last, destroys first
|
||||
//
|
||||
, public sync_ws_con_base<sync_ws_con>
|
||||
{
|
||||
@ -290,7 +297,10 @@ public:
|
||||
|
||||
// Returns the stream.
|
||||
//
|
||||
// The base class calls this to obtain the websocket stream object.
|
||||
// The base class calls this to obtain the object to use for
|
||||
// reading and writing HTTP messages. This allows the same base
|
||||
// class to work with different return types for `stream()` such
|
||||
// as a `boost::asio::ip::tcp::socket&` or a `boost::asio::ssl::stream&`
|
||||
//
|
||||
beast::websocket::stream<socket_type>&
|
||||
stream()
|
||||
@ -324,9 +334,10 @@ private:
|
||||
*/
|
||||
class ws_sync_port
|
||||
{
|
||||
// The type of the on_stream callback
|
||||
using on_new_stream_cb = std::function<
|
||||
void(beast::websocket::stream<socket_type>&)>;
|
||||
// The type of the on_new_stream callback
|
||||
//
|
||||
using on_new_stream_cb =
|
||||
boost::function<void(beast::websocket::stream<socket_type>&)>;
|
||||
|
||||
server& instance_;
|
||||
std::ostream& log_;
|
||||
@ -382,8 +393,7 @@ public:
|
||||
log_,
|
||||
instance_.next_id(),
|
||||
ep,
|
||||
cb_
|
||||
)->run();
|
||||
cb_)->run();
|
||||
}
|
||||
|
||||
/** Accept a WebSocket upgrade request.
|
||||
@ -399,13 +409,13 @@ public:
|
||||
*/
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
accept(
|
||||
on_upgrade(
|
||||
socket_type&& sock,
|
||||
endpoint_type ep,
|
||||
beast::http::request<Body, Fields>&& req)
|
||||
{
|
||||
// Create the connection object and run it,
|
||||
// transferring ownershop of the ugprade request.
|
||||
// transferring ownership of the ugprade request.
|
||||
//
|
||||
std::make_shared<sync_ws_con>(
|
||||
std::move(sock),
|
||||
@ -413,8 +423,7 @@ public:
|
||||
log_,
|
||||
instance_.next_id(),
|
||||
ep,
|
||||
cb_
|
||||
)->run(std::move(req));
|
||||
cb_)->run(std::move(req));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -25,7 +25,7 @@ namespace framework {
|
||||
template<class PortHandler>
|
||||
class ws_upgrade_service
|
||||
{
|
||||
std::shared_ptr<PortHandler> handler_;
|
||||
PortHandler& handler_;
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
@ -34,9 +34,8 @@ public:
|
||||
handle WebSocket upgrade requests.
|
||||
*/
|
||||
explicit
|
||||
ws_upgrade_service(
|
||||
std::shared_ptr<PortHandler> handler)
|
||||
: handler_(std::move(handler))
|
||||
ws_upgrade_service(PortHandler& handler)
|
||||
: handler_(handler)
|
||||
{
|
||||
}
|
||||
|
||||
@ -86,7 +85,7 @@ public:
|
||||
// Its an ugprade request, so transfer ownership
|
||||
// of the stream and request to the port handler.
|
||||
//
|
||||
handler_->accept(
|
||||
handler_.on_upgrade(
|
||||
std::move(stream),
|
||||
ep,
|
||||
std::move(req));
|
||||
|
@ -19,26 +19,32 @@ namespace framework {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// This class represents a synchronous Secure WebSocket connection
|
||||
// A synchronous WebSocket connection over an SSL 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.
|
||||
// Give this object the enable_shared_from_this, and have
|
||||
// the base class call impl().shared_from_this(). The reason
|
||||
// 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_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.
|
||||
// The stream should be created before the base class so
|
||||
// use the "base from member" idiom.
|
||||
//
|
||||
, public base_from_member<beast::websocket::stream<ssl_stream<socket_type>>>
|
||||
|
||||
// Declare this base last now that everything else got set up first.
|
||||
// Constructs last, destroys first
|
||||
//
|
||||
, public sync_ws_con_base<sync_wss_con>
|
||||
{
|
||||
public:
|
||||
// Construct the plain connection.
|
||||
// Constructor
|
||||
//
|
||||
// Additional arguments are forwarded to the base class
|
||||
//
|
||||
template<class... Args>
|
||||
explicit
|
||||
@ -51,7 +57,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// Construct the connection from an existing, handshaked SSL stream
|
||||
// Construct from an existing, handshaked SSL stream
|
||||
//
|
||||
template<class... Args>
|
||||
sync_wss_con(
|
||||
@ -64,7 +70,10 @@ public:
|
||||
|
||||
// Returns the stream.
|
||||
//
|
||||
// The base class calls this to obtain the websocket stream object.
|
||||
// The base class calls this to obtain the object to use for
|
||||
// reading and writing HTTP messages. This allows the same base
|
||||
// class to work with different return types for `stream()` such
|
||||
// as a `boost::asio::ip::tcp::socket&` or a `boost::asio::ssl::stream&`
|
||||
//
|
||||
beast::websocket::stream<ssl_stream<socket_type>>&
|
||||
stream()
|
||||
@ -90,30 +99,32 @@ private:
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// This class represents an asynchronous Secure WebSocket
|
||||
// connection which uses an OpenSSL socket as the stream.
|
||||
// An asynchronous WebSocket connection over an SSL connection
|
||||
//
|
||||
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.
|
||||
// Give this object the enable_shared_from_this, and have
|
||||
// the base class call impl().shared_from_this(). The reason
|
||||
// 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.
|
||||
// The stream should be created before the base class so
|
||||
// use the "base from member" idiom.
|
||||
//
|
||||
, public base_from_member<beast::websocket::stream<ssl_stream<socket_type>>>
|
||||
|
||||
// Declare this base last now that everything else got set up first.
|
||||
// Constructs last, destroys first
|
||||
//
|
||||
, public async_ws_con_base<async_wss_con>
|
||||
{
|
||||
public:
|
||||
// Construct the connection.
|
||||
// Constructor
|
||||
//
|
||||
// Additional arguments are forwarded to the base class
|
||||
//
|
||||
template<class... Args>
|
||||
async_wss_con(
|
||||
@ -125,7 +136,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// Construct the connection from an existing, handshaked SSL stream
|
||||
// Construct from an existing, handshaked SSL stream
|
||||
//
|
||||
template<class... Args>
|
||||
async_wss_con(
|
||||
@ -137,8 +148,11 @@ public:
|
||||
}
|
||||
|
||||
// Returns the stream.
|
||||
// The base class calls this to obtain the object to
|
||||
// use for reading and writing HTTP messages.
|
||||
//
|
||||
// The base class calls this to obtain the object to use for
|
||||
// reading and writing HTTP messages. This allows the same base
|
||||
// class to work with different return types for `stream()` such
|
||||
// as a `boost::asio::ip::tcp::socket&` or a `boost::asio::ssl::stream&`
|
||||
//
|
||||
beast::websocket::stream<ssl_stream<socket_type>>&
|
||||
stream()
|
||||
@ -159,13 +173,15 @@ private:
|
||||
//
|
||||
stream().next_layer().async_handshake(
|
||||
boost::asio::ssl::stream_base::server,
|
||||
this->strand_.wrap(std::bind(
|
||||
this->strand_.wrap(
|
||||
std::bind(
|
||||
&async_wss_con::on_handshake,
|
||||
this->shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
this->shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
// Called when the SSL handshake completes
|
||||
//
|
||||
void
|
||||
on_handshake(error_code ec)
|
||||
{
|
||||
@ -191,11 +207,13 @@ 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>>&)>;
|
||||
// The types of the on_new_stream callbacks
|
||||
//
|
||||
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_;
|
||||
@ -259,8 +277,7 @@ public:
|
||||
log_,
|
||||
instance_.next_id(),
|
||||
ep,
|
||||
cb2_
|
||||
)->run();
|
||||
cb2_)->run();
|
||||
}
|
||||
|
||||
/** Accept a WebSocket upgrade request.
|
||||
@ -276,13 +293,13 @@ public:
|
||||
*/
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
accept(
|
||||
on_upgrade(
|
||||
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.
|
||||
// transferring ownership of the ugprade request.
|
||||
//
|
||||
std::make_shared<sync_wss_con>(
|
||||
std::move(stream),
|
||||
@ -290,8 +307,7 @@ public:
|
||||
log_,
|
||||
instance_.next_id(),
|
||||
ep,
|
||||
cb2_
|
||||
)->run(std::move(req));
|
||||
cb2_)->run(std::move(req));
|
||||
}
|
||||
};
|
||||
|
||||
@ -308,15 +324,24 @@ 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>>&)>;
|
||||
// The types of the on_new_stream callbacks
|
||||
//
|
||||
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>>&)>;
|
||||
|
||||
// Reference to the server instance that made us
|
||||
server& instance_;
|
||||
|
||||
// The stream to log to
|
||||
std::ostream& log_;
|
||||
|
||||
// The context holds the SSL certificates the server uses
|
||||
boost::asio::ssl::context& ctx_;
|
||||
|
||||
// Called for each new websocket stream
|
||||
on_new_stream_cb1 cb1_;
|
||||
on_new_stream_cb2 cb2_;
|
||||
|
||||
@ -376,8 +401,7 @@ public:
|
||||
log_,
|
||||
instance_.next_id(),
|
||||
ep,
|
||||
cb2_
|
||||
)->run();
|
||||
cb2_)->run();
|
||||
}
|
||||
|
||||
/** Accept a WebSocket upgrade request.
|
||||
@ -393,7 +417,7 @@ public:
|
||||
*/
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
accept(
|
||||
on_upgrade(
|
||||
ssl_stream<socket_type>&& stream,
|
||||
endpoint_type ep,
|
||||
beast::http::request<Body, Fields>&& req)
|
||||
@ -404,8 +428,7 @@ public:
|
||||
log_,
|
||||
instance_.next_id(),
|
||||
ep,
|
||||
cb2_
|
||||
)->run(std::move(req));
|
||||
cb2_)->run(std::move(req));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include "example/doc/core_examples.hpp"
|
||||
#include "example/server-framework/detect_ssl.hpp"
|
||||
|
||||
#include <beast/core/flat_buffer.hpp>
|
||||
#include <beast/core/ostream.hpp>
|
||||
|
@ -26,6 +26,7 @@ add_executable (server-test
|
||||
http_sync_port.cpp
|
||||
https_ports.cpp
|
||||
main.cpp
|
||||
multi_port.cpp
|
||||
rfc7231.cpp
|
||||
server.cpp
|
||||
service_list.cpp
|
||||
|
@ -21,6 +21,7 @@ exe server-test :
|
||||
ws_sync_port.cpp
|
||||
ws_upgrade_service.cpp
|
||||
#https_ports.cpp
|
||||
#multi_port.cpp
|
||||
#ssl_certificate.cpp
|
||||
#ssl_stream.cpp
|
||||
;
|
||||
|
10
test/server/multi_port.cpp
Normal file
10
test/server/multi_port.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include "../../example/server-framework/multi_port.hpp"
|
||||
|
Reference in New Issue
Block a user