завел https

This commit is contained in:
Vladislav Ostapov 2024-10-30 10:24:02 +03:00
parent d6851052b4
commit 2fef65d9d9
15 changed files with 372 additions and 224 deletions

View File

@ -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})

View File

@ -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"
```

View File

@ -9,6 +9,33 @@
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/formatter_parser.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/ssl/context.hpp>
#include <cstddef>
#include <memory>
#include <fstream>
namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp>
static std::vector<char> 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<char> 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 <address> <port>\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<http::resource::StaticFileResource>("/", "static/login.html", mime_types::text_html));
s.resources.emplace_back(std::make_unique<http::resource::StaticFileResource>("/favicon.ico", "static/favicon.png", mime_types::image_png));
s.resources.emplace_back(std::make_unique<http::resource::StaticFileResource>("/js/vue.js", "static/js/vue.js", mime_types::javascript));
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/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 <ssl|nossl> <address> <port> [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<http::server::Server> s;
s.resources.emplace_back(std::make_unique<http::resource::StaticFileResource>("/", "static/login.html", mime_types::text_html));
s.resources.emplace_back(std::make_unique<http::resource::StaticFileResource>("/favicon.ico", "static/favicon.png", mime_types::image_png));
s.resources.emplace_back(std::make_unique<http::resource::StaticFileResource>("/js/vue.js", "static/js/vue.js", mime_types::javascript));
if (strcmp(argv[1], "nossl") == 0) {
s = std::make_unique<http::server::Server>(argv[2], argv[3]);
initResources(*s);
s->run();
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/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>(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<http::server::Server>(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;

View File

@ -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 <utility>
#include <boost/log/trivial.hpp>
#include <boost/beast.hpp>
#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<boost::asio::ssl::context>& 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

View File

@ -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 <boost/asio.hpp>
#include <boost/asio/ssl/context.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/beast/core/tcp_stream.hpp>
#include <array>
#include <memory>
#include "reply.hpp"
@ -22,24 +15,36 @@
namespace http::server {
using request_handler = std::function<void(const request &req, reply &rep)>;
class connection_manager;
/// Represents a single connection from a client.
class connection
: public std::enable_shared_from_this<connection> {
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<Connection> {
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<char, 8192> buffer_{};
std::array<char, 2048> buffer_{};
/// The incoming request.
request request_;
@ -69,8 +74,50 @@ namespace http::server {
reply reply_;
};
typedef std::shared_ptr<connection> connection_ptr;
} // namespace http::server
class SslConnection final : public ConnectionBase, public std::enable_shared_from_this<SslConnection> {
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<boost::asio::ssl::context>& 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<boost::beast::tcp_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<char, 2048> 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<ConnectionBase> connection_ptr;
} // namespace http::Server
#endif // HTTP_CONNECTION_HPP

View File

@ -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

View File

@ -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 <set>
#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<connection_ptr> connections_;
};
} // namespace http::server
#endif // HTTP_CONNECTION_MANAGER_HPP

View File

@ -19,7 +19,7 @@ namespace http::server {
std::string name;
std::string value;
};
} // namespace http::server
} // namespace http::Server
#endif // HTTP_HEADER_HPP

View File

@ -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

View File

@ -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

View File

@ -26,7 +26,7 @@ namespace http::server {
int http_version_minor;
std::vector<header> headers;
};
} // namespace http::server
} // namespace http::Server
#endif // HTTP_REQUEST_HPP

View File

@ -86,7 +86,7 @@ namespace http::server {
expecting_newline_3
} state_;
};
} // namespace http::server
} // namespace http::Server
#endif // HTTP_REQUEST_PARSER_HPP

View File

@ -1,10 +1,29 @@
#include "server.hpp"
#include <utility>
#include <boost/beast/core/basic_stream.hpp>
#include <boost/url/url_view.hpp>
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<boost::asio::ssl::context> 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<connection>(
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<Connection>(std::move(socket), connection_manager_, [this](const auto& req, auto& rep) { this->requestHandler(req, rep); }));
} else {
connection_manager_.start(std::make_shared<SslConnection>(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

View File

@ -1,22 +1,51 @@
#ifndef HTTP_SERVER_HPP
#define HTTP_SERVER_HPP
#include <set>
#include <boost/asio.hpp>
#include <boost/asio/ssl/context.hpp>
#include <string>
#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<connection_ptr> 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<boost::asio::ssl::context> ctx);
std::vector<std::unique_ptr<resource::BasicResource>> resources;
@ -24,11 +53,13 @@ namespace http::server {
void run();
private:
std::shared_ptr<boost::asio::ssl::context> 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

View File

@ -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: `<div>Счётчик: {{ count }}</div>`
}