blob: eb87e72b5d12fc89248ecaa3efe08e4852f737a1 [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 Tanous3d183202023-03-10 09:21:58 -080013#include "utils/dbus_utils.hpp"
Ed Tanous2c9efc32022-07-31 22:08:26 -070014#include "verb.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -070015#include "websocket.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070016
Ed Tanous88a03c52022-03-14 10:16:07 -070017#include <boost/beast/ssl/ssl_stream.hpp>
Tanousf00032d2018-11-05 01:18:10 -030018#include <boost/container/flat_map.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070019#include <boost/url/format.hpp>
Ed Tanous3d183202023-03-10 09:21:58 -080020#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050021
Ed Tanouse0d918b2018-03-27 17:41:04 -070022#include <cerrno>
Ed Tanous7045c8d2017-04-03 10:04:37 -070023#include <cstdint>
Ed Tanouse0d918b2018-03-27 17:41:04 -070024#include <cstdlib>
Ed Tanous3dac7492017-08-02 13:46:20 -070025#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070026#include <memory>
Ed Tanous2c9efc32022-07-31 22:08:26 -070027#include <optional>
Ed Tanous7045c8d2017-04-03 10:04:37 -070028#include <tuple>
Ed Tanous7045c8d2017-04-03 10:04:37 -070029#include <utility>
30#include <vector>
Ed Tanous9140a672017-04-24 17:01:32 -070031
Ed Tanous1abe55e2018-09-05 08:30:59 -070032namespace crow
33{
Tanousf00032d2018-11-05 01:18:10 -030034
Ed Tanous1abe55e2018-09-05 08:30:59 -070035class BaseRule
36{
37 public:
Patrick Williams89492a12023-05-10 07:51:34 -050038 explicit BaseRule(const std::string& thisRule) : rule(thisRule) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070039
Ed Tanous0c0084a2019-10-24 15:57:51 -070040 virtual ~BaseRule() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -070041
Ed Tanousecd6a3a2022-01-07 09:18:40 -080042 BaseRule(const BaseRule&) = delete;
43 BaseRule(BaseRule&&) = delete;
44 BaseRule& operator=(const BaseRule&) = delete;
45 BaseRule& operator=(const BaseRule&&) = delete;
46
Ed Tanous1abe55e2018-09-05 08:30:59 -070047 virtual void validate() = 0;
48 std::unique_ptr<BaseRule> upgrade()
49 {
50 if (ruleToUpgrade)
Ed Tanous3174e4d2020-10-07 11:41:22 -070051 {
Ed Tanous1abe55e2018-09-05 08:30:59 -070052 return std::move(ruleToUpgrade);
Ed Tanous3174e4d2020-10-07 11:41:22 -070053 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070054 return {};
55 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070056
Ed Tanous104f09c2022-01-25 09:56:04 -080057 virtual void handle(const Request& /*req*/,
zhanghch058d1b46d2021-04-01 11:18:24 +080058 const std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous15a42df2023-02-09 18:08:23 -080059 const std::vector<std::string>&) = 0;
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +053060#ifndef BMCWEB_ENABLE_SSL
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053061 virtual void
62 handleUpgrade(const Request& /*req*/,
63 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
64 boost::asio::ip::tcp::socket&& /*adaptor*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -070065 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053066 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 }
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +053068#else
Ed Tanous104f09c2022-01-25 09:56:04 -080069 virtual void handleUpgrade(
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053070 const Request& /*req*/,
71 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous104f09c2022-01-25 09:56:04 -080072 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&& /*adaptor*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -070073 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053074 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070075 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070076#endif
77
Ed Tanous9eb808c2022-01-25 10:19:23 -080078 size_t getMethods() const
Ed Tanous1abe55e2018-09-05 08:30:59 -070079 {
80 return methodsBitfield;
81 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070082
Tanousf00032d2018-11-05 01:18:10 -030083 bool checkPrivileges(const redfish::Privileges& userPrivileges)
84 {
85 // If there are no privileges assigned, assume no privileges
86 // required
87 if (privilegesSet.empty())
88 {
89 return true;
90 }
91
92 for (const redfish::Privileges& requiredPrivileges : privilegesSet)
93 {
94 if (userPrivileges.isSupersetOf(requiredPrivileges))
95 {
96 return true;
97 }
98 }
99 return false;
100 }
101
Ed Tanous2c9efc32022-07-31 22:08:26 -0700102 size_t methodsBitfield{1 << static_cast<size_t>(HttpVerb::Get)};
Ed Tanous44e45182022-07-26 16:47:23 -0700103 static_assert(std::numeric_limits<decltype(methodsBitfield)>::digits >
Ed Tanous759cf102022-07-31 16:36:52 -0700104 methodNotAllowedIndex,
Ed Tanous44e45182022-07-26 16:47:23 -0700105 "Not enough bits to store bitfield");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700106
Tanousf00032d2018-11-05 01:18:10 -0300107 std::vector<redfish::Privileges> privilegesSet;
108
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109 std::string rule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700110
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111 std::unique_ptr<BaseRule> ruleToUpgrade;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700112
Ed Tanous1abe55e2018-09-05 08:30:59 -0700113 friend class Router;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500114 template <typename T>
115 friend struct RuleParameterTraits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700116};
117
Ed Tanous1abe55e2018-09-05 08:30:59 -0700118namespace detail
119{
120namespace routing_handler_call_helper
121{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500122template <typename T, int Pos>
123struct CallPair
Ed Tanous1abe55e2018-09-05 08:30:59 -0700124{
125 using type = T;
126 static const int pos = Pos;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700127};
128
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500129template <typename H1>
130struct CallParams
Ed Tanous1abe55e2018-09-05 08:30:59 -0700131{
132 H1& handler;
Ed Tanous15a42df2023-02-09 18:08:23 -0800133 const std::vector<std::string>& params;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700134 const Request& req;
zhanghch058d1b46d2021-04-01 11:18:24 +0800135 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700136};
137
Ed Tanous15a42df2023-02-09 18:08:23 -0800138template <typename F, int NString, typename S1, typename S2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700139struct Call
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500140{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700141
Ed Tanous15a42df2023-02-09 18:08:23 -0800142template <typename F, int NString, typename... Args1, typename... Args2>
143struct Call<F, NString, black_magic::S<std::string, 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<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700149 CallPair<std::string, NString>>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800150 Call<F, NString + 1, black_magic::S<Args1...>, pushed>()(cparams);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700151 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700152};
153
Ed Tanous15a42df2023-02-09 18:08:23 -0800154template <typename F, int NString, typename... Args1>
155struct Call<F, NString, black_magic::S<>, black_magic::S<Args1...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700156{
157 void operator()(F cparams)
158 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800159 cparams.handler(cparams.req, cparams.asyncResp,
160 cparams.params[Args1::pos]...);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700161 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700162};
163
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500164template <typename Func, typename... ArgsWrapped>
165struct Wrapped
Ed Tanous1abe55e2018-09-05 08:30:59 -0700166{
167 template <typename... Args>
168 void set(
169 Func f,
170 typename std::enable_if<
171 !std::is_same<
172 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
173 const Request&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800174 int>::type /*enable*/
175 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700176 {
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800177 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800178 const Request&,
179 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
180 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700181 }
182
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500183 template <typename Req, typename... Args>
184 struct ReqHandlerWrapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700185 {
Patrick Williams89492a12023-05-10 07:51:34 -0500186 explicit ReqHandlerWrapper(Func fIn) : f(std::move(fIn)) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700187
zhanghch058d1b46d2021-04-01 11:18:24 +0800188 void operator()(const Request& req,
189 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
190 Args... args)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700191 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800192 asyncResp->res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700193 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700194
Ed Tanous1abe55e2018-09-05 08:30:59 -0700195 Func f;
196 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700197
Ed Tanous1abe55e2018-09-05 08:30:59 -0700198 template <typename... Args>
199 void set(
200 Func f,
201 typename std::enable_if<
202 std::is_same<
203 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
204 const Request&>::value &&
205 !std::is_same<typename std::tuple_element<
206 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800207 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800208 int>::type /*enable*/
209 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700210 {
211 handler = ReqHandlerWrapper<Args...>(std::move(f));
212 /*handler = (
213 [f = std::move(f)]
214 (const Request& req, Response& res, Args... args){
Ed Tanousde5c9f32019-03-26 09:17:55 -0700215 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700216 res.end();
217 });*/
218 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700219
Ed Tanous1abe55e2018-09-05 08:30:59 -0700220 template <typename... Args>
221 void set(
222 Func f,
223 typename std::enable_if<
224 std::is_same<
225 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
226 const Request&>::value &&
227 std::is_same<typename std::tuple_element<
228 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800229 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800230 int>::type /*enable*/
231 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700232 {
233 handler = std::move(f);
234 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700235
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500236 template <typename... Args>
237 struct HandlerTypeHelper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700238 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800239 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800240 const crow::Request& /*req*/,
241 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800242 using args_type = black_magic::S<Args...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700243 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700244
Ed Tanous1abe55e2018-09-05 08:30:59 -0700245 template <typename... Args>
246 struct HandlerTypeHelper<const Request&, Args...>
247 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800248 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800249 const crow::Request& /*req*/,
250 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800251 using args_type = black_magic::S<Args...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700252 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700253
Ed Tanous1abe55e2018-09-05 08:30:59 -0700254 template <typename... Args>
zhanghch058d1b46d2021-04-01 11:18:24 +0800255 struct HandlerTypeHelper<const Request&,
256 const std::shared_ptr<bmcweb::AsyncResp>&, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700257 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800258 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800259 const crow::Request& /*req*/,
260 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800261 using args_type = black_magic::S<Args...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700262 };
263
264 typename HandlerTypeHelper<ArgsWrapped...>::type handler;
265
zhanghch058d1b46d2021-04-01 11:18:24 +0800266 void operator()(const Request& req,
267 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800268 const std::vector<std::string>& params)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700269 {
270 detail::routing_handler_call_helper::Call<
271 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
Ed Tanous15a42df2023-02-09 18:08:23 -0800272 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700273 black_magic::S<>>()(
274 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800275 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700276 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700277};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700278} // namespace routing_handler_call_helper
279} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700280
Ed Tanous1abe55e2018-09-05 08:30:59 -0700281class WebSocketRule : public BaseRule
282{
283 using self_t = WebSocketRule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700284
Ed Tanous1abe55e2018-09-05 08:30:59 -0700285 public:
Patrick Williams89492a12023-05-10 07:51:34 -0500286 explicit WebSocketRule(const std::string& ruleIn) : BaseRule(ruleIn) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700287
Patrick Williams89492a12023-05-10 07:51:34 -0500288 void validate() override {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700289
Ed Tanous104f09c2022-01-25 09:56:04 -0800290 void handle(const Request& /*req*/,
zhanghch058d1b46d2021-04-01 11:18:24 +0800291 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800292 const std::vector<std::string>& /*params*/) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700293 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800294 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700295 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700296
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +0530297#ifndef BMCWEB_ENABLE_SSL
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +0530298 void handleUpgrade(const Request& req,
299 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800300 boost::asio::ip::tcp::socket&& adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700301 {
Nan Zhou93c02022022-02-24 18:21:07 -0800302 BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
Ratan Gupta02453b12019-10-22 14:43:36 +0530303 std::shared_ptr<
304 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>
305 myConnection = std::make_shared<
306 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000307 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanous863c1c22022-02-21 21:33:06 -0800308 messageExHandler, closeHandler, errorHandler);
Ratan Gupta02453b12019-10-22 14:43:36 +0530309 myConnection->start();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700310 }
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +0530311#else
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +0530312 void handleUpgrade(const Request& req,
313 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800314 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
315 adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700316 {
Nan Zhou93c02022022-02-24 18:21:07 -0800317 BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
Ed Tanousceac6f72018-12-02 11:58:47 -0800318 std::shared_ptr<crow::websocket::ConnectionImpl<
319 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
320 myConnection = std::make_shared<crow::websocket::ConnectionImpl<
321 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000322 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanous863c1c22022-02-21 21:33:06 -0800323 messageExHandler, closeHandler, errorHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700324 myConnection->start();
325 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700326#endif
327
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500328 template <typename Func>
329 self_t& onopen(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700330 {
331 openHandler = f;
332 return *this;
333 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700334
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500335 template <typename Func>
336 self_t& onmessage(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700337 {
338 messageHandler = f;
339 return *this;
340 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700341
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500342 template <typename Func>
Ed Tanous863c1c22022-02-21 21:33:06 -0800343 self_t& onmessageex(Func f)
344 {
345 messageExHandler = f;
346 return *this;
347 }
348
349 template <typename Func>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500350 self_t& onclose(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700351 {
352 closeHandler = f;
353 return *this;
354 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700355
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500356 template <typename Func>
357 self_t& onerror(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700358 {
359 errorHandler = f;
360 return *this;
361 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700362
Ed Tanous1abe55e2018-09-05 08:30:59 -0700363 protected:
zhanghch0577726382021-10-21 14:07:57 +0800364 std::function<void(crow::websocket::Connection&)> openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700365 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
366 messageHandler;
Ed Tanous863c1c22022-02-21 21:33:06 -0800367 std::function<void(crow::websocket::Connection&, std::string_view,
368 crow::websocket::MessageType type,
369 std::function<void()>&& whenComplete)>
370 messageExHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700371 std::function<void(crow::websocket::Connection&, const std::string&)>
372 closeHandler;
373 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700374};
375
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500376template <typename T>
377struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700378{
379 using self_t = T;
380 WebSocketRule& websocket()
381 {
Ed Tanous271584a2019-07-09 16:24:22 -0700382 self_t* self = static_cast<self_t*>(this);
383 WebSocketRule* p = new WebSocketRule(self->rule);
Ed Tanous9d192c72023-04-10 10:20:13 -0700384 p->privilegesSet = self->privilegesSet;
Ed Tanous271584a2019-07-09 16:24:22 -0700385 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700386 return *p;
387 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700388
Ed Tanous1abe55e2018-09-05 08:30:59 -0700389 self_t& methods(boost::beast::http::verb method)
390 {
Ed Tanous271584a2019-07-09 16:24:22 -0700391 self_t* self = static_cast<self_t*>(this);
Ed Tanous2c9efc32022-07-31 22:08:26 -0700392 std::optional<HttpVerb> verb = httpVerbFromBoost(method);
393 if (verb)
394 {
395 self->methodsBitfield = 1U << static_cast<size_t>(*verb);
396 }
Ed Tanous271584a2019-07-09 16:24:22 -0700397 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700398 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700399
Ed Tanous1abe55e2018-09-05 08:30:59 -0700400 template <typename... MethodArgs>
Ed Tanous81ce6092020-12-17 16:54:55 +0000401 self_t& methods(boost::beast::http::verb method, MethodArgs... argsMethod)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700402 {
Ed Tanous271584a2019-07-09 16:24:22 -0700403 self_t* self = static_cast<self_t*>(this);
Ed Tanous81ce6092020-12-17 16:54:55 +0000404 methods(argsMethod...);
Ed Tanous2c9efc32022-07-31 22:08:26 -0700405 std::optional<HttpVerb> verb = httpVerbFromBoost(method);
406 if (verb)
407 {
408 self->methodsBitfield |= 1U << static_cast<size_t>(*verb);
409 }
Ed Tanous271584a2019-07-09 16:24:22 -0700410 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700411 }
Tanousf00032d2018-11-05 01:18:10 -0300412
Ed Tanous44e45182022-07-26 16:47:23 -0700413 self_t& notFound()
414 {
415 self_t* self = static_cast<self_t*>(this);
416 self->methodsBitfield = 1U << notFoundIndex;
417 return *self;
418 }
419
Ed Tanous759cf102022-07-31 16:36:52 -0700420 self_t& methodNotAllowed()
421 {
422 self_t* self = static_cast<self_t*>(this);
423 self->methodsBitfield = 1U << methodNotAllowedIndex;
424 return *self;
425 }
426
Ed Tanous432a8902021-06-14 15:28:56 -0700427 self_t& privileges(
428 const std::initializer_list<std::initializer_list<const char*>>& p)
Tanousf00032d2018-11-05 01:18:10 -0300429 {
Ed Tanous271584a2019-07-09 16:24:22 -0700430 self_t* self = static_cast<self_t*>(this);
Ed Tanous432a8902021-06-14 15:28:56 -0700431 for (const std::initializer_list<const char*>& privilege : p)
Tanousf00032d2018-11-05 01:18:10 -0300432 {
Ed Tanous271584a2019-07-09 16:24:22 -0700433 self->privilegesSet.emplace_back(privilege);
Tanousf00032d2018-11-05 01:18:10 -0300434 }
Ed Tanous271584a2019-07-09 16:24:22 -0700435 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300436 }
Ed Tanoused398212021-06-09 17:05:54 -0700437
438 template <size_t N, typename... MethodArgs>
439 self_t& privileges(const std::array<redfish::Privileges, N>& p)
440 {
441 self_t* self = static_cast<self_t*>(this);
442 for (const redfish::Privileges& privilege : p)
443 {
444 self->privilegesSet.emplace_back(privilege);
445 }
446 return *self;
447 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700448};
449
Ed Tanous1abe55e2018-09-05 08:30:59 -0700450class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
451{
452 public:
Patrick Williams89492a12023-05-10 07:51:34 -0500453 explicit DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700454
Ed Tanous1abe55e2018-09-05 08:30:59 -0700455 void validate() override
456 {
457 if (!erasedHandler)
458 {
Ed Tanous28f4b382023-04-10 10:20:56 -0700459 throw std::runtime_error("no handler for url " + rule);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700460 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700461 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700462
zhanghch058d1b46d2021-04-01 11:18:24 +0800463 void handle(const Request& req,
464 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800465 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700466 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800467 erasedHandler(req, asyncResp, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700468 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700469
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500470 template <typename Func>
471 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700472 {
Ed Tanousc867a832022-03-10 14:17:00 -0800473 using boost::callable_traits::args_t;
474 constexpr size_t arity = std::tuple_size<args_t<Func>>::value;
475 constexpr auto is = std::make_integer_sequence<unsigned, arity>{};
476 erasedHandler = wrap(std::move(f), is);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700477 }
478
479 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500480 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481 // enable_if Arg1 != request
482
483 template <typename Func, unsigned... Indices>
zhanghch058d1b46d2021-04-01 11:18:24 +0800484 std::function<void(const Request&,
485 const std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous15a42df2023-02-09 18:08:23 -0800486 const std::vector<std::string>&)>
Ed Tanous104f09c2022-01-25 09:56:04 -0800487 wrap(Func f, std::integer_sequence<unsigned, Indices...> /*is*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700488 {
Ed Tanousc867a832022-03-10 14:17:00 -0800489 using function_t = crow::utility::FunctionTraits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700490
Ed Tanous1abe55e2018-09-05 08:30:59 -0700491 auto ret = detail::routing_handler_call_helper::Wrapped<
492 Func, typename function_t::template arg<Indices>...>();
493 ret.template set<typename function_t::template arg<Indices>...>(
494 std::move(f));
495 return ret;
496 }
497
Ed Tanous1abe55e2018-09-05 08:30:59 -0700498 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800499 std::function<void(const Request&,
500 const std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous15a42df2023-02-09 18:08:23 -0800501 const std::vector<std::string>&)>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700502 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700503};
504
505template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500506class TaggedRule :
507 public BaseRule,
508 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700509{
510 public:
511 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700512
Patrick Williams89492a12023-05-10 07:51:34 -0500513 explicit TaggedRule(const std::string& ruleIn) : BaseRule(ruleIn) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700514
Ed Tanous1abe55e2018-09-05 08:30:59 -0700515 void validate() override
516 {
517 if (!handler)
518 {
Ed Tanous28f4b382023-04-10 10:20:56 -0700519 throw std::runtime_error("no handler for url " + rule);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520 }
521 }
522
523 template <typename Func>
Ed Tanous15a42df2023-02-09 18:08:23 -0800524 void operator()(Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700525 {
526 static_assert(
Ed Tanous7045c8d2017-04-03 10:04:37 -0700527 black_magic::CallHelper<
Ed Tanous15a42df2023-02-09 18:08:23 -0800528 Func, black_magic::S<crow::Request,
529 std::shared_ptr<bmcweb::AsyncResp>&,
530 Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700531 "Handler type is mismatched with URL parameters");
532 static_assert(
zhanghch058d1b46d2021-04-01 11:18:24 +0800533 std::is_same<
534 void,
535 decltype(f(std::declval<crow::Request>(),
536 std::declval<std::shared_ptr<bmcweb::AsyncResp>&>(),
537 std::declval<Args>()...))>::value,
Ed Tanous15a42df2023-02-09 18:08:23 -0800538 "Handler function with response argument should have void return type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700539
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800540 handler = std::forward<Func>(f);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700541 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700542
zhanghch058d1b46d2021-04-01 11:18:24 +0800543 void handle(const Request& req,
544 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800545 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700546 {
547 detail::routing_handler_call_helper::Call<
548 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
Ed Tanous15a42df2023-02-09 18:08:23 -0800549 0, black_magic::S<Args...>, black_magic::S<>>()(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700550 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800551 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700552 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700553
Ed Tanous1abe55e2018-09-05 08:30:59 -0700554 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800555 std::function<void(const crow::Request&,
556 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>
557 handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700558};
559
Ed Tanous1abe55e2018-09-05 08:30:59 -0700560class Trie
561{
562 public:
563 struct Node
564 {
565 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700566 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
567 paramChildrens{};
Ed Tanousa94ac612022-02-22 11:13:24 -0800568 using ChildMap = boost::container::flat_map<
569 std::string, unsigned, std::less<>,
570 std::vector<std::pair<std::string, unsigned>>>;
571 ChildMap children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700572
Ed Tanous1abe55e2018-09-05 08:30:59 -0700573 bool isSimpleNode() const
574 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800575 return ruleIndex == 0 &&
576 std::all_of(std::begin(paramChildrens),
577 std::end(paramChildrens),
578 [](size_t x) { return x == 0U; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700579 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700580 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700581
Patrick Williams89492a12023-05-10 07:51:34 -0500582 Trie() : nodes(1) {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700583
584 private:
585 void optimizeNode(Node* node)
586 {
Ed Tanous271584a2019-07-09 16:24:22 -0700587 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700588 {
Ed Tanousdbb59d42022-01-25 11:09:55 -0800589 if (x == 0U)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700590 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700591 continue;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700592 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700593 Node* child = &nodes[x];
594 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700595 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700596 if (node->children.empty())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700597 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700598 return;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700599 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700600 bool mergeWithChild = true;
Ed Tanousa94ac612022-02-22 11:13:24 -0800601 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700602 {
603 Node* child = &nodes[kv.second];
604 if (!child->isSimpleNode())
605 {
606 mergeWithChild = false;
607 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700608 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700609 }
610 if (mergeWithChild)
611 {
Ed Tanousa94ac612022-02-22 11:13:24 -0800612 Node::ChildMap merged;
613 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700614 {
615 Node* child = &nodes[kv.second];
Ed Tanousa94ac612022-02-22 11:13:24 -0800616 for (const Node::ChildMap::value_type& childKv :
Tanousf00032d2018-11-05 01:18:10 -0300617 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700618 {
619 merged[kv.first + childKv.first] = childKv.second;
620 }
621 }
622 node->children = std::move(merged);
623 optimizeNode(node);
624 }
625 else
626 {
Ed Tanousa94ac612022-02-22 11:13:24 -0800627 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 {
629 Node* child = &nodes[kv.second];
630 optimizeNode(child);
631 }
632 }
633 }
634
635 void optimize()
636 {
637 optimizeNode(head());
638 }
639
640 public:
641 void validate()
642 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700643 optimize();
644 }
645
Ed Tanous81ce6092020-12-17 16:54:55 +0000646 void findRouteIndexes(const std::string& reqUrl,
647 std::vector<unsigned>& routeIndexes,
Tanousf00032d2018-11-05 01:18:10 -0300648 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700649 {
650 if (node == nullptr)
651 {
652 node = head();
653 }
Ed Tanousa94ac612022-02-22 11:13:24 -0800654 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700655 {
656 const std::string& fragment = kv.first;
657 const Node* child = &nodes[kv.second];
Ed Tanous81ce6092020-12-17 16:54:55 +0000658 if (pos >= reqUrl.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700659 {
660 if (child->ruleIndex != 0 && fragment != "/")
661 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000662 routeIndexes.push_back(child->ruleIndex);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000664 findRouteIndexes(reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700665 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 }
667 else
668 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000669 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700670 {
Ed Tanous271584a2019-07-09 16:24:22 -0700671 findRouteIndexes(
Ed Tanous81ce6092020-12-17 16:54:55 +0000672 reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700673 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 }
675 }
676 }
677 }
678
Ed Tanous15a42df2023-02-09 18:08:23 -0800679 std::pair<unsigned, std::vector<std::string>>
680 find(const std::string_view reqUrl, const Node* node = nullptr,
681 size_t pos = 0, std::vector<std::string>* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700682 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800683 std::vector<std::string> empty;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700684 if (params == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700685 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700686 params = &empty;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700687 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688
689 unsigned found{};
Ed Tanous15a42df2023-02-09 18:08:23 -0800690 std::vector<std::string> matchParams;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700691
692 if (node == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700693 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700694 node = head();
Ed Tanous3174e4d2020-10-07 11:41:22 -0700695 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000696 if (pos == reqUrl.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700697 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700698 return {node->ruleIndex, *params};
Ed Tanous3174e4d2020-10-07 11:41:22 -0700699 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700700
701 auto updateFound =
Ed Tanous15a42df2023-02-09 18:08:23 -0800702 [&found,
703 &matchParams](std::pair<unsigned, std::vector<std::string>>& ret) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700704 if (ret.first != 0U && (found == 0U || found > ret.first))
705 {
706 found = ret.first;
707 matchParams = std::move(ret.second);
708 }
709 };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700710
Ed Tanouse662eae2022-01-25 10:39:19 -0800711 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000713 size_t epos = pos;
Ed Tanous81ce6092020-12-17 16:54:55 +0000714 for (; epos < reqUrl.size(); epos++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700715 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000716 if (reqUrl[epos] == '/')
Ed Tanous3174e4d2020-10-07 11:41:22 -0700717 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700718 break;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700719 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700720 }
721
722 if (epos != pos)
723 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800724 params->emplace_back(reqUrl.substr(pos, epos - pos));
725 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000726 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700727 &nodes[node->paramChildrens[static_cast<size_t>(
728 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000729 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700730 updateFound(ret);
Ed Tanous15a42df2023-02-09 18:08:23 -0800731 params->pop_back();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700732 }
733 }
734
Ed Tanouse662eae2022-01-25 10:39:19 -0800735 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700736 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000737 size_t epos = reqUrl.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700738
739 if (epos != pos)
740 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800741 params->emplace_back(reqUrl.substr(pos, epos - pos));
742 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000743 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700744 &nodes[node->paramChildrens[static_cast<size_t>(
745 ParamType::PATH)]],
746 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700747 updateFound(ret);
Ed Tanous15a42df2023-02-09 18:08:23 -0800748 params->pop_back();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700749 }
750 }
751
Ed Tanousa94ac612022-02-22 11:13:24 -0800752 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 {
754 const std::string& fragment = kv.first;
755 const Node* child = &nodes[kv.second];
756
Ed Tanous81ce6092020-12-17 16:54:55 +0000757 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700758 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800759 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000760 find(reqUrl, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700761 updateFound(ret);
762 }
763 }
764
765 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700766 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700767
768 void add(const std::string& url, unsigned ruleIndex)
769 {
Ed Tanous271584a2019-07-09 16:24:22 -0700770 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700771
772 for (unsigned i = 0; i < url.size(); i++)
773 {
774 char c = url[i];
775 if (c == '<')
776 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800777 constexpr static std::array<
778 std::pair<ParamType, std::string_view>, 3>
Tanousf00032d2018-11-05 01:18:10 -0300779 paramTraits = {{
Tanousf00032d2018-11-05 01:18:10 -0300780 {ParamType::STRING, "<str>"},
781 {ParamType::STRING, "<string>"},
782 {ParamType::PATH, "<path>"},
783 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700784
Ed Tanous15a42df2023-02-09 18:08:23 -0800785 for (const std::pair<ParamType, std::string_view>& x :
786 paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 {
Tanousf00032d2018-11-05 01:18:10 -0300788 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789 {
Ed Tanous271584a2019-07-09 16:24:22 -0700790 size_t index = static_cast<size_t>(x.first);
Ed Tanouse662eae2022-01-25 10:39:19 -0800791 if (nodes[idx].paramChildrens[index] == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700792 {
Tanousf00032d2018-11-05 01:18:10 -0300793 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700794 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700795 }
Ed Tanous271584a2019-07-09 16:24:22 -0700796 idx = nodes[idx].paramChildrens[index];
797 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700798 break;
799 }
800 }
801
802 i--;
803 }
804 else
805 {
806 std::string piece(&c, 1);
Ed Tanouse662eae2022-01-25 10:39:19 -0800807 if (nodes[idx].children.count(piece) == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700808 {
Tanousf00032d2018-11-05 01:18:10 -0300809 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700810 nodes[idx].children.emplace(piece, newNodeIdx);
811 }
812 idx = nodes[idx].children[piece];
813 }
814 }
Ed Tanouse662eae2022-01-25 10:39:19 -0800815 if (nodes[idx].ruleIndex != 0U)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700816 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700817 throw std::runtime_error("handler already exists for " + url);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700818 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700819 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700820 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700821
Ed Tanous1abe55e2018-09-05 08:30:59 -0700822 private:
Ed Tanous271584a2019-07-09 16:24:22 -0700823 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700824 {
Ed Tanous271584a2019-07-09 16:24:22 -0700825 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700826 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800827 if (n->paramChildrens[i] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828 {
829 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -0700830 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
831 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700832 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 case ParamType::STRING:
834 BMCWEB_LOG_DEBUG << "<str>";
835 break;
836 case ParamType::PATH:
837 BMCWEB_LOG_DEBUG << "<path>";
838 break;
Ed Tanous23a21a12020-07-25 04:45:05 +0000839 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -0700840 BMCWEB_LOG_DEBUG << "<ERROR>";
841 break;
842 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700843
Ed Tanous1abe55e2018-09-05 08:30:59 -0700844 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
845 }
846 }
Ed Tanousa94ac612022-02-22 11:13:24 -0800847 for (const Node::ChildMap::value_type& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700848 {
849 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -0700850 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 << kv.first;
852 debugNodePrint(&nodes[kv.second], level + 1);
853 }
854 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700855
Ed Tanous1abe55e2018-09-05 08:30:59 -0700856 public:
857 void debugPrint()
858 {
Ed Tanous271584a2019-07-09 16:24:22 -0700859 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700860 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700861
Ed Tanous1abe55e2018-09-05 08:30:59 -0700862 private:
863 const Node* head() const
864 {
865 return &nodes.front();
866 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700867
Ed Tanous1abe55e2018-09-05 08:30:59 -0700868 Node* head()
869 {
870 return &nodes.front();
871 }
872
873 unsigned newNode()
874 {
875 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -0700876 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700877 }
878
879 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700880};
881
Ed Tanous1abe55e2018-09-05 08:30:59 -0700882class Router
883{
884 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -0700885 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700886
Ed Tanous1abe55e2018-09-05 08:30:59 -0700887 DynamicRule& newRuleDynamic(const std::string& rule)
888 {
889 std::unique_ptr<DynamicRule> ruleObject =
890 std::make_unique<DynamicRule>(rule);
891 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -0300892 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -0700893
Ed Tanous1abe55e2018-09-05 08:30:59 -0700894 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700895 }
896
Ed Tanous1abe55e2018-09-05 08:30:59 -0700897 template <uint64_t N>
898 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
899 newRuleTagged(const std::string& rule)
900 {
901 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
902 TaggedRule>;
903 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
904 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -0300905 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700906
907 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700908 }
909
Tanousf00032d2018-11-05 01:18:10 -0300910 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700911 {
Tanousf00032d2018-11-05 01:18:10 -0300912 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700913 {
Tanousf00032d2018-11-05 01:18:10 -0300914 return;
915 }
Ed Tanous759cf102022-07-31 16:36:52 -0700916 for (size_t method = 0, methodBit = 1; method <= methodNotAllowedIndex;
Ed Tanous2c70f802020-09-28 14:29:23 -0700917 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -0300918 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800919 if ((ruleObject->methodsBitfield & methodBit) > 0U)
Tanousf00032d2018-11-05 01:18:10 -0300920 {
921 perMethods[method].rules.emplace_back(ruleObject);
922 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -0700923 rule, static_cast<unsigned>(
924 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -0300925 // directory case:
926 // request to `/about' url matches `/about/' rule
927 if (rule.size() > 2 && rule.back() == '/')
928 {
929 perMethods[method].trie.add(
930 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -0700931 static_cast<unsigned>(perMethods[method].rules.size() -
932 1));
Tanousf00032d2018-11-05 01:18:10 -0300933 }
934 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700935 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700936 }
937
Ed Tanous1abe55e2018-09-05 08:30:59 -0700938 void validate()
939 {
Tanousf00032d2018-11-05 01:18:10 -0300940 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700941 {
942 if (rule)
943 {
Tanousf00032d2018-11-05 01:18:10 -0300944 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700945 if (upgraded)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700946 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700947 rule = std::move(upgraded);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700948 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700949 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -0300950 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700951 }
952 }
Tanousf00032d2018-11-05 01:18:10 -0300953 for (PerMethod& perMethod : perMethods)
954 {
955 perMethod.trie.validate();
956 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700957 }
958
Ed Tanous44e45182022-07-26 16:47:23 -0700959 struct FindRoute
960 {
961 BaseRule* rule = nullptr;
Ed Tanous15a42df2023-02-09 18:08:23 -0800962 std::vector<std::string> params;
Ed Tanous44e45182022-07-26 16:47:23 -0700963 };
964
965 struct FindRouteResponse
966 {
967 std::string allowHeader;
968 FindRoute route;
969 };
970
Ed Tanous759cf102022-07-31 16:36:52 -0700971 FindRoute findRouteByIndex(std::string_view url, size_t index) const
972 {
973 FindRoute route;
974 if (index >= perMethods.size())
975 {
976 BMCWEB_LOG_CRITICAL << "Bad index???";
977 return route;
978 }
979 const PerMethod& perMethod = perMethods[index];
Ed Tanous15a42df2023-02-09 18:08:23 -0800980 std::pair<unsigned, std::vector<std::string>> found =
981 perMethod.trie.find(url);
Ed Tanous759cf102022-07-31 16:36:52 -0700982 if (found.first >= perMethod.rules.size())
983 {
984 throw std::runtime_error("Trie internal structure corrupted!");
985 }
986 // Found a 404 route, switch that in
987 if (found.first != 0U)
988 {
989 route.rule = perMethod.rules[found.first];
990 route.params = std::move(found.second);
991 }
992 return route;
993 }
994
995 FindRouteResponse findRoute(Request& req) const
Ed Tanous44e45182022-07-26 16:47:23 -0700996 {
997 FindRouteResponse findRoute;
998
Ed Tanous2c9efc32022-07-31 22:08:26 -0700999 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1000 if (!verb)
1001 {
1002 return findRoute;
1003 }
1004 size_t reqMethodIndex = static_cast<size_t>(*verb);
Ed Tanous44e45182022-07-26 16:47:23 -07001005 // Check to see if this url exists at any verb
1006 for (size_t perMethodIndex = 0; perMethodIndex <= maxVerbIndex;
1007 perMethodIndex++)
1008 {
1009 // Make sure it's safe to deference the array at that index
1010 static_assert(maxVerbIndex <
1011 std::tuple_size_v<decltype(perMethods)>);
Patrick Williams89492a12023-05-10 07:51:34 -05001012 FindRoute route = findRouteByIndex(req.url().encoded_path(),
1013 perMethodIndex);
Ed Tanous759cf102022-07-31 16:36:52 -07001014 if (route.rule == nullptr)
Ed Tanous44e45182022-07-26 16:47:23 -07001015 {
1016 continue;
1017 }
1018 if (!findRoute.allowHeader.empty())
1019 {
1020 findRoute.allowHeader += ", ";
1021 }
Ed Tanous2c9efc32022-07-31 22:08:26 -07001022 HttpVerb thisVerb = static_cast<HttpVerb>(perMethodIndex);
1023 findRoute.allowHeader += httpVerbToString(thisVerb);
Ed Tanous44e45182022-07-26 16:47:23 -07001024 if (perMethodIndex == reqMethodIndex)
1025 {
Ed Tanous759cf102022-07-31 16:36:52 -07001026 findRoute.route = route;
Ed Tanous44e45182022-07-26 16:47:23 -07001027 }
1028 }
1029 return findRoute;
1030 }
1031
Ninad Palsule3e72c202023-03-27 17:19:55 -05001032 // Populate session with user information.
1033 static bool
1034 populateUserInfo(Request& req,
1035 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1036 const dbus::utility::DBusPropertiesMap& userInfoMap)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001037 {
Ed Tanous3d183202023-03-10 09:21:58 -08001038 const std::string* userRolePtr = nullptr;
1039 const bool* remoteUser = nullptr;
1040 const bool* passwordExpired = nullptr;
Ninad Palsule3e72c202023-03-27 17:19:55 -05001041 const std::vector<std::string>* userGroups = nullptr;
Ed Tanous3d183202023-03-10 09:21:58 -08001042
1043 const bool success = sdbusplus::unpackPropertiesNoThrow(
1044 redfish::dbus_utils::UnpackErrorPrinter(), userInfoMap,
1045 "UserPrivilege", userRolePtr, "RemoteUser", remoteUser,
Ninad Palsule3e72c202023-03-27 17:19:55 -05001046 "UserPasswordExpired", passwordExpired, "UserGroups", userGroups);
Ed Tanous3d183202023-03-10 09:21:58 -08001047
1048 if (!success)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001049 {
Ninad Palsule3e72c202023-03-27 17:19:55 -05001050 BMCWEB_LOG_ERROR << "Failed to unpack user properties.";
Ed Tanous3d183202023-03-10 09:21:58 -08001051 asyncResp->res.result(
1052 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301053 return false;
Ed Tanous3d183202023-03-10 09:21:58 -08001054 }
1055
1056 if (userRolePtr != nullptr)
1057 {
Ninad Palsule3e72c202023-03-27 17:19:55 -05001058 req.session->userRole = *userRolePtr;
Ed Tanous3d183202023-03-10 09:21:58 -08001059 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1060 << " userRole = " << *userRolePtr;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001061 }
1062
1063 if (remoteUser == nullptr)
1064 {
1065 BMCWEB_LOG_ERROR << "RemoteUser property missing or wrong type";
1066 asyncResp->res.result(
1067 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301068 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001069 }
Ed Tanous3d183202023-03-10 09:21:58 -08001070 bool expired = false;
1071 if (passwordExpired == nullptr)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001072 {
1073 if (!*remoteUser)
1074 {
1075 BMCWEB_LOG_ERROR
1076 << "UserPasswordExpired property is expected for"
1077 " local user but is missing or wrong type";
1078 asyncResp->res.result(
1079 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301080 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001081 }
Ed Tanous3d183202023-03-10 09:21:58 -08001082 }
1083 else
1084 {
1085 expired = *passwordExpired;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001086 }
1087
Ed Tanouse1f5c162023-03-10 09:02:51 -08001088 // Set isConfigureSelfOnly based on D-Bus results. This
1089 // ignores the results from both pamAuthenticateUser and the
1090 // value from any previous use of this session.
Ed Tanous3d183202023-03-10 09:21:58 -08001091 req.session->isConfigureSelfOnly = expired;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001092
Ninad Palsule3e72c202023-03-27 17:19:55 -05001093 if (userGroups != nullptr)
1094 {
1095 // Populate session with user groups.
1096 for (const auto& userGroup : *userGroups)
1097 {
1098 req.session->userGroups.emplace_back(userGroup);
1099 }
1100 }
1101
1102 return true;
1103 }
1104
1105 static bool
1106 isUserPrivileged(Request& req,
1107 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1108 BaseRule& rule)
1109 {
1110 // Get the user's privileges from the role
1111 redfish::Privileges userPrivileges =
1112 redfish::getUserPrivileges(*req.session);
1113
Ed Tanouse1f5c162023-03-10 09:02:51 -08001114 // Modify privileges if isConfigureSelfOnly.
1115 if (req.session->isConfigureSelfOnly)
1116 {
1117 // Remove all privileges except ConfigureSelf
1118 userPrivileges = userPrivileges.intersection(
1119 redfish::Privileges{"ConfigureSelf"});
1120 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1121 }
1122
1123 if (!rule.checkPrivileges(userPrivileges))
1124 {
1125 asyncResp->res.result(boost::beast::http::status::forbidden);
1126 if (req.session->isConfigureSelfOnly)
1127 {
1128 redfish::messages::passwordChangeRequired(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001129 asyncResp->res,
1130 boost::urls::format(
1131 "/redfish/v1/AccountService/Accounts/{}",
1132 req.session->username));
Ed Tanouse1f5c162023-03-10 09:02:51 -08001133 }
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301134 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001135 }
1136
Ninad Palsule3e72c202023-03-27 17:19:55 -05001137 req.userRole = req.session->userRole;
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301138 return true;
1139 }
1140
1141 template <typename CallbackFn>
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001142 void afterGetUserInfo(Request& req,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301143 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1144 BaseRule& rule, CallbackFn&& callback,
1145 const boost::system::error_code& ec,
1146 const dbus::utility::DBusPropertiesMap& userInfoMap)
1147 {
1148 if (ec)
1149 {
1150 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
1151 asyncResp->res.result(
1152 boost::beast::http::status::internal_server_error);
1153 return;
1154 }
1155
Ninad Palsule3e72c202023-03-27 17:19:55 -05001156 if (!populateUserInfo(req, asyncResp, userInfoMap))
1157 {
1158 BMCWEB_LOG_ERROR << "Failed to populate user information";
1159 asyncResp->res.result(
1160 boost::beast::http::status::internal_server_error);
1161 return;
1162 }
1163
1164 if (!Router::isUserPrivileged(req, asyncResp, rule))
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301165 {
1166 // User is not privileged
1167 BMCWEB_LOG_ERROR << "Insufficient Privilege";
1168 asyncResp->res.result(boost::beast::http::status::forbidden);
1169 return;
1170 }
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001171 callback(req);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301172 }
1173
1174 template <typename CallbackFn>
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001175 void validatePrivilege(Request& req,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301176 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1177 BaseRule& rule, CallbackFn&& callback)
1178 {
Ed Tanous915d2d42023-03-15 13:09:34 -07001179 if (req.session == nullptr)
1180 {
1181 return;
1182 }
1183 std::string username = req.session->username;
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301184 crow::connections::systemBus->async_method_call(
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001185 [this, &req, asyncResp, &rule,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301186 callback(std::forward<CallbackFn>(callback))](
1187 const boost::system::error_code& ec,
1188 const dbus::utility::DBusPropertiesMap& userInfoMap) mutable {
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001189 afterGetUserInfo(req, asyncResp, rule,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301190 std::forward<CallbackFn>(callback), ec,
1191 userInfoMap);
1192 },
1193 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
Ed Tanous915d2d42023-03-15 13:09:34 -07001194 "xyz.openbmc_project.User.Manager", "GetUserInfo", username);
Ed Tanouse1f5c162023-03-10 09:02:51 -08001195 }
1196
Ed Tanous1abe55e2018-09-05 08:30:59 -07001197 template <typename Adaptor>
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301198 void handleUpgrade(Request& req,
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301199 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1200 Adaptor&& adaptor)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001201 {
Ed Tanous2c9efc32022-07-31 22:08:26 -07001202 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1203 if (!verb || static_cast<size_t>(*verb) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001204 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301205 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001206 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001207 }
Ed Tanous2c9efc32022-07-31 22:08:26 -07001208 PerMethod& perMethod = perMethods[static_cast<size_t>(*verb)];
Tanousf00032d2018-11-05 01:18:10 -03001209 Trie& trie = perMethod.trie;
1210 std::vector<BaseRule*>& rules = perMethod.rules;
1211
Ed Tanous15a42df2023-02-09 18:08:23 -08001212 const std::pair<unsigned, std::vector<std::string>>& found =
Ed Tanous39662a32023-02-06 15:09:46 -08001213 trie.find(req.url().encoded_path());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001214 unsigned ruleIndex = found.first;
Ed Tanouse662eae2022-01-25 10:39:19 -08001215 if (ruleIndex == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001216 {
Ed Tanous39662a32023-02-06 15:09:46 -08001217 BMCWEB_LOG_DEBUG << "Cannot match rules "
1218 << req.url().encoded_path();
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301219 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001220 return;
1221 }
1222
1223 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001224 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001225 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001226 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001227
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301228 BaseRule& rule = *rules[ruleIndex];
1229 size_t methods = rule.getMethods();
1230 if ((methods & (1U << static_cast<size_t>(*verb))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001231 {
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301232 BMCWEB_LOG_DEBUG
1233 << "Rule found but method mismatch: "
1234 << req.url().encoded_path() << " with " << req.methodString()
1235 << "(" << static_cast<uint32_t>(*verb) << ") / " << methods;
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301236 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001237 return;
1238 }
1239
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301240 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rule.rule << "' "
1241 << static_cast<uint32_t>(*verb) << " / " << methods;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001242
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301243 // TODO(ed) This should be able to use std::bind_front, but it doesn't
1244 // appear to work with the std::move on adaptor.
Ed Tanous915d2d42023-03-15 13:09:34 -07001245 validatePrivilege(
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001246 req, asyncResp, rule,
Ed Tanous915d2d42023-03-15 13:09:34 -07001247 [&rule, asyncResp, adaptor(std::forward<Adaptor>(adaptor))](
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001248 Request& thisReq) mutable {
Ed Tanous915d2d42023-03-15 13:09:34 -07001249 rule.handleUpgrade(thisReq, asyncResp, std::move(adaptor));
1250 });
Ed Tanous7045c8d2017-04-03 10:04:37 -07001251 }
1252
zhanghch058d1b46d2021-04-01 11:18:24 +08001253 void handle(Request& req,
1254 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001255 {
Ed Tanous2c9efc32022-07-31 22:08:26 -07001256 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1257 if (!verb || static_cast<size_t>(*verb) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001258 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001259 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001260 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001261 }
Ed Tanous44e45182022-07-26 16:47:23 -07001262
1263 FindRouteResponse foundRoute = findRoute(req);
1264
Ed Tanous759cf102022-07-31 16:36:52 -07001265 if (foundRoute.route.rule == nullptr)
Ed Tanous88a03c52022-03-14 10:16:07 -07001266 {
Ed Tanous759cf102022-07-31 16:36:52 -07001267 // Couldn't find a normal route with any verb, try looking for a 404
1268 // route
1269 if (foundRoute.allowHeader.empty())
Ed Tanous44e45182022-07-26 16:47:23 -07001270 {
Patrick Williams89492a12023-05-10 07:51:34 -05001271 foundRoute.route = findRouteByIndex(req.url().encoded_path(),
1272 notFoundIndex);
Ed Tanous759cf102022-07-31 16:36:52 -07001273 }
1274 else
1275 {
1276 // See if we have a method not allowed (405) handler
Ed Tanous39662a32023-02-06 15:09:46 -08001277 foundRoute.route = findRouteByIndex(req.url().encoded_path(),
1278 methodNotAllowedIndex);
Ed Tanous44e45182022-07-26 16:47:23 -07001279 }
1280 }
Ed Tanous759cf102022-07-31 16:36:52 -07001281
1282 // Fill in the allow header if it's valid
1283 if (!foundRoute.allowHeader.empty())
Ed Tanous44e45182022-07-26 16:47:23 -07001284 {
Ed Tanous88a03c52022-03-14 10:16:07 -07001285 asyncResp->res.addHeader(boost::beast::http::field::allow,
Ed Tanous44e45182022-07-26 16:47:23 -07001286 foundRoute.allowHeader);
Ed Tanous88a03c52022-03-14 10:16:07 -07001287 }
Tanousf00032d2018-11-05 01:18:10 -03001288
Ed Tanous44e45182022-07-26 16:47:23 -07001289 // If we couldn't find a real route or a 404 route, return a generic
1290 // response
1291 if (foundRoute.route.rule == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001292 {
Ed Tanous44e45182022-07-26 16:47:23 -07001293 if (foundRoute.allowHeader.empty())
1294 {
1295 asyncResp->res.result(boost::beast::http::status::not_found);
1296 }
1297 else
Ed Tanous2634dcd2019-03-26 09:28:06 -07001298 {
Ed Tanous88a03c52022-03-14 10:16:07 -07001299 asyncResp->res.result(
1300 boost::beast::http::status::method_not_allowed);
Ed Tanous2634dcd2019-03-26 09:28:06 -07001301 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001302 return;
1303 }
1304
Ed Tanous44e45182022-07-26 16:47:23 -07001305 BaseRule& rule = *foundRoute.route.rule;
Ed Tanous15a42df2023-02-09 18:08:23 -08001306 std::vector<std::string> params = std::move(foundRoute.route.params);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001307
Ed Tanous44e45182022-07-26 16:47:23 -07001308 BMCWEB_LOG_DEBUG << "Matched rule '" << rule.rule << "' "
Snehalatha Venkatesh1c99da02022-12-27 06:45:35 +00001309 << static_cast<uint32_t>(*verb) << " / "
Ed Tanous44e45182022-07-26 16:47:23 -07001310 << rule.getMethods();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001311
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001312 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001313 {
Ed Tanous44e45182022-07-26 16:47:23 -07001314 rule.handle(req, asyncResp, params);
James Feist7166bf02019-12-10 16:52:14 +00001315 return;
1316 }
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001317 validatePrivilege(req, asyncResp, rule,
1318 [&rule, asyncResp, params](Request& thisReq) mutable {
Ed Tanous915d2d42023-03-15 13:09:34 -07001319 rule.handle(thisReq, asyncResp, params);
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001320 });
Ed Tanous7045c8d2017-04-03 10:04:37 -07001321 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001322
Ed Tanous1abe55e2018-09-05 08:30:59 -07001323 void debugPrint()
1324 {
Ed Tanous271584a2019-07-09 16:24:22 -07001325 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001326 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001327 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1328 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001329 perMethods[i].trie.debugPrint();
1330 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001331 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001332
Ed Tanous1abe55e2018-09-05 08:30:59 -07001333 std::vector<const std::string*> getRoutes(const std::string& parent)
1334 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001335 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001336
1337 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001338 {
Tanousf00032d2018-11-05 01:18:10 -03001339 std::vector<unsigned> x;
1340 pm.trie.findRouteIndexes(parent, x);
1341 for (unsigned index : x)
1342 {
1343 ret.push_back(&pm.rules[index]->rule);
1344 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001345 }
1346 return ret;
1347 }
1348
1349 private:
Tanousf00032d2018-11-05 01:18:10 -03001350 struct PerMethod
1351 {
1352 std::vector<BaseRule*> rules;
1353 Trie trie;
Ed Tanous313a3c22022-03-14 09:27:38 -07001354 // rule index 0 has special meaning; preallocate it to avoid
Tanousf00032d2018-11-05 01:18:10 -03001355 // duplication.
Patrick Williams89492a12023-05-10 07:51:34 -05001356 PerMethod() : rules(1) {}
Tanousf00032d2018-11-05 01:18:10 -03001357 };
Ed Tanous888880a2020-08-24 13:48:50 -07001358
Ed Tanous759cf102022-07-31 16:36:52 -07001359 std::array<PerMethod, methodNotAllowedIndex + 1> perMethods;
Tanousf00032d2018-11-05 01:18:10 -03001360 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001361};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001362} // namespace crow