22#include "util/Taggable.hpp"
23#include "util/log/Logger.hpp"
24#include "web/AdminVerificationStrategy.hpp"
25#include "web/HttpSession.hpp"
26#include "web/SslHttpSession.hpp"
27#include "web/dosguard/DOSGuardInterface.hpp"
28#include "web/interface/Concepts.hpp"
29#include "web/ng/impl/ServerSslContext.hpp"
31#include <boost/asio/io_context.hpp>
32#include <boost/asio/ip/address.hpp>
33#include <boost/asio/ip/tcp.hpp>
34#include <boost/asio/socket_base.hpp>
35#include <boost/asio/ssl/context.hpp>
36#include <boost/asio/ssl/error.hpp>
37#include <boost/asio/strand.hpp>
38#include <boost/beast/core/error.hpp>
39#include <boost/beast/core/flat_buffer.hpp>
40#include <boost/beast/core/stream_traits.hpp>
41#include <boost/beast/core/tcp_stream.hpp>
75 template <
typename>
class PlainSessionType,
76 template <
typename>
class SslSessionType,
77 SomeServerHandler HandlerType>
78class Detector :
public std::enable_shared_from_this<Detector<PlainSessionType, SslSessionType, HandlerType>> {
82 boost::beast::tcp_stream stream_;
83 std::optional<std::reference_wrapper<boost::asio::ssl::context>> ctx_;
84 std::reference_wrapper<util::TagDecoratorFactory const> tagFactory_;
85 std::reference_wrapper<dosguard::DOSGuardInterface>
const dosGuard_;
86 std::shared_ptr<HandlerType>
const handler_;
87 boost::beast::flat_buffer buffer_;
88 std::shared_ptr<AdminVerificationStrategy>
const adminVerification_;
89 std::uint32_t maxWsSendingQueueSize_;
104 tcp::socket&& socket,
105 std::optional<std::reference_wrapper<boost::asio::ssl::context>> ctx,
106 std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
107 std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
108 std::shared_ptr<HandlerType> handler,
109 std::shared_ptr<AdminVerificationStrategy> adminVerification,
110 std::uint32_t maxWsSendingQueueSize
112 : stream_(std::move(socket))
114 , tagFactory_(std::cref(tagFactory))
115 , dosGuard_(dosGuard)
116 , handler_(std::move(handler))
117 , adminVerification_(std::move(adminVerification))
118 , maxWsSendingQueueSize_(maxWsSendingQueueSize)
129 fail(boost::system::error_code ec,
char const* message)
131 if (ec == boost::asio::ssl::error::stream_truncated)
134 LOG(log_.
info()) <<
"Detector failed (" << message <<
"): " << ec.message();
141 boost::beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
142 async_detect_ssl(stream_, buffer_, boost::beast::bind_front_handler(&
Detector::onDetect, shared_from_this()));
155 return fail(ec,
"detect");
159 ip = stream_.socket().remote_endpoint().address().to_string();
160 }
catch (std::exception
const&) {
161 return fail(ec,
"cannot get remote endpoint");
166 return fail(ec,
"SSL is not supported by this server");
168 std::make_shared<SslSessionType<HandlerType>>(
169 stream_.release_socket(),
177 maxWsSendingQueueSize_
183 std::make_shared<PlainSessionType<HandlerType>>(
184 stream_.release_socket(),
191 maxWsSendingQueueSize_
207 template <
typename>
class PlainSessionType,
208 template <
typename>
class SslSessionType,
209 SomeServerHandler HandlerType>
210class Server :
public std::enable_shared_from_this<Server<PlainSessionType, SslSessionType, HandlerType>> {
214 std::reference_wrapper<boost::asio::io_context> ioc_;
215 std::optional<boost::asio::ssl::context> ctx_;
217 std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard_;
218 std::shared_ptr<HandlerType> handler_;
219 tcp::acceptor acceptor_;
220 std::shared_ptr<AdminVerificationStrategy> adminVerification_;
221 std::uint32_t maxWsSendingQueueSize_;
237 boost::asio::io_context& ioc,
238 std::optional<boost::asio::ssl::context> ctx,
239 tcp::endpoint endpoint,
242 std::shared_ptr<HandlerType> handler,
243 std::shared_ptr<AdminVerificationStrategy> adminVerification,
244 std::uint32_t maxWsSendingQueueSize
246 : ioc_(std::ref(ioc))
247 , ctx_(std::move(ctx))
248 , tagFactory_(tagFactory)
249 , dosGuard_(std::ref(dosGuard))
250 , handler_(std::move(handler))
251 , acceptor_(boost::asio::make_strand(ioc))
252 , adminVerification_(std::move(adminVerification))
253 , maxWsSendingQueueSize_(maxWsSendingQueueSize)
255 boost::beast::error_code ec;
257 acceptor_.open(endpoint.protocol(), ec);
261 acceptor_.set_option(boost::asio::socket_base::reuse_address(
true), ec);
265 acceptor_.bind(endpoint, ec);
267 LOG(log_.
error()) <<
"Failed to bind to endpoint: " << endpoint <<
". message: " << ec.message();
268 throw std::runtime_error(
269 fmt::format(
"Failed to bind to endpoint: {}:{}", endpoint.address().to_string(), endpoint.port())
273 acceptor_.listen(boost::asio::socket_base::max_listen_connections, ec);
275 LOG(log_.
error()) <<
"Failed to listen at endpoint: " << endpoint <<
". message: " << ec.message();
276 throw std::runtime_error(
277 fmt::format(
"Failed to listen at endpoint: {}:{}", endpoint.address().to_string(), endpoint.port())
293 acceptor_.async_accept(
294 boost::asio::make_strand(ioc_.get()),
295 boost::beast::bind_front_handler(&Server::onAccept, shared_from_this())
300 onAccept(boost::beast::error_code ec, tcp::socket socket)
304 ctx_ ? std::optional<std::reference_wrapper<boost::asio::ssl::context>>{ctx_.value()} : std::nullopt;
306 std::make_shared<Detector<PlainSessionType, SslSessionType, HandlerType>>(
309 std::cref(tagFactory_),
313 maxWsSendingQueueSize_
323template <
typename HandlerType>
336template <
typename HandlerType>
337static std::shared_ptr<HttpServer<HandlerType>>
340 boost::asio::io_context& ioc,
342 std::shared_ptr<HandlerType>
const& handler
347 auto expectedSslContext = ng::impl::makeServerSslContext(config);
348 if (not expectedSslContext) {
349 LOG(log.error()) <<
"Failed to create SSL context: " << expectedSslContext.error();
353 auto const serverConfig = config.
getObject(
"server");
354 auto const address = boost::asio::ip::make_address(serverConfig.get<std::string>(
"ip"));
355 auto const port = serverConfig.get<
unsigned short>(
"port");
358 if (not expectedAdminVerification.has_value()) {
359 LOG(log.error()) << expectedAdminVerification.error();
360 throw std::logic_error{expectedAdminVerification.error()};
365 auto const maxWsSendingQueueSize = serverConfig.get<uint32_t>(
"ws_max_sending_queue_size");
367 auto server = std::make_shared<HttpServer<HandlerType>>(
369 std::move(expectedSslContext).value(),
370 boost::asio::ip::tcp::endpoint{address, port},
374 std::move(expectedAdminVerification).value(),
375 maxWsSendingQueueSize
A simple thread-safe logger for the channel specified in the constructor.
Definition Logger.hpp:110
Pump error(SourceLocationType const &loc=CURRENT_SRC_LOCATION) const
Interface for logging at Severity::ERR severity.
Definition Logger.cpp:215
Pump info(SourceLocationType const &loc=CURRENT_SRC_LOCATION) const
Interface for logging at Severity::NFO severity.
Definition Logger.cpp:205
A factory for TagDecorator instantiation.
Definition Taggable.hpp:169
All the config data will be stored and extracted from this class.
Definition ConfigDefinition.hpp:54
ObjectView getObject(std::string_view prefix, std::optional< std::size_t > idx=std::nullopt) const
Returns the ObjectView specified with the prefix.
Definition ConfigDefinition.cpp:61
The Detector class to detect if the connection is a ssl or not.
Definition Server.hpp:78
void onDetect(boost::beast::error_code ec, bool result)
Handles detection result.
Definition Server.hpp:152
Detector(tcp::socket &&socket, std::optional< std::reference_wrapper< boost::asio::ssl::context > > ctx, std::reference_wrapper< util::TagDecoratorFactory const > tagFactory, std::reference_wrapper< dosguard::DOSGuardInterface > dosGuard, std::shared_ptr< HandlerType > handler, std::shared_ptr< AdminVerificationStrategy > adminVerification, std::uint32_t maxWsSendingQueueSize)
Create a new detector.
Definition Server.hpp:103
void run()
Initiate the detection.
Definition Server.hpp:139
void fail(boost::system::error_code ec, char const *message)
A helper function that is called when any error ocurs.
Definition Server.hpp:129
The WebServer class. It creates server socket and start listening on it.
Definition Server.hpp:210
void run()
Start accepting incoming connections.
Definition Server.hpp:284
Server(boost::asio::io_context &ioc, std::optional< boost::asio::ssl::context > ctx, tcp::endpoint endpoint, util::TagDecoratorFactory tagFactory, dosguard::DOSGuardInterface &dosGuard, std::shared_ptr< HandlerType > handler, std::shared_ptr< AdminVerificationStrategy > adminVerification, std::uint32_t maxWsSendingQueueSize)
Create a new instance of the web server.
Definition Server.hpp:236
The interface of a denial of service guard.
Definition DOSGuardInterface.hpp:44
This namespace implements the web server and related components.
Definition Types.hpp:43
static std::shared_ptr< HttpServer< HandlerType > > makeHttpServer(util::config::ClioConfigDefinition const &config, boost::asio::io_context &ioc, dosguard::DOSGuardInterface &dosGuard, std::shared_ptr< HandlerType > const &handler)
A factory function that spawns a ready to use HTTP server.
Definition Server.hpp:338
std::shared_ptr< AdminVerificationStrategy > makeAdminVerificationStrategy(std::optional< std::string > password)
Factory function for creating an admin verification strategy.
Definition AdminVerificationStrategy.cpp:75