diff options
author | Roland Reichwein <mail@reichwein.it> | 2023-01-09 13:15:18 +0100 |
---|---|---|
committer | Roland Reichwein <mail@reichwein.it> | 2023-01-09 13:15:18 +0100 |
commit | dc2e2b3e293a8374a2627982b521cc6865129c49 (patch) | |
tree | bd34d6c13e330be5937aec29503cbe6649d0fa74 /https.cpp | |
parent | d747193e76baf689211d9f1e42335360288d43c0 (diff) |
Separated out websocket
Diffstat (limited to 'https.cpp')
-rw-r--r-- | https.cpp | 270 |
1 files changed, 5 insertions, 265 deletions
@@ -1,8 +1,10 @@ #include "https.h" #include "config.h" +#include "error.h" #include "server.h" #include "response.h" +#include "websocket.h" #include "libreichwein/file.h" @@ -17,13 +19,7 @@ #include <boost/asio/buffers_iterator.hpp> #include <boost/asio/dispatch.hpp> #include <boost/asio/ssl/context.hpp> -#ifdef BOOST_LATEST #include <boost/beast/ssl.hpp> -#else -#include <boost/asio/ip/tcp.hpp> -#include <boost/asio/ssl/stream.hpp> -#include <boost/asio/bind_executor.hpp> -#endif #include <boost/asio/strand.hpp> #include <boost/config.hpp> @@ -52,155 +48,10 @@ namespace { //------------------------------------------------------------------------------ -// Report a failure -void fail( -#ifdef BOOST_LATEST - beast::error_code ec, -#else - boost::system::error_code ec, -#endif - char const* what) -{ -#ifdef BOOST_LATEST - // ssl::error::stream_truncated, also known as an SSL "short read", - // indicates the peer closed the connection without performing the - // required closing handshake (for example, Google does this to - // improve performance). Generally this can be a security issue, - // but if your communication protocol is self-terminated (as - // it is with both HTTP and WebSocket) then you may simply - // ignore the lack of close_notify. - // - // https://github.com/boostorg/beast/issues/38 - // - // https://security.stackexchange.com/questions/91435/how-to-handle-a-malicious-ssl-tls-shutdown - // - // When a short read would cut off the end of an HTTP message, - // Beast returns the error beast::http::error::partial_message. - // Therefore, if we see a short read here, it has occurred - // after the message has been completed, so it is safe to ignore it. - - if(ec == net::ssl::error::stream_truncated) - return; -#endif - - 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> { -#ifdef BOOST_LATEST beast::ssl_stream<beast::tcp_stream> stream_; -#else - tcp::socket socket_; - ssl::stream<tcp::socket&> stream_; - boost::asio::strand<boost::asio::io_context::executor_type> strand_; -#endif beast::flat_buffer buffer_; Server& m_server; std::optional<http::request_parser<http::string_body>> parser_; // need to reset parser every time, no other mechanism currently @@ -209,17 +60,12 @@ class session : public std::enable_shared_from_this<session> void handle_request(::Server& server, request_type&& req) { -#ifdef BOOST_LATEST beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(300)); // timeout on write by server much longer than read timeout from client -#else - // beast::get_lowest_layer<tcp::socket>(stream_).expires_after(std::chrono::seconds(300)); // not supported by boost -#endif auto sp = std::make_shared<response_type>(generate_response(req, server)); res_ = sp; // Write the response -#ifdef BOOST_LATEST http::async_write( stream_, *sp, @@ -227,38 +73,15 @@ class session : public std::enable_shared_from_this<session> &session::on_write, shared_from_this(), sp->need_eof())); -#else - http::async_write( - stream_, - *sp, - boost::asio::bind_executor( - strand_, - std::bind( - &session::on_write, - shared_from_this(), - std::placeholders::_1, - std::placeholders::_2, - sp->need_eof()))); -#endif } public: // Take ownership of the socket explicit session( -#ifdef BOOST_LATEST tcp::socket&& socket, -#else - tcp::socket socket, -#endif ssl::context& ctx, Server& server) -#ifdef BOOST_LATEST : stream_(std::move(socket), ctx) -#else - : socket_(std::move(socket)) - , stream_(socket_, ctx) - , strand_(socket_.get_executor()) -#endif , m_server(server) { } @@ -267,7 +90,6 @@ public: void run() { -#ifdef BOOST_LATEST // We need to be executing within a strand to perform async operations // on the I/O objects in this session. net::dispatch( @@ -275,19 +97,8 @@ public: beast::bind_front_handler( &session::on_run, shared_from_this())); -#else - stream_.async_handshake( - ssl::stream_base::server, - boost::asio::bind_executor( - strand_, - std::bind( - &session::on_handshake, - shared_from_this(), - std::placeholders::_1))); -#endif } -#ifdef BOOST_LATEST void on_run() { @@ -302,15 +113,10 @@ public: &session::on_handshake, shared_from_this())); } -#endif void on_handshake( -#ifdef BOOST_LATEST beast::error_code ec -#else - boost::system::error_code ec -#endif ) { if(ec) @@ -331,7 +137,6 @@ public: parser_.emplace(); parser_->body_limit(1000000000); // 1GB limit -#ifdef BOOST_LATEST // Set the timeout. beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(30)); @@ -340,25 +145,11 @@ public: beast::bind_front_handler( &session::on_read, shared_from_this())); -#else - http::async_read(stream_, buffer_, *parser_, - boost::asio::bind_executor( - strand_, - std::bind( - &session::on_read, - shared_from_this(), - std::placeholders::_1, - std::placeholders::_2))); -#endif } void on_read( -#ifdef BOOST_LATEST beast::error_code ec, -#else - boost::system::error_code ec, -#endif std::size_t bytes_transferred) { boost::ignore_unused(bytes_transferred); @@ -388,15 +179,9 @@ public: void on_write( -#ifdef BOOST_LATEST bool close, beast::error_code ec, std::size_t bytes_transferred -#else - boost::system::error_code ec, - std::size_t bytes_transferred, - bool close -#endif ) { boost::ignore_unused(bytes_transferred); @@ -421,7 +206,6 @@ public: void do_close() { -#ifdef BOOST_LATEST // Set the timeout. beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(30)); @@ -430,15 +214,6 @@ public: beast::bind_front_handler( &session::on_shutdown, shared_from_this())); -#else - stream_.async_shutdown( - boost::asio::bind_executor( - strand_, - std::bind( - &session::on_shutdown, - shared_from_this(), - std::placeholders::_1))); -#endif } void @@ -456,14 +231,9 @@ public: // Accepts incoming connections and launches the sessions class listener : public std::enable_shared_from_this<listener> { -#ifdef BOOST_LATEST net::io_context& ioc_; -#endif ssl::context& ctx_; tcp::acceptor acceptor_; -#ifndef BOOST_LATEST - tcp::socket socket_; -#endif ::Server& m_server; public: @@ -472,21 +242,12 @@ public: ssl::context& ctx, tcp::endpoint endpoint, Server& server) : -#ifdef BOOST_LATEST ioc_(ioc), -#endif - ctx_(ctx) - , acceptor_(ioc) -#ifndef BOOST_LATEST - , socket_(ioc) -#endif - , m_server(server) + ctx_(ctx), + acceptor_(ioc), + m_server(server) { -#ifdef BOOST_LATEST beast::error_code ec; -#else - boost::system::error_code ec; -#endif // Open the acceptor acceptor_.open(endpoint.protocol(), ec); @@ -526,10 +287,6 @@ public: void run() { -#ifndef BOOST_LATEST - if(! acceptor_.is_open()) - return; -#endif do_accept(); } @@ -538,28 +295,15 @@ private: do_accept() { // The new connection gets its own strand -#ifdef BOOST_LATEST acceptor_.async_accept( net::make_strand(ioc_), beast::bind_front_handler( &listener::on_accept, shared_from_this())); -#else - acceptor_.async_accept( - socket_, - std::bind( - &listener::on_accept, - shared_from_this(), - std::placeholders::_1)); -#endif } void -#ifdef BOOST_LATEST on_accept(beast::error_code ec, tcp::socket socket) -#else - on_accept(boost::system::error_code ec) -#endif { if(ec) { @@ -569,11 +313,7 @@ private: { // Create the session and run it std::make_shared<session>( -#ifdef BOOST_LATEST std::move(socket), -#else - std::move(socket_), -#endif ctx_, m_server)->run(); } |