blob: a85bd3ae59588cf81eeb2529176c7651a267fd80 [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
2
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08003#include "async_resp.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -07004#include "common.hpp"
Ed Tanous168e20c2021-12-13 14:39:53 -08005#include "dbus_utility.hpp"
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06006#include "error_messages.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -07007#include "http_request.hpp"
8#include "http_response.hpp"
9#include "logging.hpp"
Tanousf00032d2018-11-05 01:18:10 -030010#include "privileges.hpp"
Ratan Gupta6f359562019-04-03 10:39:08 +053011#include "sessions.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -070012#include "utility.hpp"
Ed Tanous2c9efc32022-07-31 22:08:26 -070013#include "verb.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -070014#include "websocket.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070015
Ed Tanous88a03c52022-03-14 10:16:07 -070016#include <boost/beast/ssl/ssl_stream.hpp>
Tanousf00032d2018-11-05 01:18:10 -030017#include <boost/container/flat_map.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050018
Ed Tanouse0d918b2018-03-27 17:41:04 -070019#include <cerrno>
Ed Tanous7045c8d2017-04-03 10:04:37 -070020#include <cstdint>
Ed Tanouse0d918b2018-03-27 17:41:04 -070021#include <cstdlib>
Ed Tanous3dac7492017-08-02 13:46:20 -070022#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070023#include <memory>
Ed Tanous2c9efc32022-07-31 22:08:26 -070024#include <optional>
Ed Tanous7045c8d2017-04-03 10:04:37 -070025#include <tuple>
Ed Tanous7045c8d2017-04-03 10:04:37 -070026#include <utility>
27#include <vector>
Ed Tanous9140a672017-04-24 17:01:32 -070028
Ed Tanous1abe55e2018-09-05 08:30:59 -070029namespace crow
30{
Tanousf00032d2018-11-05 01:18:10 -030031
Ed Tanous1abe55e2018-09-05 08:30:59 -070032class BaseRule
33{
34 public:
Ed Tanous4e23a442022-06-06 09:57:26 -070035 explicit BaseRule(const std::string& thisRule) : rule(thisRule)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050036 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070037
Ed Tanous0c0084a2019-10-24 15:57:51 -070038 virtual ~BaseRule() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -070039
Ed Tanousecd6a3a2022-01-07 09:18:40 -080040 BaseRule(const BaseRule&) = delete;
41 BaseRule(BaseRule&&) = delete;
42 BaseRule& operator=(const BaseRule&) = delete;
43 BaseRule& operator=(const BaseRule&&) = delete;
44
Ed Tanous1abe55e2018-09-05 08:30:59 -070045 virtual void validate() = 0;
46 std::unique_ptr<BaseRule> upgrade()
47 {
48 if (ruleToUpgrade)
Ed Tanous3174e4d2020-10-07 11:41:22 -070049 {
Ed Tanous1abe55e2018-09-05 08:30:59 -070050 return std::move(ruleToUpgrade);
Ed Tanous3174e4d2020-10-07 11:41:22 -070051 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070052 return {};
53 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070054
Ed Tanous104f09c2022-01-25 09:56:04 -080055 virtual void handle(const Request& /*req*/,
zhanghch058d1b46d2021-04-01 11:18:24 +080056 const std::shared_ptr<bmcweb::AsyncResp>&,
57 const RoutingParams&) = 0;
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053058 virtual void
59 handleUpgrade(const Request& /*req*/,
60 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
61 boost::asio::ip::tcp::socket&& /*adaptor*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -070062 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053063 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070064 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -070065#ifdef BMCWEB_ENABLE_SSL
Ed Tanous104f09c2022-01-25 09:56:04 -080066 virtual void handleUpgrade(
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053067 const Request& /*req*/,
68 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous104f09c2022-01-25 09:56:04 -080069 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&& /*adaptor*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -070070 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053071 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070072 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070073#endif
74
Ed Tanous9eb808c2022-01-25 10:19:23 -080075 size_t getMethods() const
Ed Tanous1abe55e2018-09-05 08:30:59 -070076 {
77 return methodsBitfield;
78 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070079
Tanousf00032d2018-11-05 01:18:10 -030080 bool checkPrivileges(const redfish::Privileges& userPrivileges)
81 {
82 // If there are no privileges assigned, assume no privileges
83 // required
84 if (privilegesSet.empty())
85 {
86 return true;
87 }
88
89 for (const redfish::Privileges& requiredPrivileges : privilegesSet)
90 {
91 if (userPrivileges.isSupersetOf(requiredPrivileges))
92 {
93 return true;
94 }
95 }
96 return false;
97 }
98
Ed Tanous2c9efc32022-07-31 22:08:26 -070099 size_t methodsBitfield{1 << static_cast<size_t>(HttpVerb::Get)};
Ed Tanous44e45182022-07-26 16:47:23 -0700100 static_assert(std::numeric_limits<decltype(methodsBitfield)>::digits >
Ed Tanous759cf102022-07-31 16:36:52 -0700101 methodNotAllowedIndex,
Ed Tanous44e45182022-07-26 16:47:23 -0700102 "Not enough bits to store bitfield");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700103
Tanousf00032d2018-11-05 01:18:10 -0300104 std::vector<redfish::Privileges> privilegesSet;
105
Ed Tanous1abe55e2018-09-05 08:30:59 -0700106 std::string rule;
107 std::string nameStr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700108
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109 std::unique_ptr<BaseRule> ruleToUpgrade;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700110
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111 friend class Router;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500112 template <typename T>
113 friend struct RuleParameterTraits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700114};
115
Ed Tanous1abe55e2018-09-05 08:30:59 -0700116namespace detail
117{
118namespace routing_handler_call_helper
119{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500120template <typename T, int Pos>
121struct CallPair
Ed Tanous1abe55e2018-09-05 08:30:59 -0700122{
123 using type = T;
124 static const int pos = Pos;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700125};
126
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500127template <typename H1>
128struct CallParams
Ed Tanous1abe55e2018-09-05 08:30:59 -0700129{
130 H1& handler;
131 const RoutingParams& params;
132 const Request& req;
zhanghch058d1b46d2021-04-01 11:18:24 +0800133 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700134};
135
136template <typename F, int NInt, int NUint, int NDouble, int NString,
137 typename S1, typename S2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700138struct Call
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500139{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700140
141template <typename F, int NInt, int NUint, int NDouble, int NString,
142 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700143struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<int64_t, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700144 black_magic::S<Args2...>>
145{
146 void operator()(F cparams)
147 {
148 using pushed = typename black_magic::S<Args2...>::template push_back<
149 CallPair<int64_t, NInt>>;
150 Call<F, NInt + 1, NUint, NDouble, NString, black_magic::S<Args1...>,
151 pushed>()(cparams);
152 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700153};
154
155template <typename F, int NInt, int NUint, int NDouble, int NString,
156 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700157struct Call<F, NInt, NUint, NDouble, NString,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700158 black_magic::S<uint64_t, Args1...>, black_magic::S<Args2...>>
159{
160 void operator()(F cparams)
161 {
162 using pushed = typename black_magic::S<Args2...>::template push_back<
163 CallPair<uint64_t, NUint>>;
164 Call<F, NInt, NUint + 1, NDouble, NString, black_magic::S<Args1...>,
165 pushed>()(cparams);
166 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700167};
168
169template <typename F, int NInt, int NUint, int NDouble, int NString,
170 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700171struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<double, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700172 black_magic::S<Args2...>>
173{
174 void operator()(F cparams)
175 {
176 using pushed = typename black_magic::S<Args2...>::template push_back<
177 CallPair<double, NDouble>>;
178 Call<F, NInt, NUint, NDouble + 1, NString, black_magic::S<Args1...>,
179 pushed>()(cparams);
180 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700181};
182
183template <typename F, int NInt, int NUint, int NDouble, int NString,
184 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700185struct Call<F, NInt, NUint, NDouble, NString,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700186 black_magic::S<std::string, Args1...>, black_magic::S<Args2...>>
187{
188 void operator()(F cparams)
189 {
190 using pushed = typename black_magic::S<Args2...>::template push_back<
191 CallPair<std::string, NString>>;
192 Call<F, NInt, NUint, NDouble, NString + 1, black_magic::S<Args1...>,
193 pushed>()(cparams);
194 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700195};
196
197template <typename F, int NInt, int NUint, int NDouble, int NString,
198 typename... Args1>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700199struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700200 black_magic::S<Args1...>>
201{
202 void operator()(F cparams)
203 {
204 cparams.handler(
zhanghch058d1b46d2021-04-01 11:18:24 +0800205 cparams.req, cparams.asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700206 cparams.params.template get<typename Args1::type>(Args1::pos)...);
207 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700208};
209
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500210template <typename Func, typename... ArgsWrapped>
211struct Wrapped
Ed Tanous1abe55e2018-09-05 08:30:59 -0700212{
213 template <typename... Args>
214 void set(
215 Func f,
216 typename std::enable_if<
217 !std::is_same<
218 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
219 const Request&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800220 int>::type /*enable*/
221 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700222 {
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800223 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800224 const Request&,
225 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
226 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700227 }
228
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500229 template <typename Req, typename... Args>
230 struct ReqHandlerWrapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700231 {
Ed Tanous4e23a442022-06-06 09:57:26 -0700232 explicit ReqHandlerWrapper(Func fIn) : f(std::move(fIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500233 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700234
zhanghch058d1b46d2021-04-01 11:18:24 +0800235 void operator()(const Request& req,
236 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
237 Args... args)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700238 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800239 asyncResp->res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700240 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700241
Ed Tanous1abe55e2018-09-05 08:30:59 -0700242 Func f;
243 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700244
Ed Tanous1abe55e2018-09-05 08:30:59 -0700245 template <typename... Args>
246 void set(
247 Func f,
248 typename std::enable_if<
249 std::is_same<
250 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
251 const Request&>::value &&
252 !std::is_same<typename std::tuple_element<
253 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800254 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800255 int>::type /*enable*/
256 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700257 {
258 handler = ReqHandlerWrapper<Args...>(std::move(f));
259 /*handler = (
260 [f = std::move(f)]
261 (const Request& req, Response& res, Args... args){
Ed Tanousde5c9f32019-03-26 09:17:55 -0700262 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700263 res.end();
264 });*/
265 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700266
Ed Tanous1abe55e2018-09-05 08:30:59 -0700267 template <typename... Args>
268 void set(
269 Func f,
270 typename std::enable_if<
271 std::is_same<
272 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
273 const Request&>::value &&
274 std::is_same<typename std::tuple_element<
275 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800276 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800277 int>::type /*enable*/
278 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700279 {
280 handler = std::move(f);
281 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700282
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500283 template <typename... Args>
284 struct HandlerTypeHelper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700285 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800286 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800287 const crow::Request& /*req*/,
288 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700289 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700290 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700291 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700292
Ed Tanous1abe55e2018-09-05 08:30:59 -0700293 template <typename... Args>
294 struct HandlerTypeHelper<const Request&, Args...>
295 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800296 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800297 const crow::Request& /*req*/,
298 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700299 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700300 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700301 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700302
Ed Tanous1abe55e2018-09-05 08:30:59 -0700303 template <typename... Args>
zhanghch058d1b46d2021-04-01 11:18:24 +0800304 struct HandlerTypeHelper<const Request&,
305 const std::shared_ptr<bmcweb::AsyncResp>&, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700306 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800307 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800308 const crow::Request& /*req*/,
309 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700310 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700311 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700312 };
313
314 typename HandlerTypeHelper<ArgsWrapped...>::type handler;
315
zhanghch058d1b46d2021-04-01 11:18:24 +0800316 void operator()(const Request& req,
317 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700318 const RoutingParams& params)
319 {
320 detail::routing_handler_call_helper::Call<
321 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
322 0, 0, 0, 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
323 black_magic::S<>>()(
324 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800325 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700326 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700327};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700328} // namespace routing_handler_call_helper
329} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700330
Ed Tanous1abe55e2018-09-05 08:30:59 -0700331class WebSocketRule : public BaseRule
332{
333 using self_t = WebSocketRule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700334
Ed Tanous1abe55e2018-09-05 08:30:59 -0700335 public:
Ed Tanous4e23a442022-06-06 09:57:26 -0700336 explicit WebSocketRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500337 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700338
Ed Tanous1abe55e2018-09-05 08:30:59 -0700339 void validate() override
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500340 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700341
Ed Tanous104f09c2022-01-25 09:56:04 -0800342 void handle(const Request& /*req*/,
zhanghch058d1b46d2021-04-01 11:18:24 +0800343 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous104f09c2022-01-25 09:56:04 -0800344 const RoutingParams& /*params*/) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700345 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800346 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700347 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700348
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +0530349 void handleUpgrade(const Request& req,
350 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800351 boost::asio::ip::tcp::socket&& adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700352 {
Nan Zhou93c02022022-02-24 18:21:07 -0800353 BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
Ratan Gupta02453b12019-10-22 14:43:36 +0530354 std::shared_ptr<
355 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>
356 myConnection = std::make_shared<
357 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000358 req, std::move(adaptor), openHandler, messageHandler,
Ratan Gupta02453b12019-10-22 14:43:36 +0530359 closeHandler, errorHandler);
360 myConnection->start();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700361 }
362#ifdef BMCWEB_ENABLE_SSL
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +0530363 void handleUpgrade(const Request& req,
364 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800365 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
366 adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700367 {
Nan Zhou93c02022022-02-24 18:21:07 -0800368 BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
Ed Tanousceac6f72018-12-02 11:58:47 -0800369 std::shared_ptr<crow::websocket::ConnectionImpl<
370 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
371 myConnection = std::make_shared<crow::websocket::ConnectionImpl<
372 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000373 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanousceac6f72018-12-02 11:58:47 -0800374 closeHandler, errorHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700375 myConnection->start();
376 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700377#endif
378
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500379 template <typename Func>
380 self_t& onopen(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700381 {
382 openHandler = f;
383 return *this;
384 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700385
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500386 template <typename Func>
387 self_t& onmessage(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700388 {
389 messageHandler = f;
390 return *this;
391 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700392
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500393 template <typename Func>
394 self_t& onclose(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700395 {
396 closeHandler = f;
397 return *this;
398 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700399
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500400 template <typename Func>
401 self_t& onerror(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700402 {
403 errorHandler = f;
404 return *this;
405 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700406
Ed Tanous1abe55e2018-09-05 08:30:59 -0700407 protected:
zhanghch0577726382021-10-21 14:07:57 +0800408 std::function<void(crow::websocket::Connection&)> openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700409 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
410 messageHandler;
411 std::function<void(crow::websocket::Connection&, const std::string&)>
412 closeHandler;
413 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700414};
415
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500416template <typename T>
417struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700418{
419 using self_t = T;
420 WebSocketRule& websocket()
421 {
Ed Tanous271584a2019-07-09 16:24:22 -0700422 self_t* self = static_cast<self_t*>(this);
423 WebSocketRule* p = new WebSocketRule(self->rule);
424 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700425 return *p;
426 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700427
Ed Tanous26ccae32023-02-16 10:28:44 -0800428 self_t& name(std::string_view name) noexcept
Ed Tanous1abe55e2018-09-05 08:30:59 -0700429 {
Ed Tanous271584a2019-07-09 16:24:22 -0700430 self_t* self = static_cast<self_t*>(this);
Ed Tanousf23b7292020-10-15 09:41:17 -0700431 self->nameStr = name;
Ed Tanous271584a2019-07-09 16:24:22 -0700432 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700433 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700434
Ed Tanous1abe55e2018-09-05 08:30:59 -0700435 self_t& methods(boost::beast::http::verb method)
436 {
Ed Tanous271584a2019-07-09 16:24:22 -0700437 self_t* self = static_cast<self_t*>(this);
Ed Tanous2c9efc32022-07-31 22:08:26 -0700438 std::optional<HttpVerb> verb = httpVerbFromBoost(method);
439 if (verb)
440 {
441 self->methodsBitfield = 1U << static_cast<size_t>(*verb);
442 }
Ed Tanous271584a2019-07-09 16:24:22 -0700443 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700444 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700445
Ed Tanous1abe55e2018-09-05 08:30:59 -0700446 template <typename... MethodArgs>
Ed Tanous81ce6092020-12-17 16:54:55 +0000447 self_t& methods(boost::beast::http::verb method, MethodArgs... argsMethod)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700448 {
Ed Tanous271584a2019-07-09 16:24:22 -0700449 self_t* self = static_cast<self_t*>(this);
Ed Tanous81ce6092020-12-17 16:54:55 +0000450 methods(argsMethod...);
Ed Tanous2c9efc32022-07-31 22:08:26 -0700451 std::optional<HttpVerb> verb = httpVerbFromBoost(method);
452 if (verb)
453 {
454 self->methodsBitfield |= 1U << static_cast<size_t>(*verb);
455 }
Ed Tanous271584a2019-07-09 16:24:22 -0700456 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700457 }
Tanousf00032d2018-11-05 01:18:10 -0300458
Ed Tanous44e45182022-07-26 16:47:23 -0700459 self_t& notFound()
460 {
461 self_t* self = static_cast<self_t*>(this);
462 self->methodsBitfield = 1U << notFoundIndex;
463 return *self;
464 }
465
Ed Tanous759cf102022-07-31 16:36:52 -0700466 self_t& methodNotAllowed()
467 {
468 self_t* self = static_cast<self_t*>(this);
469 self->methodsBitfield = 1U << methodNotAllowedIndex;
470 return *self;
471 }
472
Ed Tanous432a8902021-06-14 15:28:56 -0700473 self_t& privileges(
474 const std::initializer_list<std::initializer_list<const char*>>& p)
Tanousf00032d2018-11-05 01:18:10 -0300475 {
Ed Tanous271584a2019-07-09 16:24:22 -0700476 self_t* self = static_cast<self_t*>(this);
Ed Tanous432a8902021-06-14 15:28:56 -0700477 for (const std::initializer_list<const char*>& privilege : p)
Tanousf00032d2018-11-05 01:18:10 -0300478 {
Ed Tanous271584a2019-07-09 16:24:22 -0700479 self->privilegesSet.emplace_back(privilege);
Tanousf00032d2018-11-05 01:18:10 -0300480 }
Ed Tanous271584a2019-07-09 16:24:22 -0700481 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300482 }
Ed Tanoused398212021-06-09 17:05:54 -0700483
484 template <size_t N, typename... MethodArgs>
485 self_t& privileges(const std::array<redfish::Privileges, N>& p)
486 {
487 self_t* self = static_cast<self_t*>(this);
488 for (const redfish::Privileges& privilege : p)
489 {
490 self->privilegesSet.emplace_back(privilege);
491 }
492 return *self;
493 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700494};
495
Ed Tanous1abe55e2018-09-05 08:30:59 -0700496class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
497{
498 public:
Ed Tanous4e23a442022-06-06 09:57:26 -0700499 explicit DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500500 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700501
Ed Tanous1abe55e2018-09-05 08:30:59 -0700502 void validate() override
503 {
504 if (!erasedHandler)
505 {
506 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
507 "no handler for url " + rule);
508 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700509 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700510
zhanghch058d1b46d2021-04-01 11:18:24 +0800511 void handle(const Request& req,
512 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700513 const RoutingParams& params) override
514 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800515 erasedHandler(req, asyncResp, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700516 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700517
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500518 template <typename Func>
519 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520 {
Ed Tanousc867a832022-03-10 14:17:00 -0800521 using boost::callable_traits::args_t;
522 constexpr size_t arity = std::tuple_size<args_t<Func>>::value;
523 constexpr auto is = std::make_integer_sequence<unsigned, arity>{};
524 erasedHandler = wrap(std::move(f), is);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700525 }
526
527 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500528 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700529 // enable_if Arg1 != request
530
531 template <typename Func, unsigned... Indices>
zhanghch058d1b46d2021-04-01 11:18:24 +0800532 std::function<void(const Request&,
533 const std::shared_ptr<bmcweb::AsyncResp>&,
534 const RoutingParams&)>
Ed Tanous104f09c2022-01-25 09:56:04 -0800535 wrap(Func f, std::integer_sequence<unsigned, Indices...> /*is*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 {
Ed Tanousc867a832022-03-10 14:17:00 -0800537 using function_t = crow::utility::FunctionTraits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700538
539 if (!black_magic::isParameterTagCompatible(
Ed Tanous988403c2020-08-24 11:29:49 -0700540 black_magic::getParameterTag(rule.c_str()),
541 black_magic::computeParameterTagFromArgsList<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700542 typename function_t::template arg<Indices>...>::value))
543 {
544 throw std::runtime_error("routeDynamic: Handler type is mismatched "
545 "with URL parameters: " +
546 rule);
547 }
548 auto ret = detail::routing_handler_call_helper::Wrapped<
549 Func, typename function_t::template arg<Indices>...>();
550 ret.template set<typename function_t::template arg<Indices>...>(
551 std::move(f));
552 return ret;
553 }
554
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500555 template <typename Func>
556 void operator()(std::string name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700557 {
558 nameStr = std::move(name);
559 (*this).template operator()<Func>(std::forward(f));
560 }
561
562 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800563 std::function<void(const Request&,
564 const std::shared_ptr<bmcweb::AsyncResp>&,
565 const RoutingParams&)>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700566 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700567};
568
569template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500570class TaggedRule :
571 public BaseRule,
572 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700573{
574 public:
575 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700576
Ed Tanous4e23a442022-06-06 09:57:26 -0700577 explicit TaggedRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500578 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700579
Ed Tanous1abe55e2018-09-05 08:30:59 -0700580 void validate() override
581 {
582 if (!handler)
583 {
584 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
585 "no handler for url " + rule);
586 }
587 }
588
589 template <typename Func>
590 typename std::enable_if<
591 black_magic::CallHelper<Func, black_magic::S<Args...>>::value,
592 void>::type
593 operator()(Func&& f)
594 {
595 static_assert(
596 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
597 black_magic::CallHelper<
598 Func, black_magic::S<crow::Request, Args...>>::value,
599 "Handler type is mismatched with URL parameters");
600 static_assert(
601 !std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
602 "Handler function cannot have void return type; valid return "
603 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500604 "string, int, crow::response, nlohmann::json");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700605
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800606 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800607 const Request&,
608 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
609 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700610 }
611
612 template <typename Func>
613 typename std::enable_if<
614 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
Ed Tanous7045c8d2017-04-03 10:04:37 -0700615 black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700616 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700617 void>::type
618 operator()(Func&& f)
619 {
620 static_assert(
621 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
622 black_magic::CallHelper<
623 Func, black_magic::S<crow::Request, Args...>>::value,
624 "Handler type is mismatched with URL parameters");
625 static_assert(
626 !std::is_same<void, decltype(f(std::declval<crow::Request>(),
627 std::declval<Args>()...))>::value,
628 "Handler function cannot have void return type; valid return "
629 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500630 "string, int, crow::response,nlohmann::json");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700631
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800632 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800633 const crow::Request& req,
634 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
635 Args... args) { asyncResp->res.result(f(req, args...)); };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700637
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638 template <typename Func>
639 typename std::enable_if<
640 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
641 !black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700642 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700643 void>::type
644 operator()(Func&& f)
645 {
646 static_assert(
647 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
648 black_magic::CallHelper<
649 Func, black_magic::S<crow::Request, Args...>>::value ||
650 black_magic::CallHelper<
zhanghch058d1b46d2021-04-01 11:18:24 +0800651 Func, black_magic::S<crow::Request,
652 std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700653 Args...>>::value,
654 "Handler type is mismatched with URL parameters");
655 static_assert(
zhanghch058d1b46d2021-04-01 11:18:24 +0800656 std::is_same<
657 void,
658 decltype(f(std::declval<crow::Request>(),
659 std::declval<std::shared_ptr<bmcweb::AsyncResp>&>(),
660 std::declval<Args>()...))>::value,
Tanousf00032d2018-11-05 01:18:10 -0300661 "Handler function with response argument should have void "
662 "return "
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 "type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700664
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800665 handler = std::forward<Func>(f);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700667
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500668 template <typename Func>
Ed Tanous26ccae32023-02-16 10:28:44 -0800669 void operator()(std::string_view name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700670 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700671 nameStr = name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700672 (*this).template operator()<Func>(std::forward(f));
673 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700674
zhanghch058d1b46d2021-04-01 11:18:24 +0800675 void handle(const Request& req,
676 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700677 const RoutingParams& params) override
678 {
679 detail::routing_handler_call_helper::Call<
680 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
681 0, 0, 0, 0, black_magic::S<Args...>, black_magic::S<>>()(
682 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800683 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700684 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700685
Ed Tanous1abe55e2018-09-05 08:30:59 -0700686 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800687 std::function<void(const crow::Request&,
688 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>
689 handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700690};
691
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692class Trie
693{
694 public:
695 struct Node
696 {
697 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700698 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
699 paramChildrens{};
Ed Tanousa94ac612022-02-22 11:13:24 -0800700 using ChildMap = boost::container::flat_map<
701 std::string, unsigned, std::less<>,
702 std::vector<std::pair<std::string, unsigned>>>;
703 ChildMap children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700704
Ed Tanous1abe55e2018-09-05 08:30:59 -0700705 bool isSimpleNode() const
706 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800707 return ruleIndex == 0 &&
708 std::all_of(std::begin(paramChildrens),
709 std::end(paramChildrens),
710 [](size_t x) { return x == 0U; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700711 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700712 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700713
Ed Tanous1abe55e2018-09-05 08:30:59 -0700714 Trie() : nodes(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500715 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700716
717 private:
718 void optimizeNode(Node* node)
719 {
Ed Tanous271584a2019-07-09 16:24:22 -0700720 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700721 {
Ed Tanousdbb59d42022-01-25 11:09:55 -0800722 if (x == 0U)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700723 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700724 continue;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700725 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700726 Node* child = &nodes[x];
727 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700728 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 if (node->children.empty())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700730 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700731 return;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700732 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700733 bool mergeWithChild = true;
Ed Tanousa94ac612022-02-22 11:13:24 -0800734 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700735 {
736 Node* child = &nodes[kv.second];
737 if (!child->isSimpleNode())
738 {
739 mergeWithChild = false;
740 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700741 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700742 }
743 if (mergeWithChild)
744 {
Ed Tanousa94ac612022-02-22 11:13:24 -0800745 Node::ChildMap merged;
746 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700747 {
748 Node* child = &nodes[kv.second];
Ed Tanousa94ac612022-02-22 11:13:24 -0800749 for (const Node::ChildMap::value_type& childKv :
Tanousf00032d2018-11-05 01:18:10 -0300750 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700751 {
752 merged[kv.first + childKv.first] = childKv.second;
753 }
754 }
755 node->children = std::move(merged);
756 optimizeNode(node);
757 }
758 else
759 {
Ed Tanousa94ac612022-02-22 11:13:24 -0800760 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700761 {
762 Node* child = &nodes[kv.second];
763 optimizeNode(child);
764 }
765 }
766 }
767
768 void optimize()
769 {
770 optimizeNode(head());
771 }
772
773 public:
774 void validate()
775 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700776 optimize();
777 }
778
Ed Tanous81ce6092020-12-17 16:54:55 +0000779 void findRouteIndexes(const std::string& reqUrl,
780 std::vector<unsigned>& routeIndexes,
Tanousf00032d2018-11-05 01:18:10 -0300781 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700782 {
783 if (node == nullptr)
784 {
785 node = head();
786 }
Ed Tanousa94ac612022-02-22 11:13:24 -0800787 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700788 {
789 const std::string& fragment = kv.first;
790 const Node* child = &nodes[kv.second];
Ed Tanous81ce6092020-12-17 16:54:55 +0000791 if (pos >= reqUrl.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700792 {
793 if (child->ruleIndex != 0 && fragment != "/")
794 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000795 routeIndexes.push_back(child->ruleIndex);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700796 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000797 findRouteIndexes(reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700798 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700799 }
800 else
801 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000802 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700803 {
Ed Tanous271584a2019-07-09 16:24:22 -0700804 findRouteIndexes(
Ed Tanous81ce6092020-12-17 16:54:55 +0000805 reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700806 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807 }
808 }
809 }
810 }
811
812 std::pair<unsigned, RoutingParams>
Ed Tanous26ccae32023-02-16 10:28:44 -0800813 find(std::string_view reqUrl, const Node* node = nullptr,
Ed Tanous271584a2019-07-09 16:24:22 -0700814 size_t pos = 0, RoutingParams* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700815 {
816 RoutingParams empty;
817 if (params == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700818 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700819 params = &empty;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700820 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700821
822 unsigned found{};
823 RoutingParams matchParams;
824
825 if (node == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700826 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 node = head();
Ed Tanous3174e4d2020-10-07 11:41:22 -0700828 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000829 if (pos == reqUrl.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700830 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700831 return {node->ruleIndex, *params};
Ed Tanous3174e4d2020-10-07 11:41:22 -0700832 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833
834 auto updateFound =
835 [&found, &matchParams](std::pair<unsigned, RoutingParams>& ret) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700836 if (ret.first != 0U && (found == 0U || found > ret.first))
837 {
838 found = ret.first;
839 matchParams = std::move(ret.second);
840 }
841 };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700842
Ed Tanouse662eae2022-01-25 10:39:19 -0800843 if (node->paramChildrens[static_cast<size_t>(ParamType::INT)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700844 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000845 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700846 if ((c >= '0' && c <= '9') || c == '+' || c == '-')
847 {
Ed Tanous543f4402022-01-06 13:12:53 -0800848 char* eptr = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700849 errno = 0;
850 long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000851 std::strtoll(reqUrl.data() + pos, &eptr, 10);
852 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700853 {
854 params->intParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000855 std::pair<unsigned, RoutingParams> ret =
856 find(reqUrl,
857 &nodes[node->paramChildrens[static_cast<size_t>(
858 ParamType::INT)]],
859 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700860 updateFound(ret);
861 params->intParams.pop_back();
862 }
863 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700864 }
865
Ed Tanouse662eae2022-01-25 10:39:19 -0800866 if (node->paramChildrens[static_cast<size_t>(ParamType::UINT)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700867 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000868 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700869 if ((c >= '0' && c <= '9') || c == '+')
870 {
Ed Tanous543f4402022-01-06 13:12:53 -0800871 char* eptr = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700872 errno = 0;
873 unsigned long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000874 std::strtoull(reqUrl.data() + pos, &eptr, 10);
875 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700876 {
877 params->uintParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000878 std::pair<unsigned, RoutingParams> ret =
879 find(reqUrl,
880 &nodes[node->paramChildrens[static_cast<size_t>(
881 ParamType::UINT)]],
882 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700883 updateFound(ret);
884 params->uintParams.pop_back();
885 }
886 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700887 }
888
Ed Tanouse662eae2022-01-25 10:39:19 -0800889 if (node->paramChildrens[static_cast<size_t>(ParamType::DOUBLE)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700890 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000891 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700892 if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
893 {
Ed Tanous543f4402022-01-06 13:12:53 -0800894 char* eptr = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700895 errno = 0;
Ed Tanous81ce6092020-12-17 16:54:55 +0000896 double value = std::strtod(reqUrl.data() + pos, &eptr);
897 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700898 {
899 params->doubleParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000900 std::pair<unsigned, RoutingParams> ret =
901 find(reqUrl,
902 &nodes[node->paramChildrens[static_cast<size_t>(
903 ParamType::DOUBLE)]],
904 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700905 updateFound(ret);
906 params->doubleParams.pop_back();
907 }
908 }
909 }
910
Ed Tanouse662eae2022-01-25 10:39:19 -0800911 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700912 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000913 size_t epos = pos;
Ed Tanous81ce6092020-12-17 16:54:55 +0000914 for (; epos < reqUrl.size(); epos++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700915 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000916 if (reqUrl[epos] == '/')
Ed Tanous3174e4d2020-10-07 11:41:22 -0700917 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700918 break;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700919 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700920 }
921
922 if (epos != pos)
923 {
924 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000925 reqUrl.substr(pos, epos - pos));
Tanousf00032d2018-11-05 01:18:10 -0300926 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000927 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700928 &nodes[node->paramChildrens[static_cast<size_t>(
929 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000930 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700931 updateFound(ret);
932 params->stringParams.pop_back();
933 }
934 }
935
Ed Tanouse662eae2022-01-25 10:39:19 -0800936 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700937 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000938 size_t epos = reqUrl.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700939
940 if (epos != pos)
941 {
942 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000943 reqUrl.substr(pos, epos - pos));
Ed Tanous271584a2019-07-09 16:24:22 -0700944 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000945 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700946 &nodes[node->paramChildrens[static_cast<size_t>(
947 ParamType::PATH)]],
948 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700949 updateFound(ret);
950 params->stringParams.pop_back();
951 }
952 }
953
Ed Tanousa94ac612022-02-22 11:13:24 -0800954 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700955 {
956 const std::string& fragment = kv.first;
957 const Node* child = &nodes[kv.second];
958
Ed Tanous81ce6092020-12-17 16:54:55 +0000959 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700960 {
Tanousf00032d2018-11-05 01:18:10 -0300961 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000962 find(reqUrl, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700963 updateFound(ret);
964 }
965 }
966
967 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700968 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700969
970 void add(const std::string& url, unsigned ruleIndex)
971 {
Ed Tanous271584a2019-07-09 16:24:22 -0700972 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700973
974 for (unsigned i = 0; i < url.size(); i++)
975 {
976 char c = url[i];
977 if (c == '<')
978 {
Tanousf00032d2018-11-05 01:18:10 -0300979 const static std::array<std::pair<ParamType, std::string>, 7>
980 paramTraits = {{
981 {ParamType::INT, "<int>"},
982 {ParamType::UINT, "<uint>"},
983 {ParamType::DOUBLE, "<float>"},
984 {ParamType::DOUBLE, "<double>"},
985 {ParamType::STRING, "<str>"},
986 {ParamType::STRING, "<string>"},
987 {ParamType::PATH, "<path>"},
988 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700989
Tanousf00032d2018-11-05 01:18:10 -0300990 for (const std::pair<ParamType, std::string>& x : paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700991 {
Tanousf00032d2018-11-05 01:18:10 -0300992 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700993 {
Ed Tanous271584a2019-07-09 16:24:22 -0700994 size_t index = static_cast<size_t>(x.first);
Ed Tanouse662eae2022-01-25 10:39:19 -0800995 if (nodes[idx].paramChildrens[index] == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700996 {
Tanousf00032d2018-11-05 01:18:10 -0300997 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700998 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700999 }
Ed Tanous271584a2019-07-09 16:24:22 -07001000 idx = nodes[idx].paramChildrens[index];
1001 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001002 break;
1003 }
1004 }
1005
1006 i--;
1007 }
1008 else
1009 {
1010 std::string piece(&c, 1);
Ed Tanouse662eae2022-01-25 10:39:19 -08001011 if (nodes[idx].children.count(piece) == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001012 {
Tanousf00032d2018-11-05 01:18:10 -03001013 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001014 nodes[idx].children.emplace(piece, newNodeIdx);
1015 }
1016 idx = nodes[idx].children[piece];
1017 }
1018 }
Ed Tanouse662eae2022-01-25 10:39:19 -08001019 if (nodes[idx].ruleIndex != 0U)
Ed Tanous3174e4d2020-10-07 11:41:22 -07001020 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001021 throw std::runtime_error("handler already exists for " + url);
Ed Tanous3174e4d2020-10-07 11:41:22 -07001022 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001023 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001024 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001025
Ed Tanous1abe55e2018-09-05 08:30:59 -07001026 private:
Ed Tanous271584a2019-07-09 16:24:22 -07001027 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001028 {
Ed Tanous271584a2019-07-09 16:24:22 -07001029 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001030 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001031 if (n->paramChildrens[i] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001032 {
1033 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -07001034 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
1035 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001036 {
1037 case ParamType::INT:
1038 BMCWEB_LOG_DEBUG << "<int>";
1039 break;
1040 case ParamType::UINT:
1041 BMCWEB_LOG_DEBUG << "<uint>";
1042 break;
1043 case ParamType::DOUBLE:
1044 BMCWEB_LOG_DEBUG << "<float>";
1045 break;
1046 case ParamType::STRING:
1047 BMCWEB_LOG_DEBUG << "<str>";
1048 break;
1049 case ParamType::PATH:
1050 BMCWEB_LOG_DEBUG << "<path>";
1051 break;
Ed Tanous23a21a12020-07-25 04:45:05 +00001052 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -07001053 BMCWEB_LOG_DEBUG << "<ERROR>";
1054 break;
1055 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001056
Ed Tanous1abe55e2018-09-05 08:30:59 -07001057 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
1058 }
1059 }
Ed Tanousa94ac612022-02-22 11:13:24 -08001060 for (const Node::ChildMap::value_type& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001061 {
1062 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -07001063 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -07001064 << kv.first;
1065 debugNodePrint(&nodes[kv.second], level + 1);
1066 }
1067 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001068
Ed Tanous1abe55e2018-09-05 08:30:59 -07001069 public:
1070 void debugPrint()
1071 {
Ed Tanous271584a2019-07-09 16:24:22 -07001072 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001073 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001074
Ed Tanous1abe55e2018-09-05 08:30:59 -07001075 private:
1076 const Node* head() const
1077 {
1078 return &nodes.front();
1079 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001080
Ed Tanous1abe55e2018-09-05 08:30:59 -07001081 Node* head()
1082 {
1083 return &nodes.front();
1084 }
1085
1086 unsigned newNode()
1087 {
1088 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -07001089 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001090 }
1091
1092 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001093};
1094
Ed Tanous1abe55e2018-09-05 08:30:59 -07001095class Router
1096{
1097 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -07001098 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001099
Ed Tanous1abe55e2018-09-05 08:30:59 -07001100 DynamicRule& newRuleDynamic(const std::string& rule)
1101 {
1102 std::unique_ptr<DynamicRule> ruleObject =
1103 std::make_unique<DynamicRule>(rule);
1104 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001105 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -07001106
Ed Tanous1abe55e2018-09-05 08:30:59 -07001107 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001108 }
1109
Ed Tanous1abe55e2018-09-05 08:30:59 -07001110 template <uint64_t N>
1111 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
1112 newRuleTagged(const std::string& rule)
1113 {
1114 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
1115 TaggedRule>;
1116 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
1117 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001118 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001119
1120 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001121 }
1122
Tanousf00032d2018-11-05 01:18:10 -03001123 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001124 {
Tanousf00032d2018-11-05 01:18:10 -03001125 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001126 {
Tanousf00032d2018-11-05 01:18:10 -03001127 return;
1128 }
Ed Tanous759cf102022-07-31 16:36:52 -07001129 for (size_t method = 0, methodBit = 1; method <= methodNotAllowedIndex;
Ed Tanous2c70f802020-09-28 14:29:23 -07001130 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -03001131 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001132 if ((ruleObject->methodsBitfield & methodBit) > 0U)
Tanousf00032d2018-11-05 01:18:10 -03001133 {
1134 perMethods[method].rules.emplace_back(ruleObject);
1135 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -07001136 rule, static_cast<unsigned>(
1137 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -03001138 // directory case:
1139 // request to `/about' url matches `/about/' rule
1140 if (rule.size() > 2 && rule.back() == '/')
1141 {
1142 perMethods[method].trie.add(
1143 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -07001144 static_cast<unsigned>(perMethods[method].rules.size() -
1145 1));
Tanousf00032d2018-11-05 01:18:10 -03001146 }
1147 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001148 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001149 }
1150
Ed Tanous1abe55e2018-09-05 08:30:59 -07001151 void validate()
1152 {
Tanousf00032d2018-11-05 01:18:10 -03001153 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001154 {
1155 if (rule)
1156 {
Tanousf00032d2018-11-05 01:18:10 -03001157 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001158 if (upgraded)
Ed Tanous3174e4d2020-10-07 11:41:22 -07001159 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001160 rule = std::move(upgraded);
Ed Tanous3174e4d2020-10-07 11:41:22 -07001161 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001162 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -03001163 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001164 }
1165 }
Tanousf00032d2018-11-05 01:18:10 -03001166 for (PerMethod& perMethod : perMethods)
1167 {
1168 perMethod.trie.validate();
1169 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001170 }
1171
Ed Tanous44e45182022-07-26 16:47:23 -07001172 struct FindRoute
1173 {
1174 BaseRule* rule = nullptr;
1175 RoutingParams params;
1176 };
1177
1178 struct FindRouteResponse
1179 {
1180 std::string allowHeader;
1181 FindRoute route;
1182 };
1183
Ed Tanous759cf102022-07-31 16:36:52 -07001184 FindRoute findRouteByIndex(std::string_view url, size_t index) const
1185 {
1186 FindRoute route;
1187 if (index >= perMethods.size())
1188 {
1189 BMCWEB_LOG_CRITICAL << "Bad index???";
1190 return route;
1191 }
1192 const PerMethod& perMethod = perMethods[index];
1193 std::pair<unsigned, RoutingParams> found = perMethod.trie.find(url);
1194 if (found.first >= perMethod.rules.size())
1195 {
1196 throw std::runtime_error("Trie internal structure corrupted!");
1197 }
1198 // Found a 404 route, switch that in
1199 if (found.first != 0U)
1200 {
1201 route.rule = perMethod.rules[found.first];
1202 route.params = std::move(found.second);
1203 }
1204 return route;
1205 }
1206
1207 FindRouteResponse findRoute(Request& req) const
Ed Tanous44e45182022-07-26 16:47:23 -07001208 {
1209 FindRouteResponse findRoute;
1210
Ed Tanous2c9efc32022-07-31 22:08:26 -07001211 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1212 if (!verb)
1213 {
1214 return findRoute;
1215 }
1216 size_t reqMethodIndex = static_cast<size_t>(*verb);
Ed Tanous44e45182022-07-26 16:47:23 -07001217 // Check to see if this url exists at any verb
1218 for (size_t perMethodIndex = 0; perMethodIndex <= maxVerbIndex;
1219 perMethodIndex++)
1220 {
1221 // Make sure it's safe to deference the array at that index
1222 static_assert(maxVerbIndex <
1223 std::tuple_size_v<decltype(perMethods)>);
Ed Tanous39662a32023-02-06 15:09:46 -08001224 FindRoute route =
1225 findRouteByIndex(req.url().encoded_path(), perMethodIndex);
Ed Tanous759cf102022-07-31 16:36:52 -07001226 if (route.rule == nullptr)
Ed Tanous44e45182022-07-26 16:47:23 -07001227 {
1228 continue;
1229 }
1230 if (!findRoute.allowHeader.empty())
1231 {
1232 findRoute.allowHeader += ", ";
1233 }
Ed Tanous2c9efc32022-07-31 22:08:26 -07001234 HttpVerb thisVerb = static_cast<HttpVerb>(perMethodIndex);
1235 findRoute.allowHeader += httpVerbToString(thisVerb);
Ed Tanous44e45182022-07-26 16:47:23 -07001236 if (perMethodIndex == reqMethodIndex)
1237 {
Ed Tanous759cf102022-07-31 16:36:52 -07001238 findRoute.route = route;
Ed Tanous44e45182022-07-26 16:47:23 -07001239 }
1240 }
1241 return findRoute;
1242 }
1243
Ed Tanous1abe55e2018-09-05 08:30:59 -07001244 template <typename Adaptor>
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301245 void handleUpgrade(const Request& req,
1246 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1247 Adaptor&& adaptor)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001248 {
Ed Tanous2c9efc32022-07-31 22:08:26 -07001249 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1250 if (!verb || static_cast<size_t>(*verb) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001251 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301252 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001253 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001254 }
Ed Tanous2c9efc32022-07-31 22:08:26 -07001255 PerMethod& perMethod = perMethods[static_cast<size_t>(*verb)];
Tanousf00032d2018-11-05 01:18:10 -03001256 Trie& trie = perMethod.trie;
1257 std::vector<BaseRule*>& rules = perMethod.rules;
1258
Ed Tanous39662a32023-02-06 15:09:46 -08001259 const std::pair<unsigned, RoutingParams>& found =
1260 trie.find(req.url().encoded_path());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001261 unsigned ruleIndex = found.first;
Ed Tanouse662eae2022-01-25 10:39:19 -08001262 if (ruleIndex == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001263 {
Ed Tanous39662a32023-02-06 15:09:46 -08001264 BMCWEB_LOG_DEBUG << "Cannot match rules "
1265 << req.url().encoded_path();
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301266 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001267 return;
1268 }
1269
1270 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001271 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001272 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001273 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001274
Ed Tanous271584a2019-07-09 16:24:22 -07001275 if ((rules[ruleIndex]->getMethods() &
Snehalatha Venkatesh1c99da02022-12-27 06:45:35 +00001276 (1U << static_cast<size_t>(*verb))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001277 {
Ed Tanous39662a32023-02-06 15:09:46 -08001278 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: "
1279 << req.url().encoded_path() << " with "
1280 << req.methodString() << "("
Snehalatha Venkatesh1c99da02022-12-27 06:45:35 +00001281 << static_cast<uint32_t>(*verb) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001282 << rules[ruleIndex]->getMethods();
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301283 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001284 return;
1285 }
1286
1287 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rules[ruleIndex]->rule
Snehalatha Venkatesh1c99da02022-12-27 06:45:35 +00001288 << "' " << static_cast<uint32_t>(*verb) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001289 << rules[ruleIndex]->getMethods();
1290
1291 // any uncaught exceptions become 500s
1292 try
1293 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301294 rules[ruleIndex]->handleUpgrade(req, asyncResp,
Ed Tanousf94c4ec2022-01-06 12:44:41 -08001295 std::forward<Adaptor>(adaptor));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001296 }
Patrick Williamsc5967042021-10-06 12:39:54 -05001297 catch (const std::exception& e)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001298 {
1299 BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301300 asyncResp->res.result(
1301 boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001302 return;
1303 }
1304 catch (...)
1305 {
1306 BMCWEB_LOG_ERROR
1307 << "An uncaught exception occurred. The type was unknown "
1308 "so no information was available.";
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301309 asyncResp->res.result(
1310 boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001311 return;
1312 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001313 }
1314
zhanghch058d1b46d2021-04-01 11:18:24 +08001315 void handle(Request& req,
1316 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001317 {
Ed Tanous2c9efc32022-07-31 22:08:26 -07001318 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1319 if (!verb || static_cast<size_t>(*verb) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001320 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001321 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001322 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001323 }
Ed Tanous44e45182022-07-26 16:47:23 -07001324
1325 FindRouteResponse foundRoute = findRoute(req);
1326
Ed Tanous759cf102022-07-31 16:36:52 -07001327 if (foundRoute.route.rule == nullptr)
Ed Tanous88a03c52022-03-14 10:16:07 -07001328 {
Ed Tanous759cf102022-07-31 16:36:52 -07001329 // Couldn't find a normal route with any verb, try looking for a 404
1330 // route
1331 if (foundRoute.allowHeader.empty())
Ed Tanous44e45182022-07-26 16:47:23 -07001332 {
Ed Tanous39662a32023-02-06 15:09:46 -08001333 foundRoute.route =
1334 findRouteByIndex(req.url().encoded_path(), notFoundIndex);
Ed Tanous759cf102022-07-31 16:36:52 -07001335 }
1336 else
1337 {
1338 // See if we have a method not allowed (405) handler
Ed Tanous39662a32023-02-06 15:09:46 -08001339 foundRoute.route = findRouteByIndex(req.url().encoded_path(),
1340 methodNotAllowedIndex);
Ed Tanous44e45182022-07-26 16:47:23 -07001341 }
1342 }
Ed Tanous759cf102022-07-31 16:36:52 -07001343
1344 // Fill in the allow header if it's valid
1345 if (!foundRoute.allowHeader.empty())
Ed Tanous44e45182022-07-26 16:47:23 -07001346 {
Ed Tanous759cf102022-07-31 16:36:52 -07001347
Ed Tanous88a03c52022-03-14 10:16:07 -07001348 asyncResp->res.addHeader(boost::beast::http::field::allow,
Ed Tanous44e45182022-07-26 16:47:23 -07001349 foundRoute.allowHeader);
Ed Tanous88a03c52022-03-14 10:16:07 -07001350 }
Tanousf00032d2018-11-05 01:18:10 -03001351
Ed Tanous44e45182022-07-26 16:47:23 -07001352 // If we couldn't find a real route or a 404 route, return a generic
1353 // response
1354 if (foundRoute.route.rule == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001355 {
Ed Tanous44e45182022-07-26 16:47:23 -07001356 if (foundRoute.allowHeader.empty())
1357 {
1358 asyncResp->res.result(boost::beast::http::status::not_found);
1359 }
1360 else
Ed Tanous2634dcd2019-03-26 09:28:06 -07001361 {
Ed Tanous88a03c52022-03-14 10:16:07 -07001362 asyncResp->res.result(
1363 boost::beast::http::status::method_not_allowed);
Ed Tanous2634dcd2019-03-26 09:28:06 -07001364 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001365 return;
1366 }
1367
Ed Tanous44e45182022-07-26 16:47:23 -07001368 BaseRule& rule = *foundRoute.route.rule;
1369 RoutingParams params = std::move(foundRoute.route.params);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001370
Ed Tanous44e45182022-07-26 16:47:23 -07001371 BMCWEB_LOG_DEBUG << "Matched rule '" << rule.rule << "' "
Snehalatha Venkatesh1c99da02022-12-27 06:45:35 +00001372 << static_cast<uint32_t>(*verb) << " / "
Ed Tanous44e45182022-07-26 16:47:23 -07001373 << rule.getMethods();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001374
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001375 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001376 {
Ed Tanous44e45182022-07-26 16:47:23 -07001377 rule.handle(req, asyncResp, params);
James Feist7166bf02019-12-10 16:52:14 +00001378 return;
1379 }
Ed Tanous2d6cb562022-07-07 20:44:54 -07001380 std::string username = req.session->username;
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001381
1382 crow::connections::systemBus->async_method_call(
Ed Tanous2d6cb562022-07-07 20:44:54 -07001383 [req{std::move(req)}, asyncResp, &rule, params](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001384 const boost::system::error_code& ec,
Ed Tanous2d6cb562022-07-07 20:44:54 -07001385 const dbus::utility::DBusPropertiesMap& userInfoMap) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -07001386 if (ec)
1387 {
1388 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
1389 asyncResp->res.result(
1390 boost::beast::http::status::internal_server_error);
1391 return;
1392 }
1393 std::string userRole{};
1394 const bool* remoteUser = nullptr;
1395 std::optional<bool> passwordExpired;
Ed Tanousb9d36b42022-02-26 21:42:46 -08001396
Ed Tanous002d39b2022-05-31 08:59:27 -07001397 for (const auto& userInfo : userInfoMap)
1398 {
1399 if (userInfo.first == "UserPrivilege")
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001400 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001401 const std::string* userRolePtr =
1402 std::get_if<std::string>(&userInfo.second);
1403 if (userRolePtr == nullptr)
Ed Tanousb9d36b42022-02-26 21:42:46 -08001404 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001405 continue;
Ed Tanousb9d36b42022-02-26 21:42:46 -08001406 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001407 userRole = *userRolePtr;
1408 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1409 << " userRole = " << *userRolePtr;
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001410 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001411 else if (userInfo.first == "RemoteUser")
1412 {
1413 remoteUser = std::get_if<bool>(&userInfo.second);
1414 }
1415 else if (userInfo.first == "UserPasswordExpired")
1416 {
1417 const bool* passwordExpiredPtr =
1418 std::get_if<bool>(&userInfo.second);
1419 if (passwordExpiredPtr == nullptr)
1420 {
1421 continue;
1422 }
1423 passwordExpired = *passwordExpiredPtr;
1424 }
1425 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001426
Ed Tanous002d39b2022-05-31 08:59:27 -07001427 if (remoteUser == nullptr)
1428 {
1429 BMCWEB_LOG_ERROR << "RemoteUser property missing or wrong type";
1430 asyncResp->res.result(
1431 boost::beast::http::status::internal_server_error);
1432 return;
1433 }
1434
1435 if (passwordExpired == std::nullopt)
1436 {
1437 if (!*remoteUser)
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001438 {
1439 BMCWEB_LOG_ERROR
Ed Tanous002d39b2022-05-31 08:59:27 -07001440 << "UserPasswordExpired property is expected for"
1441 " local user but is missing or wrong type";
zhanghch058d1b46d2021-04-01 11:18:24 +08001442 asyncResp->res.result(
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001443 boost::beast::http::status::internal_server_error);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001444 return;
1445 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001446 passwordExpired = false;
1447 }
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001448
Nan Zhouac6250a2022-08-09 20:15:44 +00001449 // Get the user's privileges from the role
Ed Tanous002d39b2022-05-31 08:59:27 -07001450 redfish::Privileges userPrivileges =
1451 redfish::getUserPrivileges(userRole);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001452
Ed Tanous002d39b2022-05-31 08:59:27 -07001453 // Set isConfigureSelfOnly based on D-Bus results. This
1454 // ignores the results from both pamAuthenticateUser and the
1455 // value from any previous use of this session.
1456 req.session->isConfigureSelfOnly = *passwordExpired;
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001457
Nan Zhouac6250a2022-08-09 20:15:44 +00001458 // Modify privileges if isConfigureSelfOnly.
Ed Tanous002d39b2022-05-31 08:59:27 -07001459 if (req.session->isConfigureSelfOnly)
1460 {
Nan Zhouac6250a2022-08-09 20:15:44 +00001461 // Remove all privileges except ConfigureSelf
Ed Tanous002d39b2022-05-31 08:59:27 -07001462 userPrivileges = userPrivileges.intersection(
1463 redfish::Privileges{"ConfigureSelf"});
1464 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1465 }
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001466
Ed Tanous44e45182022-07-26 16:47:23 -07001467 if (!rule.checkPrivileges(userPrivileges))
Ed Tanous002d39b2022-05-31 08:59:27 -07001468 {
1469 asyncResp->res.result(boost::beast::http::status::forbidden);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001470 if (req.session->isConfigureSelfOnly)
1471 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001472 redfish::messages::passwordChangeRequired(
1473 asyncResp->res, crow::utility::urlFromPieces(
1474 "redfish", "v1", "AccountService",
1475 "Accounts", req.session->username));
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001476 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001477 return;
1478 }
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001479
Ed Tanous002d39b2022-05-31 08:59:27 -07001480 req.userRole = userRole;
Ed Tanous44e45182022-07-26 16:47:23 -07001481 rule.handle(req, asyncResp, params);
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001482 },
1483 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
Ed Tanous2d6cb562022-07-07 20:44:54 -07001484 "xyz.openbmc_project.User.Manager", "GetUserInfo", username);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001485 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001486
Ed Tanous1abe55e2018-09-05 08:30:59 -07001487 void debugPrint()
1488 {
Ed Tanous271584a2019-07-09 16:24:22 -07001489 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001490 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001491 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1492 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001493 perMethods[i].trie.debugPrint();
1494 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001495 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001496
Ed Tanous1abe55e2018-09-05 08:30:59 -07001497 std::vector<const std::string*> getRoutes(const std::string& parent)
1498 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001499 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001500
1501 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001502 {
Tanousf00032d2018-11-05 01:18:10 -03001503 std::vector<unsigned> x;
1504 pm.trie.findRouteIndexes(parent, x);
1505 for (unsigned index : x)
1506 {
1507 ret.push_back(&pm.rules[index]->rule);
1508 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001509 }
1510 return ret;
1511 }
1512
1513 private:
Tanousf00032d2018-11-05 01:18:10 -03001514 struct PerMethod
1515 {
1516 std::vector<BaseRule*> rules;
1517 Trie trie;
Ed Tanous313a3c22022-03-14 09:27:38 -07001518 // rule index 0 has special meaning; preallocate it to avoid
Tanousf00032d2018-11-05 01:18:10 -03001519 // duplication.
Ed Tanous313a3c22022-03-14 09:27:38 -07001520 PerMethod() : rules(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001521 {}
Tanousf00032d2018-11-05 01:18:10 -03001522 };
Ed Tanous888880a2020-08-24 13:48:50 -07001523
Ed Tanous759cf102022-07-31 16:36:52 -07001524 std::array<PerMethod, methodNotAllowedIndex + 1> perMethods;
Tanousf00032d2018-11-05 01:18:10 -03001525 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001526};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001527} // namespace crow