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::make_unique<server_t>(this, bindaddrStr, portUint, 127 nullptr, io); 128 } 129 else 130 { 131 server = std::make_unique<server_t>(this, socketFd, nullptr, io); 132 } 133 server->run(); 134 135 #endif 136 } 137 138 void stop() 139 { 140 io->stop(); 141 } 142 143 void debugPrint() 144 { 145 BMCWEB_LOG_DEBUG << "Routing:"; 146 router.debugPrint(); 147 } 148 149 std::vector<const std::string*> getRoutes() 150 { 151 const std::string root; 152 return router.getRoutes(root); 153 } 154 std::vector<const std::string*> getRoutes(const std::string& parent) 155 { 156 return router.getRoutes(parent); 157 } 158 159 #ifdef BMCWEB_ENABLE_SSL 160 App& ssl(std::shared_ptr<boost::asio::ssl::context>&& ctx) 161 { 162 sslContext = std::move(ctx); 163 BMCWEB_LOG_INFO << "app::ssl context use_count=" 164 << sslContext.use_count(); 165 return *this; 166 } 167 168 std::shared_ptr<ssl_context_t> sslContext = nullptr; 169 170 #else 171 template <typename T> 172 App& ssl(T&&) 173 { 174 // We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is 175 // defined. 176 static_assert( 177 // make static_assert dependent to T; always false 178 std::is_base_of<T, void>::value, 179 "Define BMCWEB_ENABLE_SSL to enable ssl support."); 180 return *this; 181 } 182 #endif 183 184 private: 185 std::shared_ptr<boost::asio::io_context> io; 186 #ifdef BMCWEB_ENABLE_SSL 187 uint16_t portUint = 443; 188 #else 189 uint16_t portUint = 80; 190 #endif 191 std::string bindaddrStr = "0.0.0.0"; 192 int socketFd = -1; 193 Router router; 194 195 #ifdef BMCWEB_ENABLE_SSL 196 std::unique_ptr<ssl_server_t> sslServer; 197 #else 198 std::unique_ptr<server_t> server; 199 #endif 200 }; 201 } // namespace crow 202 using App = crow::App; 203