1 #pragma once 2 3 #include "async_resp.hpp" 4 #include "http_request.hpp" 5 #include "http_server.hpp" 6 #include "logging.hpp" 7 #include "privileges.hpp" 8 #include "routing.hpp" 9 #include "utility.hpp" 10 11 #include <boost/asio/io_context.hpp> 12 #include <boost/asio/ip/tcp.hpp> 13 #ifdef BMCWEB_ENABLE_SSL 14 #include <boost/asio/ssl/context.hpp> 15 #include <boost/beast/ssl/ssl_stream.hpp> 16 #endif 17 18 #include <chrono> 19 #include <cstdint> 20 #include <functional> 21 #include <future> 22 #include <memory> 23 #include <string> 24 #include <utility> 25 26 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 27 #define BMCWEB_ROUTE(app, url) \ 28 app.template route<crow::black_magic::getParameterTag(url)>(url) 29 30 namespace crow 31 { 32 #ifdef BMCWEB_ENABLE_SSL 33 using ssl_context_t = boost::asio::ssl::context; 34 #endif 35 class App 36 { 37 public: 38 #ifdef BMCWEB_ENABLE_SSL 39 using ssl_socket_t = boost::beast::ssl_stream<boost::asio::ip::tcp::socket>; 40 using ssl_server_t = Server<App, ssl_socket_t>; 41 #else 42 using socket_t = boost::asio::ip::tcp::socket; 43 using server_t = Server<App, socket_t>; 44 #endif 45 46 explicit App(std::shared_ptr<boost::asio::io_context> ioIn = 47 std::make_shared<boost::asio::io_context>()) : 48 io(std::move(ioIn)) 49 {} 50 ~App() 51 { 52 this->stop(); 53 } 54 55 App(const App&) = delete; 56 App(App&&) = delete; 57 App& operator=(const App&) = delete; 58 App& operator=(const App&&) = delete; 59 60 template <typename Adaptor> 61 void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor) 62 { 63 router.handleUpgrade(req, res, std::forward<Adaptor>(adaptor)); 64 } 65 66 void handle(Request& req, 67 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 68 { 69 router.handle(req, asyncResp); 70 } 71 72 DynamicRule& routeDynamic(std::string&& rule) 73 { 74 return router.newRuleDynamic(rule); 75 } 76 77 template <uint64_t Tag> 78 auto& route(std::string&& rule) 79 { 80 return router.newRuleTagged<Tag>(std::move(rule)); 81 } 82 83 App& socket(int existingSocket) 84 { 85 socketFd = existingSocket; 86 return *this; 87 } 88 89 App& port(std::uint16_t port) 90 { 91 portUint = port; 92 return *this; 93 } 94 95 App& bindaddr(std::string bindaddr) 96 { 97 bindaddrStr = std::move(bindaddr); 98 return *this; 99 } 100 101 void validate() 102 { 103 router.validate(); 104 } 105 106 void run() 107 { 108 validate(); 109 #ifdef BMCWEB_ENABLE_SSL 110 if (-1 == socketFd) 111 { 112 sslServer = std::make_unique<ssl_server_t>( 113 this, bindaddrStr, portUint, sslContext, io); 114 } 115 else 116 { 117 sslServer = 118 std::make_unique<ssl_server_t>(this, socketFd, sslContext, io); 119 } 120 sslServer->run(); 121 122 #else 123 124 if (-1 == socketFd) 125 { 126 server = std::move(std::make_unique<server_t>( 127 this, bindaddrStr, portUint, nullptr, io)); 128 } 129 else 130 { 131 server = std::move( 132 std::make_unique<server_t>(this, socketFd, nullptr, io)); 133 } 134 server->run(); 135 136 #endif 137 } 138 139 void stop() 140 { 141 io->stop(); 142 } 143 144 void debugPrint() 145 { 146 BMCWEB_LOG_DEBUG << "Routing:"; 147 router.debugPrint(); 148 } 149 150 std::vector<const std::string*> getRoutes() 151 { 152 const std::string root; 153 return router.getRoutes(root); 154 } 155 std::vector<const std::string*> getRoutes(const std::string& parent) 156 { 157 return router.getRoutes(parent); 158 } 159 160 #ifdef BMCWEB_ENABLE_SSL 161 App& ssl(std::shared_ptr<boost::asio::ssl::context>&& ctx) 162 { 163 sslContext = std::move(ctx); 164 BMCWEB_LOG_INFO << "app::ssl context use_count=" 165 << sslContext.use_count(); 166 return *this; 167 } 168 169 std::shared_ptr<ssl_context_t> sslContext = nullptr; 170 171 #else 172 template <typename T> 173 App& ssl(T&&) 174 { 175 // We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is 176 // defined. 177 static_assert( 178 // make static_assert dependent to T; always false 179 std::is_base_of<T, void>::value, 180 "Define BMCWEB_ENABLE_SSL to enable ssl support."); 181 return *this; 182 } 183 #endif 184 185 private: 186 std::shared_ptr<boost::asio::io_context> io; 187 #ifdef BMCWEB_ENABLE_SSL 188 uint16_t portUint = 443; 189 #else 190 uint16_t portUint = 80; 191 #endif 192 std::string bindaddrStr = "0.0.0.0"; 193 int socketFd = -1; 194 Router router; 195 196 #ifdef BMCWEB_ENABLE_SSL 197 std::unique_ptr<ssl_server_t> sslServer; 198 #else 199 std::unique_ptr<server_t> server; 200 #endif 201 }; 202 } // namespace crow 203 using App = crow::App; 204