blob: 03de3f8952676f0d9ccd813987adabb06d986b54 [file] [log] [blame]
#pragma once
#include "async_resp.hpp"
#include "http_request.hpp"
#include "http_server.hpp"
#include "logging.hpp"
#include "privileges.hpp"
#include "routing.hpp"
#include "utility.hpp"
#include <chrono>
#include <cstdint>
#include <functional>
#include <future>
#include <memory>
#include <string>
#include <utility>
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define BMCWEB_ROUTE(app, url) \
app.template route<crow::black_magic::getParameterTag(url)>(url)
namespace crow
{
#ifdef BMCWEB_ENABLE_SSL
using ssl_context_t = boost::asio::ssl::context;
#endif
class App
{
public:
#ifdef BMCWEB_ENABLE_SSL
using ssl_socket_t = boost::beast::ssl_stream<boost::asio::ip::tcp::socket>;
using ssl_server_t = Server<App, ssl_socket_t>;
#else
using socket_t = boost::asio::ip::tcp::socket;
using server_t = Server<App, socket_t>;
#endif
explicit App(std::shared_ptr<boost::asio::io_context> ioIn =
std::make_shared<boost::asio::io_context>()) :
io(std::move(ioIn))
{}
~App()
{
this->stop();
}
App(const App&) = delete;
App(App&&) = delete;
App& operator=(const App&) = delete;
App& operator=(const App&&) = delete;
template <typename Adaptor>
void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
{
router.handleUpgrade(req, res, std::forward<Adaptor>(adaptor));
}
void handle(Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
{
router.handle(req, asyncResp);
}
DynamicRule& routeDynamic(std::string&& rule)
{
return router.newRuleDynamic(rule);
}
template <uint64_t Tag>
auto& route(std::string&& rule)
{
return router.newRuleTagged<Tag>(std::move(rule));
}
App& socket(int existingSocket)
{
socketFd = existingSocket;
return *this;
}
App& port(std::uint16_t port)
{
portUint = port;
return *this;
}
App& bindaddr(std::string bindaddr)
{
bindaddrStr = std::move(bindaddr);
return *this;
}
void validate()
{
router.validate();
}
void run()
{
validate();
#ifdef BMCWEB_ENABLE_SSL
if (-1 == socketFd)
{
sslServer = std::make_unique<ssl_server_t>(
this, bindaddrStr, portUint, sslContext, io);
}
else
{
sslServer =
std::make_unique<ssl_server_t>(this, socketFd, sslContext, io);
}
sslServer->run();
#else
if (-1 == socketFd)
{
server = std::move(std::make_unique<server_t>(
this, bindaddrStr, portUint, nullptr, io));
}
else
{
server = std::move(
std::make_unique<server_t>(this, socketFd, nullptr, io));
}
server->run();
#endif
}
void stop()
{
io->stop();
}
void debugPrint()
{
BMCWEB_LOG_DEBUG << "Routing:";
router.debugPrint();
}
std::vector<const std::string*> getRoutes()
{
const std::string root("");
return router.getRoutes(root);
}
std::vector<const std::string*> getRoutes(const std::string& parent)
{
return router.getRoutes(parent);
}
#ifdef BMCWEB_ENABLE_SSL
App& sslFile(const std::string& crtFilename, const std::string& keyFilename)
{
sslContext = std::make_shared<ssl_context_t>(
boost::asio::ssl::context::tls_server);
sslContext->set_verify_mode(boost::asio::ssl::verify_peer);
sslContext->use_certificate_file(crtFilename, ssl_context_t::pem);
sslContext->use_private_key_file(keyFilename, ssl_context_t::pem);
sslContext->set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::no_sslv3 |
boost::asio::ssl::context::no_tlsv1 |
boost::asio::ssl::context::no_tlsv1_1);
return *this;
}
App& sslFile(const std::string& pemFilename)
{
sslContext = std::make_shared<ssl_context_t>(
boost::asio::ssl::context::tls_server);
sslContext->set_verify_mode(boost::asio::ssl::verify_peer);
sslContext->load_verify_file(pemFilename);
sslContext->set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::no_sslv3 |
boost::asio::ssl::context::no_tlsv1 |
boost::asio::ssl::context::no_tlsv1_1);
return *this;
}
App& ssl(std::shared_ptr<boost::asio::ssl::context>&& ctx)
{
sslContext = std::move(ctx);
BMCWEB_LOG_INFO << "app::ssl context use_count="
<< sslContext.use_count();
return *this;
}
std::shared_ptr<ssl_context_t> sslContext = nullptr;
#else
template <typename T, typename... Remain>
App& ssl_file(T&&, Remain&&...)
{
// We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is
// defined.
static_assert(
// make static_assert dependent to T; always false
std::is_base_of<T, void>::value,
"Define BMCWEB_ENABLE_SSL to enable ssl support.");
return *this;
}
template <typename T>
App& ssl(T&&)
{
// We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is
// defined.
static_assert(
// make static_assert dependent to T; always false
std::is_base_of<T, void>::value,
"Define BMCWEB_ENABLE_SSL to enable ssl support.");
return *this;
}
#endif
private:
std::shared_ptr<boost::asio::io_context> io;
#ifdef BMCWEB_ENABLE_SSL
uint16_t portUint = 443;
#else
uint16_t portUint = 80;
#endif
std::string bindaddrStr = "0.0.0.0";
int socketFd = -1;
Router router;
#ifdef BMCWEB_ENABLE_SSL
std::unique_ptr<ssl_server_t> sslServer;
#else
std::unique_ptr<server_t> server;
#endif
};
} // namespace crow
using App = crow::App;