xref: /openbmc/bmcweb/http/app.hpp (revision 262d7d4b)
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 = "::";
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