diff options
Diffstat (limited to 'websocket.h')
-rw-r--r-- | websocket.h | 94 |
1 files changed, 74 insertions, 20 deletions
diff --git a/websocket.h b/websocket.h index 951155e..b941433 100644 --- a/websocket.h +++ b/websocket.h @@ -1,6 +1,10 @@ +// +// Websocket, implemented via CRTP for both plain and ssl websockets +// #pragma once #include "error.h" +#include "response.h" #include <boost/asio/buffer.hpp> #include <boost/beast/core.hpp> @@ -36,12 +40,18 @@ namespace websocket = beast::websocket; using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp> using namespace std::placeholders; -// Server session, asynchronous, proxying -class websocket_session: public std::enable_shared_from_this<websocket_session> +// Server session, asynchronous, proxying, implemented w/ CRTP for plain+ssl variants +template<class Derived> +class websocket_session { +private: + Derived& derived() + { + return static_cast<Derived&>(*this); + } + boost::asio::io_context& ioc_; boost::asio::ip::tcp::resolver resolver_; - boost::beast::websocket::stream<beast::ssl_stream<beast::tcp_stream>> ws_in_; boost::beast::flat_buffer buffer_in_; boost::beast::websocket::stream<beast::tcp_stream> ws_app_; boost::beast::flat_buffer buffer_out_; @@ -50,11 +60,10 @@ class websocket_session: public std::enable_shared_from_this<websocket_session> std::string subprotocol_; std::string relative_target_; -public: - explicit websocket_session(boost::asio::io_context& ioc, beast::ssl_stream<beast::tcp_stream>&& stream, const std::string& websocket_address): +public: + explicit websocket_session(boost::asio::io_context& ioc, std::string&& websocket_address): ioc_(ioc), resolver_(boost::asio::make_strand(ioc_)), - ws_in_(std::move(stream)), ws_app_(boost::asio::make_strand(ioc_)), host_{}, port_{}, @@ -90,16 +99,17 @@ public: // // Start the asynchronous accept operation + // TODO: why template here? template<class Body, class Allocator> void do_accept_in(http::request<Body, http::basic_fields<Allocator>> req) { // Set suggested timeout settings for the websocket - ws_in_.set_option( + derived().ws_in().set_option( websocket::stream_base::timeout::suggested( beast::role_type::server)); // Set a decorator to change the Server of the handshake - ws_in_.set_option(websocket::stream_base::decorator( + derived().ws_in().set_option(websocket::stream_base::decorator( [](websocket::response_type& res) { res.set(http::field::server, @@ -110,11 +120,11 @@ public: subprotocol_ = std::string{req[http::field::sec_websocket_protocol]}; // Accept the websocket handshake - ws_in_.async_accept( + derived().ws_in().async_accept( req, beast::bind_front_handler( &websocket_session::on_accept_in, - shared_from_this())); + derived().shared_from_this())); } private: @@ -124,7 +134,7 @@ private: return fail(ec, "accept in"); resolver_.async_resolve(host_, port_, - beast::bind_front_handler(&websocket_session::on_resolve_app, shared_from_this())); + beast::bind_front_handler(&websocket_session::on_resolve_app, derived().shared_from_this())); } void on_resolve_app(beast::error_code ec, tcp::resolver::results_type results) @@ -133,7 +143,7 @@ private: return fail(ec, "resolve app"); beast::get_lowest_layer(ws_app_).async_connect(results, - beast::bind_front_handler(&websocket_session::on_connect_app, shared_from_this())); + beast::bind_front_handler(&websocket_session::on_connect_app, derived().shared_from_this())); } void on_connect_app(beast::error_code ec, tcp::resolver::results_type::endpoint_type endpoint) @@ -163,7 +173,7 @@ private: })); ws_app_.async_handshake(host_, relative_target_, - beast::bind_front_handler(&websocket_session::on_handshake_app, shared_from_this())); + beast::bind_front_handler(&websocket_session::on_handshake_app, derived().shared_from_this())); } void on_handshake_app(beast::error_code ec) @@ -184,11 +194,11 @@ private: do_read_in() { // Read a message into our buffer - ws_in_.async_read( + derived().ws_in().async_read( buffer_in_, beast::bind_front_handler( &websocket_session::on_read_in, - shared_from_this())); + derived().shared_from_this())); } void @@ -205,7 +215,7 @@ private: if (ec) fail(ec, "read in"); - ws_app_.text(ws_in_.got_text()); + ws_app_.text(derived().ws_in().got_text()); do_write_app(); } @@ -215,7 +225,7 @@ private: ws_app_.async_write(buffer_in_.data(), beast::bind_front_handler( &websocket_session::on_write_app, - shared_from_this())); + derived().shared_from_this())); } void on_write_app(beast::error_code ec, std::size_t bytes_transferred) @@ -242,7 +252,7 @@ private: buffer_out_, beast::bind_front_handler( &websocket_session::on_read_app, - shared_from_this())); + derived().shared_from_this())); } void on_read_app(beast::error_code ec, std::size_t bytes_transferred) @@ -260,10 +270,10 @@ private: void do_write_out() { - ws_in_.async_write(buffer_out_.data(), + derived().ws_in().async_write(buffer_out_.data(), beast::bind_front_handler( &websocket_session::on_write_out, - shared_from_this())); + derived().shared_from_this())); } void on_write_out( @@ -283,3 +293,47 @@ private: } }; // class + +class plain_websocket_session: + public websocket_session<plain_websocket_session>, + public std::enable_shared_from_this<plain_websocket_session> +{ + boost::beast::websocket::stream<beast::tcp_stream> ws_in_; + +public: + + explicit plain_websocket_session(boost::asio::io_context& ioc, beast::tcp_stream&& stream, std::string&& websocket_address): + websocket_session(ioc, std::move(websocket_address)), + ws_in_(std::move(stream)) + { + } + + boost::beast::websocket::stream<beast::tcp_stream>& ws_in() + { + return ws_in_; + } +}; // class + +class ssl_websocket_session: + public websocket_session<ssl_websocket_session>, + public std::enable_shared_from_this<ssl_websocket_session> +{ + boost::beast::websocket::stream<beast::ssl_stream<beast::tcp_stream>> ws_in_; + +public: + + explicit ssl_websocket_session(boost::asio::io_context& ioc, beast::ssl_stream<beast::tcp_stream>&& stream, std::string&& websocket_address): + websocket_session(ioc, std::move(websocket_address)), + ws_in_(std::move(stream)) + { + } + + boost::beast::websocket::stream<beast::ssl_stream<beast::tcp_stream>>& ws_in() + { + return ws_in_; + } +}; // class + +void make_websocket_session(boost::asio::io_context& ioc, beast::tcp_stream&& stream, std::string websocket_address, request_type&& req); +void make_websocket_session(boost::asio::io_context& ioc, beast::ssl_stream<beast::tcp_stream>&& stream, std::string websocket_address, request_type&& req); + |