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