blob: 18d3c2afd9ef8f6f85baf6a89cab807ba7a24c6b [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;
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 {
Ed Tanous4e23a442022-06-06 09:57:26 -0700186 explicit ReqHandlerWrapper(Func fIn) : f(std::move(fIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500187 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700188
zhanghch058d1b46d2021-04-01 11:18:24 +0800189 void operator()(const Request& req,
190 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
191 Args... args)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700192 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800193 asyncResp->res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700194 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700195
Ed Tanous1abe55e2018-09-05 08:30:59 -0700196 Func f;
197 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700198
Ed Tanous1abe55e2018-09-05 08:30:59 -0700199 template <typename... Args>
200 void set(
201 Func f,
202 typename std::enable_if<
203 std::is_same<
204 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
205 const Request&>::value &&
206 !std::is_same<typename std::tuple_element<
207 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800208 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800209 int>::type /*enable*/
210 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700211 {
212 handler = ReqHandlerWrapper<Args...>(std::move(f));
213 /*handler = (
214 [f = std::move(f)]
215 (const Request& req, Response& res, Args... args){
Ed Tanousde5c9f32019-03-26 09:17:55 -0700216 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700217 res.end();
218 });*/
219 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700220
Ed Tanous1abe55e2018-09-05 08:30:59 -0700221 template <typename... Args>
222 void set(
223 Func f,
224 typename std::enable_if<
225 std::is_same<
226 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
227 const Request&>::value &&
228 std::is_same<typename std::tuple_element<
229 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800230 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800231 int>::type /*enable*/
232 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700233 {
234 handler = std::move(f);
235 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700236
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500237 template <typename... Args>
238 struct HandlerTypeHelper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700239 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800240 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800241 const crow::Request& /*req*/,
242 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800243 using args_type = black_magic::S<Args...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700244 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700245
Ed Tanous1abe55e2018-09-05 08:30:59 -0700246 template <typename... Args>
247 struct HandlerTypeHelper<const Request&, Args...>
248 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800249 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800250 const crow::Request& /*req*/,
251 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800252 using args_type = black_magic::S<Args...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700253 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700254
Ed Tanous1abe55e2018-09-05 08:30:59 -0700255 template <typename... Args>
zhanghch058d1b46d2021-04-01 11:18:24 +0800256 struct HandlerTypeHelper<const Request&,
257 const std::shared_ptr<bmcweb::AsyncResp>&, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700258 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800259 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800260 const crow::Request& /*req*/,
261 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800262 using args_type = black_magic::S<Args...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700263 };
264
265 typename HandlerTypeHelper<ArgsWrapped...>::type handler;
266
zhanghch058d1b46d2021-04-01 11:18:24 +0800267 void operator()(const Request& req,
268 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800269 const std::vector<std::string>& params)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700270 {
271 detail::routing_handler_call_helper::Call<
272 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
Ed Tanous15a42df2023-02-09 18:08:23 -0800273 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700274 black_magic::S<>>()(
275 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800276 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700277 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700278};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700279} // namespace routing_handler_call_helper
280} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700281
Ed Tanous1abe55e2018-09-05 08:30:59 -0700282class WebSocketRule : public BaseRule
283{
284 using self_t = WebSocketRule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700285
Ed Tanous1abe55e2018-09-05 08:30:59 -0700286 public:
Ed Tanous4e23a442022-06-06 09:57:26 -0700287 explicit WebSocketRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500288 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700289
Ed Tanous1abe55e2018-09-05 08:30:59 -0700290 void validate() override
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500291 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700292
Ed Tanous104f09c2022-01-25 09:56:04 -0800293 void handle(const Request& /*req*/,
zhanghch058d1b46d2021-04-01 11:18:24 +0800294 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800295 const std::vector<std::string>& /*params*/) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700296 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800297 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700298 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700299
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +0530300#ifndef BMCWEB_ENABLE_SSL
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +0530301 void handleUpgrade(const Request& req,
302 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800303 boost::asio::ip::tcp::socket&& adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700304 {
Nan Zhou93c02022022-02-24 18:21:07 -0800305 BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
Ratan Gupta02453b12019-10-22 14:43:36 +0530306 std::shared_ptr<
307 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>
308 myConnection = std::make_shared<
309 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000310 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanous863c1c22022-02-21 21:33:06 -0800311 messageExHandler, closeHandler, errorHandler);
Ratan Gupta02453b12019-10-22 14:43:36 +0530312 myConnection->start();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700313 }
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +0530314#else
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +0530315 void handleUpgrade(const Request& req,
316 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800317 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
318 adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700319 {
Nan Zhou93c02022022-02-24 18:21:07 -0800320 BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
Ed Tanousceac6f72018-12-02 11:58:47 -0800321 std::shared_ptr<crow::websocket::ConnectionImpl<
322 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
323 myConnection = std::make_shared<crow::websocket::ConnectionImpl<
324 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000325 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanous863c1c22022-02-21 21:33:06 -0800326 messageExHandler, closeHandler, errorHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700327 myConnection->start();
328 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700329#endif
330
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500331 template <typename Func>
332 self_t& onopen(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700333 {
334 openHandler = f;
335 return *this;
336 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700337
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500338 template <typename Func>
339 self_t& onmessage(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700340 {
341 messageHandler = f;
342 return *this;
343 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700344
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500345 template <typename Func>
Ed Tanous863c1c22022-02-21 21:33:06 -0800346 self_t& onmessageex(Func f)
347 {
348 messageExHandler = f;
349 return *this;
350 }
351
352 template <typename Func>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500353 self_t& onclose(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700354 {
355 closeHandler = f;
356 return *this;
357 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700358
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500359 template <typename Func>
360 self_t& onerror(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700361 {
362 errorHandler = f;
363 return *this;
364 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700365
Ed Tanous1abe55e2018-09-05 08:30:59 -0700366 protected:
zhanghch0577726382021-10-21 14:07:57 +0800367 std::function<void(crow::websocket::Connection&)> openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700368 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
369 messageHandler;
Ed Tanous863c1c22022-02-21 21:33:06 -0800370 std::function<void(crow::websocket::Connection&, std::string_view,
371 crow::websocket::MessageType type,
372 std::function<void()>&& whenComplete)>
373 messageExHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700374 std::function<void(crow::websocket::Connection&, const std::string&)>
375 closeHandler;
376 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700377};
378
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500379template <typename T>
380struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700381{
382 using self_t = T;
383 WebSocketRule& websocket()
384 {
Ed Tanous271584a2019-07-09 16:24:22 -0700385 self_t* self = static_cast<self_t*>(this);
386 WebSocketRule* p = new WebSocketRule(self->rule);
Ed Tanous9d192c72023-04-10 10:20:13 -0700387 p->privilegesSet = self->privilegesSet;
Ed Tanous271584a2019-07-09 16:24:22 -0700388 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700389 return *p;
390 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700391
Ed Tanous1abe55e2018-09-05 08:30:59 -0700392 self_t& methods(boost::beast::http::verb method)
393 {
Ed Tanous271584a2019-07-09 16:24:22 -0700394 self_t* self = static_cast<self_t*>(this);
Ed Tanous2c9efc32022-07-31 22:08:26 -0700395 std::optional<HttpVerb> verb = httpVerbFromBoost(method);
396 if (verb)
397 {
398 self->methodsBitfield = 1U << static_cast<size_t>(*verb);
399 }
Ed Tanous271584a2019-07-09 16:24:22 -0700400 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700401 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700402
Ed Tanous1abe55e2018-09-05 08:30:59 -0700403 template <typename... MethodArgs>
Ed Tanous81ce6092020-12-17 16:54:55 +0000404 self_t& methods(boost::beast::http::verb method, MethodArgs... argsMethod)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700405 {
Ed Tanous271584a2019-07-09 16:24:22 -0700406 self_t* self = static_cast<self_t*>(this);
Ed Tanous81ce6092020-12-17 16:54:55 +0000407 methods(argsMethod...);
Ed Tanous2c9efc32022-07-31 22:08:26 -0700408 std::optional<HttpVerb> verb = httpVerbFromBoost(method);
409 if (verb)
410 {
411 self->methodsBitfield |= 1U << static_cast<size_t>(*verb);
412 }
Ed Tanous271584a2019-07-09 16:24:22 -0700413 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700414 }
Tanousf00032d2018-11-05 01:18:10 -0300415
Ed Tanous44e45182022-07-26 16:47:23 -0700416 self_t& notFound()
417 {
418 self_t* self = static_cast<self_t*>(this);
419 self->methodsBitfield = 1U << notFoundIndex;
420 return *self;
421 }
422
Ed Tanous759cf102022-07-31 16:36:52 -0700423 self_t& methodNotAllowed()
424 {
425 self_t* self = static_cast<self_t*>(this);
426 self->methodsBitfield = 1U << methodNotAllowedIndex;
427 return *self;
428 }
429
Ed Tanous432a8902021-06-14 15:28:56 -0700430 self_t& privileges(
431 const std::initializer_list<std::initializer_list<const char*>>& p)
Tanousf00032d2018-11-05 01:18:10 -0300432 {
Ed Tanous271584a2019-07-09 16:24:22 -0700433 self_t* self = static_cast<self_t*>(this);
Ed Tanous432a8902021-06-14 15:28:56 -0700434 for (const std::initializer_list<const char*>& privilege : p)
Tanousf00032d2018-11-05 01:18:10 -0300435 {
Ed Tanous271584a2019-07-09 16:24:22 -0700436 self->privilegesSet.emplace_back(privilege);
Tanousf00032d2018-11-05 01:18:10 -0300437 }
Ed Tanous271584a2019-07-09 16:24:22 -0700438 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300439 }
Ed Tanoused398212021-06-09 17:05:54 -0700440
441 template <size_t N, typename... MethodArgs>
442 self_t& privileges(const std::array<redfish::Privileges, N>& p)
443 {
444 self_t* self = static_cast<self_t*>(this);
445 for (const redfish::Privileges& privilege : p)
446 {
447 self->privilegesSet.emplace_back(privilege);
448 }
449 return *self;
450 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700451};
452
Ed Tanous1abe55e2018-09-05 08:30:59 -0700453class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
454{
455 public:
Ed Tanous4e23a442022-06-06 09:57:26 -0700456 explicit DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500457 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700458
Ed Tanous1abe55e2018-09-05 08:30:59 -0700459 void validate() override
460 {
461 if (!erasedHandler)
462 {
Ed Tanous28f4b382023-04-10 10:20:56 -0700463 throw std::runtime_error("no handler for url " + rule);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700464 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700465 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700466
zhanghch058d1b46d2021-04-01 11:18:24 +0800467 void handle(const Request& req,
468 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800469 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700470 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800471 erasedHandler(req, asyncResp, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700472 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700473
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500474 template <typename Func>
475 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700476 {
Ed Tanousc867a832022-03-10 14:17:00 -0800477 using boost::callable_traits::args_t;
478 constexpr size_t arity = std::tuple_size<args_t<Func>>::value;
479 constexpr auto is = std::make_integer_sequence<unsigned, arity>{};
480 erasedHandler = wrap(std::move(f), is);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481 }
482
483 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500484 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700485 // enable_if Arg1 != request
486
487 template <typename Func, unsigned... Indices>
zhanghch058d1b46d2021-04-01 11:18:24 +0800488 std::function<void(const Request&,
489 const std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous15a42df2023-02-09 18:08:23 -0800490 const std::vector<std::string>&)>
Ed Tanous104f09c2022-01-25 09:56:04 -0800491 wrap(Func f, std::integer_sequence<unsigned, Indices...> /*is*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700492 {
Ed Tanousc867a832022-03-10 14:17:00 -0800493 using function_t = crow::utility::FunctionTraits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700494
Ed Tanous1abe55e2018-09-05 08:30:59 -0700495 auto ret = detail::routing_handler_call_helper::Wrapped<
496 Func, typename function_t::template arg<Indices>...>();
497 ret.template set<typename function_t::template arg<Indices>...>(
498 std::move(f));
499 return ret;
500 }
501
Ed Tanous1abe55e2018-09-05 08:30:59 -0700502 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800503 std::function<void(const Request&,
504 const std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous15a42df2023-02-09 18:08:23 -0800505 const std::vector<std::string>&)>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700506 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700507};
508
509template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500510class TaggedRule :
511 public BaseRule,
512 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700513{
514 public:
515 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700516
Ed Tanous4e23a442022-06-06 09:57:26 -0700517 explicit TaggedRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500518 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700519
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520 void validate() override
521 {
522 if (!handler)
523 {
Ed Tanous28f4b382023-04-10 10:20:56 -0700524 throw std::runtime_error("no handler for url " + rule);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700525 }
526 }
527
528 template <typename Func>
Ed Tanous15a42df2023-02-09 18:08:23 -0800529 void operator()(Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700530 {
531 static_assert(
Ed Tanous7045c8d2017-04-03 10:04:37 -0700532 black_magic::CallHelper<
Ed Tanous15a42df2023-02-09 18:08:23 -0800533 Func, black_magic::S<crow::Request,
534 std::shared_ptr<bmcweb::AsyncResp>&,
535 Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 "Handler type is mismatched with URL parameters");
537 static_assert(
zhanghch058d1b46d2021-04-01 11:18:24 +0800538 std::is_same<
539 void,
540 decltype(f(std::declval<crow::Request>(),
541 std::declval<std::shared_ptr<bmcweb::AsyncResp>&>(),
542 std::declval<Args>()...))>::value,
Ed Tanous15a42df2023-02-09 18:08:23 -0800543 "Handler function with response argument should have void return type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700544
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800545 handler = std::forward<Func>(f);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700546 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700547
zhanghch058d1b46d2021-04-01 11:18:24 +0800548 void handle(const Request& req,
549 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800550 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700551 {
552 detail::routing_handler_call_helper::Call<
553 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
Ed Tanous15a42df2023-02-09 18:08:23 -0800554 0, black_magic::S<Args...>, black_magic::S<>>()(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700555 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800556 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700557 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700558
Ed Tanous1abe55e2018-09-05 08:30:59 -0700559 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800560 std::function<void(const crow::Request&,
561 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>
562 handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700563};
564
Ed Tanous1abe55e2018-09-05 08:30:59 -0700565class Trie
566{
567 public:
568 struct Node
569 {
570 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700571 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
572 paramChildrens{};
Ed Tanousa94ac612022-02-22 11:13:24 -0800573 using ChildMap = boost::container::flat_map<
574 std::string, unsigned, std::less<>,
575 std::vector<std::pair<std::string, unsigned>>>;
576 ChildMap children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700577
Ed Tanous1abe55e2018-09-05 08:30:59 -0700578 bool isSimpleNode() const
579 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800580 return ruleIndex == 0 &&
581 std::all_of(std::begin(paramChildrens),
582 std::end(paramChildrens),
583 [](size_t x) { return x == 0U; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700584 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700585 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700586
Ed Tanous1abe55e2018-09-05 08:30:59 -0700587 Trie() : nodes(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500588 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700589
590 private:
591 void optimizeNode(Node* node)
592 {
Ed Tanous271584a2019-07-09 16:24:22 -0700593 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700594 {
Ed Tanousdbb59d42022-01-25 11:09:55 -0800595 if (x == 0U)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700596 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700597 continue;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700598 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599 Node* child = &nodes[x];
600 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700601 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700602 if (node->children.empty())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700603 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700604 return;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700605 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700606 bool mergeWithChild = true;
Ed Tanousa94ac612022-02-22 11:13:24 -0800607 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700608 {
609 Node* child = &nodes[kv.second];
610 if (!child->isSimpleNode())
611 {
612 mergeWithChild = false;
613 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700614 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700615 }
616 if (mergeWithChild)
617 {
Ed Tanousa94ac612022-02-22 11:13:24 -0800618 Node::ChildMap merged;
619 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700620 {
621 Node* child = &nodes[kv.second];
Ed Tanousa94ac612022-02-22 11:13:24 -0800622 for (const Node::ChildMap::value_type& childKv :
Tanousf00032d2018-11-05 01:18:10 -0300623 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700624 {
625 merged[kv.first + childKv.first] = childKv.second;
626 }
627 }
628 node->children = std::move(merged);
629 optimizeNode(node);
630 }
631 else
632 {
Ed Tanousa94ac612022-02-22 11:13:24 -0800633 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700634 {
635 Node* child = &nodes[kv.second];
636 optimizeNode(child);
637 }
638 }
639 }
640
641 void optimize()
642 {
643 optimizeNode(head());
644 }
645
646 public:
647 void validate()
648 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700649 optimize();
650 }
651
Ed Tanous81ce6092020-12-17 16:54:55 +0000652 void findRouteIndexes(const std::string& reqUrl,
653 std::vector<unsigned>& routeIndexes,
Tanousf00032d2018-11-05 01:18:10 -0300654 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700655 {
656 if (node == nullptr)
657 {
658 node = head();
659 }
Ed Tanousa94ac612022-02-22 11:13:24 -0800660 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700661 {
662 const std::string& fragment = kv.first;
663 const Node* child = &nodes[kv.second];
Ed Tanous81ce6092020-12-17 16:54:55 +0000664 if (pos >= reqUrl.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 {
666 if (child->ruleIndex != 0 && fragment != "/")
667 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000668 routeIndexes.push_back(child->ruleIndex);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700669 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000670 findRouteIndexes(reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700671 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700672 }
673 else
674 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000675 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700676 {
Ed Tanous271584a2019-07-09 16:24:22 -0700677 findRouteIndexes(
Ed Tanous81ce6092020-12-17 16:54:55 +0000678 reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700679 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700680 }
681 }
682 }
683 }
684
Ed Tanous15a42df2023-02-09 18:08:23 -0800685 std::pair<unsigned, std::vector<std::string>>
686 find(const std::string_view reqUrl, const Node* node = nullptr,
687 size_t pos = 0, std::vector<std::string>* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800689 std::vector<std::string> empty;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700690 if (params == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700691 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 params = &empty;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700693 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700694
695 unsigned found{};
Ed Tanous15a42df2023-02-09 18:08:23 -0800696 std::vector<std::string> matchParams;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700697
698 if (node == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700699 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700700 node = head();
Ed Tanous3174e4d2020-10-07 11:41:22 -0700701 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000702 if (pos == reqUrl.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700703 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700704 return {node->ruleIndex, *params};
Ed Tanous3174e4d2020-10-07 11:41:22 -0700705 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700706
707 auto updateFound =
Ed Tanous15a42df2023-02-09 18:08:23 -0800708 [&found,
709 &matchParams](std::pair<unsigned, std::vector<std::string>>& ret) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700710 if (ret.first != 0U && (found == 0U || found > ret.first))
711 {
712 found = ret.first;
713 matchParams = std::move(ret.second);
714 }
715 };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700716
Ed Tanouse662eae2022-01-25 10:39:19 -0800717 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700718 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000719 size_t epos = pos;
Ed Tanous81ce6092020-12-17 16:54:55 +0000720 for (; epos < reqUrl.size(); epos++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700721 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000722 if (reqUrl[epos] == '/')
Ed Tanous3174e4d2020-10-07 11:41:22 -0700723 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700724 break;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700725 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700726 }
727
728 if (epos != pos)
729 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800730 params->emplace_back(reqUrl.substr(pos, epos - pos));
731 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000732 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700733 &nodes[node->paramChildrens[static_cast<size_t>(
734 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000735 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700736 updateFound(ret);
Ed Tanous15a42df2023-02-09 18:08:23 -0800737 params->pop_back();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700738 }
739 }
740
Ed Tanouse662eae2022-01-25 10:39:19 -0800741 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700742 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000743 size_t epos = reqUrl.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700744
745 if (epos != pos)
746 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800747 params->emplace_back(reqUrl.substr(pos, epos - pos));
748 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000749 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700750 &nodes[node->paramChildrens[static_cast<size_t>(
751 ParamType::PATH)]],
752 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 updateFound(ret);
Ed Tanous15a42df2023-02-09 18:08:23 -0800754 params->pop_back();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700755 }
756 }
757
Ed Tanousa94ac612022-02-22 11:13:24 -0800758 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700759 {
760 const std::string& fragment = kv.first;
761 const Node* child = &nodes[kv.second];
762
Ed Tanous81ce6092020-12-17 16:54:55 +0000763 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800765 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000766 find(reqUrl, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700767 updateFound(ret);
768 }
769 }
770
771 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700772 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700773
774 void add(const std::string& url, unsigned ruleIndex)
775 {
Ed Tanous271584a2019-07-09 16:24:22 -0700776 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700777
778 for (unsigned i = 0; i < url.size(); i++)
779 {
780 char c = url[i];
781 if (c == '<')
782 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800783 constexpr static std::array<
784 std::pair<ParamType, std::string_view>, 3>
Tanousf00032d2018-11-05 01:18:10 -0300785 paramTraits = {{
Tanousf00032d2018-11-05 01:18:10 -0300786 {ParamType::STRING, "<str>"},
787 {ParamType::STRING, "<string>"},
788 {ParamType::PATH, "<path>"},
789 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700790
Ed Tanous15a42df2023-02-09 18:08:23 -0800791 for (const std::pair<ParamType, std::string_view>& x :
792 paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700793 {
Tanousf00032d2018-11-05 01:18:10 -0300794 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700795 {
Ed Tanous271584a2019-07-09 16:24:22 -0700796 size_t index = static_cast<size_t>(x.first);
Ed Tanouse662eae2022-01-25 10:39:19 -0800797 if (nodes[idx].paramChildrens[index] == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700798 {
Tanousf00032d2018-11-05 01:18:10 -0300799 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700800 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 }
Ed Tanous271584a2019-07-09 16:24:22 -0700802 idx = nodes[idx].paramChildrens[index];
803 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700804 break;
805 }
806 }
807
808 i--;
809 }
810 else
811 {
812 std::string piece(&c, 1);
Ed Tanouse662eae2022-01-25 10:39:19 -0800813 if (nodes[idx].children.count(piece) == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700814 {
Tanousf00032d2018-11-05 01:18:10 -0300815 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700816 nodes[idx].children.emplace(piece, newNodeIdx);
817 }
818 idx = nodes[idx].children[piece];
819 }
820 }
Ed Tanouse662eae2022-01-25 10:39:19 -0800821 if (nodes[idx].ruleIndex != 0U)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700822 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700823 throw std::runtime_error("handler already exists for " + url);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700824 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700826 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700827
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828 private:
Ed Tanous271584a2019-07-09 16:24:22 -0700829 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700830 {
Ed Tanous271584a2019-07-09 16:24:22 -0700831 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700832 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800833 if (n->paramChildrens[i] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700834 {
835 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -0700836 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
837 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700838 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700839 case ParamType::STRING:
840 BMCWEB_LOG_DEBUG << "<str>";
841 break;
842 case ParamType::PATH:
843 BMCWEB_LOG_DEBUG << "<path>";
844 break;
Ed Tanous23a21a12020-07-25 04:45:05 +0000845 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -0700846 BMCWEB_LOG_DEBUG << "<ERROR>";
847 break;
848 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700849
Ed Tanous1abe55e2018-09-05 08:30:59 -0700850 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
851 }
852 }
Ed Tanousa94ac612022-02-22 11:13:24 -0800853 for (const Node::ChildMap::value_type& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700854 {
855 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -0700856 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -0700857 << kv.first;
858 debugNodePrint(&nodes[kv.second], level + 1);
859 }
860 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700861
Ed Tanous1abe55e2018-09-05 08:30:59 -0700862 public:
863 void debugPrint()
864 {
Ed Tanous271584a2019-07-09 16:24:22 -0700865 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700866 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700867
Ed Tanous1abe55e2018-09-05 08:30:59 -0700868 private:
869 const Node* head() const
870 {
871 return &nodes.front();
872 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700873
Ed Tanous1abe55e2018-09-05 08:30:59 -0700874 Node* head()
875 {
876 return &nodes.front();
877 }
878
879 unsigned newNode()
880 {
881 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -0700882 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700883 }
884
885 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700886};
887
Ed Tanous1abe55e2018-09-05 08:30:59 -0700888class Router
889{
890 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -0700891 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700892
Ed Tanous1abe55e2018-09-05 08:30:59 -0700893 DynamicRule& newRuleDynamic(const std::string& rule)
894 {
895 std::unique_ptr<DynamicRule> ruleObject =
896 std::make_unique<DynamicRule>(rule);
897 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -0300898 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -0700899
Ed Tanous1abe55e2018-09-05 08:30:59 -0700900 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700901 }
902
Ed Tanous1abe55e2018-09-05 08:30:59 -0700903 template <uint64_t N>
904 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
905 newRuleTagged(const std::string& rule)
906 {
907 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
908 TaggedRule>;
909 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
910 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -0300911 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700912
913 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700914 }
915
Tanousf00032d2018-11-05 01:18:10 -0300916 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700917 {
Tanousf00032d2018-11-05 01:18:10 -0300918 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700919 {
Tanousf00032d2018-11-05 01:18:10 -0300920 return;
921 }
Ed Tanous759cf102022-07-31 16:36:52 -0700922 for (size_t method = 0, methodBit = 1; method <= methodNotAllowedIndex;
Ed Tanous2c70f802020-09-28 14:29:23 -0700923 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -0300924 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800925 if ((ruleObject->methodsBitfield & methodBit) > 0U)
Tanousf00032d2018-11-05 01:18:10 -0300926 {
927 perMethods[method].rules.emplace_back(ruleObject);
928 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -0700929 rule, static_cast<unsigned>(
930 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -0300931 // directory case:
932 // request to `/about' url matches `/about/' rule
933 if (rule.size() > 2 && rule.back() == '/')
934 {
935 perMethods[method].trie.add(
936 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -0700937 static_cast<unsigned>(perMethods[method].rules.size() -
938 1));
Tanousf00032d2018-11-05 01:18:10 -0300939 }
940 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700941 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700942 }
943
Ed Tanous1abe55e2018-09-05 08:30:59 -0700944 void validate()
945 {
Tanousf00032d2018-11-05 01:18:10 -0300946 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700947 {
948 if (rule)
949 {
Tanousf00032d2018-11-05 01:18:10 -0300950 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700951 if (upgraded)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700952 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700953 rule = std::move(upgraded);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700954 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700955 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -0300956 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700957 }
958 }
Tanousf00032d2018-11-05 01:18:10 -0300959 for (PerMethod& perMethod : perMethods)
960 {
961 perMethod.trie.validate();
962 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700963 }
964
Ed Tanous44e45182022-07-26 16:47:23 -0700965 struct FindRoute
966 {
967 BaseRule* rule = nullptr;
Ed Tanous15a42df2023-02-09 18:08:23 -0800968 std::vector<std::string> params;
Ed Tanous44e45182022-07-26 16:47:23 -0700969 };
970
971 struct FindRouteResponse
972 {
973 std::string allowHeader;
974 FindRoute route;
975 };
976
Ed Tanous759cf102022-07-31 16:36:52 -0700977 FindRoute findRouteByIndex(std::string_view url, size_t index) const
978 {
979 FindRoute route;
980 if (index >= perMethods.size())
981 {
982 BMCWEB_LOG_CRITICAL << "Bad index???";
983 return route;
984 }
985 const PerMethod& perMethod = perMethods[index];
Ed Tanous15a42df2023-02-09 18:08:23 -0800986 std::pair<unsigned, std::vector<std::string>> found =
987 perMethod.trie.find(url);
Ed Tanous759cf102022-07-31 16:36:52 -0700988 if (found.first >= perMethod.rules.size())
989 {
990 throw std::runtime_error("Trie internal structure corrupted!");
991 }
992 // Found a 404 route, switch that in
993 if (found.first != 0U)
994 {
995 route.rule = perMethod.rules[found.first];
996 route.params = std::move(found.second);
997 }
998 return route;
999 }
1000
1001 FindRouteResponse findRoute(Request& req) const
Ed Tanous44e45182022-07-26 16:47:23 -07001002 {
1003 FindRouteResponse findRoute;
1004
Ed Tanous2c9efc32022-07-31 22:08:26 -07001005 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1006 if (!verb)
1007 {
1008 return findRoute;
1009 }
1010 size_t reqMethodIndex = static_cast<size_t>(*verb);
Ed Tanous44e45182022-07-26 16:47:23 -07001011 // Check to see if this url exists at any verb
1012 for (size_t perMethodIndex = 0; perMethodIndex <= maxVerbIndex;
1013 perMethodIndex++)
1014 {
1015 // Make sure it's safe to deference the array at that index
1016 static_assert(maxVerbIndex <
1017 std::tuple_size_v<decltype(perMethods)>);
Ed Tanous39662a32023-02-06 15:09:46 -08001018 FindRoute route =
1019 findRouteByIndex(req.url().encoded_path(), perMethodIndex);
Ed Tanous759cf102022-07-31 16:36:52 -07001020 if (route.rule == nullptr)
Ed Tanous44e45182022-07-26 16:47:23 -07001021 {
1022 continue;
1023 }
1024 if (!findRoute.allowHeader.empty())
1025 {
1026 findRoute.allowHeader += ", ";
1027 }
Ed Tanous2c9efc32022-07-31 22:08:26 -07001028 HttpVerb thisVerb = static_cast<HttpVerb>(perMethodIndex);
1029 findRoute.allowHeader += httpVerbToString(thisVerb);
Ed Tanous44e45182022-07-26 16:47:23 -07001030 if (perMethodIndex == reqMethodIndex)
1031 {
Ed Tanous759cf102022-07-31 16:36:52 -07001032 findRoute.route = route;
Ed Tanous44e45182022-07-26 16:47:23 -07001033 }
1034 }
1035 return findRoute;
1036 }
1037
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301038 static bool isUserPrivileged(
1039 Request& req, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1040 BaseRule& rule, const dbus::utility::DBusPropertiesMap& userInfoMap)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001041 {
Ed Tanous3d183202023-03-10 09:21:58 -08001042 std::string userRole{};
1043 const std::string* userRolePtr = nullptr;
1044 const bool* remoteUser = nullptr;
1045 const bool* passwordExpired = nullptr;
1046
1047 const bool success = sdbusplus::unpackPropertiesNoThrow(
1048 redfish::dbus_utils::UnpackErrorPrinter(), userInfoMap,
1049 "UserPrivilege", userRolePtr, "RemoteUser", remoteUser,
1050 "UserPasswordExpired", passwordExpired);
1051
1052 if (!success)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001053 {
Ed Tanous3d183202023-03-10 09:21:58 -08001054 asyncResp->res.result(
1055 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301056 return false;
Ed Tanous3d183202023-03-10 09:21:58 -08001057 }
1058
1059 if (userRolePtr != nullptr)
1060 {
1061 userRole = *userRolePtr;
1062 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1063 << " userRole = " << *userRolePtr;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001064 }
1065
1066 if (remoteUser == nullptr)
1067 {
1068 BMCWEB_LOG_ERROR << "RemoteUser property missing or wrong type";
1069 asyncResp->res.result(
1070 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301071 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001072 }
Ed Tanous3d183202023-03-10 09:21:58 -08001073 bool expired = false;
1074 if (passwordExpired == nullptr)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001075 {
1076 if (!*remoteUser)
1077 {
1078 BMCWEB_LOG_ERROR
1079 << "UserPasswordExpired property is expected for"
1080 " local user but is missing or wrong type";
1081 asyncResp->res.result(
1082 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301083 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001084 }
Ed Tanous3d183202023-03-10 09:21:58 -08001085 }
1086 else
1087 {
1088 expired = *passwordExpired;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001089 }
1090
1091 // Get the user's privileges from the role
1092 redfish::Privileges userPrivileges =
1093 redfish::getUserPrivileges(userRole);
1094
1095 // Set isConfigureSelfOnly based on D-Bus results. This
1096 // ignores the results from both pamAuthenticateUser and the
1097 // value from any previous use of this session.
Ed Tanous3d183202023-03-10 09:21:58 -08001098 req.session->isConfigureSelfOnly = expired;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001099
1100 // Modify privileges if isConfigureSelfOnly.
1101 if (req.session->isConfigureSelfOnly)
1102 {
1103 // Remove all privileges except ConfigureSelf
1104 userPrivileges = userPrivileges.intersection(
1105 redfish::Privileges{"ConfigureSelf"});
1106 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1107 }
1108
1109 if (!rule.checkPrivileges(userPrivileges))
1110 {
1111 asyncResp->res.result(boost::beast::http::status::forbidden);
1112 if (req.session->isConfigureSelfOnly)
1113 {
1114 redfish::messages::passwordChangeRequired(
1115 asyncResp->res, crow::utility::urlFromPieces(
1116 "redfish", "v1", "AccountService",
1117 "Accounts", req.session->username));
1118 }
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301119 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001120 }
1121
1122 req.userRole = userRole;
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301123
1124 return true;
1125 }
1126
1127 template <typename CallbackFn>
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001128 void afterGetUserInfo(Request& req,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301129 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1130 BaseRule& rule, CallbackFn&& callback,
1131 const boost::system::error_code& ec,
1132 const dbus::utility::DBusPropertiesMap& userInfoMap)
1133 {
1134 if (ec)
1135 {
1136 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
1137 asyncResp->res.result(
1138 boost::beast::http::status::internal_server_error);
1139 return;
1140 }
1141
1142 if (!Router::isUserPrivileged(req, asyncResp, rule, userInfoMap))
1143 {
1144 // User is not privileged
1145 BMCWEB_LOG_ERROR << "Insufficient Privilege";
1146 asyncResp->res.result(boost::beast::http::status::forbidden);
1147 return;
1148 }
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001149 callback(req);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301150 }
1151
1152 template <typename CallbackFn>
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001153 void validatePrivilege(Request& req,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301154 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1155 BaseRule& rule, CallbackFn&& callback)
1156 {
Ed Tanous915d2d42023-03-15 13:09:34 -07001157 if (req.session == nullptr)
1158 {
1159 return;
1160 }
1161 std::string username = req.session->username;
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301162 crow::connections::systemBus->async_method_call(
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001163 [this, &req, asyncResp, &rule,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301164 callback(std::forward<CallbackFn>(callback))](
1165 const boost::system::error_code& ec,
1166 const dbus::utility::DBusPropertiesMap& userInfoMap) mutable {
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001167 afterGetUserInfo(req, asyncResp, rule,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301168 std::forward<CallbackFn>(callback), ec,
1169 userInfoMap);
1170 },
1171 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
Ed Tanous915d2d42023-03-15 13:09:34 -07001172 "xyz.openbmc_project.User.Manager", "GetUserInfo", username);
Ed Tanouse1f5c162023-03-10 09:02:51 -08001173 }
1174
Ed Tanous1abe55e2018-09-05 08:30:59 -07001175 template <typename Adaptor>
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301176 void handleUpgrade(Request& req,
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301177 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1178 Adaptor&& adaptor)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001179 {
Ed Tanous2c9efc32022-07-31 22:08:26 -07001180 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1181 if (!verb || static_cast<size_t>(*verb) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001182 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301183 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001184 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001185 }
Ed Tanous2c9efc32022-07-31 22:08:26 -07001186 PerMethod& perMethod = perMethods[static_cast<size_t>(*verb)];
Tanousf00032d2018-11-05 01:18:10 -03001187 Trie& trie = perMethod.trie;
1188 std::vector<BaseRule*>& rules = perMethod.rules;
1189
Ed Tanous15a42df2023-02-09 18:08:23 -08001190 const std::pair<unsigned, std::vector<std::string>>& found =
Ed Tanous39662a32023-02-06 15:09:46 -08001191 trie.find(req.url().encoded_path());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001192 unsigned ruleIndex = found.first;
Ed Tanouse662eae2022-01-25 10:39:19 -08001193 if (ruleIndex == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001194 {
Ed Tanous39662a32023-02-06 15:09:46 -08001195 BMCWEB_LOG_DEBUG << "Cannot match rules "
1196 << req.url().encoded_path();
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301197 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001198 return;
1199 }
1200
1201 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001202 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001203 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001204 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001205
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301206 BaseRule& rule = *rules[ruleIndex];
1207 size_t methods = rule.getMethods();
1208 if ((methods & (1U << static_cast<size_t>(*verb))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001209 {
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301210 BMCWEB_LOG_DEBUG
1211 << "Rule found but method mismatch: "
1212 << req.url().encoded_path() << " with " << req.methodString()
1213 << "(" << static_cast<uint32_t>(*verb) << ") / " << methods;
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301214 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001215 return;
1216 }
1217
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301218 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rule.rule << "' "
1219 << static_cast<uint32_t>(*verb) << " / " << methods;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001220
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301221 // TODO(ed) This should be able to use std::bind_front, but it doesn't
1222 // appear to work with the std::move on adaptor.
Ed Tanous915d2d42023-03-15 13:09:34 -07001223 validatePrivilege(
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001224 req, asyncResp, rule,
Ed Tanous915d2d42023-03-15 13:09:34 -07001225 [&rule, asyncResp, adaptor(std::forward<Adaptor>(adaptor))](
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001226 Request& thisReq) mutable {
Ed Tanous915d2d42023-03-15 13:09:34 -07001227 rule.handleUpgrade(thisReq, asyncResp, std::move(adaptor));
1228 });
Ed Tanous7045c8d2017-04-03 10:04:37 -07001229 }
1230
zhanghch058d1b46d2021-04-01 11:18:24 +08001231 void handle(Request& req,
1232 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001233 {
Ed Tanous2c9efc32022-07-31 22:08:26 -07001234 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1235 if (!verb || static_cast<size_t>(*verb) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001236 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001237 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001238 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001239 }
Ed Tanous44e45182022-07-26 16:47:23 -07001240
1241 FindRouteResponse foundRoute = findRoute(req);
1242
Ed Tanous759cf102022-07-31 16:36:52 -07001243 if (foundRoute.route.rule == nullptr)
Ed Tanous88a03c52022-03-14 10:16:07 -07001244 {
Ed Tanous759cf102022-07-31 16:36:52 -07001245 // Couldn't find a normal route with any verb, try looking for a 404
1246 // route
1247 if (foundRoute.allowHeader.empty())
Ed Tanous44e45182022-07-26 16:47:23 -07001248 {
Ed Tanous39662a32023-02-06 15:09:46 -08001249 foundRoute.route =
1250 findRouteByIndex(req.url().encoded_path(), notFoundIndex);
Ed Tanous759cf102022-07-31 16:36:52 -07001251 }
1252 else
1253 {
1254 // See if we have a method not allowed (405) handler
Ed Tanous39662a32023-02-06 15:09:46 -08001255 foundRoute.route = findRouteByIndex(req.url().encoded_path(),
1256 methodNotAllowedIndex);
Ed Tanous44e45182022-07-26 16:47:23 -07001257 }
1258 }
Ed Tanous759cf102022-07-31 16:36:52 -07001259
1260 // Fill in the allow header if it's valid
1261 if (!foundRoute.allowHeader.empty())
Ed Tanous44e45182022-07-26 16:47:23 -07001262 {
Ed Tanous759cf102022-07-31 16:36:52 -07001263
Ed Tanous88a03c52022-03-14 10:16:07 -07001264 asyncResp->res.addHeader(boost::beast::http::field::allow,
Ed Tanous44e45182022-07-26 16:47:23 -07001265 foundRoute.allowHeader);
Ed Tanous88a03c52022-03-14 10:16:07 -07001266 }
Tanousf00032d2018-11-05 01:18:10 -03001267
Ed Tanous44e45182022-07-26 16:47:23 -07001268 // If we couldn't find a real route or a 404 route, return a generic
1269 // response
1270 if (foundRoute.route.rule == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001271 {
Ed Tanous44e45182022-07-26 16:47:23 -07001272 if (foundRoute.allowHeader.empty())
1273 {
1274 asyncResp->res.result(boost::beast::http::status::not_found);
1275 }
1276 else
Ed Tanous2634dcd2019-03-26 09:28:06 -07001277 {
Ed Tanous88a03c52022-03-14 10:16:07 -07001278 asyncResp->res.result(
1279 boost::beast::http::status::method_not_allowed);
Ed Tanous2634dcd2019-03-26 09:28:06 -07001280 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001281 return;
1282 }
1283
Ed Tanous44e45182022-07-26 16:47:23 -07001284 BaseRule& rule = *foundRoute.route.rule;
Ed Tanous15a42df2023-02-09 18:08:23 -08001285 std::vector<std::string> params = std::move(foundRoute.route.params);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001286
Ed Tanous44e45182022-07-26 16:47:23 -07001287 BMCWEB_LOG_DEBUG << "Matched rule '" << rule.rule << "' "
Snehalatha Venkatesh1c99da02022-12-27 06:45:35 +00001288 << static_cast<uint32_t>(*verb) << " / "
Ed Tanous44e45182022-07-26 16:47:23 -07001289 << rule.getMethods();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001290
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001291 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001292 {
Ed Tanous44e45182022-07-26 16:47:23 -07001293 rule.handle(req, asyncResp, params);
James Feist7166bf02019-12-10 16:52:14 +00001294 return;
1295 }
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001296 validatePrivilege(req, asyncResp, rule,
1297 [&rule, asyncResp, params](Request& thisReq) mutable {
Ed Tanous915d2d42023-03-15 13:09:34 -07001298 rule.handle(thisReq, asyncResp, params);
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001299 });
Ed Tanous7045c8d2017-04-03 10:04:37 -07001300 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001301
Ed Tanous1abe55e2018-09-05 08:30:59 -07001302 void debugPrint()
1303 {
Ed Tanous271584a2019-07-09 16:24:22 -07001304 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001305 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001306 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1307 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001308 perMethods[i].trie.debugPrint();
1309 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001310 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001311
Ed Tanous1abe55e2018-09-05 08:30:59 -07001312 std::vector<const std::string*> getRoutes(const std::string& parent)
1313 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001314 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001315
1316 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001317 {
Tanousf00032d2018-11-05 01:18:10 -03001318 std::vector<unsigned> x;
1319 pm.trie.findRouteIndexes(parent, x);
1320 for (unsigned index : x)
1321 {
1322 ret.push_back(&pm.rules[index]->rule);
1323 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001324 }
1325 return ret;
1326 }
1327
1328 private:
Tanousf00032d2018-11-05 01:18:10 -03001329 struct PerMethod
1330 {
1331 std::vector<BaseRule*> rules;
1332 Trie trie;
Ed Tanous313a3c22022-03-14 09:27:38 -07001333 // rule index 0 has special meaning; preallocate it to avoid
Tanousf00032d2018-11-05 01:18:10 -03001334 // duplication.
Ed Tanous313a3c22022-03-14 09:27:38 -07001335 PerMethod() : rules(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001336 {}
Tanousf00032d2018-11-05 01:18:10 -03001337 };
Ed Tanous888880a2020-08-24 13:48:50 -07001338
Ed Tanous759cf102022-07-31 16:36:52 -07001339 std::array<PerMethod, methodNotAllowedIndex + 1> perMethods;
Tanousf00032d2018-11-05 01:18:10 -03001340 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001341};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001342} // namespace crow