diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d613bc..fb269d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,8 @@ endif() add_compile_options(-Wall -Wextra -Wsign-conversion) +add_subdirectory(dependencies/control_system-dvbs-2) + add_executable(terminal-web-server src/server/mime_types.hpp src/server/mime_types.cpp @@ -26,8 +28,6 @@ add_executable(terminal-web-server src/server/request_parser.cpp src/server/server.cpp src/server/header.hpp - src/server/connection_manager.cpp - src/server/connection_manager.hpp src/server/reply.hpp src/server/reply.cpp src/server/connection.cpp @@ -38,18 +38,7 @@ add_executable(terminal-web-server ) find_package(Boost 1.53.0 COMPONENTS system thread filesystem url log log_setup REQUIRED) -target_link_libraries(terminal-web-server ${Boost_LIBRARIES}) -target_include_directories(terminal-web-server PRIVATE ${Boost_INCLUDE_DIR}) - -#find_package(OpenSSL) -#if(OPENSSL_FOUND) -# target_compile_definitions(simple-web-server INTERFACE HAVE_OPENSSL) -# target_link_libraries(simple-web-server INTERFACE ${OPENSSL_LIBRARIES}) -# target_include_directories(simple-web-server INTERFACE ${OPENSSL_INCLUDE_DIR}) -# -# add_executable(https_examples https_examples.cpp) -# target_link_libraries(https_examples simple-web-server) -# target_link_libraries(https_examples ${Boost_LIBRARIES}) -# target_include_directories(https_examples PRIVATE ${Boost_INCLUDE_DIR}) -#endif() +find_package(OpenSSL REQUIRED) +target_link_libraries(terminal-web-server ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES}) +target_include_directories(terminal-web-server PRIVATE ${Boost_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR}) diff --git a/README.md b/README.md index 9c9eeaa..8021cf7 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,19 @@ sudo apt-get install libboost-all-dev ``` +Для библиотеки api нужно еще такое: + +```shell +sudo apt install cereal libcereal-dev +``` + +# SSL + +В коде установлена версия `TSL 1.2`. + +Генерировать сертификаты в тестовых целях можно так: + +```shell +openssl dhparam -out dh.pem 2048 +openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 3600 -out cert.pem -subj "/C=ru/ST=ru/L=Moscow/O=NTC RSS/CN=terminal" +``` diff --git a/src/main.cpp b/src/main.cpp index 2f6426e..0fc979e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,33 @@ #include #include #include +#include +#include +#include +#include +#include + + +namespace ssl = boost::asio::ssl; // from + + +static std::vector loadFile(const std::string& path) { + std::ifstream is(path, std::ios::in | std::ios::binary); + if (!is) { + throw std::runtime_error("File not found"); + } + + std::vector content; + for (;;) { + char buf[512]; + auto len = is.read(buf, sizeof(buf)).gcount(); + if (len <= 0) { + break; + } + content.insert(content.end(), buf, buf + len); + } + return content; +} namespace mime_types = http::server::mime_types; @@ -43,19 +70,36 @@ void init_logging() { log::add_common_attributes(); } -int main(int argc, char *argv[]) { - try { - // Check command line arguments. - if (argc != 3) { - std::cerr << "Usage: http_server
\n"; - std::cerr << " For IPv4, try:\n"; - std::cerr << " receiver 0.0.0.0 80\n"; - std::cerr << " For IPv6, try:\n"; - std::cerr << " receiver 0::0 80\n"; - return 1; +static void initResources(http::server::Server& s) { + s.resources.emplace_back(std::make_unique("/", "static/login.html", mime_types::text_html)); + s.resources.emplace_back(std::make_unique("/favicon.ico", "static/favicon.png", mime_types::image_png)); + s.resources.emplace_back(std::make_unique("/js/vue.js", "static/js/vue.js", mime_types::javascript)); + + s.resources.emplace_back(std::make_unique("/api/statistics", [](const auto& req, auto& rep) { + if (req.method != "GET") { + http::server::stock_reply(http::server::bad_request, rep); } + rep.status = http::server::ok; + rep.headers.clear(); + rep.headers.push_back({.name = "Content-Type", .value = to_string(mime_types::json)}); + const char* json = R"({"key":"value"})"; + rep.content.insert(rep.content.end(), json, json + strlen(json)); + })); +} + +int main(int argc, char *argv[]) { + try { prctl(PR_SET_NAME, "main", 0, 0, 0); + // Check command line arguments. + if (argc != 4 && argc != 5) { + std::cerr << "Usage: http_server
[static files directory]\n"; + std::cerr << " For IPv4, try:\n"; + std::cerr << " receiver nossl 0.0.0.0 80\n"; + std::cerr << " For IPv6, try:\n"; + std::cerr << " receiver nossl 0::0 80\n"; + return 1; + } init_logging(); boost::log::core::get()->add_thread_attribute("Scope", boost::log::attributes::named_scope()); @@ -67,26 +111,40 @@ int main(int argc, char *argv[]) { #endif // Initialise the server. - http::server::server s(argv[1], argv[2]); + std::unique_ptr s; - s.resources.emplace_back(std::make_unique("/", "static/login.html", mime_types::text_html)); - s.resources.emplace_back(std::make_unique("/favicon.ico", "static/favicon.png", mime_types::image_png)); - s.resources.emplace_back(std::make_unique("/js/vue.js", "static/js/vue.js", mime_types::javascript)); + if (strcmp(argv[1], "nossl") == 0) { + s = std::make_unique(argv[2], argv[3]); + initResources(*s); + s->run(); - s.resources.emplace_back(std::make_unique("/api/statistics", [](const auto& req, auto& rep) { - if (req.method != "GET") { - http::server::stock_reply(http::server::bad_request, rep); - } + } else if (strcmp(argv[1], "ssl") == 0) { + const auto cert = loadFile("cert.pem"); + const auto key = loadFile("key.pem"); + const auto dh = loadFile("dh.pem"); - rep.status = http::server::ok; - rep.headers.clear(); - rep.headers.push_back({.name = "Content-Type", .value = to_string(mime_types::json)}); - const char* json = R"({"key":"value"})"; - rep.content.insert(rep.content.end(), json, json + strlen(json)); - })); + auto ctx = std::make_shared(ssl::context::tlsv12); - // Run the server until stopped. - s.run(); + ctx->set_password_callback( + [](std::size_t, ssl::context_base::password_purpose) { + return "test"; + }); + + ctx->set_options(ssl::context::default_workarounds | ssl::context::no_sslv2 | ssl::context::single_dh_use); + + ctx->use_certificate_chain(boost::asio::buffer(cert)); + + ctx->use_private_key(boost::asio::buffer(key), ssl::context::file_format::pem); + + ctx->use_tmp_dh(boost::asio::buffer(dh)); + + s = std::make_unique(argv[2], argv[3], ctx); + initResources(*s); + s->run(); + } else { + std::cerr << "Unsupported ssl mode: " << argv[1] << std::endl; + return 1; + } } catch (std::exception &e) { BOOST_LOG_TRIVIAL(error) << e.what() << std::endl; return -1; diff --git a/src/server/connection.cpp b/src/server/connection.cpp index 241ded4..d636b23 100644 --- a/src/server/connection.cpp +++ b/src/server/connection.cpp @@ -1,38 +1,28 @@ -// -// connection.cpp -// ~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - #include "connection.hpp" #include #include #include - -#include "connection_manager.hpp" +#include "server.hpp" namespace http::server { - connection::connection(boost::asio::ip::tcp::socket socket, - connection_manager &manager, request_handler handler) - : socket_(std::move(socket)), - connection_manager_(manager), - request_handler_(std::move(handler)), request_(), reply_() { + const char* SERVER_HEADER_VALUE = "TerminalWebServer v0.1"; + + Connection::Connection(boost::asio::ip::tcp::socket socket, ConnectionManager &manager, request_handler handler) + : socket_(std::move(socket)), connection_manager_(manager), request_handler_(std::move(handler)), request_(), reply_() { } - void connection::start() { + void Connection::start() { do_read(); } - void connection::stop() { + void Connection::stop() { socket_.close(); } - void connection::do_read() { + Connection::~Connection() = default; + + void Connection::do_read() { request_parser_.reset(); request_.headers.clear(); request_.method.clear(); @@ -60,8 +50,8 @@ namespace http::server { }); } - void connection::do_write() { - reply_.headers.push_back({.name = "Server", .value = "TerminalWebServer v0.1"}); + void Connection::do_write() { + reply_.headers.push_back({.name = "Server", .value = SERVER_HEADER_VALUE}); if (!reply_.content.empty()) { reply_.headers.push_back({.name = "Content-Length", .value = std::to_string(reply_.content.size())}); } @@ -74,11 +64,83 @@ namespace http::server { auto self(shared_from_this()); async_write(socket_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) { if (!ec) { - // keep alive connection + // keep alive Connection do_read(); } else { connection_manager_.stop(shared_from_this()); } }); } -} // namespace http::server + + SslConnection::SslConnection(boost::asio::ip::tcp::socket socket, ConnectionManager &manager, request_handler handler, const std::shared_ptr& ctx): + stream_(std::move(socket), *ctx), connection_manager_(manager), request_handler_(std::move(handler)), request_(), reply_() { + } + + void SslConnection::start() { + get_lowest_layer(stream_).expires_after(std::chrono::seconds(30)); + + // Perform the SSL handshake + stream_.async_handshake(boost::asio::ssl::stream_base::server, boost::beast::bind_front_handler([this](auto ec) { + boost::ignore_unused(ec); + doRead(); + })); + } + + void SslConnection::stop() { + } + + SslConnection::~SslConnection() = default; + + void SslConnection::doRead() { + get_lowest_layer(stream_).expires_after(std::chrono::seconds(30)); + + request_parser_.reset(); + request_.headers.clear(); + request_.method.clear(); + request_.uri.clear(); + + auto self(shared_from_this()); + stream_.async_read_some(boost::asio::buffer(buffer_), [this, self](boost::system::error_code ec, std::size_t bytes_transferred) { + if (!ec) { + request_parser::result_type result; + std::tie(result, std::ignore) = request_parser_.parse( + request_, buffer_.data(), buffer_.data() + bytes_transferred); + + if (result == request_parser::good) { + request_handler_(request_, reply_); + doWrite(); + } else if (result == request_parser::bad) { + stock_reply(bad_request, reply_); + doWrite(); + } else { + doRead(); + } + } else { + connection_manager_.stop(shared_from_this()); + } + }); + } + + void SslConnection::doWrite() { + reply_.headers.push_back({.name = "Server", .value = SERVER_HEADER_VALUE}); + if (!reply_.content.empty()) { + reply_.headers.push_back({.name = "Content-Length", .value = std::to_string(reply_.content.size())}); + } + if (request_.http_version_major == 1) { + reply_.headers.push_back({.name = "Connection", .value = "keep-alive"}); + } + + BOOST_LOG_TRIVIAL(info) << "HTTP query " << reply_.status << " " << request_.method << " " << request_.uri; + + auto self(shared_from_this()); + async_write(stream_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) { + if (!ec) { + // keep alive Connection + doRead(); + } else { + connection_manager_.stop(shared_from_this()); + } + }); + } + +} // namespace http::Server diff --git a/src/server/connection.hpp b/src/server/connection.hpp index 29328e1..6cd2f89 100644 --- a/src/server/connection.hpp +++ b/src/server/connection.hpp @@ -1,17 +1,10 @@ -// -// connection.hpp -// ~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - #ifndef HTTP_CONNECTION_HPP #define HTTP_CONNECTION_HPP #include +#include +#include +#include #include #include #include "reply.hpp" @@ -22,24 +15,36 @@ namespace http::server { using request_handler = std::function; - class connection_manager; - /// Represents a single connection from a client. - class connection - : public std::enable_shared_from_this { + class ConnectionManager; + /// Represents a single Connection from a client. Base class + class ConnectionBase { public: - connection(const connection &) = delete; + ConnectionBase(const ConnectionBase &) = delete; + ConnectionBase &operator=(const ConnectionBase &) = delete; + ConnectionBase() = default; - connection &operator=(const connection &) = delete; + /// Start the first asynchronous operation for the Connection. + virtual void start() = 0; - /// Construct a connection with the given socket. - explicit connection(boost::asio::ip::tcp::socket socket, connection_manager &manager, request_handler handler); + /// Stop all asynchronous operations associated with the Connection. + virtual void stop() = 0; - /// Start the first asynchronous operation for the connection. - void start(); + virtual ~ConnectionBase() = default; + }; - /// Stop all asynchronous operations associated with the connection. - void stop(); + class Connection final : public ConnectionBase, public std::enable_shared_from_this { + public: + /// Construct a Connection with the given socket. + explicit Connection(boost::asio::ip::tcp::socket socket, ConnectionManager &manager, request_handler handler); + + /// Start the first asynchronous operation for the Connection. + void start() override; + + /// Stop all asynchronous operations associated with the Connection. + void stop() override; + + ~Connection() override; private: /// Perform an asynchronous read operation. void do_read(); @@ -47,17 +52,17 @@ namespace http::server { /// Perform an asynchronous write operation. void do_write(); - /// Socket for the connection. + /// Socket for the Connection. boost::asio::ip::tcp::socket socket_; - /// The manager for this connection. - connection_manager &connection_manager_; + /// The manager for this Connection. + ConnectionManager &connection_manager_; /// The handler used to process the incoming request. request_handler request_handler_; /// Buffer for incoming data. - std::array buffer_{}; + std::array buffer_{}; /// The incoming request. request request_; @@ -69,8 +74,50 @@ namespace http::server { reply reply_; }; - typedef std::shared_ptr connection_ptr; -} // namespace http::server + class SslConnection final : public ConnectionBase, public std::enable_shared_from_this { + public: + + /// Construct a Connection with the given socket. + explicit SslConnection(boost::asio::ip::tcp::socket socket, ConnectionManager &manager, request_handler handler, const std::shared_ptr& ctx); + + /// Start the first asynchronous operation for the Connection. + void start() override; + + /// Stop all asynchronous operations associated with the Connection. + void stop() override; + + ~SslConnection() override; + private: + /// Perform an asynchronous read operation. + void doRead(); + + /// Perform an asynchronous write operation. + void doWrite(); + + /// Socket for the Connection. + boost::asio::ssl::stream stream_; + + /// The manager for this Connection. + ConnectionManager &connection_manager_; + + /// The handler used to process the incoming request. + request_handler request_handler_; + + /// Buffer for incoming data. + std::array buffer_{}; + + /// The incoming request. + request request_; + + /// The parser for the incoming request. + request_parser request_parser_; + + /// The reply to be sent back to the client. + reply reply_; + }; + + typedef std::shared_ptr connection_ptr; +} // namespace http::Server #endif // HTTP_CONNECTION_HPP diff --git a/src/server/connection_manager.cpp b/src/server/connection_manager.cpp deleted file mode 100644 index 9bacaeb..0000000 --- a/src/server/connection_manager.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// -// connection_manager.cpp -// ~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#include "connection_manager.hpp" - - -namespace http::server { - connection_manager::connection_manager() = default; - - void connection_manager::start(connection_ptr c) { - connections_.insert(c); - c->start(); - } - - void connection_manager::stop(connection_ptr c) { - connections_.erase(c); - c->stop(); - } - - void connection_manager::stop_all() { - for (auto& c: connections_) - c->stop(); - connections_.clear(); - } -} // namespace http::server diff --git a/src/server/connection_manager.hpp b/src/server/connection_manager.hpp deleted file mode 100644 index 838bdd8..0000000 --- a/src/server/connection_manager.hpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// connection_manager.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef HTTP_CONNECTION_MANAGER_HPP -#define HTTP_CONNECTION_MANAGER_HPP - -#include -#include "connection.hpp" - - -namespace http::server { - /// Manages open connections so that they may be cleanly stopped when the server - /// needs to shut down. - class connection_manager { - public: - connection_manager(const connection_manager &) = delete; - - connection_manager &operator=(const connection_manager &) = delete; - - /// Construct a connection manager. - connection_manager(); - - /// Add the specified connection to the manager and start it. - void start(connection_ptr c); - - /// Stop the specified connection. - void stop(connection_ptr c); - - /// Stop all connections. - void stop_all(); - - private: - /// The managed connections. - std::set connections_; - }; -} // namespace http::server - - -#endif // HTTP_CONNECTION_MANAGER_HPP diff --git a/src/server/header.hpp b/src/server/header.hpp index 53f961b..1d70080 100644 --- a/src/server/header.hpp +++ b/src/server/header.hpp @@ -19,7 +19,7 @@ namespace http::server { std::string name; std::string value; }; -} // namespace http::server +} // namespace http::Server #endif // HTTP_HEADER_HPP diff --git a/src/server/mime_types.hpp b/src/server/mime_types.hpp index 70c0678..31272d5 100644 --- a/src/server/mime_types.hpp +++ b/src/server/mime_types.hpp @@ -34,7 +34,7 @@ namespace http::server::mime_types { /// Convert a file extension into a MIME type. std::string extension_to_type(const std::string &extension); -} // namespace http::server::mime_types +} // namespace http::Server::mime_types #endif // HTTP_MIME_TYPES_HPP diff --git a/src/server/reply.hpp b/src/server/reply.hpp index 74bc90b..a2abac6 100644 --- a/src/server/reply.hpp +++ b/src/server/reply.hpp @@ -57,7 +57,7 @@ namespace http::server { /// Get a stock reply. void stock_reply(status_type status, reply& rep); -} // namespace http::server +} // namespace http::Server #endif // HTTP_REPLY_HPP diff --git a/src/server/request.hpp b/src/server/request.hpp index a6b0622..09f4249 100644 --- a/src/server/request.hpp +++ b/src/server/request.hpp @@ -26,7 +26,7 @@ namespace http::server { int http_version_minor; std::vector
headers; }; -} // namespace http::server +} // namespace http::Server #endif // HTTP_REQUEST_HPP diff --git a/src/server/request_parser.hpp b/src/server/request_parser.hpp index 1d7fb53..8836eca 100644 --- a/src/server/request_parser.hpp +++ b/src/server/request_parser.hpp @@ -86,7 +86,7 @@ namespace http::server { expecting_newline_3 } state_; }; -} // namespace http::server +} // namespace http::Server #endif // HTTP_REQUEST_PARSER_HPP diff --git a/src/server/server.cpp b/src/server/server.cpp index d46d52e..c24a49d 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -1,10 +1,29 @@ #include "server.hpp" #include +#include #include namespace http::server { - server::server(const std::string &address, const std::string &port) + ConnectionManager::ConnectionManager() = default; + + void ConnectionManager::start(const connection_ptr& c) { + connections_.insert(c); + c->start(); + } + + void ConnectionManager::stop(const connection_ptr& c) { + connections_.erase(c); + c->stop(); + } + + void ConnectionManager::stop_all() { + for (auto& c: connections_) + c->stop(); + connections_.clear(); + } + + Server::Server(const std::string &address, const std::string &port) : io_context_(1), signals_(io_context_), acceptor_(io_context_) { // Register to handle the signals that indicate when the server should exit. // It is safe to register for the same signal multiple times in a program, @@ -15,7 +34,7 @@ namespace http::server { signals_.add(SIGQUIT); #endif // defined(SIGQUIT) - do_await_stop(); + doAwaitStop(); // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). boost::asio::ip::tcp::resolver resolver(io_context_); @@ -26,10 +45,34 @@ namespace http::server { acceptor_.bind(endpoint); acceptor_.listen(128); - do_accept(); + doAccept(); } - void server::run() { + Server::Server(const std::string &address, const std::string &port, std::shared_ptr ctx): + ssl_ctx(std::move(ctx)), io_context_(1), signals_(io_context_), acceptor_(io_context_) { + // Register to handle the signals that indicate when the server should exit. + // It is safe to register for the same signal multiple times in a program, + // provided all registration for the specified signal is made through Asio. + signals_.add(SIGINT); + signals_.add(SIGTERM); +#if defined(SIGQUIT) + signals_.add(SIGQUIT); +#endif // defined(SIGQUIT) + + doAwaitStop(); + + // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). + boost::asio::ip::tcp::resolver resolver(io_context_); + boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(address, port).begin(); + acceptor_.open(endpoint.protocol()); + acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor_.bind(endpoint); + acceptor_.listen(128); + + doAccept(); + } + + void Server::run() { // The io_context::run() call will block until all asynchronous operations // have finished. While the server is running, there is always at least one // asynchronous operation outstanding: the asynchronous accept call waiting @@ -37,7 +80,7 @@ namespace http::server { io_context_.run(); } - void server::do_accept() { + void Server::doAccept() { acceptor_.async_accept( [this](boost::system::error_code ec, boost::asio::ip::tcp::socket socket) { // Check whether the server was stopped by a signal before this @@ -47,15 +90,18 @@ namespace http::server { } if (!ec) { - connection_manager_.start(std::make_shared( - std::move(socket), connection_manager_, [this](const auto& req, auto& rep) { this->handle_request(req, rep); })); + if (ssl_ctx == nullptr) { + connection_manager_.start(std::make_shared(std::move(socket), connection_manager_, [this](const auto& req, auto& rep) { this->requestHandler(req, rep); })); + } else { + connection_manager_.start(std::make_shared(std::move(socket), connection_manager_, [this](const auto& req, auto& rep) { this->requestHandler(req, rep); }, ssl_ctx)); + } } - do_accept(); + doAccept(); }); } - void server::do_await_stop() { + void Server::doAwaitStop() { signals_.async_wait( [this](boost::system::error_code /*ec*/, int /*signo*/) { // The server is stopped by cancelling all outstanding asynchronous @@ -66,8 +112,7 @@ namespace http::server { }); } - - void server::handle_request(const request &req, reply &rep) { + void Server::requestHandler(const request &req, reply &rep) { boost::urls::url_view url(req.uri); const auto path = url.path(); @@ -92,4 +137,5 @@ namespace http::server { stock_reply(not_found, rep); } -} // namespace http::server + +} // namespace http::Server diff --git a/src/server/server.hpp b/src/server/server.hpp index ba3c1e0..d13755c 100644 --- a/src/server/server.hpp +++ b/src/server/server.hpp @@ -1,22 +1,51 @@ #ifndef HTTP_SERVER_HPP #define HTTP_SERVER_HPP +#include #include +#include #include -#include "connection_manager.hpp" +#include "connection.hpp" #include "resource.h" namespace http::server { - /// The top-level class of the HTTP server. - class server { + /// Manages open connections so that they may be cleanly stopped when the server + /// needs to shut down. + class ConnectionManager { public: - server(const server &) = delete; + ConnectionManager(const ConnectionManager &) = delete; - server &operator=(const server &) = delete; + ConnectionManager &operator=(const ConnectionManager &) = delete; + + /// Construct a Connection manager. + ConnectionManager(); + + /// Add the specified Connection to the manager and start it. + void start(const connection_ptr& c); + + /// Stop the specified Connection. + void stop(const connection_ptr& c); + + /// Stop all connections. + void stop_all(); + + private: + /// The managed connections. + std::set connections_; + }; + + + /// The top-level class of the HTTP server. + class Server { + public: + Server(const Server &) = delete; + + Server &operator=(const Server &) = delete; /// Construct the server to listen on the specified TCP address and port - explicit server(const std::string &address, const std::string &port); + explicit Server(const std::string &address, const std::string &port); + explicit Server(const std::string &address, const std::string &port, std::shared_ptr ctx); std::vector> resources; @@ -24,11 +53,13 @@ namespace http::server { void run(); private: + std::shared_ptr ssl_ctx; + /// Perform an asynchronous accept operation. - void do_accept(); + void doAccept(); /// Wait for a request to stop the server. - void do_await_stop(); + void doAwaitStop(); /// The io_context used to perform asynchronous operations. boost::asio::io_context io_context_; @@ -39,13 +70,13 @@ namespace http::server { /// Acceptor used to listen for incoming connections. boost::asio::ip::tcp::acceptor acceptor_; - /// The connection manager which owns all live connections. - connection_manager connection_manager_; + /// The Connection manager which owns all live connections. + ConnectionManager connection_manager_; /// Handle a request and produce a reply. - void handle_request(const request &req, reply &rep); + void requestHandler(const request &req, reply &rep); }; -} // namespace http::server +} // namespace http::Server #endif // HTTP_SERVER_HPP diff --git a/static/js/modules/header.js b/static/js/modules/header.js deleted file mode 100644 index 370aa51..0000000 --- a/static/js/modules/header.js +++ /dev/null @@ -1,23 +0,0 @@ -import { ref } from 'vue' -export default { - el: '#status-header', - data: { - message: 'Hello Vue!', - now: new Date() - }, - methods: { - updateDate() { - this.now = new Date(); - } - }, - mounted() { - setInterval(() => { - this.updateDate(); - }, 1000); - }, - setup() { - const count = ref(0) - return { count } - }, - template: `
Счётчик: {{ count }}
` -} \ No newline at end of file