blob: ca871dcead95602a5015f2c1e2aca501090bbf56 [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
2
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003#include "http_request.h"
4#include "http_server.h"
5#include "logging.h"
6#include "middleware_context.h"
7#include "routing.h"
8#include "utility.h"
9
Tanousf00032d2018-11-05 01:18:10 -030010#include "privileges.hpp"
11
Ed Tanous7045c8d2017-04-03 10:04:37 -070012#include <chrono>
13#include <cstdint>
14#include <functional>
15#include <future>
16#include <memory>
17#include <string>
Ed Tanous911ac312017-08-15 09:37:42 -070018#include <utility>
Ed Tanous1abe55e2018-09-05 08:30:59 -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
Gunnar Mills1214b7e2020-06-04 10:11:30 -050028template <typename... Middlewares>
29class Crow
Ed Tanous1abe55e2018-09-05 08:30:59 -070030{
31 public:
32 using self_t = Crow;
Ed Tanous789a6a32018-11-29 15:17:22 -080033
Ed Tanous55c7b7a2018-05-22 15:27:24 -070034#ifdef BMCWEB_ENABLE_SSL
Ed Tanousceac6f72018-12-02 11:58:47 -080035 using ssl_socket_t = boost::beast::ssl_stream<boost::asio::ip::tcp::socket>;
Ed Tanous789a6a32018-11-29 15:17:22 -080036 using ssl_server_t = Server<Crow, ssl_socket_t, Middlewares...>;
37#else
Ed Tanousceac6f72018-12-02 11:58:47 -080038 using socket_t = boost::asio::ip::tcp::socket;
Ed Tanous789a6a32018-11-29 15:17:22 -080039 using server_t = Server<Crow, socket_t, Middlewares...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -070040#endif
Ed Tanousceac6f72018-12-02 11:58:47 -080041
Ed Tanous271584a2019-07-09 16:24:22 -070042 explicit Crow(std::shared_ptr<boost::asio::io_context> ioIn =
Ed Tanous8f626352018-12-19 14:51:54 -080043 std::make_shared<boost::asio::io_context>()) :
Ed Tanous271584a2019-07-09 16:24:22 -070044 io(std::move(ioIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -050045 {}
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
Gunnar Mills1214b7e2020-06-04 10:11:30 -050067 template <uint64_t Tag>
68 auto& route(std::string&& rule)
Ed Tanous1abe55e2018-09-05 08:30:59 -070069 {
70 return router.newRuleTagged<Tag>(std::move(rule));
71 }
72
73 self_t& socket(int existing_socket)
74 {
75 socketFd = existing_socket;
76 return *this;
77 }
78
79 self_t& port(std::uint16_t port)
80 {
81 portUint = port;
82 return *this;
83 }
84
85 self_t& bindaddr(std::string bindaddr)
86 {
87 bindaddrStr = bindaddr;
88 return *this;
89 }
90
91 void validate()
92 {
93 router.validate();
94 }
95
96 void run()
97 {
98 validate();
99#ifdef BMCWEB_ENABLE_SSL
Ed Tanous789a6a32018-11-29 15:17:22 -0800100 if (-1 == socketFd)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700101 {
Ed Tanous789a6a32018-11-29 15:17:22 -0800102 sslServer = std::move(std::make_unique<ssl_server_t>(
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600103 this, bindaddrStr, portUint, sslContext, &middlewares, io));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700104 }
105 else
Ed Tanous1abe55e2018-09-05 08:30:59 -0700106 {
Ed Tanous789a6a32018-11-29 15:17:22 -0800107 sslServer = std::move(std::make_unique<ssl_server_t>(
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600108 this, socketFd, sslContext, &middlewares, io));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109 }
Ed Tanous789a6a32018-11-29 15:17:22 -0800110 sslServer->setTickFunction(tickInterval, tickFunction);
111 sslServer->run();
112
113#else
114
115 if (-1 == socketFd)
116 {
117 server = std::move(std::make_unique<server_t>(
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600118 this, bindaddrStr, portUint, nullptr, &middlewares, io));
Ed Tanous789a6a32018-11-29 15:17:22 -0800119 }
120 else
121 {
122 server = std::move(std::make_unique<server_t>(
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600123 this, socketFd, nullptr, &middlewares, io));
Ed Tanous789a6a32018-11-29 15:17:22 -0800124 }
125 server->setTickFunction(tickInterval, tickFunction);
126 server->run();
127
128#endif
Ed Tanous1abe55e2018-09-05 08:30:59 -0700129 }
130
131 void stop()
132 {
133 io->stop();
134 }
135
136 void debugPrint()
137 {
138 BMCWEB_LOG_DEBUG << "Routing:";
139 router.debugPrint();
140 }
141
142 std::vector<const std::string*> getRoutes()
143 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700144 const std::string root("");
145 return router.getRoutes(root);
146 }
147 std::vector<const std::string*> getRoutes(const std::string& parent)
148 {
149 return router.getRoutes(parent);
150 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -0700151
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700152#ifdef BMCWEB_ENABLE_SSL
Ed Tanous1abe55e2018-09-05 08:30:59 -0700153 self_t& sslFile(const std::string& crt_filename,
154 const std::string& key_filename)
155 {
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600156 sslContext = std::make_shared<ssl_context_t>(
157 boost::asio::ssl::context::tls_server);
158 sslContext->set_verify_mode(boost::asio::ssl::verify_peer);
159 sslContext->use_certificate_file(crt_filename, ssl_context_t::pem);
160 sslContext->use_private_key_file(key_filename, ssl_context_t::pem);
161 sslContext->set_options(boost::asio::ssl::context::default_workarounds |
162 boost::asio::ssl::context::no_sslv2 |
163 boost::asio::ssl::context::no_sslv3 |
164 boost::asio::ssl::context::no_tlsv1 |
165 boost::asio::ssl::context::no_tlsv1_1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700166 return *this;
167 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700168
Ed Tanous1abe55e2018-09-05 08:30:59 -0700169 self_t& sslFile(const std::string& pem_filename)
170 {
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600171 sslContext = std::make_shared<ssl_context_t>(
172 boost::asio::ssl::context::tls_server);
173 sslContext->set_verify_mode(boost::asio::ssl::verify_peer);
174 sslContext->load_verify_file(pem_filename);
175 sslContext->set_options(boost::asio::ssl::context::default_workarounds |
176 boost::asio::ssl::context::no_sslv2 |
177 boost::asio::ssl::context::no_sslv3 |
178 boost::asio::ssl::context::no_tlsv1 |
179 boost::asio::ssl::context::no_tlsv1_1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700180 return *this;
181 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700182
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600183 self_t& ssl(std::shared_ptr<boost::asio::ssl::context>&& ctx)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700184 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700185 sslContext = std::move(ctx);
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600186 BMCWEB_LOG_INFO << "app::ssl context use_count="
187 << sslContext.use_count();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700188 return *this;
189 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700190
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600191 std::shared_ptr<ssl_context_t> sslContext = nullptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700192
193#else
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500194 template <typename T, typename... Remain>
195 self_t& ssl_file(T&&, Remain&&...)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700196 {
197 // We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is
198 // defined.
199 static_assert(
200 // make static_assert dependent to T; always false
201 std::is_base_of<T, void>::value,
202 "Define BMCWEB_ENABLE_SSL to enable ssl support.");
203 return *this;
204 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700205
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500206 template <typename T>
207 self_t& ssl(T&&)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700208 {
209 // We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is
210 // defined.
211 static_assert(
212 // make static_assert dependent to T; always false
213 std::is_base_of<T, void>::value,
214 "Define BMCWEB_ENABLE_SSL to enable ssl support.");
215 return *this;
216 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700217#endif
218
Ed Tanous1abe55e2018-09-05 08:30:59 -0700219 // middleware
220 using context_t = detail::Context<Middlewares...>;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500221 template <typename T>
222 typename T::Context& getContext(const Request& req)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700223 {
224 static_assert(black_magic::Contains<T, Middlewares...>::value,
225 "App doesn't have the specified middleware type.");
226 auto& ctx = *reinterpret_cast<context_t*>(req.middlewareContext);
227 return ctx.template get<T>();
228 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700229
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500230 template <typename T>
231 T& getMiddleware()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700232 {
233 return utility::getElementByType<T, Middlewares...>(middlewares);
234 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700235
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500236 template <typename Duration, typename Func>
237 self_t& tick(Duration d, Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700238 {
239 tickInterval = std::chrono::duration_cast<std::chrono::milliseconds>(d);
240 tickFunction = f;
241 return *this;
242 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700243
Ed Tanous1abe55e2018-09-05 08:30:59 -0700244 private:
Ed Tanous8f626352018-12-19 14:51:54 -0800245 std::shared_ptr<asio::io_context> io;
Ed Tanous789a6a32018-11-29 15:17:22 -0800246#ifdef BMCWEB_ENABLE_SSL
247 uint16_t portUint = 443;
248#else
Ed Tanous1abe55e2018-09-05 08:30:59 -0700249 uint16_t portUint = 80;
Ed Tanous789a6a32018-11-29 15:17:22 -0800250#endif
Ed Tanous1abe55e2018-09-05 08:30:59 -0700251 std::string bindaddrStr = "::";
252 int socketFd = -1;
253 Router router;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700254
Ed Tanous1abe55e2018-09-05 08:30:59 -0700255 std::chrono::milliseconds tickInterval{};
256 std::function<void()> tickFunction;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700257
Ed Tanous1abe55e2018-09-05 08:30:59 -0700258 std::tuple<Middlewares...> middlewares;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700259
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700260#ifdef BMCWEB_ENABLE_SSL
Ed Tanous1abe55e2018-09-05 08:30:59 -0700261 std::unique_ptr<ssl_server_t> sslServer;
Ed Tanous789a6a32018-11-29 15:17:22 -0800262#else
Ed Tanous1abe55e2018-09-05 08:30:59 -0700263 std::unique_ptr<server_t> server;
Ed Tanous789a6a32018-11-29 15:17:22 -0800264#endif
Ed Tanous7045c8d2017-04-03 10:04:37 -0700265};
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500266template <typename... Middlewares>
267using App = Crow<Middlewares...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700268using SimpleApp = Crow<>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700269} // namespace crow