xref: /openbmc/bmcweb/http/app.hpp (revision 9d424669)
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