summaryrefslogtreecommitdiffhomepage
path: root/https.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'https.cpp')
-rw-r--r--https.cpp116
1 files changed, 116 insertions, 0 deletions
diff --git a/https.cpp b/https.cpp
index 523acb5..ccf14d7 100644
--- a/https.cpp
+++ b/https.cpp
@@ -12,6 +12,9 @@
#include <boost/asio/buffer.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
+#include <boost/beast/websocket.hpp>
+#include <boost/beast/websocket/ssl.hpp>
+#include <boost/asio/buffers_iterator.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/ssl/context.hpp>
#ifdef BOOST_LATEST
@@ -41,6 +44,7 @@ namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
namespace net = boost::asio; // from <boost/asio.hpp>
namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp>
+namespace websocket = beast::websocket;
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
using namespace Reichwein;
@@ -82,6 +86,111 @@ void fail(
std::cerr << what << ": " << ec.message() << "\n";
}
+class websocket_session: public std::enable_shared_from_this<websocket_session>
+{
+ websocket::stream<beast::ssl_stream<beast::tcp_stream>> ws_;
+ beast::flat_buffer buffer_;
+
+public:
+ explicit websocket_session(beast::ssl_stream<beast::tcp_stream>&& stream) :
+ ws_(std::move(stream))
+ {
+ }
+
+ // Start the asynchronous accept operation
+ template<class Body, class Allocator>
+ void
+ do_accept(http::request<Body, http::basic_fields<Allocator>> req)
+ {
+ // Set suggested timeout settings for the websocket
+ ws_.set_option(
+ websocket::stream_base::timeout::suggested(
+ beast::role_type::server));
+
+ // Set a decorator to change the Server of the handshake
+ ws_.set_option(websocket::stream_base::decorator(
+ [](websocket::response_type& res)
+ {
+ res.set(http::field::server,
+ std::string{"Reichwein.IT Webserver"});
+ }));
+
+ // Accept the websocket handshake
+ ws_.async_accept(
+ req,
+ beast::bind_front_handler(
+ &websocket_session::on_accept,
+ shared_from_this()));
+ }
+
+private:
+ void
+ on_accept(beast::error_code ec)
+ {
+ if(ec)
+ return fail(ec, "accept");
+
+ // Read a message
+ do_read();
+ }
+
+ void
+ do_read()
+ {
+ // Read a message into our buffer
+ ws_.async_read(
+ buffer_,
+ beast::bind_front_handler(
+ &websocket_session::on_read,
+ shared_from_this()));
+ }
+
+ void
+ on_read(
+ beast::error_code ec,
+ std::size_t bytes_transferred)
+ {
+ boost::ignore_unused(bytes_transferred);
+
+ // This indicates that the websocket_session was closed
+ if(ec == websocket::error::closed)
+ return;
+
+ if(ec)
+ fail(ec, "read");
+
+ // Echo the message
+ ws_.text(ws_.got_text());
+ std::string data(boost::asio::buffers_begin(buffer_.data()), boost::asio::buffers_end(buffer_.data()));
+ static int count{};
+ data += ": " + std::to_string(count++);
+ buffer_.consume(buffer_.size());
+ boost::beast::ostream(buffer_) << data;
+ ws_.async_write(
+ buffer_.data(),
+ beast::bind_front_handler(
+ &websocket_session::on_write,
+ shared_from_this()));
+ }
+
+ void
+ on_write(
+ beast::error_code ec,
+ std::size_t bytes_transferred)
+ {
+ boost::ignore_unused(bytes_transferred);
+
+ if(ec)
+ return fail(ec, "write");
+
+ // Clear the buffer
+ buffer_.consume(buffer_.size());
+
+ // Do another read
+ do_read();
+ }
+};
+
// Handles an HTTP server connection
class session : public std::enable_shared_from_this<session>
{
@@ -265,6 +374,13 @@ public:
return fail(ec, "https read");
req_ = parser_->get();
+
+ if (websocket::is_upgrade(req_))
+ {
+ beast::get_lowest_layer(stream_).expires_never();
+ std::make_shared<websocket_session>(std::move(stream_))->do_accept(parser_->release());
+ return;
+ }
// Send the response
handle_request(m_server, std::move(req_));