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