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