summaryrefslogtreecommitdiffhomepage
path: root/websocket.h
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2023-01-11 18:36:43 +0100
committerRoland Reichwein <mail@reichwein.it>2023-01-11 18:36:43 +0100
commitdeb28a9ce73ed7e38aaa53659027b61976fdca6b (patch)
tree7458809ca11ee8e59b32eb4aed4cd482894035dc /websocket.h
parent64493507905412e36848b9bd97c26f3d7a578ab5 (diff)
Websocket for both http and https
Diffstat (limited to 'websocket.h')
-rw-r--r--websocket.h94
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);
+