xref: /openbmc/bmcweb/http/app.hpp (revision 8b2521a5)
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(Request& req,
62                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
63                        Adaptor&& adaptor)
64     {
65         router.handleUpgrade(req, asyncResp, std::forward<Adaptor>(adaptor));
66     }
67 
68     void handle(Request& req,
69                 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
70     {
71         router.handle(req, asyncResp);
72     }
73 
74     DynamicRule& routeDynamic(std::string&& rule)
75     {
76         return router.newRuleDynamic(rule);
77     }
78 
79     template <uint64_t Tag>
80     auto& route(std::string&& rule)
81     {
82         return router.newRuleTagged<Tag>(std::move(rule));
83     }
84 
85     App& socket(int existingSocket)
86     {
87         socketFd = existingSocket;
88         return *this;
89     }
90 
91     App& port(std::uint16_t port)
92     {
93         portUint = port;
94         return *this;
95     }
96 
97     App& bindaddr(std::string bindaddr)
98     {
99         bindaddrStr = std::move(bindaddr);
100         return *this;
101     }
102 
103     void validate()
104     {
105         router.validate();
106     }
107 
108     void run()
109     {
110         validate();
111 #ifdef BMCWEB_ENABLE_SSL
112         if (-1 == socketFd)
113         {
114             sslServer = std::make_unique<ssl_server_t>(
115                 this, bindaddrStr, portUint, sslContext, io);
116         }
117         else
118         {
119             sslServer =
120                 std::make_unique<ssl_server_t>(this, socketFd, sslContext, io);
121         }
122         sslServer->run();
123 
124 #else
125 
126         if (-1 == socketFd)
127         {
128             server = std::make_unique<server_t>(this, bindaddrStr, portUint,
129                                                 nullptr, io);
130         }
131         else
132         {
133             server = std::make_unique<server_t>(this, socketFd, nullptr, io);
134         }
135         server->run();
136 
137 #endif
138     }
139 
140     void stop()
141     {
142         io->stop();
143     }
144 
145     void debugPrint()
146     {
147         BMCWEB_LOG_DEBUG << "Routing:";
148         router.debugPrint();
149     }
150 
151     std::vector<const std::string*> getRoutes()
152     {
153         const std::string root;
154         return router.getRoutes(root);
155     }
156     std::vector<const std::string*> getRoutes(const std::string& parent)
157     {
158         return router.getRoutes(parent);
159     }
160 
161 #ifdef BMCWEB_ENABLE_SSL
162     App& ssl(std::shared_ptr<boost::asio::ssl::context>&& ctx)
163     {
164         sslContext = std::move(ctx);
165         BMCWEB_LOG_INFO << "app::ssl context use_count="
166                         << sslContext.use_count();
167         return *this;
168     }
169 
170     std::shared_ptr<ssl_context_t> sslContext = nullptr;
171 
172 #else
173     template <typename T>
174     App& ssl(T&&)
175     {
176         // We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is
177         // defined.
178         static_assert(
179             // make static_assert dependent to T; always false
180             std::is_base_of<T, void>::value,
181             "Define BMCWEB_ENABLE_SSL to enable ssl support.");
182         return *this;
183     }
184 #endif
185 
186   private:
187     std::shared_ptr<boost::asio::io_context> io;
188 #ifdef BMCWEB_ENABLE_SSL
189     uint16_t portUint = 443;
190 #else
191     uint16_t portUint = 80;
192 #endif
193     std::string bindaddrStr = "0.0.0.0";
194     int socketFd = -1;
195     Router router;
196 
197 #ifdef BMCWEB_ENABLE_SSL
198     std::unique_ptr<ssl_server_t> sslServer;
199 #else
200     std::unique_ptr<server_t> server;
201 #endif
202 };
203 } // namespace crow
204 using App = crow::App;
205