| #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; |