blob: 1e5f985cc40d9435acc9b940eddd864f20aad83b [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
2
Tanousf00032d2018-11-05 01:18:10 -03003#include "privileges.hpp"
4
Ed Tanous7045c8d2017-04-03 10:04:37 -07005#include <chrono>
6#include <cstdint>
7#include <functional>
8#include <future>
9#include <memory>
10#include <string>
Ed Tanous911ac312017-08-15 09:37:42 -070011#include <utility>
Ed Tanous1abe55e2018-09-05 08:30:59 -070012
Ed Tanousc94ad492019-10-10 15:39:33 -070013#include "http_request.h"
14#include "http_server.h"
15#include "logging.h"
16#include "middleware_context.h"
17#include "routing.h"
18#include "utility.h"
Ed Tanous7045c8d2017-04-03 10:04:37 -070019
Ed Tanous1abe55e2018-09-05 08:30:59 -070020#define BMCWEB_ROUTE(app, url) \
21 app.template route<crow::black_magic::get_parameter_tag(url)>(url)
Ed Tanous7045c8d2017-04-03 10:04:37 -070022
Ed Tanous1abe55e2018-09-05 08:30:59 -070023namespace crow
24{
Ed Tanous55c7b7a2018-05-22 15:27:24 -070025#ifdef BMCWEB_ENABLE_SSL
Ed Tanous7045c8d2017-04-03 10:04:37 -070026using ssl_context_t = boost::asio::ssl::context;
27#endif
Ed Tanous1abe55e2018-09-05 08:30:59 -070028template <typename... Middlewares> class Crow
29{
30 public:
31 using self_t = Crow;
Ed Tanous789a6a32018-11-29 15:17:22 -080032
Ed Tanous55c7b7a2018-05-22 15:27:24 -070033#ifdef BMCWEB_ENABLE_SSL
Ed Tanousceac6f72018-12-02 11:58:47 -080034 using ssl_socket_t = boost::beast::ssl_stream<boost::asio::ip::tcp::socket>;
Ed Tanous789a6a32018-11-29 15:17:22 -080035 using ssl_server_t = Server<Crow, ssl_socket_t, Middlewares...>;
36#else
Ed Tanousceac6f72018-12-02 11:58:47 -080037 using socket_t = boost::asio::ip::tcp::socket;
Ed Tanous789a6a32018-11-29 15:17:22 -080038 using server_t = Server<Crow, socket_t, Middlewares...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -070039#endif
Ed Tanousceac6f72018-12-02 11:58:47 -080040
Ed Tanous271584a2019-07-09 16:24:22 -070041 explicit Crow(std::shared_ptr<boost::asio::io_context> ioIn =
Ed Tanous8f626352018-12-19 14:51:54 -080042 std::make_shared<boost::asio::io_context>()) :
Ed Tanous271584a2019-07-09 16:24:22 -070043 io(std::move(ioIn))
Ed Tanous7045c8d2017-04-03 10:04:37 -070044 {
Ed Tanous7045c8d2017-04-03 10:04:37 -070045 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070046 ~Crow()
47 {
48 this->stop();
49 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070050
Ed Tanous1abe55e2018-09-05 08:30:59 -070051 template <typename Adaptor>
52 void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
53 {
Ed Tanousceac6f72018-12-02 11:58:47 -080054 router.handleUpgrade(req, res, std::move(adaptor));
Ed Tanous1abe55e2018-09-05 08:30:59 -070055 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070056
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -060057 void handle(Request& req, Response& res)
Ed Tanous1abe55e2018-09-05 08:30:59 -070058 {
59 router.handle(req, res);
60 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070061
Ed Tanous1abe55e2018-09-05 08:30:59 -070062 DynamicRule& routeDynamic(std::string&& rule)
63 {
64 return router.newRuleDynamic(rule);
65 }
66
Brad Bishop4fa8b842018-11-21 08:09:28 -050067 template <uint64_t Tag> auto& route(std::string&& rule)
Ed Tanous1abe55e2018-09-05 08:30:59 -070068 {
69 return router.newRuleTagged<Tag>(std::move(rule));
70 }
71
72 self_t& socket(int existing_socket)
73 {
74 socketFd = existing_socket;
75 return *this;
76 }
77
78 self_t& port(std::uint16_t port)
79 {
80 portUint = port;
81 return *this;
82 }
83
84 self_t& bindaddr(std::string bindaddr)
85 {
86 bindaddrStr = bindaddr;
87 return *this;
88 }
89
90 void validate()
91 {
92 router.validate();
93 }
94
95 void run()
96 {
97 validate();
98#ifdef BMCWEB_ENABLE_SSL
Ed Tanous789a6a32018-11-29 15:17:22 -080099 if (-1 == socketFd)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700100 {
Ed Tanous789a6a32018-11-29 15:17:22 -0800101 sslServer = std::move(std::make_unique<ssl_server_t>(
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600102 this, bindaddrStr, portUint, sslContext, &middlewares, io));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700103 }
104 else
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105 {
Ed Tanous789a6a32018-11-29 15:17:22 -0800106 sslServer = std::move(std::make_unique<ssl_server_t>(
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600107 this, socketFd, sslContext, &middlewares, io));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700108 }
Ed Tanous789a6a32018-11-29 15:17:22 -0800109 sslServer->setTickFunction(tickInterval, tickFunction);
110 sslServer->run();
111
112#else
113
114 if (-1 == socketFd)
115 {
116 server = std::move(std::make_unique<server_t>(
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600117 this, bindaddrStr, portUint, nullptr, &middlewares, io));
Ed Tanous789a6a32018-11-29 15:17:22 -0800118 }
119 else
120 {
121 server = std::move(std::make_unique<server_t>(
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600122 this, socketFd, nullptr, &middlewares, io));
Ed Tanous789a6a32018-11-29 15:17:22 -0800123 }
124 server->setTickFunction(tickInterval, tickFunction);
125 server->run();
126
127#endif
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128 }
129
130 void stop()
131 {
132 io->stop();
133 }
134
135 void debugPrint()
136 {
137 BMCWEB_LOG_DEBUG << "Routing:";
138 router.debugPrint();
139 }
140
141 std::vector<const std::string*> getRoutes()
142 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700143 const std::string root("");
144 return router.getRoutes(root);
145 }
146 std::vector<const std::string*> getRoutes(const std::string& parent)
147 {
148 return router.getRoutes(parent);
149 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -0700150
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700151#ifdef BMCWEB_ENABLE_SSL
Ed Tanous1abe55e2018-09-05 08:30:59 -0700152 self_t& sslFile(const std::string& crt_filename,
153 const std::string& key_filename)
154 {
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600155 sslContext = std::make_shared<ssl_context_t>(
156 boost::asio::ssl::context::tls_server);
157 sslContext->set_verify_mode(boost::asio::ssl::verify_peer);
158 sslContext->use_certificate_file(crt_filename, ssl_context_t::pem);
159 sslContext->use_private_key_file(key_filename, ssl_context_t::pem);
160 sslContext->set_options(boost::asio::ssl::context::default_workarounds |
161 boost::asio::ssl::context::no_sslv2 |
162 boost::asio::ssl::context::no_sslv3 |
163 boost::asio::ssl::context::no_tlsv1 |
164 boost::asio::ssl::context::no_tlsv1_1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165 return *this;
166 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700167
Ed Tanous1abe55e2018-09-05 08:30:59 -0700168 self_t& sslFile(const std::string& pem_filename)
169 {
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600170 sslContext = std::make_shared<ssl_context_t>(
171 boost::asio::ssl::context::tls_server);
172 sslContext->set_verify_mode(boost::asio::ssl::verify_peer);
173 sslContext->load_verify_file(pem_filename);
174 sslContext->set_options(boost::asio::ssl::context::default_workarounds |
175 boost::asio::ssl::context::no_sslv2 |
176 boost::asio::ssl::context::no_sslv3 |
177 boost::asio::ssl::context::no_tlsv1 |
178 boost::asio::ssl::context::no_tlsv1_1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700179 return *this;
180 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700181
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600182 self_t& ssl(std::shared_ptr<boost::asio::ssl::context>&& ctx)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700183 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700184 sslContext = std::move(ctx);
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600185 BMCWEB_LOG_INFO << "app::ssl context use_count="
186 << sslContext.use_count();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700187 return *this;
188 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700189
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600190 std::shared_ptr<ssl_context_t> sslContext = nullptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700191
192#else
Ed Tanous1abe55e2018-09-05 08:30:59 -0700193 template <typename T, typename... Remain> self_t& ssl_file(T&&, Remain&&...)
194 {
195 // We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is
196 // defined.
197 static_assert(
198 // make static_assert dependent to T; always false
199 std::is_base_of<T, void>::value,
200 "Define BMCWEB_ENABLE_SSL to enable ssl support.");
201 return *this;
202 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700203
Ed Tanous1abe55e2018-09-05 08:30:59 -0700204 template <typename T> self_t& ssl(T&&)
205 {
206 // We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is
207 // defined.
208 static_assert(
209 // make static_assert dependent to T; always false
210 std::is_base_of<T, void>::value,
211 "Define BMCWEB_ENABLE_SSL to enable ssl support.");
212 return *this;
213 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700214#endif
215
Ed Tanous1abe55e2018-09-05 08:30:59 -0700216 // middleware
217 using context_t = detail::Context<Middlewares...>;
218 template <typename T> typename T::Context& getContext(const Request& req)
219 {
220 static_assert(black_magic::Contains<T, Middlewares...>::value,
221 "App doesn't have the specified middleware type.");
222 auto& ctx = *reinterpret_cast<context_t*>(req.middlewareContext);
223 return ctx.template get<T>();
224 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700225
Ed Tanous1abe55e2018-09-05 08:30:59 -0700226 template <typename T> T& getMiddleware()
227 {
228 return utility::getElementByType<T, Middlewares...>(middlewares);
229 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700230
Ed Tanous1abe55e2018-09-05 08:30:59 -0700231 template <typename Duration, typename Func> self_t& tick(Duration d, Func f)
232 {
233 tickInterval = std::chrono::duration_cast<std::chrono::milliseconds>(d);
234 tickFunction = f;
235 return *this;
236 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700237
Ed Tanous1abe55e2018-09-05 08:30:59 -0700238 private:
Ed Tanous8f626352018-12-19 14:51:54 -0800239 std::shared_ptr<asio::io_context> io;
Ed Tanous789a6a32018-11-29 15:17:22 -0800240#ifdef BMCWEB_ENABLE_SSL
241 uint16_t portUint = 443;
242#else
Ed Tanous1abe55e2018-09-05 08:30:59 -0700243 uint16_t portUint = 80;
Ed Tanous789a6a32018-11-29 15:17:22 -0800244#endif
Ed Tanous1abe55e2018-09-05 08:30:59 -0700245 std::string bindaddrStr = "::";
246 int socketFd = -1;
247 Router router;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700248
Ed Tanous1abe55e2018-09-05 08:30:59 -0700249 std::chrono::milliseconds tickInterval{};
250 std::function<void()> tickFunction;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700251
Ed Tanous1abe55e2018-09-05 08:30:59 -0700252 std::tuple<Middlewares...> middlewares;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700253
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700254#ifdef BMCWEB_ENABLE_SSL
Ed Tanous1abe55e2018-09-05 08:30:59 -0700255 std::unique_ptr<ssl_server_t> sslServer;
Ed Tanous789a6a32018-11-29 15:17:22 -0800256#else
Ed Tanous1abe55e2018-09-05 08:30:59 -0700257 std::unique_ptr<server_t> server;
Ed Tanous789a6a32018-11-29 15:17:22 -0800258#endif
Ed Tanous7045c8d2017-04-03 10:04:37 -0700259};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700260template <typename... Middlewares> using App = Crow<Middlewares...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700261using SimpleApp = Crow<>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700262} // namespace crow