blob: 9cd3d7b3f639ed841dacd1b7342dfc776cc1684e [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
2
Ed Tanous04e438c2020-10-03 08:06:26 -07003#include "common.hpp"
Ed Tanous168e20c2021-12-13 14:39:53 -08004#include "dbus_utility.hpp"
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06005#include "error_messages.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -07006#include "http_request.hpp"
7#include "http_response.hpp"
8#include "logging.hpp"
Tanousf00032d2018-11-05 01:18:10 -03009#include "privileges.hpp"
Ratan Gupta6f359562019-04-03 10:39:08 +053010#include "sessions.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -070011#include "utility.hpp"
12#include "websocket.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070013
Iwona Klimaszewskac0a1c8a2019-07-12 18:26:38 +020014#include <async_resp.hpp>
Tanousf00032d2018-11-05 01:18:10 -030015#include <boost/container/flat_map.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050016
Ed Tanouse0d918b2018-03-27 17:41:04 -070017#include <cerrno>
Ed Tanous7045c8d2017-04-03 10:04:37 -070018#include <cstdint>
Ed Tanouse0d918b2018-03-27 17:41:04 -070019#include <cstdlib>
Ed Tanous3dac7492017-08-02 13:46:20 -070020#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070021#include <memory>
22#include <tuple>
Ed Tanous7045c8d2017-04-03 10:04:37 -070023#include <utility>
24#include <vector>
Ed Tanous9140a672017-04-24 17:01:32 -070025
Ed Tanous1abe55e2018-09-05 08:30:59 -070026namespace crow
27{
Tanousf00032d2018-11-05 01:18:10 -030028
Ed Tanous1abe55e2018-09-05 08:30:59 -070029class BaseRule
30{
31 public:
Ed Tanousf23b7292020-10-15 09:41:17 -070032 BaseRule(const std::string& thisRule) : rule(thisRule)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050033 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070034
Ed Tanous0c0084a2019-10-24 15:57:51 -070035 virtual ~BaseRule() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -070036
Ed Tanousecd6a3a2022-01-07 09:18:40 -080037 BaseRule(const BaseRule&) = delete;
38 BaseRule(BaseRule&&) = delete;
39 BaseRule& operator=(const BaseRule&) = delete;
40 BaseRule& operator=(const BaseRule&&) = delete;
41
Ed Tanous1abe55e2018-09-05 08:30:59 -070042 virtual void validate() = 0;
43 std::unique_ptr<BaseRule> upgrade()
44 {
45 if (ruleToUpgrade)
Ed Tanous3174e4d2020-10-07 11:41:22 -070046 {
Ed Tanous1abe55e2018-09-05 08:30:59 -070047 return std::move(ruleToUpgrade);
Ed Tanous3174e4d2020-10-07 11:41:22 -070048 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070049 return {};
50 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070051
Ed Tanous104f09c2022-01-25 09:56:04 -080052 virtual void handle(const Request& /*req*/,
zhanghch058d1b46d2021-04-01 11:18:24 +080053 const std::shared_ptr<bmcweb::AsyncResp>&,
54 const RoutingParams&) = 0;
Ed Tanous104f09c2022-01-25 09:56:04 -080055 virtual void handleUpgrade(const Request& /*req*/, Response& res,
56 boost::asio::ip::tcp::socket&& /*adaptor*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -070057 {
Ed Tanousde5c9f32019-03-26 09:17:55 -070058 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070059 res.end();
60 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -070061#ifdef BMCWEB_ENABLE_SSL
Ed Tanous104f09c2022-01-25 09:56:04 -080062 virtual void handleUpgrade(
63 const Request& /*req*/, Response& res,
64 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&& /*adaptor*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -070065 {
Ed Tanousde5c9f32019-03-26 09:17:55 -070066 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 res.end();
68 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070069#endif
70
Ed Tanous271584a2019-07-09 16:24:22 -070071 size_t getMethods()
Ed Tanous1abe55e2018-09-05 08:30:59 -070072 {
73 return methodsBitfield;
74 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070075
Tanousf00032d2018-11-05 01:18:10 -030076 bool checkPrivileges(const redfish::Privileges& userPrivileges)
77 {
78 // If there are no privileges assigned, assume no privileges
79 // required
80 if (privilegesSet.empty())
81 {
82 return true;
83 }
84
85 for (const redfish::Privileges& requiredPrivileges : privilegesSet)
86 {
87 if (userPrivileges.isSupersetOf(requiredPrivileges))
88 {
89 return true;
90 }
91 }
92 return false;
93 }
94
Ed Tanous271584a2019-07-09 16:24:22 -070095 size_t methodsBitfield{
96 1 << static_cast<size_t>(boost::beast::http::verb::get)};
Ed Tanous7045c8d2017-04-03 10:04:37 -070097
Tanousf00032d2018-11-05 01:18:10 -030098 std::vector<redfish::Privileges> privilegesSet;
99
Ed Tanous1abe55e2018-09-05 08:30:59 -0700100 std::string rule;
101 std::string nameStr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700102
Ed Tanous1abe55e2018-09-05 08:30:59 -0700103 std::unique_ptr<BaseRule> ruleToUpgrade;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700104
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105 friend class Router;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500106 template <typename T>
107 friend struct RuleParameterTraits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700108};
109
Ed Tanous1abe55e2018-09-05 08:30:59 -0700110namespace detail
111{
112namespace routing_handler_call_helper
113{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500114template <typename T, int Pos>
115struct CallPair
Ed Tanous1abe55e2018-09-05 08:30:59 -0700116{
117 using type = T;
118 static const int pos = Pos;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700119};
120
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500121template <typename H1>
122struct CallParams
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123{
124 H1& handler;
125 const RoutingParams& params;
126 const Request& req;
zhanghch058d1b46d2021-04-01 11:18:24 +0800127 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700128};
129
130template <typename F, int NInt, int NUint, int NDouble, int NString,
131 typename S1, typename S2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700132struct Call
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500133{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700134
135template <typename F, int NInt, int NUint, int NDouble, int NString,
136 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700137struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<int64_t, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700138 black_magic::S<Args2...>>
139{
140 void operator()(F cparams)
141 {
142 using pushed = typename black_magic::S<Args2...>::template push_back<
143 CallPair<int64_t, NInt>>;
144 Call<F, NInt + 1, NUint, NDouble, NString, black_magic::S<Args1...>,
145 pushed>()(cparams);
146 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700147};
148
149template <typename F, int NInt, int NUint, int NDouble, int NString,
150 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700151struct Call<F, NInt, NUint, NDouble, NString,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700152 black_magic::S<uint64_t, Args1...>, black_magic::S<Args2...>>
153{
154 void operator()(F cparams)
155 {
156 using pushed = typename black_magic::S<Args2...>::template push_back<
157 CallPair<uint64_t, NUint>>;
158 Call<F, NInt, NUint + 1, NDouble, NString, black_magic::S<Args1...>,
159 pushed>()(cparams);
160 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700161};
162
163template <typename F, int NInt, int NUint, int NDouble, int NString,
164 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700165struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<double, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700166 black_magic::S<Args2...>>
167{
168 void operator()(F cparams)
169 {
170 using pushed = typename black_magic::S<Args2...>::template push_back<
171 CallPair<double, NDouble>>;
172 Call<F, NInt, NUint, NDouble + 1, NString, black_magic::S<Args1...>,
173 pushed>()(cparams);
174 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700175};
176
177template <typename F, int NInt, int NUint, int NDouble, int NString,
178 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700179struct Call<F, NInt, NUint, NDouble, NString,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700180 black_magic::S<std::string, Args1...>, black_magic::S<Args2...>>
181{
182 void operator()(F cparams)
183 {
184 using pushed = typename black_magic::S<Args2...>::template push_back<
185 CallPair<std::string, NString>>;
186 Call<F, NInt, NUint, NDouble, NString + 1, black_magic::S<Args1...>,
187 pushed>()(cparams);
188 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700189};
190
191template <typename F, int NInt, int NUint, int NDouble, int NString,
192 typename... Args1>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700193struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700194 black_magic::S<Args1...>>
195{
196 void operator()(F cparams)
197 {
198 cparams.handler(
zhanghch058d1b46d2021-04-01 11:18:24 +0800199 cparams.req, cparams.asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700200 cparams.params.template get<typename Args1::type>(Args1::pos)...);
201 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700202};
203
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500204template <typename Func, typename... ArgsWrapped>
205struct Wrapped
Ed Tanous1abe55e2018-09-05 08:30:59 -0700206{
207 template <typename... Args>
208 void set(
209 Func f,
210 typename std::enable_if<
211 !std::is_same<
212 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
213 const Request&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800214 int>::type /*enable*/
215 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700216 {
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800217 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800218 const Request&,
219 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
220 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700221 }
222
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500223 template <typename Req, typename... Args>
224 struct ReqHandlerWrapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700225 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000226 ReqHandlerWrapper(Func fIn) : f(std::move(fIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500227 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700228
zhanghch058d1b46d2021-04-01 11:18:24 +0800229 void operator()(const Request& req,
230 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
231 Args... args)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700232 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800233 asyncResp->res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700234 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700235
Ed Tanous1abe55e2018-09-05 08:30:59 -0700236 Func f;
237 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700238
Ed Tanous1abe55e2018-09-05 08:30:59 -0700239 template <typename... Args>
240 void set(
241 Func f,
242 typename std::enable_if<
243 std::is_same<
244 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
245 const Request&>::value &&
246 !std::is_same<typename std::tuple_element<
247 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800248 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800249 int>::type /*enable*/
250 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700251 {
252 handler = ReqHandlerWrapper<Args...>(std::move(f));
253 /*handler = (
254 [f = std::move(f)]
255 (const Request& req, Response& res, Args... args){
Ed Tanousde5c9f32019-03-26 09:17:55 -0700256 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700257 res.end();
258 });*/
259 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700260
Ed Tanous1abe55e2018-09-05 08:30:59 -0700261 template <typename... Args>
262 void set(
263 Func f,
264 typename std::enable_if<
265 std::is_same<
266 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
267 const Request&>::value &&
268 std::is_same<typename std::tuple_element<
269 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800270 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800271 int>::type /*enable*/
272 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700273 {
274 handler = std::move(f);
275 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700276
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500277 template <typename... Args>
278 struct HandlerTypeHelper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700279 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800280 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800281 const crow::Request& /*req*/,
282 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700283 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700284 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700285 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700286
Ed Tanous1abe55e2018-09-05 08:30:59 -0700287 template <typename... Args>
288 struct HandlerTypeHelper<const Request&, Args...>
289 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800290 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800291 const crow::Request& /*req*/,
292 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700293 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700294 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700295 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700296
Ed Tanous1abe55e2018-09-05 08:30:59 -0700297 template <typename... Args>
zhanghch058d1b46d2021-04-01 11:18:24 +0800298 struct HandlerTypeHelper<const Request&,
299 const std::shared_ptr<bmcweb::AsyncResp>&, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700300 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800301 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800302 const crow::Request& /*req*/,
303 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700304 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700305 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700306 };
307
308 typename HandlerTypeHelper<ArgsWrapped...>::type handler;
309
zhanghch058d1b46d2021-04-01 11:18:24 +0800310 void operator()(const Request& req,
311 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700312 const RoutingParams& params)
313 {
314 detail::routing_handler_call_helper::Call<
315 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
316 0, 0, 0, 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
317 black_magic::S<>>()(
318 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800319 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700320 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700321};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700322} // namespace routing_handler_call_helper
323} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700324
Ed Tanous1abe55e2018-09-05 08:30:59 -0700325class WebSocketRule : public BaseRule
326{
327 using self_t = WebSocketRule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700328
Ed Tanous1abe55e2018-09-05 08:30:59 -0700329 public:
Ed Tanousf23b7292020-10-15 09:41:17 -0700330 WebSocketRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500331 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700332
Ed Tanous1abe55e2018-09-05 08:30:59 -0700333 void validate() override
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500334 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700335
Ed Tanous104f09c2022-01-25 09:56:04 -0800336 void handle(const Request& /*req*/,
zhanghch058d1b46d2021-04-01 11:18:24 +0800337 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous104f09c2022-01-25 09:56:04 -0800338 const RoutingParams& /*params*/) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700339 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800340 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700341 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700342
Ed Tanous104f09c2022-01-25 09:56:04 -0800343 void handleUpgrade(const Request& req, Response& /*res*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800344 boost::asio::ip::tcp::socket&& adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700345 {
Ratan Gupta02453b12019-10-22 14:43:36 +0530346 std::shared_ptr<
347 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>
348 myConnection = std::make_shared<
349 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000350 req, std::move(adaptor), openHandler, messageHandler,
Ratan Gupta02453b12019-10-22 14:43:36 +0530351 closeHandler, errorHandler);
352 myConnection->start();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700353 }
354#ifdef BMCWEB_ENABLE_SSL
Ed Tanous104f09c2022-01-25 09:56:04 -0800355 void handleUpgrade(const Request& req, Response& /*res*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800356 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
357 adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700358 {
Ed Tanousceac6f72018-12-02 11:58:47 -0800359 std::shared_ptr<crow::websocket::ConnectionImpl<
360 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
361 myConnection = std::make_shared<crow::websocket::ConnectionImpl<
362 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000363 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanousceac6f72018-12-02 11:58:47 -0800364 closeHandler, errorHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700365 myConnection->start();
366 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700367#endif
368
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500369 template <typename Func>
370 self_t& onopen(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700371 {
372 openHandler = f;
373 return *this;
374 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700375
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500376 template <typename Func>
377 self_t& onmessage(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700378 {
379 messageHandler = f;
380 return *this;
381 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700382
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500383 template <typename Func>
384 self_t& onclose(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700385 {
386 closeHandler = f;
387 return *this;
388 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700389
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500390 template <typename Func>
391 self_t& onerror(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700392 {
393 errorHandler = f;
394 return *this;
395 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700396
Ed Tanous1abe55e2018-09-05 08:30:59 -0700397 protected:
Gunnar Millsccd584f2021-11-16 11:36:33 -0600398 std::function<void(crow::websocket::Connection&,
399 std::shared_ptr<bmcweb::AsyncResp>)>
400 openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700401 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
402 messageHandler;
403 std::function<void(crow::websocket::Connection&, const std::string&)>
404 closeHandler;
405 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700406};
407
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500408template <typename T>
409struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700410{
411 using self_t = T;
412 WebSocketRule& websocket()
413 {
Ed Tanous271584a2019-07-09 16:24:22 -0700414 self_t* self = static_cast<self_t*>(this);
415 WebSocketRule* p = new WebSocketRule(self->rule);
416 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700417 return *p;
418 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700419
Ed Tanousf23b7292020-10-15 09:41:17 -0700420 self_t& name(const std::string_view name) noexcept
Ed Tanous1abe55e2018-09-05 08:30:59 -0700421 {
Ed Tanous271584a2019-07-09 16:24:22 -0700422 self_t* self = static_cast<self_t*>(this);
Ed Tanousf23b7292020-10-15 09:41:17 -0700423 self->nameStr = name;
Ed Tanous271584a2019-07-09 16:24:22 -0700424 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700425 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700426
Ed Tanous1abe55e2018-09-05 08:30:59 -0700427 self_t& methods(boost::beast::http::verb method)
428 {
Ed Tanous271584a2019-07-09 16:24:22 -0700429 self_t* self = static_cast<self_t*>(this);
430 self->methodsBitfield = 1U << static_cast<size_t>(method);
431 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700432 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700433
Ed Tanous1abe55e2018-09-05 08:30:59 -0700434 template <typename... MethodArgs>
Ed Tanous81ce6092020-12-17 16:54:55 +0000435 self_t& methods(boost::beast::http::verb method, MethodArgs... argsMethod)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700436 {
Ed Tanous271584a2019-07-09 16:24:22 -0700437 self_t* self = static_cast<self_t*>(this);
Ed Tanous81ce6092020-12-17 16:54:55 +0000438 methods(argsMethod...);
Ed Tanous271584a2019-07-09 16:24:22 -0700439 self->methodsBitfield |= 1U << static_cast<size_t>(method);
440 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700441 }
Tanousf00032d2018-11-05 01:18:10 -0300442
Ed Tanous432a8902021-06-14 15:28:56 -0700443 self_t& privileges(
444 const std::initializer_list<std::initializer_list<const char*>>& p)
Tanousf00032d2018-11-05 01:18:10 -0300445 {
Ed Tanous271584a2019-07-09 16:24:22 -0700446 self_t* self = static_cast<self_t*>(this);
Ed Tanous432a8902021-06-14 15:28:56 -0700447 for (const std::initializer_list<const char*>& privilege : p)
Tanousf00032d2018-11-05 01:18:10 -0300448 {
Ed Tanous271584a2019-07-09 16:24:22 -0700449 self->privilegesSet.emplace_back(privilege);
Tanousf00032d2018-11-05 01:18:10 -0300450 }
Ed Tanous271584a2019-07-09 16:24:22 -0700451 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300452 }
Ed Tanoused398212021-06-09 17:05:54 -0700453
454 template <size_t N, typename... MethodArgs>
455 self_t& privileges(const std::array<redfish::Privileges, N>& p)
456 {
457 self_t* self = static_cast<self_t*>(this);
458 for (const redfish::Privileges& privilege : p)
459 {
460 self->privilegesSet.emplace_back(privilege);
461 }
462 return *self;
463 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700464};
465
Ed Tanous1abe55e2018-09-05 08:30:59 -0700466class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
467{
468 public:
Ed Tanousf23b7292020-10-15 09:41:17 -0700469 DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500470 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700471
Ed Tanous1abe55e2018-09-05 08:30:59 -0700472 void validate() override
473 {
474 if (!erasedHandler)
475 {
476 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
477 "no handler for url " + rule);
478 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700479 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700480
zhanghch058d1b46d2021-04-01 11:18:24 +0800481 void handle(const Request& req,
482 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700483 const RoutingParams& params) override
484 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800485 erasedHandler(req, asyncResp, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700486 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700487
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500488 template <typename Func>
489 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700490 {
491 using function_t = utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700492 erasedHandler =
Ed Tanous988403c2020-08-24 11:29:49 -0700493 wrap(std::move(f),
494 std::make_integer_sequence<unsigned, function_t::arity>{});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700495 }
496
497 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500498 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700499 // enable_if Arg1 != request
500
501 template <typename Func, unsigned... Indices>
zhanghch058d1b46d2021-04-01 11:18:24 +0800502 std::function<void(const Request&,
503 const std::shared_ptr<bmcweb::AsyncResp>&,
504 const RoutingParams&)>
Ed Tanous104f09c2022-01-25 09:56:04 -0800505 wrap(Func f, std::integer_sequence<unsigned, Indices...> /*is*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700506 {
Ed Tanous988403c2020-08-24 11:29:49 -0700507 using function_t = crow::utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700508
509 if (!black_magic::isParameterTagCompatible(
Ed Tanous988403c2020-08-24 11:29:49 -0700510 black_magic::getParameterTag(rule.c_str()),
511 black_magic::computeParameterTagFromArgsList<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700512 typename function_t::template arg<Indices>...>::value))
513 {
514 throw std::runtime_error("routeDynamic: Handler type is mismatched "
515 "with URL parameters: " +
516 rule);
517 }
518 auto ret = detail::routing_handler_call_helper::Wrapped<
519 Func, typename function_t::template arg<Indices>...>();
520 ret.template set<typename function_t::template arg<Indices>...>(
521 std::move(f));
522 return ret;
523 }
524
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500525 template <typename Func>
526 void operator()(std::string name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700527 {
528 nameStr = std::move(name);
529 (*this).template operator()<Func>(std::forward(f));
530 }
531
532 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800533 std::function<void(const Request&,
534 const std::shared_ptr<bmcweb::AsyncResp>&,
535 const RoutingParams&)>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700537};
538
539template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500540class TaggedRule :
541 public BaseRule,
542 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700543{
544 public:
545 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700546
Ed Tanousf23b7292020-10-15 09:41:17 -0700547 TaggedRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500548 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700549
Ed Tanous1abe55e2018-09-05 08:30:59 -0700550 void validate() override
551 {
552 if (!handler)
553 {
554 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
555 "no handler for url " + rule);
556 }
557 }
558
559 template <typename Func>
560 typename std::enable_if<
561 black_magic::CallHelper<Func, black_magic::S<Args...>>::value,
562 void>::type
563 operator()(Func&& f)
564 {
565 static_assert(
566 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
567 black_magic::CallHelper<
568 Func, black_magic::S<crow::Request, Args...>>::value,
569 "Handler type is mismatched with URL parameters");
570 static_assert(
571 !std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
572 "Handler function cannot have void return type; valid return "
573 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500574 "string, int, crow::response, nlohmann::json");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700575
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800576 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800577 const Request&,
578 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
579 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700580 }
581
582 template <typename Func>
583 typename std::enable_if<
584 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
Ed Tanous7045c8d2017-04-03 10:04:37 -0700585 black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700586 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700587 void>::type
588 operator()(Func&& f)
589 {
590 static_assert(
591 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
592 black_magic::CallHelper<
593 Func, black_magic::S<crow::Request, Args...>>::value,
594 "Handler type is mismatched with URL parameters");
595 static_assert(
596 !std::is_same<void, decltype(f(std::declval<crow::Request>(),
597 std::declval<Args>()...))>::value,
598 "Handler function cannot have void return type; valid return "
599 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500600 "string, int, crow::response,nlohmann::json");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700601
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800602 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800603 const crow::Request& req,
604 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
605 Args... args) { asyncResp->res.result(f(req, args...)); };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700606 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700607
Ed Tanous1abe55e2018-09-05 08:30:59 -0700608 template <typename Func>
609 typename std::enable_if<
610 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
611 !black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700612 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700613 void>::type
614 operator()(Func&& f)
615 {
616 static_assert(
617 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
618 black_magic::CallHelper<
619 Func, black_magic::S<crow::Request, Args...>>::value ||
620 black_magic::CallHelper<
zhanghch058d1b46d2021-04-01 11:18:24 +0800621 Func, black_magic::S<crow::Request,
622 std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700623 Args...>>::value,
624 "Handler type is mismatched with URL parameters");
625 static_assert(
zhanghch058d1b46d2021-04-01 11:18:24 +0800626 std::is_same<
627 void,
628 decltype(f(std::declval<crow::Request>(),
629 std::declval<std::shared_ptr<bmcweb::AsyncResp>&>(),
630 std::declval<Args>()...))>::value,
Tanousf00032d2018-11-05 01:18:10 -0300631 "Handler function with response argument should have void "
632 "return "
Ed Tanous1abe55e2018-09-05 08:30:59 -0700633 "type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700634
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800635 handler = std::forward<Func>(f);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700637
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500638 template <typename Func>
Ed Tanousf23b7292020-10-15 09:41:17 -0700639 void operator()(const std::string_view name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700640 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700641 nameStr = name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700642 (*this).template operator()<Func>(std::forward(f));
643 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700644
zhanghch058d1b46d2021-04-01 11:18:24 +0800645 void handle(const Request& req,
646 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700647 const RoutingParams& params) override
648 {
649 detail::routing_handler_call_helper::Call<
650 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
651 0, 0, 0, 0, black_magic::S<Args...>, black_magic::S<>>()(
652 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800653 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700654 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700655
Ed Tanous1abe55e2018-09-05 08:30:59 -0700656 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800657 std::function<void(const crow::Request&,
658 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>
659 handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700660};
661
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700662const int ruleSpecialRedirectSlash = 1;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700663
Ed Tanous1abe55e2018-09-05 08:30:59 -0700664class Trie
665{
666 public:
667 struct Node
668 {
669 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700670 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
671 paramChildrens{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700672 boost::container::flat_map<std::string, unsigned> children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700673
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 bool isSimpleNode() const
675 {
676 return !ruleIndex && std::all_of(std::begin(paramChildrens),
677 std::end(paramChildrens),
Ed Tanous271584a2019-07-09 16:24:22 -0700678 [](size_t x) { return !x; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700679 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700680 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700681
Ed Tanous1abe55e2018-09-05 08:30:59 -0700682 Trie() : nodes(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500683 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700684
685 private:
686 void optimizeNode(Node* node)
687 {
Ed Tanous271584a2019-07-09 16:24:22 -0700688 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700689 {
690 if (!x)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700691 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 continue;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700693 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700694 Node* child = &nodes[x];
695 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700696 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700697 if (node->children.empty())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700698 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700699 return;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700700 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700701 bool mergeWithChild = true;
Tanousf00032d2018-11-05 01:18:10 -0300702 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700703 {
704 Node* child = &nodes[kv.second];
705 if (!child->isSimpleNode())
706 {
707 mergeWithChild = false;
708 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700709 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700710 }
711 if (mergeWithChild)
712 {
713 decltype(node->children) merged;
Tanousf00032d2018-11-05 01:18:10 -0300714 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700715 {
716 Node* child = &nodes[kv.second];
Tanousf00032d2018-11-05 01:18:10 -0300717 for (const std::pair<std::string, unsigned>& childKv :
718 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700719 {
720 merged[kv.first + childKv.first] = childKv.second;
721 }
722 }
723 node->children = std::move(merged);
724 optimizeNode(node);
725 }
726 else
727 {
Tanousf00032d2018-11-05 01:18:10 -0300728 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 {
730 Node* child = &nodes[kv.second];
731 optimizeNode(child);
732 }
733 }
734 }
735
736 void optimize()
737 {
738 optimizeNode(head());
739 }
740
741 public:
742 void validate()
743 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700744 optimize();
745 }
746
Ed Tanous81ce6092020-12-17 16:54:55 +0000747 void findRouteIndexes(const std::string& reqUrl,
748 std::vector<unsigned>& routeIndexes,
Tanousf00032d2018-11-05 01:18:10 -0300749 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700750 {
751 if (node == nullptr)
752 {
753 node = head();
754 }
Tanousf00032d2018-11-05 01:18:10 -0300755 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 {
757 const std::string& fragment = kv.first;
758 const Node* child = &nodes[kv.second];
Ed Tanous81ce6092020-12-17 16:54:55 +0000759 if (pos >= reqUrl.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700760 {
761 if (child->ruleIndex != 0 && fragment != "/")
762 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000763 routeIndexes.push_back(child->ruleIndex);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000765 findRouteIndexes(reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700766 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700767 }
768 else
769 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000770 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700771 {
Ed Tanous271584a2019-07-09 16:24:22 -0700772 findRouteIndexes(
Ed Tanous81ce6092020-12-17 16:54:55 +0000773 reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700774 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700775 }
776 }
777 }
778 }
779
780 std::pair<unsigned, RoutingParams>
Ed Tanous81ce6092020-12-17 16:54:55 +0000781 find(const std::string_view reqUrl, const Node* node = nullptr,
Ed Tanous271584a2019-07-09 16:24:22 -0700782 size_t pos = 0, RoutingParams* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700783 {
784 RoutingParams empty;
785 if (params == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700786 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 params = &empty;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700788 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789
790 unsigned found{};
791 RoutingParams matchParams;
792
793 if (node == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700794 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700795 node = head();
Ed Tanous3174e4d2020-10-07 11:41:22 -0700796 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000797 if (pos == reqUrl.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700798 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700799 return {node->ruleIndex, *params};
Ed Tanous3174e4d2020-10-07 11:41:22 -0700800 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801
802 auto updateFound =
803 [&found, &matchParams](std::pair<unsigned, RoutingParams>& ret) {
804 if (ret.first && (!found || found > ret.first))
805 {
806 found = ret.first;
807 matchParams = std::move(ret.second);
808 }
809 };
810
Ed Tanous271584a2019-07-09 16:24:22 -0700811 if (node->paramChildrens[static_cast<size_t>(ParamType::INT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700812 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000813 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700814 if ((c >= '0' && c <= '9') || c == '+' || c == '-')
815 {
Ed Tanous543f4402022-01-06 13:12:53 -0800816 char* eptr = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700817 errno = 0;
818 long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000819 std::strtoll(reqUrl.data() + pos, &eptr, 10);
820 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700821 {
822 params->intParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000823 std::pair<unsigned, RoutingParams> ret =
824 find(reqUrl,
825 &nodes[node->paramChildrens[static_cast<size_t>(
826 ParamType::INT)]],
827 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828 updateFound(ret);
829 params->intParams.pop_back();
830 }
831 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700832 }
833
Ed Tanous271584a2019-07-09 16:24:22 -0700834 if (node->paramChildrens[static_cast<size_t>(ParamType::UINT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700835 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000836 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700837 if ((c >= '0' && c <= '9') || c == '+')
838 {
Ed Tanous543f4402022-01-06 13:12:53 -0800839 char* eptr = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700840 errno = 0;
841 unsigned long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000842 std::strtoull(reqUrl.data() + pos, &eptr, 10);
843 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700844 {
845 params->uintParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000846 std::pair<unsigned, RoutingParams> ret =
847 find(reqUrl,
848 &nodes[node->paramChildrens[static_cast<size_t>(
849 ParamType::UINT)]],
850 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 updateFound(ret);
852 params->uintParams.pop_back();
853 }
854 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700855 }
856
Ed Tanous271584a2019-07-09 16:24:22 -0700857 if (node->paramChildrens[static_cast<size_t>(ParamType::DOUBLE)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700858 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000859 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700860 if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
861 {
Ed Tanous543f4402022-01-06 13:12:53 -0800862 char* eptr = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700863 errno = 0;
Ed Tanous81ce6092020-12-17 16:54:55 +0000864 double value = std::strtod(reqUrl.data() + pos, &eptr);
865 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700866 {
867 params->doubleParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000868 std::pair<unsigned, RoutingParams> ret =
869 find(reqUrl,
870 &nodes[node->paramChildrens[static_cast<size_t>(
871 ParamType::DOUBLE)]],
872 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700873 updateFound(ret);
874 params->doubleParams.pop_back();
875 }
876 }
877 }
878
Ed Tanous271584a2019-07-09 16:24:22 -0700879 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700880 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000881 size_t epos = pos;
Ed Tanous81ce6092020-12-17 16:54:55 +0000882 for (; epos < reqUrl.size(); epos++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700883 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000884 if (reqUrl[epos] == '/')
Ed Tanous3174e4d2020-10-07 11:41:22 -0700885 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886 break;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700887 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700888 }
889
890 if (epos != pos)
891 {
892 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000893 reqUrl.substr(pos, epos - pos));
Tanousf00032d2018-11-05 01:18:10 -0300894 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000895 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700896 &nodes[node->paramChildrens[static_cast<size_t>(
897 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000898 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700899 updateFound(ret);
900 params->stringParams.pop_back();
901 }
902 }
903
Ed Tanous271584a2019-07-09 16:24:22 -0700904 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700905 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000906 size_t epos = reqUrl.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700907
908 if (epos != pos)
909 {
910 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000911 reqUrl.substr(pos, epos - pos));
Ed Tanous271584a2019-07-09 16:24:22 -0700912 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000913 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700914 &nodes[node->paramChildrens[static_cast<size_t>(
915 ParamType::PATH)]],
916 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700917 updateFound(ret);
918 params->stringParams.pop_back();
919 }
920 }
921
Tanousf00032d2018-11-05 01:18:10 -0300922 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700923 {
924 const std::string& fragment = kv.first;
925 const Node* child = &nodes[kv.second];
926
Ed Tanous81ce6092020-12-17 16:54:55 +0000927 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700928 {
Tanousf00032d2018-11-05 01:18:10 -0300929 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000930 find(reqUrl, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700931 updateFound(ret);
932 }
933 }
934
935 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700936 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700937
938 void add(const std::string& url, unsigned ruleIndex)
939 {
Ed Tanous271584a2019-07-09 16:24:22 -0700940 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700941
942 for (unsigned i = 0; i < url.size(); i++)
943 {
944 char c = url[i];
945 if (c == '<')
946 {
Tanousf00032d2018-11-05 01:18:10 -0300947 const static std::array<std::pair<ParamType, std::string>, 7>
948 paramTraits = {{
949 {ParamType::INT, "<int>"},
950 {ParamType::UINT, "<uint>"},
951 {ParamType::DOUBLE, "<float>"},
952 {ParamType::DOUBLE, "<double>"},
953 {ParamType::STRING, "<str>"},
954 {ParamType::STRING, "<string>"},
955 {ParamType::PATH, "<path>"},
956 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700957
Tanousf00032d2018-11-05 01:18:10 -0300958 for (const std::pair<ParamType, std::string>& x : paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700959 {
Tanousf00032d2018-11-05 01:18:10 -0300960 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700961 {
Ed Tanous271584a2019-07-09 16:24:22 -0700962 size_t index = static_cast<size_t>(x.first);
963 if (!nodes[idx].paramChildrens[index])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700964 {
Tanousf00032d2018-11-05 01:18:10 -0300965 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700966 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700967 }
Ed Tanous271584a2019-07-09 16:24:22 -0700968 idx = nodes[idx].paramChildrens[index];
969 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700970 break;
971 }
972 }
973
974 i--;
975 }
976 else
977 {
978 std::string piece(&c, 1);
979 if (!nodes[idx].children.count(piece))
980 {
Tanousf00032d2018-11-05 01:18:10 -0300981 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700982 nodes[idx].children.emplace(piece, newNodeIdx);
983 }
984 idx = nodes[idx].children[piece];
985 }
986 }
987 if (nodes[idx].ruleIndex)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700988 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700989 throw std::runtime_error("handler already exists for " + url);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700990 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700991 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700992 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700993
Ed Tanous1abe55e2018-09-05 08:30:59 -0700994 private:
Ed Tanous271584a2019-07-09 16:24:22 -0700995 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700996 {
Ed Tanous271584a2019-07-09 16:24:22 -0700997 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700998 {
999 if (n->paramChildrens[i])
1000 {
1001 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -07001002 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
1003 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001004 {
1005 case ParamType::INT:
1006 BMCWEB_LOG_DEBUG << "<int>";
1007 break;
1008 case ParamType::UINT:
1009 BMCWEB_LOG_DEBUG << "<uint>";
1010 break;
1011 case ParamType::DOUBLE:
1012 BMCWEB_LOG_DEBUG << "<float>";
1013 break;
1014 case ParamType::STRING:
1015 BMCWEB_LOG_DEBUG << "<str>";
1016 break;
1017 case ParamType::PATH:
1018 BMCWEB_LOG_DEBUG << "<path>";
1019 break;
Ed Tanous23a21a12020-07-25 04:45:05 +00001020 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -07001021 BMCWEB_LOG_DEBUG << "<ERROR>";
1022 break;
1023 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001024
Ed Tanous1abe55e2018-09-05 08:30:59 -07001025 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
1026 }
1027 }
Tanousf00032d2018-11-05 01:18:10 -03001028 for (const std::pair<std::string, unsigned>& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001029 {
1030 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -07001031 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -07001032 << kv.first;
1033 debugNodePrint(&nodes[kv.second], level + 1);
1034 }
1035 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001036
Ed Tanous1abe55e2018-09-05 08:30:59 -07001037 public:
1038 void debugPrint()
1039 {
Ed Tanous271584a2019-07-09 16:24:22 -07001040 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001041 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001042
Ed Tanous1abe55e2018-09-05 08:30:59 -07001043 private:
1044 const Node* head() const
1045 {
1046 return &nodes.front();
1047 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001048
Ed Tanous1abe55e2018-09-05 08:30:59 -07001049 Node* head()
1050 {
1051 return &nodes.front();
1052 }
1053
1054 unsigned newNode()
1055 {
1056 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -07001057 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001058 }
1059
1060 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001061};
1062
Ed Tanous1abe55e2018-09-05 08:30:59 -07001063class Router
1064{
1065 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -07001066 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001067
Ed Tanous1abe55e2018-09-05 08:30:59 -07001068 DynamicRule& newRuleDynamic(const std::string& rule)
1069 {
1070 std::unique_ptr<DynamicRule> ruleObject =
1071 std::make_unique<DynamicRule>(rule);
1072 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001073 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -07001074
Ed Tanous1abe55e2018-09-05 08:30:59 -07001075 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001076 }
1077
Ed Tanous1abe55e2018-09-05 08:30:59 -07001078 template <uint64_t N>
1079 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
1080 newRuleTagged(const std::string& rule)
1081 {
1082 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
1083 TaggedRule>;
1084 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
1085 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001086 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001087
1088 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001089 }
1090
Tanousf00032d2018-11-05 01:18:10 -03001091 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001092 {
Tanousf00032d2018-11-05 01:18:10 -03001093 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001094 {
Tanousf00032d2018-11-05 01:18:10 -03001095 return;
1096 }
Ed Tanous888880a2020-08-24 13:48:50 -07001097 for (size_t method = 0, methodBit = 1; method < maxHttpVerbCount;
Ed Tanous2c70f802020-09-28 14:29:23 -07001098 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -03001099 {
Ed Tanous2c70f802020-09-28 14:29:23 -07001100 if (ruleObject->methodsBitfield & methodBit)
Tanousf00032d2018-11-05 01:18:10 -03001101 {
1102 perMethods[method].rules.emplace_back(ruleObject);
1103 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -07001104 rule, static_cast<unsigned>(
1105 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -03001106 // directory case:
1107 // request to `/about' url matches `/about/' rule
1108 if (rule.size() > 2 && rule.back() == '/')
1109 {
1110 perMethods[method].trie.add(
1111 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -07001112 static_cast<unsigned>(perMethods[method].rules.size() -
1113 1));
Tanousf00032d2018-11-05 01:18:10 -03001114 }
1115 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001116 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001117 }
1118
Ed Tanous1abe55e2018-09-05 08:30:59 -07001119 void validate()
1120 {
Tanousf00032d2018-11-05 01:18:10 -03001121 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001122 {
1123 if (rule)
1124 {
Tanousf00032d2018-11-05 01:18:10 -03001125 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001126 if (upgraded)
Ed Tanous3174e4d2020-10-07 11:41:22 -07001127 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001128 rule = std::move(upgraded);
Ed Tanous3174e4d2020-10-07 11:41:22 -07001129 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001130 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -03001131 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001132 }
1133 }
Tanousf00032d2018-11-05 01:18:10 -03001134 for (PerMethod& perMethod : perMethods)
1135 {
1136 perMethod.trie.validate();
1137 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001138 }
1139
Ed Tanous1abe55e2018-09-05 08:30:59 -07001140 template <typename Adaptor>
1141 void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
1142 {
Ed Tanous271584a2019-07-09 16:24:22 -07001143 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001144 {
1145 res.result(boost::beast::http::status::not_found);
1146 res.end();
Tanousf00032d2018-11-05 01:18:10 -03001147 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001148 }
Tanousf00032d2018-11-05 01:18:10 -03001149
Ed Tanous271584a2019-07-09 16:24:22 -07001150 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001151 Trie& trie = perMethod.trie;
1152 std::vector<BaseRule*>& rules = perMethod.rules;
1153
1154 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001155 unsigned ruleIndex = found.first;
1156 if (!ruleIndex)
1157 {
1158 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001159 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001160 res.end();
1161 return;
1162 }
1163
1164 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001165 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001166 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001167 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001168
1169 if (ruleIndex == ruleSpecialRedirectSlash)
1170 {
1171 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1172 << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001173 res.result(boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001174
1175 // TODO absolute url building
1176 if (req.getHeaderValue("Host").empty())
1177 {
1178 res.addHeader("Location", std::string(req.url) + "/");
1179 }
1180 else
1181 {
1182 res.addHeader(
1183 "Location",
1184 req.isSecure
1185 ? "https://"
1186 : "http://" + std::string(req.getHeaderValue("Host")) +
1187 std::string(req.url) + "/");
1188 }
1189 res.end();
1190 return;
1191 }
1192
Ed Tanous271584a2019-07-09 16:24:22 -07001193 if ((rules[ruleIndex]->getMethods() &
1194 (1U << static_cast<size_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001195 {
1196 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1197 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001198 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001199 << rules[ruleIndex]->getMethods();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001200 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001201 res.end();
1202 return;
1203 }
1204
1205 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rules[ruleIndex]->rule
Ed Tanous271584a2019-07-09 16:24:22 -07001206 << "' " << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001207 << rules[ruleIndex]->getMethods();
1208
1209 // any uncaught exceptions become 500s
1210 try
1211 {
Ed Tanousf94c4ec2022-01-06 12:44:41 -08001212 rules[ruleIndex]->handleUpgrade(req, res,
1213 std::forward<Adaptor>(adaptor));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001214 }
Patrick Williamsc5967042021-10-06 12:39:54 -05001215 catch (const std::exception& e)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001216 {
1217 BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001218 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001219 res.end();
1220 return;
1221 }
1222 catch (...)
1223 {
1224 BMCWEB_LOG_ERROR
1225 << "An uncaught exception occurred. The type was unknown "
1226 "so no information was available.";
Ed Tanousde5c9f32019-03-26 09:17:55 -07001227 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001228 res.end();
1229 return;
1230 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001231 }
1232
zhanghch058d1b46d2021-04-01 11:18:24 +08001233 void handle(Request& req,
1234 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001235 {
Ed Tanous271584a2019-07-09 16:24:22 -07001236 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001237 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001238 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001239 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001240 }
Ed Tanous271584a2019-07-09 16:24:22 -07001241 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001242 Trie& trie = perMethod.trie;
1243 std::vector<BaseRule*>& rules = perMethod.rules;
1244
1245 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001246
Ed Tanous1abe55e2018-09-05 08:30:59 -07001247 unsigned ruleIndex = found.first;
1248
1249 if (!ruleIndex)
1250 {
Ed Tanous2634dcd2019-03-26 09:28:06 -07001251 // Check to see if this url exists at any verb
1252 for (const PerMethod& p : perMethods)
1253 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001254 const std::pair<unsigned, RoutingParams>& found2 =
Ed Tanous2634dcd2019-03-26 09:28:06 -07001255 p.trie.find(req.url);
Ed Tanous23a21a12020-07-25 04:45:05 +00001256 if (found2.first > 0)
Ed Tanous2634dcd2019-03-26 09:28:06 -07001257 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001258 asyncResp->res.result(
1259 boost::beast::http::status::method_not_allowed);
Ed Tanous2634dcd2019-03-26 09:28:06 -07001260 return;
1261 }
1262 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001263 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
zhanghch058d1b46d2021-04-01 11:18:24 +08001264 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001265 return;
1266 }
1267
1268 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001269 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001270 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001271 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001272
1273 if (ruleIndex == ruleSpecialRedirectSlash)
1274 {
1275 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1276 << req.url;
zhanghch058d1b46d2021-04-01 11:18:24 +08001277 asyncResp->res.result(
1278 boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001279
1280 // TODO absolute url building
1281 if (req.getHeaderValue("Host").empty())
1282 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001283 asyncResp->res.addHeader("Location",
1284 std::string(req.url) + "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001285 }
1286 else
1287 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001288 asyncResp->res.addHeader(
1289 "Location", (req.isSecure ? "https://" : "http://") +
1290 std::string(req.getHeaderValue("Host")) +
1291 std::string(req.url) + "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001292 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001293 return;
1294 }
1295
Ed Tanous271584a2019-07-09 16:24:22 -07001296 if ((rules[ruleIndex]->getMethods() &
1297 (1U << static_cast<uint32_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001298 {
1299 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1300 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001301 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001302 << rules[ruleIndex]->getMethods();
zhanghch058d1b46d2021-04-01 11:18:24 +08001303 asyncResp->res.result(
1304 boost::beast::http::status::method_not_allowed);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001305 return;
1306 }
1307
1308 BMCWEB_LOG_DEBUG << "Matched rule '" << rules[ruleIndex]->rule << "' "
Ed Tanous271584a2019-07-09 16:24:22 -07001309 << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001310 << rules[ruleIndex]->getMethods();
1311
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001312 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001313 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001314 rules[ruleIndex]->handle(req, asyncResp, found.second);
James Feist7166bf02019-12-10 16:52:14 +00001315 return;
1316 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001317
1318 crow::connections::systemBus->async_method_call(
Ed Tanous168e20c2021-12-13 14:39:53 -08001319 [&req, asyncResp, &rules, ruleIndex,
1320 found](const boost::system::error_code ec,
1321 const std::map<std::string, dbus::utility::DbusVariantType>&
1322 userInfo) {
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001323 if (ec)
1324 {
1325 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
zhanghch058d1b46d2021-04-01 11:18:24 +08001326 asyncResp->res.result(
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001327 boost::beast::http::status::internal_server_error);
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001328 return;
1329 }
1330
1331 const std::string* userRolePtr = nullptr;
1332 auto userInfoIter = userInfo.find("UserPrivilege");
1333 if (userInfoIter != userInfo.end())
1334 {
1335 userRolePtr =
1336 std::get_if<std::string>(&userInfoIter->second);
1337 }
1338
1339 std::string userRole{};
1340 if (userRolePtr != nullptr)
1341 {
1342 userRole = *userRolePtr;
1343 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1344 << " userRole = " << *userRolePtr;
1345 }
1346
Ed Tanous5dc924d2021-12-20 09:17:28 -08001347 const bool* remoteUserPtr = nullptr;
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001348 auto remoteUserIter = userInfo.find("RemoteUser");
1349 if (remoteUserIter != userInfo.end())
1350 {
1351 remoteUserPtr = std::get_if<bool>(&remoteUserIter->second);
1352 }
1353 if (remoteUserPtr == nullptr)
1354 {
1355 BMCWEB_LOG_ERROR
1356 << "RemoteUser property missing or wrong type";
zhanghch058d1b46d2021-04-01 11:18:24 +08001357 asyncResp->res.result(
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001358 boost::beast::http::status::internal_server_error);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001359 return;
1360 }
1361 bool remoteUser = *remoteUserPtr;
1362
1363 bool passwordExpired = false; // default for remote user
1364 if (!remoteUser)
1365 {
Ed Tanous5dc924d2021-12-20 09:17:28 -08001366 const bool* passwordExpiredPtr = nullptr;
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001367 auto passwordExpiredIter =
1368 userInfo.find("UserPasswordExpired");
1369 if (passwordExpiredIter != userInfo.end())
1370 {
1371 passwordExpiredPtr =
1372 std::get_if<bool>(&passwordExpiredIter->second);
1373 }
1374 if (passwordExpiredPtr != nullptr)
1375 {
1376 passwordExpired = *passwordExpiredPtr;
1377 }
1378 else
1379 {
1380 BMCWEB_LOG_ERROR
1381 << "UserPasswordExpired property is expected for"
1382 " local user but is missing or wrong type";
zhanghch058d1b46d2021-04-01 11:18:24 +08001383 asyncResp->res.result(
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001384 boost::beast::http::status::internal_server_error);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001385 return;
1386 }
1387 }
1388
Ed Tanous23a21a12020-07-25 04:45:05 +00001389 // Get the userprivileges from the role
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001390 redfish::Privileges userPrivileges =
1391 redfish::getUserPrivileges(userRole);
1392
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001393 // Set isConfigureSelfOnly based on D-Bus results. This
1394 // ignores the results from both pamAuthenticateUser and the
1395 // value from any previous use of this session.
1396 req.session->isConfigureSelfOnly = passwordExpired;
1397
Ed Tanous23a21a12020-07-25 04:45:05 +00001398 // Modifyprivileges if isConfigureSelfOnly.
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001399 if (req.session->isConfigureSelfOnly)
1400 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001401 // Remove allprivileges except ConfigureSelf
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001402 userPrivileges = userPrivileges.intersection(
1403 redfish::Privileges{"ConfigureSelf"});
1404 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1405 }
1406
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001407 if (!rules[ruleIndex]->checkPrivileges(userPrivileges))
1408 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001409 asyncResp->res.result(
1410 boost::beast::http::status::forbidden);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001411 if (req.session->isConfigureSelfOnly)
1412 {
1413 redfish::messages::passwordChangeRequired(
zhanghch058d1b46d2021-04-01 11:18:24 +08001414 asyncResp->res,
1415 "/redfish/v1/AccountService/Accounts/" +
1416 req.session->username);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001417 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001418 return;
1419 }
1420
1421 req.userRole = userRole;
zhanghch058d1b46d2021-04-01 11:18:24 +08001422 rules[ruleIndex]->handle(req, asyncResp, found.second);
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001423 },
1424 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1425 "xyz.openbmc_project.User.Manager", "GetUserInfo",
1426 req.session->username);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001427 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001428
Ed Tanous1abe55e2018-09-05 08:30:59 -07001429 void debugPrint()
1430 {
Ed Tanous271584a2019-07-09 16:24:22 -07001431 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001432 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001433 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1434 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001435 perMethods[i].trie.debugPrint();
1436 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001437 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001438
Ed Tanous1abe55e2018-09-05 08:30:59 -07001439 std::vector<const std::string*> getRoutes(const std::string& parent)
1440 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001441 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001442
1443 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001444 {
Tanousf00032d2018-11-05 01:18:10 -03001445 std::vector<unsigned> x;
1446 pm.trie.findRouteIndexes(parent, x);
1447 for (unsigned index : x)
1448 {
1449 ret.push_back(&pm.rules[index]->rule);
1450 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001451 }
1452 return ret;
1453 }
1454
1455 private:
Tanousf00032d2018-11-05 01:18:10 -03001456 struct PerMethod
1457 {
1458 std::vector<BaseRule*> rules;
1459 Trie trie;
1460 // rule index 0, 1 has special meaning; preallocate it to avoid
1461 // duplication.
1462 PerMethod() : rules(2)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001463 {}
Tanousf00032d2018-11-05 01:18:10 -03001464 };
Ed Tanous888880a2020-08-24 13:48:50 -07001465
1466 const static size_t maxHttpVerbCount =
Ed Tanouscc090442020-10-07 08:20:50 -07001467 static_cast<size_t>(boost::beast::http::verb::unlink);
Ed Tanous888880a2020-08-24 13:48:50 -07001468
Tanousf00032d2018-11-05 01:18:10 -03001469 std::array<PerMethod, maxHttpVerbCount> perMethods;
1470 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001471};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001472} // namespace crow