blob: e73297c3e43d2d325eb56301eff7b4ce4b1509b5 [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 Tanous3d183202023-03-10 09:21:58 -080019#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050020
Ed Tanouse0d918b2018-03-27 17:41:04 -070021#include <cerrno>
Ed Tanous7045c8d2017-04-03 10:04:37 -070022#include <cstdint>
Ed Tanouse0d918b2018-03-27 17:41:04 -070023#include <cstdlib>
Ed Tanous3dac7492017-08-02 13:46:20 -070024#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070025#include <memory>
Ed Tanous2c9efc32022-07-31 22:08:26 -070026#include <optional>
Ed Tanous7045c8d2017-04-03 10:04:37 -070027#include <tuple>
Ed Tanous7045c8d2017-04-03 10:04:37 -070028#include <utility>
29#include <vector>
Ed Tanous9140a672017-04-24 17:01:32 -070030
Ed Tanous1abe55e2018-09-05 08:30:59 -070031namespace crow
32{
Tanousf00032d2018-11-05 01:18:10 -030033
Ed Tanous1abe55e2018-09-05 08:30:59 -070034class BaseRule
35{
36 public:
Ed Tanous4e23a442022-06-06 09:57:26 -070037 explicit BaseRule(const std::string& thisRule) : rule(thisRule)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050038 {}
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;
110 std::string nameStr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700111
Ed Tanous1abe55e2018-09-05 08:30:59 -0700112 std::unique_ptr<BaseRule> ruleToUpgrade;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700113
Ed Tanous1abe55e2018-09-05 08:30:59 -0700114 friend class Router;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500115 template <typename T>
116 friend struct RuleParameterTraits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700117};
118
Ed Tanous1abe55e2018-09-05 08:30:59 -0700119namespace detail
120{
121namespace routing_handler_call_helper
122{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500123template <typename T, int Pos>
124struct CallPair
Ed Tanous1abe55e2018-09-05 08:30:59 -0700125{
126 using type = T;
127 static const int pos = Pos;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700128};
129
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500130template <typename H1>
131struct CallParams
Ed Tanous1abe55e2018-09-05 08:30:59 -0700132{
133 H1& handler;
Ed Tanous15a42df2023-02-09 18:08:23 -0800134 const std::vector<std::string>& params;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700135 const Request& req;
zhanghch058d1b46d2021-04-01 11:18:24 +0800136 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700137};
138
Ed Tanous15a42df2023-02-09 18:08:23 -0800139template <typename F, int NString, typename S1, typename S2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700140struct Call
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500141{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700142
Ed Tanous15a42df2023-02-09 18:08:23 -0800143template <typename F, int NString, typename... Args1, typename... Args2>
144struct Call<F, NString, black_magic::S<std::string, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700145 black_magic::S<Args2...>>
146{
147 void operator()(F cparams)
148 {
149 using pushed = typename black_magic::S<Args2...>::template push_back<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700150 CallPair<std::string, NString>>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800151 Call<F, NString + 1, black_magic::S<Args1...>, pushed>()(cparams);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700152 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700153};
154
Ed Tanous15a42df2023-02-09 18:08:23 -0800155template <typename F, int NString, typename... Args1>
156struct Call<F, NString, black_magic::S<>, black_magic::S<Args1...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700157{
158 void operator()(F cparams)
159 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800160 cparams.handler(cparams.req, cparams.asyncResp,
161 cparams.params[Args1::pos]...);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700162 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700163};
164
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500165template <typename Func, typename... ArgsWrapped>
166struct Wrapped
Ed Tanous1abe55e2018-09-05 08:30:59 -0700167{
168 template <typename... Args>
169 void set(
170 Func f,
171 typename std::enable_if<
172 !std::is_same<
173 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
174 const Request&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800175 int>::type /*enable*/
176 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700177 {
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800178 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800179 const Request&,
180 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
181 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700182 }
183
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500184 template <typename Req, typename... Args>
185 struct ReqHandlerWrapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700186 {
Ed Tanous4e23a442022-06-06 09:57:26 -0700187 explicit ReqHandlerWrapper(Func fIn) : f(std::move(fIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500188 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700189
zhanghch058d1b46d2021-04-01 11:18:24 +0800190 void operator()(const Request& req,
191 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
192 Args... args)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700193 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800194 asyncResp->res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700195 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700196
Ed Tanous1abe55e2018-09-05 08:30:59 -0700197 Func f;
198 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700199
Ed Tanous1abe55e2018-09-05 08:30:59 -0700200 template <typename... Args>
201 void set(
202 Func f,
203 typename std::enable_if<
204 std::is_same<
205 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
206 const Request&>::value &&
207 !std::is_same<typename std::tuple_element<
208 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800209 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800210 int>::type /*enable*/
211 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700212 {
213 handler = ReqHandlerWrapper<Args...>(std::move(f));
214 /*handler = (
215 [f = std::move(f)]
216 (const Request& req, Response& res, Args... args){
Ed Tanousde5c9f32019-03-26 09:17:55 -0700217 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700218 res.end();
219 });*/
220 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700221
Ed Tanous1abe55e2018-09-05 08:30:59 -0700222 template <typename... Args>
223 void set(
224 Func f,
225 typename std::enable_if<
226 std::is_same<
227 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
228 const Request&>::value &&
229 std::is_same<typename std::tuple_element<
230 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800231 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800232 int>::type /*enable*/
233 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700234 {
235 handler = std::move(f);
236 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700237
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500238 template <typename... Args>
239 struct HandlerTypeHelper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700240 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800241 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800242 const crow::Request& /*req*/,
243 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800244 using args_type = black_magic::S<Args...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700245 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700246
Ed Tanous1abe55e2018-09-05 08:30:59 -0700247 template <typename... Args>
248 struct HandlerTypeHelper<const Request&, Args...>
249 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800250 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800251 const crow::Request& /*req*/,
252 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800253 using args_type = black_magic::S<Args...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700254 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700255
Ed Tanous1abe55e2018-09-05 08:30:59 -0700256 template <typename... Args>
zhanghch058d1b46d2021-04-01 11:18:24 +0800257 struct HandlerTypeHelper<const Request&,
258 const std::shared_ptr<bmcweb::AsyncResp>&, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700259 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800260 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800261 const crow::Request& /*req*/,
262 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800263 using args_type = black_magic::S<Args...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700264 };
265
266 typename HandlerTypeHelper<ArgsWrapped...>::type handler;
267
zhanghch058d1b46d2021-04-01 11:18:24 +0800268 void operator()(const Request& req,
269 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800270 const std::vector<std::string>& params)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700271 {
272 detail::routing_handler_call_helper::Call<
273 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
Ed Tanous15a42df2023-02-09 18:08:23 -0800274 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700275 black_magic::S<>>()(
276 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800277 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700278 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700279};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280} // namespace routing_handler_call_helper
281} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700282
Ed Tanous1abe55e2018-09-05 08:30:59 -0700283class WebSocketRule : public BaseRule
284{
285 using self_t = WebSocketRule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700286
Ed Tanous1abe55e2018-09-05 08:30:59 -0700287 public:
Ed Tanous4e23a442022-06-06 09:57:26 -0700288 explicit WebSocketRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500289 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700290
Ed Tanous1abe55e2018-09-05 08:30:59 -0700291 void validate() override
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500292 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700293
Ed Tanous104f09c2022-01-25 09:56:04 -0800294 void handle(const Request& /*req*/,
zhanghch058d1b46d2021-04-01 11:18:24 +0800295 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800296 const std::vector<std::string>& /*params*/) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700297 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800298 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700299 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700300
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +0530301#ifndef BMCWEB_ENABLE_SSL
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +0530302 void handleUpgrade(const Request& req,
303 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800304 boost::asio::ip::tcp::socket&& adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700305 {
Nan Zhou93c02022022-02-24 18:21:07 -0800306 BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
Ratan Gupta02453b12019-10-22 14:43:36 +0530307 std::shared_ptr<
308 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>
309 myConnection = std::make_shared<
310 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000311 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanous863c1c22022-02-21 21:33:06 -0800312 messageExHandler, closeHandler, errorHandler);
Ratan Gupta02453b12019-10-22 14:43:36 +0530313 myConnection->start();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700314 }
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +0530315#else
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +0530316 void handleUpgrade(const Request& req,
317 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800318 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
319 adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700320 {
Nan Zhou93c02022022-02-24 18:21:07 -0800321 BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
Ed Tanousceac6f72018-12-02 11:58:47 -0800322 std::shared_ptr<crow::websocket::ConnectionImpl<
323 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
324 myConnection = std::make_shared<crow::websocket::ConnectionImpl<
325 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000326 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanous863c1c22022-02-21 21:33:06 -0800327 messageExHandler, closeHandler, errorHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700328 myConnection->start();
329 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700330#endif
331
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500332 template <typename Func>
333 self_t& onopen(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700334 {
335 openHandler = f;
336 return *this;
337 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700338
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500339 template <typename Func>
340 self_t& onmessage(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700341 {
342 messageHandler = f;
343 return *this;
344 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700345
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500346 template <typename Func>
Ed Tanous863c1c22022-02-21 21:33:06 -0800347 self_t& onmessageex(Func f)
348 {
349 messageExHandler = f;
350 return *this;
351 }
352
353 template <typename Func>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500354 self_t& onclose(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700355 {
356 closeHandler = f;
357 return *this;
358 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700359
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500360 template <typename Func>
361 self_t& onerror(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700362 {
363 errorHandler = f;
364 return *this;
365 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700366
Ed Tanous1abe55e2018-09-05 08:30:59 -0700367 protected:
zhanghch0577726382021-10-21 14:07:57 +0800368 std::function<void(crow::websocket::Connection&)> openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700369 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
370 messageHandler;
Ed Tanous863c1c22022-02-21 21:33:06 -0800371 std::function<void(crow::websocket::Connection&, std::string_view,
372 crow::websocket::MessageType type,
373 std::function<void()>&& whenComplete)>
374 messageExHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700375 std::function<void(crow::websocket::Connection&, const std::string&)>
376 closeHandler;
377 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700378};
379
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500380template <typename T>
381struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700382{
383 using self_t = T;
384 WebSocketRule& websocket()
385 {
Ed Tanous271584a2019-07-09 16:24:22 -0700386 self_t* self = static_cast<self_t*>(this);
387 WebSocketRule* p = new WebSocketRule(self->rule);
Ed Tanous9d192c72023-04-10 10:20:13 -0700388 p->privilegesSet = self->privilegesSet;
Ed Tanous271584a2019-07-09 16:24:22 -0700389 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700390 return *p;
391 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700392
Ed Tanous26ccae32023-02-16 10:28:44 -0800393 self_t& name(std::string_view name) noexcept
Ed Tanous1abe55e2018-09-05 08:30:59 -0700394 {
Ed Tanous271584a2019-07-09 16:24:22 -0700395 self_t* self = static_cast<self_t*>(this);
Ed Tanousf23b7292020-10-15 09:41:17 -0700396 self->nameStr = name;
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 self_t& methods(boost::beast::http::verb method)
401 {
Ed Tanous271584a2019-07-09 16:24:22 -0700402 self_t* self = static_cast<self_t*>(this);
Ed Tanous2c9efc32022-07-31 22:08:26 -0700403 std::optional<HttpVerb> verb = httpVerbFromBoost(method);
404 if (verb)
405 {
406 self->methodsBitfield = 1U << static_cast<size_t>(*verb);
407 }
Ed Tanous271584a2019-07-09 16:24:22 -0700408 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700409 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700410
Ed Tanous1abe55e2018-09-05 08:30:59 -0700411 template <typename... MethodArgs>
Ed Tanous81ce6092020-12-17 16:54:55 +0000412 self_t& methods(boost::beast::http::verb method, MethodArgs... argsMethod)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700413 {
Ed Tanous271584a2019-07-09 16:24:22 -0700414 self_t* self = static_cast<self_t*>(this);
Ed Tanous81ce6092020-12-17 16:54:55 +0000415 methods(argsMethod...);
Ed Tanous2c9efc32022-07-31 22:08:26 -0700416 std::optional<HttpVerb> verb = httpVerbFromBoost(method);
417 if (verb)
418 {
419 self->methodsBitfield |= 1U << static_cast<size_t>(*verb);
420 }
Ed Tanous271584a2019-07-09 16:24:22 -0700421 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700422 }
Tanousf00032d2018-11-05 01:18:10 -0300423
Ed Tanous44e45182022-07-26 16:47:23 -0700424 self_t& notFound()
425 {
426 self_t* self = static_cast<self_t*>(this);
427 self->methodsBitfield = 1U << notFoundIndex;
428 return *self;
429 }
430
Ed Tanous759cf102022-07-31 16:36:52 -0700431 self_t& methodNotAllowed()
432 {
433 self_t* self = static_cast<self_t*>(this);
434 self->methodsBitfield = 1U << methodNotAllowedIndex;
435 return *self;
436 }
437
Ed Tanous432a8902021-06-14 15:28:56 -0700438 self_t& privileges(
439 const std::initializer_list<std::initializer_list<const char*>>& p)
Tanousf00032d2018-11-05 01:18:10 -0300440 {
Ed Tanous271584a2019-07-09 16:24:22 -0700441 self_t* self = static_cast<self_t*>(this);
Ed Tanous432a8902021-06-14 15:28:56 -0700442 for (const std::initializer_list<const char*>& privilege : p)
Tanousf00032d2018-11-05 01:18:10 -0300443 {
Ed Tanous271584a2019-07-09 16:24:22 -0700444 self->privilegesSet.emplace_back(privilege);
Tanousf00032d2018-11-05 01:18:10 -0300445 }
Ed Tanous271584a2019-07-09 16:24:22 -0700446 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300447 }
Ed Tanoused398212021-06-09 17:05:54 -0700448
449 template <size_t N, typename... MethodArgs>
450 self_t& privileges(const std::array<redfish::Privileges, N>& p)
451 {
452 self_t* self = static_cast<self_t*>(this);
453 for (const redfish::Privileges& privilege : p)
454 {
455 self->privilegesSet.emplace_back(privilege);
456 }
457 return *self;
458 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700459};
460
Ed Tanous1abe55e2018-09-05 08:30:59 -0700461class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
462{
463 public:
Ed Tanous4e23a442022-06-06 09:57:26 -0700464 explicit DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500465 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700466
Ed Tanous1abe55e2018-09-05 08:30:59 -0700467 void validate() override
468 {
469 if (!erasedHandler)
470 {
471 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
472 "no handler for url " + rule);
473 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700474 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700475
zhanghch058d1b46d2021-04-01 11:18:24 +0800476 void handle(const Request& req,
477 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800478 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800480 erasedHandler(req, asyncResp, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700482
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500483 template <typename Func>
484 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700485 {
Ed Tanousc867a832022-03-10 14:17:00 -0800486 using boost::callable_traits::args_t;
487 constexpr size_t arity = std::tuple_size<args_t<Func>>::value;
488 constexpr auto is = std::make_integer_sequence<unsigned, arity>{};
489 erasedHandler = wrap(std::move(f), is);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700490 }
491
492 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500493 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700494 // enable_if Arg1 != request
495
496 template <typename Func, unsigned... Indices>
zhanghch058d1b46d2021-04-01 11:18:24 +0800497 std::function<void(const Request&,
498 const std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous15a42df2023-02-09 18:08:23 -0800499 const std::vector<std::string>&)>
Ed Tanous104f09c2022-01-25 09:56:04 -0800500 wrap(Func f, std::integer_sequence<unsigned, Indices...> /*is*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700501 {
Ed Tanousc867a832022-03-10 14:17:00 -0800502 using function_t = crow::utility::FunctionTraits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503
Ed Tanous1abe55e2018-09-05 08:30:59 -0700504 auto ret = detail::routing_handler_call_helper::Wrapped<
505 Func, typename function_t::template arg<Indices>...>();
506 ret.template set<typename function_t::template arg<Indices>...>(
507 std::move(f));
508 return ret;
509 }
510
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500511 template <typename Func>
512 void operator()(std::string name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700513 {
514 nameStr = std::move(name);
515 (*this).template operator()<Func>(std::forward(f));
516 }
517
518 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800519 std::function<void(const Request&,
520 const std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous15a42df2023-02-09 18:08:23 -0800521 const std::vector<std::string>&)>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700522 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700523};
524
525template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500526class TaggedRule :
527 public BaseRule,
528 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700529{
530 public:
531 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700532
Ed Tanous4e23a442022-06-06 09:57:26 -0700533 explicit TaggedRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500534 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700535
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 void validate() override
537 {
538 if (!handler)
539 {
540 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
541 "no handler for url " + rule);
542 }
543 }
544
545 template <typename Func>
Ed Tanous15a42df2023-02-09 18:08:23 -0800546 void operator()(Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700547 {
548 static_assert(
Ed Tanous7045c8d2017-04-03 10:04:37 -0700549 black_magic::CallHelper<
Ed Tanous15a42df2023-02-09 18:08:23 -0800550 Func, black_magic::S<crow::Request,
551 std::shared_ptr<bmcweb::AsyncResp>&,
552 Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700553 "Handler type is mismatched with URL parameters");
554 static_assert(
zhanghch058d1b46d2021-04-01 11:18:24 +0800555 std::is_same<
556 void,
557 decltype(f(std::declval<crow::Request>(),
558 std::declval<std::shared_ptr<bmcweb::AsyncResp>&>(),
559 std::declval<Args>()...))>::value,
Ed Tanous15a42df2023-02-09 18:08:23 -0800560 "Handler function with response argument should have void return type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700561
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800562 handler = std::forward<Func>(f);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700563 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700564
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500565 template <typename Func>
Ed Tanous26ccae32023-02-16 10:28:44 -0800566 void operator()(std::string_view name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700567 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700568 nameStr = name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700569 (*this).template operator()<Func>(std::forward(f));
570 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700571
zhanghch058d1b46d2021-04-01 11:18:24 +0800572 void handle(const Request& req,
573 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800574 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700575 {
576 detail::routing_handler_call_helper::Call<
577 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
Ed Tanous15a42df2023-02-09 18:08:23 -0800578 0, black_magic::S<Args...>, black_magic::S<>>()(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700579 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800580 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700581 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700582
Ed Tanous1abe55e2018-09-05 08:30:59 -0700583 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800584 std::function<void(const crow::Request&,
585 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>
586 handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700587};
588
Ed Tanous1abe55e2018-09-05 08:30:59 -0700589class Trie
590{
591 public:
592 struct Node
593 {
594 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700595 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
596 paramChildrens{};
Ed Tanousa94ac612022-02-22 11:13:24 -0800597 using ChildMap = boost::container::flat_map<
598 std::string, unsigned, std::less<>,
599 std::vector<std::pair<std::string, unsigned>>>;
600 ChildMap children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700601
Ed Tanous1abe55e2018-09-05 08:30:59 -0700602 bool isSimpleNode() const
603 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800604 return ruleIndex == 0 &&
605 std::all_of(std::begin(paramChildrens),
606 std::end(paramChildrens),
607 [](size_t x) { return x == 0U; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700608 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700609 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700610
Ed Tanous1abe55e2018-09-05 08:30:59 -0700611 Trie() : nodes(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500612 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700613
614 private:
615 void optimizeNode(Node* node)
616 {
Ed Tanous271584a2019-07-09 16:24:22 -0700617 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700618 {
Ed Tanousdbb59d42022-01-25 11:09:55 -0800619 if (x == 0U)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700620 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700621 continue;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700622 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700623 Node* child = &nodes[x];
624 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700625 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700626 if (node->children.empty())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700627 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 return;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700629 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700630 bool mergeWithChild = true;
Ed Tanousa94ac612022-02-22 11:13:24 -0800631 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700632 {
633 Node* child = &nodes[kv.second];
634 if (!child->isSimpleNode())
635 {
636 mergeWithChild = false;
637 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700638 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700639 }
640 if (mergeWithChild)
641 {
Ed Tanousa94ac612022-02-22 11:13:24 -0800642 Node::ChildMap merged;
643 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700644 {
645 Node* child = &nodes[kv.second];
Ed Tanousa94ac612022-02-22 11:13:24 -0800646 for (const Node::ChildMap::value_type& childKv :
Tanousf00032d2018-11-05 01:18:10 -0300647 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700648 {
649 merged[kv.first + childKv.first] = childKv.second;
650 }
651 }
652 node->children = std::move(merged);
653 optimizeNode(node);
654 }
655 else
656 {
Ed Tanousa94ac612022-02-22 11:13:24 -0800657 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700658 {
659 Node* child = &nodes[kv.second];
660 optimizeNode(child);
661 }
662 }
663 }
664
665 void optimize()
666 {
667 optimizeNode(head());
668 }
669
670 public:
671 void validate()
672 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673 optimize();
674 }
675
Ed Tanous81ce6092020-12-17 16:54:55 +0000676 void findRouteIndexes(const std::string& reqUrl,
677 std::vector<unsigned>& routeIndexes,
Tanousf00032d2018-11-05 01:18:10 -0300678 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700679 {
680 if (node == nullptr)
681 {
682 node = head();
683 }
Ed Tanousa94ac612022-02-22 11:13:24 -0800684 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685 {
686 const std::string& fragment = kv.first;
687 const Node* child = &nodes[kv.second];
Ed Tanous81ce6092020-12-17 16:54:55 +0000688 if (pos >= reqUrl.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700689 {
690 if (child->ruleIndex != 0 && fragment != "/")
691 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000692 routeIndexes.push_back(child->ruleIndex);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700693 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000694 findRouteIndexes(reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700695 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700696 }
697 else
698 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000699 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700700 {
Ed Tanous271584a2019-07-09 16:24:22 -0700701 findRouteIndexes(
Ed Tanous81ce6092020-12-17 16:54:55 +0000702 reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700703 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700704 }
705 }
706 }
707 }
708
Ed Tanous15a42df2023-02-09 18:08:23 -0800709 std::pair<unsigned, std::vector<std::string>>
710 find(const std::string_view reqUrl, const Node* node = nullptr,
711 size_t pos = 0, std::vector<std::string>* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800713 std::vector<std::string> empty;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700714 if (params == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700715 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700716 params = &empty;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700717 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700718
719 unsigned found{};
Ed Tanous15a42df2023-02-09 18:08:23 -0800720 std::vector<std::string> matchParams;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700721
722 if (node == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700723 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700724 node = head();
Ed Tanous3174e4d2020-10-07 11:41:22 -0700725 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000726 if (pos == reqUrl.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700727 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700728 return {node->ruleIndex, *params};
Ed Tanous3174e4d2020-10-07 11:41:22 -0700729 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700730
731 auto updateFound =
Ed Tanous15a42df2023-02-09 18:08:23 -0800732 [&found,
733 &matchParams](std::pair<unsigned, std::vector<std::string>>& ret) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700734 if (ret.first != 0U && (found == 0U || found > ret.first))
735 {
736 found = ret.first;
737 matchParams = std::move(ret.second);
738 }
739 };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700740
Ed Tanouse662eae2022-01-25 10:39:19 -0800741 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700742 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000743 size_t epos = pos;
Ed Tanous81ce6092020-12-17 16:54:55 +0000744 for (; epos < reqUrl.size(); epos++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700745 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000746 if (reqUrl[epos] == '/')
Ed Tanous3174e4d2020-10-07 11:41:22 -0700747 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700748 break;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700749 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700750 }
751
752 if (epos != pos)
753 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800754 params->emplace_back(reqUrl.substr(pos, epos - pos));
755 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000756 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700757 &nodes[node->paramChildrens[static_cast<size_t>(
758 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000759 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700760 updateFound(ret);
Ed Tanous15a42df2023-02-09 18:08:23 -0800761 params->pop_back();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700762 }
763 }
764
Ed Tanouse662eae2022-01-25 10:39:19 -0800765 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000767 size_t epos = reqUrl.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700768
769 if (epos != pos)
770 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800771 params->emplace_back(reqUrl.substr(pos, epos - pos));
772 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000773 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700774 &nodes[node->paramChildrens[static_cast<size_t>(
775 ParamType::PATH)]],
776 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700777 updateFound(ret);
Ed Tanous15a42df2023-02-09 18:08:23 -0800778 params->pop_back();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700779 }
780 }
781
Ed Tanousa94ac612022-02-22 11:13:24 -0800782 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700783 {
784 const std::string& fragment = kv.first;
785 const Node* child = &nodes[kv.second];
786
Ed Tanous81ce6092020-12-17 16:54:55 +0000787 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700788 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800789 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000790 find(reqUrl, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791 updateFound(ret);
792 }
793 }
794
795 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700796 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700797
798 void add(const std::string& url, unsigned ruleIndex)
799 {
Ed Tanous271584a2019-07-09 16:24:22 -0700800 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801
802 for (unsigned i = 0; i < url.size(); i++)
803 {
804 char c = url[i];
805 if (c == '<')
806 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800807 constexpr static std::array<
808 std::pair<ParamType, std::string_view>, 3>
Tanousf00032d2018-11-05 01:18:10 -0300809 paramTraits = {{
Tanousf00032d2018-11-05 01:18:10 -0300810 {ParamType::STRING, "<str>"},
811 {ParamType::STRING, "<string>"},
812 {ParamType::PATH, "<path>"},
813 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700814
Ed Tanous15a42df2023-02-09 18:08:23 -0800815 for (const std::pair<ParamType, std::string_view>& x :
816 paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700817 {
Tanousf00032d2018-11-05 01:18:10 -0300818 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700819 {
Ed Tanous271584a2019-07-09 16:24:22 -0700820 size_t index = static_cast<size_t>(x.first);
Ed Tanouse662eae2022-01-25 10:39:19 -0800821 if (nodes[idx].paramChildrens[index] == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700822 {
Tanousf00032d2018-11-05 01:18:10 -0300823 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700824 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825 }
Ed Tanous271584a2019-07-09 16:24:22 -0700826 idx = nodes[idx].paramChildrens[index];
827 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828 break;
829 }
830 }
831
832 i--;
833 }
834 else
835 {
836 std::string piece(&c, 1);
Ed Tanouse662eae2022-01-25 10:39:19 -0800837 if (nodes[idx].children.count(piece) == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700838 {
Tanousf00032d2018-11-05 01:18:10 -0300839 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700840 nodes[idx].children.emplace(piece, newNodeIdx);
841 }
842 idx = nodes[idx].children[piece];
843 }
844 }
Ed Tanouse662eae2022-01-25 10:39:19 -0800845 if (nodes[idx].ruleIndex != 0U)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700846 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700847 throw std::runtime_error("handler already exists for " + url);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700848 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700849 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700850 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700851
Ed Tanous1abe55e2018-09-05 08:30:59 -0700852 private:
Ed Tanous271584a2019-07-09 16:24:22 -0700853 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700854 {
Ed Tanous271584a2019-07-09 16:24:22 -0700855 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700856 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800857 if (n->paramChildrens[i] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700858 {
859 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -0700860 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
861 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700862 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700863 case ParamType::STRING:
864 BMCWEB_LOG_DEBUG << "<str>";
865 break;
866 case ParamType::PATH:
867 BMCWEB_LOG_DEBUG << "<path>";
868 break;
Ed Tanous23a21a12020-07-25 04:45:05 +0000869 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -0700870 BMCWEB_LOG_DEBUG << "<ERROR>";
871 break;
872 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700873
Ed Tanous1abe55e2018-09-05 08:30:59 -0700874 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
875 }
876 }
Ed Tanousa94ac612022-02-22 11:13:24 -0800877 for (const Node::ChildMap::value_type& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700878 {
879 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -0700880 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -0700881 << kv.first;
882 debugNodePrint(&nodes[kv.second], level + 1);
883 }
884 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700885
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886 public:
887 void debugPrint()
888 {
Ed Tanous271584a2019-07-09 16:24:22 -0700889 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700890 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700891
Ed Tanous1abe55e2018-09-05 08:30:59 -0700892 private:
893 const Node* head() const
894 {
895 return &nodes.front();
896 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700897
Ed Tanous1abe55e2018-09-05 08:30:59 -0700898 Node* head()
899 {
900 return &nodes.front();
901 }
902
903 unsigned newNode()
904 {
905 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -0700906 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700907 }
908
909 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700910};
911
Ed Tanous1abe55e2018-09-05 08:30:59 -0700912class Router
913{
914 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -0700915 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700916
Ed Tanous1abe55e2018-09-05 08:30:59 -0700917 DynamicRule& newRuleDynamic(const std::string& rule)
918 {
919 std::unique_ptr<DynamicRule> ruleObject =
920 std::make_unique<DynamicRule>(rule);
921 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -0300922 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -0700923
Ed Tanous1abe55e2018-09-05 08:30:59 -0700924 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700925 }
926
Ed Tanous1abe55e2018-09-05 08:30:59 -0700927 template <uint64_t N>
928 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
929 newRuleTagged(const std::string& rule)
930 {
931 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
932 TaggedRule>;
933 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
934 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -0300935 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700936
937 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700938 }
939
Tanousf00032d2018-11-05 01:18:10 -0300940 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700941 {
Tanousf00032d2018-11-05 01:18:10 -0300942 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700943 {
Tanousf00032d2018-11-05 01:18:10 -0300944 return;
945 }
Ed Tanous759cf102022-07-31 16:36:52 -0700946 for (size_t method = 0, methodBit = 1; method <= methodNotAllowedIndex;
Ed Tanous2c70f802020-09-28 14:29:23 -0700947 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -0300948 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800949 if ((ruleObject->methodsBitfield & methodBit) > 0U)
Tanousf00032d2018-11-05 01:18:10 -0300950 {
951 perMethods[method].rules.emplace_back(ruleObject);
952 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -0700953 rule, static_cast<unsigned>(
954 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -0300955 // directory case:
956 // request to `/about' url matches `/about/' rule
957 if (rule.size() > 2 && rule.back() == '/')
958 {
959 perMethods[method].trie.add(
960 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -0700961 static_cast<unsigned>(perMethods[method].rules.size() -
962 1));
Tanousf00032d2018-11-05 01:18:10 -0300963 }
964 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700965 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700966 }
967
Ed Tanous1abe55e2018-09-05 08:30:59 -0700968 void validate()
969 {
Tanousf00032d2018-11-05 01:18:10 -0300970 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700971 {
972 if (rule)
973 {
Tanousf00032d2018-11-05 01:18:10 -0300974 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700975 if (upgraded)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700976 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700977 rule = std::move(upgraded);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700978 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700979 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -0300980 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700981 }
982 }
Tanousf00032d2018-11-05 01:18:10 -0300983 for (PerMethod& perMethod : perMethods)
984 {
985 perMethod.trie.validate();
986 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700987 }
988
Ed Tanous44e45182022-07-26 16:47:23 -0700989 struct FindRoute
990 {
991 BaseRule* rule = nullptr;
Ed Tanous15a42df2023-02-09 18:08:23 -0800992 std::vector<std::string> params;
Ed Tanous44e45182022-07-26 16:47:23 -0700993 };
994
995 struct FindRouteResponse
996 {
997 std::string allowHeader;
998 FindRoute route;
999 };
1000
Ed Tanous759cf102022-07-31 16:36:52 -07001001 FindRoute findRouteByIndex(std::string_view url, size_t index) const
1002 {
1003 FindRoute route;
1004 if (index >= perMethods.size())
1005 {
1006 BMCWEB_LOG_CRITICAL << "Bad index???";
1007 return route;
1008 }
1009 const PerMethod& perMethod = perMethods[index];
Ed Tanous15a42df2023-02-09 18:08:23 -08001010 std::pair<unsigned, std::vector<std::string>> found =
1011 perMethod.trie.find(url);
Ed Tanous759cf102022-07-31 16:36:52 -07001012 if (found.first >= perMethod.rules.size())
1013 {
1014 throw std::runtime_error("Trie internal structure corrupted!");
1015 }
1016 // Found a 404 route, switch that in
1017 if (found.first != 0U)
1018 {
1019 route.rule = perMethod.rules[found.first];
1020 route.params = std::move(found.second);
1021 }
1022 return route;
1023 }
1024
1025 FindRouteResponse findRoute(Request& req) const
Ed Tanous44e45182022-07-26 16:47:23 -07001026 {
1027 FindRouteResponse findRoute;
1028
Ed Tanous2c9efc32022-07-31 22:08:26 -07001029 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1030 if (!verb)
1031 {
1032 return findRoute;
1033 }
1034 size_t reqMethodIndex = static_cast<size_t>(*verb);
Ed Tanous44e45182022-07-26 16:47:23 -07001035 // Check to see if this url exists at any verb
1036 for (size_t perMethodIndex = 0; perMethodIndex <= maxVerbIndex;
1037 perMethodIndex++)
1038 {
1039 // Make sure it's safe to deference the array at that index
1040 static_assert(maxVerbIndex <
1041 std::tuple_size_v<decltype(perMethods)>);
Ed Tanous39662a32023-02-06 15:09:46 -08001042 FindRoute route =
1043 findRouteByIndex(req.url().encoded_path(), perMethodIndex);
Ed Tanous759cf102022-07-31 16:36:52 -07001044 if (route.rule == nullptr)
Ed Tanous44e45182022-07-26 16:47:23 -07001045 {
1046 continue;
1047 }
1048 if (!findRoute.allowHeader.empty())
1049 {
1050 findRoute.allowHeader += ", ";
1051 }
Ed Tanous2c9efc32022-07-31 22:08:26 -07001052 HttpVerb thisVerb = static_cast<HttpVerb>(perMethodIndex);
1053 findRoute.allowHeader += httpVerbToString(thisVerb);
Ed Tanous44e45182022-07-26 16:47:23 -07001054 if (perMethodIndex == reqMethodIndex)
1055 {
Ed Tanous759cf102022-07-31 16:36:52 -07001056 findRoute.route = route;
Ed Tanous44e45182022-07-26 16:47:23 -07001057 }
1058 }
1059 return findRoute;
1060 }
1061
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301062 static bool isUserPrivileged(
1063 Request& req, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1064 BaseRule& rule, const dbus::utility::DBusPropertiesMap& userInfoMap)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001065 {
Ed Tanous3d183202023-03-10 09:21:58 -08001066 std::string userRole{};
1067 const std::string* userRolePtr = nullptr;
1068 const bool* remoteUser = nullptr;
1069 const bool* passwordExpired = nullptr;
1070
1071 const bool success = sdbusplus::unpackPropertiesNoThrow(
1072 redfish::dbus_utils::UnpackErrorPrinter(), userInfoMap,
1073 "UserPrivilege", userRolePtr, "RemoteUser", remoteUser,
1074 "UserPasswordExpired", passwordExpired);
1075
1076 if (!success)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001077 {
Ed Tanous3d183202023-03-10 09:21:58 -08001078 asyncResp->res.result(
1079 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301080 return false;
Ed Tanous3d183202023-03-10 09:21:58 -08001081 }
1082
1083 if (userRolePtr != nullptr)
1084 {
1085 userRole = *userRolePtr;
1086 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1087 << " userRole = " << *userRolePtr;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001088 }
1089
1090 if (remoteUser == nullptr)
1091 {
1092 BMCWEB_LOG_ERROR << "RemoteUser property missing or wrong type";
1093 asyncResp->res.result(
1094 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301095 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001096 }
Ed Tanous3d183202023-03-10 09:21:58 -08001097 bool expired = false;
1098 if (passwordExpired == nullptr)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001099 {
1100 if (!*remoteUser)
1101 {
1102 BMCWEB_LOG_ERROR
1103 << "UserPasswordExpired property is expected for"
1104 " local user but is missing or wrong type";
1105 asyncResp->res.result(
1106 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301107 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001108 }
Ed Tanous3d183202023-03-10 09:21:58 -08001109 }
1110 else
1111 {
1112 expired = *passwordExpired;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001113 }
1114
1115 // Get the user's privileges from the role
1116 redfish::Privileges userPrivileges =
1117 redfish::getUserPrivileges(userRole);
1118
1119 // Set isConfigureSelfOnly based on D-Bus results. This
1120 // ignores the results from both pamAuthenticateUser and the
1121 // value from any previous use of this session.
Ed Tanous3d183202023-03-10 09:21:58 -08001122 req.session->isConfigureSelfOnly = expired;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001123
1124 // Modify privileges if isConfigureSelfOnly.
1125 if (req.session->isConfigureSelfOnly)
1126 {
1127 // Remove all privileges except ConfigureSelf
1128 userPrivileges = userPrivileges.intersection(
1129 redfish::Privileges{"ConfigureSelf"});
1130 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1131 }
1132
1133 if (!rule.checkPrivileges(userPrivileges))
1134 {
1135 asyncResp->res.result(boost::beast::http::status::forbidden);
1136 if (req.session->isConfigureSelfOnly)
1137 {
1138 redfish::messages::passwordChangeRequired(
1139 asyncResp->res, crow::utility::urlFromPieces(
1140 "redfish", "v1", "AccountService",
1141 "Accounts", req.session->username));
1142 }
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301143 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001144 }
1145
1146 req.userRole = userRole;
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301147
1148 return true;
1149 }
1150
1151 template <typename CallbackFn>
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001152 void afterGetUserInfo(Request& req,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301153 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1154 BaseRule& rule, CallbackFn&& callback,
1155 const boost::system::error_code& ec,
1156 const dbus::utility::DBusPropertiesMap& userInfoMap)
1157 {
1158 if (ec)
1159 {
1160 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
1161 asyncResp->res.result(
1162 boost::beast::http::status::internal_server_error);
1163 return;
1164 }
1165
1166 if (!Router::isUserPrivileged(req, asyncResp, rule, userInfoMap))
1167 {
1168 // User is not privileged
1169 BMCWEB_LOG_ERROR << "Insufficient Privilege";
1170 asyncResp->res.result(boost::beast::http::status::forbidden);
1171 return;
1172 }
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001173 callback(req);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301174 }
1175
1176 template <typename CallbackFn>
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001177 void validatePrivilege(Request& req,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301178 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1179 BaseRule& rule, CallbackFn&& callback)
1180 {
Ed Tanous915d2d42023-03-15 13:09:34 -07001181 if (req.session == nullptr)
1182 {
1183 return;
1184 }
1185 std::string username = req.session->username;
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301186 crow::connections::systemBus->async_method_call(
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001187 [this, &req, asyncResp, &rule,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301188 callback(std::forward<CallbackFn>(callback))](
1189 const boost::system::error_code& ec,
1190 const dbus::utility::DBusPropertiesMap& userInfoMap) mutable {
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001191 afterGetUserInfo(req, asyncResp, rule,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301192 std::forward<CallbackFn>(callback), ec,
1193 userInfoMap);
1194 },
1195 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
Ed Tanous915d2d42023-03-15 13:09:34 -07001196 "xyz.openbmc_project.User.Manager", "GetUserInfo", username);
Ed Tanouse1f5c162023-03-10 09:02:51 -08001197 }
1198
Ed Tanous1abe55e2018-09-05 08:30:59 -07001199 template <typename Adaptor>
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301200 void handleUpgrade(Request& req,
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301201 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1202 Adaptor&& adaptor)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001203 {
Ed Tanous2c9efc32022-07-31 22:08:26 -07001204 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1205 if (!verb || static_cast<size_t>(*verb) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001206 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301207 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001208 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001209 }
Ed Tanous2c9efc32022-07-31 22:08:26 -07001210 PerMethod& perMethod = perMethods[static_cast<size_t>(*verb)];
Tanousf00032d2018-11-05 01:18:10 -03001211 Trie& trie = perMethod.trie;
1212 std::vector<BaseRule*>& rules = perMethod.rules;
1213
Ed Tanous15a42df2023-02-09 18:08:23 -08001214 const std::pair<unsigned, std::vector<std::string>>& found =
Ed Tanous39662a32023-02-06 15:09:46 -08001215 trie.find(req.url().encoded_path());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001216 unsigned ruleIndex = found.first;
Ed Tanouse662eae2022-01-25 10:39:19 -08001217 if (ruleIndex == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001218 {
Ed Tanous39662a32023-02-06 15:09:46 -08001219 BMCWEB_LOG_DEBUG << "Cannot match rules "
1220 << req.url().encoded_path();
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301221 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001222 return;
1223 }
1224
1225 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001226 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001227 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001228 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001229
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301230 BaseRule& rule = *rules[ruleIndex];
1231 size_t methods = rule.getMethods();
1232 if ((methods & (1U << static_cast<size_t>(*verb))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001233 {
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301234 BMCWEB_LOG_DEBUG
1235 << "Rule found but method mismatch: "
1236 << req.url().encoded_path() << " with " << req.methodString()
1237 << "(" << static_cast<uint32_t>(*verb) << ") / " << methods;
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301238 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001239 return;
1240 }
1241
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301242 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rule.rule << "' "
1243 << static_cast<uint32_t>(*verb) << " / " << methods;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001244
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301245 // TODO(ed) This should be able to use std::bind_front, but it doesn't
1246 // appear to work with the std::move on adaptor.
Ed Tanous915d2d42023-03-15 13:09:34 -07001247 validatePrivilege(
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001248 req, asyncResp, rule,
Ed Tanous915d2d42023-03-15 13:09:34 -07001249 [&rule, asyncResp, adaptor(std::forward<Adaptor>(adaptor))](
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001250 Request& thisReq) mutable {
Ed Tanous915d2d42023-03-15 13:09:34 -07001251 rule.handleUpgrade(thisReq, asyncResp, std::move(adaptor));
1252 });
Ed Tanous7045c8d2017-04-03 10:04:37 -07001253 }
1254
zhanghch058d1b46d2021-04-01 11:18:24 +08001255 void handle(Request& req,
1256 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001257 {
Ed Tanous2c9efc32022-07-31 22:08:26 -07001258 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1259 if (!verb || static_cast<size_t>(*verb) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001260 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001261 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001262 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001263 }
Ed Tanous44e45182022-07-26 16:47:23 -07001264
1265 FindRouteResponse foundRoute = findRoute(req);
1266
Ed Tanous759cf102022-07-31 16:36:52 -07001267 if (foundRoute.route.rule == nullptr)
Ed Tanous88a03c52022-03-14 10:16:07 -07001268 {
Ed Tanous759cf102022-07-31 16:36:52 -07001269 // Couldn't find a normal route with any verb, try looking for a 404
1270 // route
1271 if (foundRoute.allowHeader.empty())
Ed Tanous44e45182022-07-26 16:47:23 -07001272 {
Ed Tanous39662a32023-02-06 15:09:46 -08001273 foundRoute.route =
1274 findRouteByIndex(req.url().encoded_path(), notFoundIndex);
Ed Tanous759cf102022-07-31 16:36:52 -07001275 }
1276 else
1277 {
1278 // See if we have a method not allowed (405) handler
Ed Tanous39662a32023-02-06 15:09:46 -08001279 foundRoute.route = findRouteByIndex(req.url().encoded_path(),
1280 methodNotAllowedIndex);
Ed Tanous44e45182022-07-26 16:47:23 -07001281 }
1282 }
Ed Tanous759cf102022-07-31 16:36:52 -07001283
1284 // Fill in the allow header if it's valid
1285 if (!foundRoute.allowHeader.empty())
Ed Tanous44e45182022-07-26 16:47:23 -07001286 {
Ed Tanous759cf102022-07-31 16:36:52 -07001287
Ed Tanous88a03c52022-03-14 10:16:07 -07001288 asyncResp->res.addHeader(boost::beast::http::field::allow,
Ed Tanous44e45182022-07-26 16:47:23 -07001289 foundRoute.allowHeader);
Ed Tanous88a03c52022-03-14 10:16:07 -07001290 }
Tanousf00032d2018-11-05 01:18:10 -03001291
Ed Tanous44e45182022-07-26 16:47:23 -07001292 // If we couldn't find a real route or a 404 route, return a generic
1293 // response
1294 if (foundRoute.route.rule == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001295 {
Ed Tanous44e45182022-07-26 16:47:23 -07001296 if (foundRoute.allowHeader.empty())
1297 {
1298 asyncResp->res.result(boost::beast::http::status::not_found);
1299 }
1300 else
Ed Tanous2634dcd2019-03-26 09:28:06 -07001301 {
Ed Tanous88a03c52022-03-14 10:16:07 -07001302 asyncResp->res.result(
1303 boost::beast::http::status::method_not_allowed);
Ed Tanous2634dcd2019-03-26 09:28:06 -07001304 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001305 return;
1306 }
1307
Ed Tanous44e45182022-07-26 16:47:23 -07001308 BaseRule& rule = *foundRoute.route.rule;
Ed Tanous15a42df2023-02-09 18:08:23 -08001309 std::vector<std::string> params = std::move(foundRoute.route.params);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001310
Ed Tanous44e45182022-07-26 16:47:23 -07001311 BMCWEB_LOG_DEBUG << "Matched rule '" << rule.rule << "' "
Snehalatha Venkatesh1c99da02022-12-27 06:45:35 +00001312 << static_cast<uint32_t>(*verb) << " / "
Ed Tanous44e45182022-07-26 16:47:23 -07001313 << rule.getMethods();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001314
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001315 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001316 {
Ed Tanous44e45182022-07-26 16:47:23 -07001317 rule.handle(req, asyncResp, params);
James Feist7166bf02019-12-10 16:52:14 +00001318 return;
1319 }
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001320 validatePrivilege(req, asyncResp, rule,
1321 [&rule, asyncResp, params](Request& thisReq) mutable {
Ed Tanous915d2d42023-03-15 13:09:34 -07001322 rule.handle(thisReq, asyncResp, params);
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001323 });
Ed Tanous7045c8d2017-04-03 10:04:37 -07001324 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001325
Ed Tanous1abe55e2018-09-05 08:30:59 -07001326 void debugPrint()
1327 {
Ed Tanous271584a2019-07-09 16:24:22 -07001328 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001329 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001330 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1331 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001332 perMethods[i].trie.debugPrint();
1333 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001334 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001335
Ed Tanous1abe55e2018-09-05 08:30:59 -07001336 std::vector<const std::string*> getRoutes(const std::string& parent)
1337 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001338 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001339
1340 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001341 {
Tanousf00032d2018-11-05 01:18:10 -03001342 std::vector<unsigned> x;
1343 pm.trie.findRouteIndexes(parent, x);
1344 for (unsigned index : x)
1345 {
1346 ret.push_back(&pm.rules[index]->rule);
1347 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001348 }
1349 return ret;
1350 }
1351
1352 private:
Tanousf00032d2018-11-05 01:18:10 -03001353 struct PerMethod
1354 {
1355 std::vector<BaseRule*> rules;
1356 Trie trie;
Ed Tanous313a3c22022-03-14 09:27:38 -07001357 // rule index 0 has special meaning; preallocate it to avoid
Tanousf00032d2018-11-05 01:18:10 -03001358 // duplication.
Ed Tanous313a3c22022-03-14 09:27:38 -07001359 PerMethod() : rules(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001360 {}
Tanousf00032d2018-11-05 01:18:10 -03001361 };
Ed Tanous888880a2020-08-24 13:48:50 -07001362
Ed Tanous759cf102022-07-31 16:36:52 -07001363 std::array<PerMethod, methodNotAllowedIndex + 1> perMethods;
Tanousf00032d2018-11-05 01:18:10 -03001364 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001365};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001366} // namespace crow