summaryrefslogtreecommitdiffhomepage
path: root/https.cpp
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2023-01-09 13:15:18 +0100
committerRoland Reichwein <mail@reichwein.it>2023-01-09 13:15:18 +0100
commitdc2e2b3e293a8374a2627982b521cc6865129c49 (patch)
treebd34d6c13e330be5937aec29503cbe6649d0fa74 /https.cpp
parentd747193e76baf689211d9f1e42335360288d43c0 (diff)
Separated out websocket
Diffstat (limited to 'https.cpp')
-rw-r--r--https.cpp270
1 files changed, 5 insertions, 265 deletions
diff --git a/https.cpp b/https.cpp
index ccf14d7..3a68b00 100644
--- a/https.cpp
+++ b/https.cpp
@@ -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();
}