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(Request& req, 62 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 63 Adaptor&& adaptor) 64 { 65 router.handleUpgrade(req, asyncResp, std::forward<Adaptor>(adaptor)); 66 } 67 68 void handle(Request& req, 69 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 70 { 71 router.handle(req, asyncResp); 72 } 73 74 DynamicRule& routeDynamic(std::string&& rule) 75 { 76 return router.newRuleDynamic(rule); 77 } 78 79 template <uint64_t Tag> 80 auto& route(std::string&& rule) 81 { 82 return router.newRuleTagged<Tag>(std::move(rule)); 83 } 84 85 App& socket(int existingSocket) 86 { 87 socketFd = existingSocket; 88 return *this; 89 } 90 91 App& port(std::uint16_t port) 92 { 93 portUint = port; 94 return *this; 95 } 96 97 App& bindaddr(std::string bindaddr) 98 { 99 bindaddrStr = std::move(bindaddr); 100 return *this; 101 } 102 103 void validate() 104 { 105 router.validate(); 106 } 107 108 void run() 109 { 110 validate(); 111 #ifdef BMCWEB_ENABLE_SSL 112 if (-1 == socketFd) 113 { 114 sslServer = std::make_unique<ssl_server_t>( 115 this, bindaddrStr, portUint, sslContext, io); 116 } 117 else 118 { 119 sslServer = 120 std::make_unique<ssl_server_t>(this, socketFd, sslContext, io); 121 } 122 sslServer->run(); 123 124 #else 125 126 if (-1 == socketFd) 127 { 128 server = std::make_unique<server_t>(this, bindaddrStr, portUint, 129 nullptr, io); 130 } 131 else 132 { 133 server = std::make_unique<server_t>(this, socketFd, nullptr, io); 134 } 135 server->run(); 136 137 #endif 138 } 139 140 void stop() 141 { 142 io->stop(); 143 } 144 145 void debugPrint() 146 { 147 BMCWEB_LOG_DEBUG << "Routing:"; 148 router.debugPrint(); 149 } 150 151 std::vector<const std::string*> getRoutes() 152 { 153 const std::string root; 154 return router.getRoutes(root); 155 } 156 std::vector<const std::string*> getRoutes(const std::string& parent) 157 { 158 return router.getRoutes(parent); 159 } 160 161 #ifdef BMCWEB_ENABLE_SSL 162 App& ssl(std::shared_ptr<boost::asio::ssl::context>&& ctx) 163 { 164 sslContext = std::move(ctx); 165 BMCWEB_LOG_INFO << "app::ssl context use_count=" 166 << sslContext.use_count(); 167 return *this; 168 } 169 170 std::shared_ptr<ssl_context_t> sslContext = nullptr; 171 172 #else 173 template <typename T> 174 App& ssl(T&&) 175 { 176 // We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is 177 // defined. 178 static_assert( 179 // make static_assert dependent to T; always false 180 std::is_base_of<T, void>::value, 181 "Define BMCWEB_ENABLE_SSL to enable ssl support."); 182 return *this; 183 } 184 #endif 185 186 private: 187 std::shared_ptr<boost::asio::io_context> io; 188 #ifdef BMCWEB_ENABLE_SSL 189 uint16_t portUint = 443; 190 #else 191 uint16_t portUint = 80; 192 #endif 193 std::string bindaddrStr = "0.0.0.0"; 194 int socketFd = -1; 195 Router router; 196 197 #ifdef BMCWEB_ENABLE_SSL 198 std::unique_ptr<ssl_server_t> sslServer; 199 #else 200 std::unique_ptr<server_t> server; 201 #endif 202 }; 203 } // namespace crow 204 using App = crow::App; 205