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