xref: /openbmc/bmcweb/http/app.hpp (revision ed76121b)
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::make_unique<server_t>(this, bindaddrStr, portUint,
127                                                 nullptr, io);
128         }
129         else
130         {
131             server = std::make_unique<server_t>(this, socketFd, nullptr, io);
132         }
133         server->run();
134 
135 #endif
136     }
137 
138     void stop()
139     {
140         io->stop();
141     }
142 
143     void debugPrint()
144     {
145         BMCWEB_LOG_DEBUG << "Routing:";
146         router.debugPrint();
147     }
148 
149     std::vector<const std::string*> getRoutes()
150     {
151         const std::string root;
152         return router.getRoutes(root);
153     }
154     std::vector<const std::string*> getRoutes(const std::string& parent)
155     {
156         return router.getRoutes(parent);
157     }
158 
159 #ifdef BMCWEB_ENABLE_SSL
160     App& ssl(std::shared_ptr<boost::asio::ssl::context>&& ctx)
161     {
162         sslContext = std::move(ctx);
163         BMCWEB_LOG_INFO << "app::ssl context use_count="
164                         << sslContext.use_count();
165         return *this;
166     }
167 
168     std::shared_ptr<ssl_context_t> sslContext = nullptr;
169 
170 #else
171     template <typename T>
172     App& ssl(T&&)
173     {
174         // We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is
175         // defined.
176         static_assert(
177             // make static_assert dependent to T; always false
178             std::is_base_of<T, void>::value,
179             "Define BMCWEB_ENABLE_SSL to enable ssl support.");
180         return *this;
181     }
182 #endif
183 
184   private:
185     std::shared_ptr<boost::asio::io_context> io;
186 #ifdef BMCWEB_ENABLE_SSL
187     uint16_t portUint = 443;
188 #else
189     uint16_t portUint = 80;
190 #endif
191     std::string bindaddrStr = "0.0.0.0";
192     int socketFd = -1;
193     Router router;
194 
195 #ifdef BMCWEB_ENABLE_SSL
196     std::unique_ptr<ssl_server_t> sslServer;
197 #else
198     std::unique_ptr<server_t> server;
199 #endif
200 };
201 } // namespace crow
202 using App = crow::App;
203