blob: ac1c310ae29a7a34d08f888d47151dc0a66f2cb9 [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"
V-Sanjana88ada3b2023-04-13 15:18:31 +053011#include "server_sent_event.hpp"
Ratan Gupta6f359562019-04-03 10:39:08 +053012#include "sessions.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -070013#include "utility.hpp"
Ed Tanous3d183202023-03-10 09:21:58 -080014#include "utils/dbus_utils.hpp"
Ed Tanous2c9efc32022-07-31 22:08:26 -070015#include "verb.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -070016#include "websocket.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070017
Ed Tanous88a03c52022-03-14 10:16:07 -070018#include <boost/beast/ssl/ssl_stream.hpp>
Tanousf00032d2018-11-05 01:18:10 -030019#include <boost/container/flat_map.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070020#include <boost/url/format.hpp>
Ed Tanous3d183202023-03-10 09:21:58 -080021#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050022
Ed Tanouse0d918b2018-03-27 17:41:04 -070023#include <cerrno>
Ed Tanous7045c8d2017-04-03 10:04:37 -070024#include <cstdint>
Ed Tanouse0d918b2018-03-27 17:41:04 -070025#include <cstdlib>
Ed Tanous3dac7492017-08-02 13:46:20 -070026#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070027#include <memory>
Ed Tanous2c9efc32022-07-31 22:08:26 -070028#include <optional>
Ed Tanous7045c8d2017-04-03 10:04:37 -070029#include <tuple>
Ed Tanous7045c8d2017-04-03 10:04:37 -070030#include <utility>
31#include <vector>
Ed Tanous9140a672017-04-24 17:01:32 -070032
Ed Tanous1abe55e2018-09-05 08:30:59 -070033namespace crow
34{
Tanousf00032d2018-11-05 01:18:10 -030035
Ed Tanous1abe55e2018-09-05 08:30:59 -070036class BaseRule
37{
38 public:
Patrick Williams89492a12023-05-10 07:51:34 -050039 explicit BaseRule(const std::string& thisRule) : rule(thisRule) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070040
Ed Tanous0c0084a2019-10-24 15:57:51 -070041 virtual ~BaseRule() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -070042
Ed Tanousecd6a3a2022-01-07 09:18:40 -080043 BaseRule(const BaseRule&) = delete;
44 BaseRule(BaseRule&&) = delete;
45 BaseRule& operator=(const BaseRule&) = delete;
46 BaseRule& operator=(const BaseRule&&) = delete;
47
Ed Tanous1abe55e2018-09-05 08:30:59 -070048 virtual void validate() = 0;
49 std::unique_ptr<BaseRule> upgrade()
50 {
51 if (ruleToUpgrade)
Ed Tanous3174e4d2020-10-07 11:41:22 -070052 {
Ed Tanous1abe55e2018-09-05 08:30:59 -070053 return std::move(ruleToUpgrade);
Ed Tanous3174e4d2020-10-07 11:41:22 -070054 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070055 return {};
56 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070057
Ed Tanous104f09c2022-01-25 09:56:04 -080058 virtual void handle(const Request& /*req*/,
zhanghch058d1b46d2021-04-01 11:18:24 +080059 const std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous15a42df2023-02-09 18:08:23 -080060 const std::vector<std::string>&) = 0;
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +053061#ifndef BMCWEB_ENABLE_SSL
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053062 virtual void
63 handleUpgrade(const Request& /*req*/,
64 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
65 boost::asio::ip::tcp::socket&& /*adaptor*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -070066 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053067 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070068 }
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +053069#else
Ed Tanous104f09c2022-01-25 09:56:04 -080070 virtual void handleUpgrade(
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053071 const Request& /*req*/,
72 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous104f09c2022-01-25 09:56:04 -080073 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&& /*adaptor*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -070074 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053075 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070076 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070077#endif
78
Ed Tanous9eb808c2022-01-25 10:19:23 -080079 size_t getMethods() const
Ed Tanous1abe55e2018-09-05 08:30:59 -070080 {
81 return methodsBitfield;
82 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070083
Tanousf00032d2018-11-05 01:18:10 -030084 bool checkPrivileges(const redfish::Privileges& userPrivileges)
85 {
86 // If there are no privileges assigned, assume no privileges
87 // required
88 if (privilegesSet.empty())
89 {
90 return true;
91 }
92
93 for (const redfish::Privileges& requiredPrivileges : privilegesSet)
94 {
95 if (userPrivileges.isSupersetOf(requiredPrivileges))
96 {
97 return true;
98 }
99 }
100 return false;
101 }
102
Ed Tanous2c9efc32022-07-31 22:08:26 -0700103 size_t methodsBitfield{1 << static_cast<size_t>(HttpVerb::Get)};
Ed Tanous44e45182022-07-26 16:47:23 -0700104 static_assert(std::numeric_limits<decltype(methodsBitfield)>::digits >
Ed Tanous759cf102022-07-31 16:36:52 -0700105 methodNotAllowedIndex,
Ed Tanous44e45182022-07-26 16:47:23 -0700106 "Not enough bits to store bitfield");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700107
Tanousf00032d2018-11-05 01:18:10 -0300108 std::vector<redfish::Privileges> privilegesSet;
109
Ed Tanous1abe55e2018-09-05 08:30:59 -0700110 std::string rule;
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 {
Patrick Williams89492a12023-05-10 07:51:34 -0500187 explicit ReqHandlerWrapper(Func fIn) : f(std::move(fIn)) {}
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:
Patrick Williams89492a12023-05-10 07:51:34 -0500287 explicit WebSocketRule(const std::string& ruleIn) : BaseRule(ruleIn) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700288
Patrick Williams89492a12023-05-10 07:51:34 -0500289 void validate() override {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700290
Ed Tanous104f09c2022-01-25 09:56:04 -0800291 void handle(const Request& /*req*/,
zhanghch058d1b46d2021-04-01 11:18:24 +0800292 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800293 const std::vector<std::string>& /*params*/) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700294 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800295 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700296 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700297
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +0530298#ifndef BMCWEB_ENABLE_SSL
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +0530299 void handleUpgrade(const Request& req,
300 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800301 boost::asio::ip::tcp::socket&& adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700302 {
Nan Zhou93c02022022-02-24 18:21:07 -0800303 BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
Ratan Gupta02453b12019-10-22 14:43:36 +0530304 std::shared_ptr<
305 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>
306 myConnection = std::make_shared<
307 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000308 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanous863c1c22022-02-21 21:33:06 -0800309 messageExHandler, closeHandler, errorHandler);
Ratan Gupta02453b12019-10-22 14:43:36 +0530310 myConnection->start();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700311 }
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +0530312#else
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +0530313 void handleUpgrade(const Request& req,
314 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800315 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
316 adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700317 {
Nan Zhou93c02022022-02-24 18:21:07 -0800318 BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
Ed Tanousceac6f72018-12-02 11:58:47 -0800319 std::shared_ptr<crow::websocket::ConnectionImpl<
320 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
321 myConnection = std::make_shared<crow::websocket::ConnectionImpl<
322 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000323 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanous863c1c22022-02-21 21:33:06 -0800324 messageExHandler, closeHandler, errorHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700325 myConnection->start();
326 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700327#endif
328
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500329 template <typename Func>
330 self_t& onopen(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700331 {
332 openHandler = f;
333 return *this;
334 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700335
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500336 template <typename Func>
337 self_t& onmessage(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700338 {
339 messageHandler = f;
340 return *this;
341 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700342
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500343 template <typename Func>
Ed Tanous863c1c22022-02-21 21:33:06 -0800344 self_t& onmessageex(Func f)
345 {
346 messageExHandler = f;
347 return *this;
348 }
349
350 template <typename Func>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500351 self_t& onclose(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700352 {
353 closeHandler = f;
354 return *this;
355 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700356
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500357 template <typename Func>
358 self_t& onerror(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700359 {
360 errorHandler = f;
361 return *this;
362 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700363
Ed Tanous1abe55e2018-09-05 08:30:59 -0700364 protected:
zhanghch0577726382021-10-21 14:07:57 +0800365 std::function<void(crow::websocket::Connection&)> openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700366 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
367 messageHandler;
Ed Tanous863c1c22022-02-21 21:33:06 -0800368 std::function<void(crow::websocket::Connection&, std::string_view,
369 crow::websocket::MessageType type,
370 std::function<void()>&& whenComplete)>
371 messageExHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700372 std::function<void(crow::websocket::Connection&, const std::string&)>
373 closeHandler;
374 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700375};
376
V-Sanjana88ada3b2023-04-13 15:18:31 +0530377class SseSocketRule : public BaseRule
378{
379 using self_t = SseSocketRule;
380
381 public:
382 explicit SseSocketRule(const std::string& ruleIn) : BaseRule(ruleIn) {}
383
384 void validate() override {}
385
386 void handle(const Request& /*req*/,
387 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
388 const std::vector<std::string>& /*params*/) override
389 {
390 asyncResp->res.result(boost::beast::http::status::not_found);
391 }
392
393#ifndef BMCWEB_ENABLE_SSL
Ed Tanous6fde95f2023-06-01 07:33:34 -0700394 void handleUpgrade(const Request& /*req*/,
V-Sanjana88ada3b2023-04-13 15:18:31 +0530395 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
396 boost::asio::ip::tcp::socket&& adaptor) override
397 {
398 std::shared_ptr<
399 crow::sse_socket::ConnectionImpl<boost::asio::ip::tcp::socket>>
400 myConnection = std::make_shared<
401 crow::sse_socket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Ed Tanous6fde95f2023-06-01 07:33:34 -0700402 std::move(adaptor), openHandler, closeHandler);
V-Sanjana88ada3b2023-04-13 15:18:31 +0530403 myConnection->start();
404 }
405#else
Ed Tanous6fde95f2023-06-01 07:33:34 -0700406 void handleUpgrade(const Request& /*req*/,
V-Sanjana88ada3b2023-04-13 15:18:31 +0530407 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
408 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
409 adaptor) override
410 {
411 std::shared_ptr<crow::sse_socket::ConnectionImpl<
412 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
413 myConnection = std::make_shared<crow::sse_socket::ConnectionImpl<
414 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Ed Tanous6fde95f2023-06-01 07:33:34 -0700415 std::move(adaptor), openHandler, closeHandler);
V-Sanjana88ada3b2023-04-13 15:18:31 +0530416 myConnection->start();
417 }
418#endif
419
420 template <typename Func>
421 self_t& onopen(Func f)
422 {
423 openHandler = f;
424 return *this;
425 }
426
427 template <typename Func>
428 self_t& onclose(Func f)
429 {
430 closeHandler = f;
431 return *this;
432 }
433
434 private:
Ed Tanous6fde95f2023-06-01 07:33:34 -0700435 std::function<void(crow::sse_socket::Connection&)> openHandler;
436 std::function<void(crow::sse_socket::Connection&)> closeHandler;
V-Sanjana88ada3b2023-04-13 15:18:31 +0530437};
438
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500439template <typename T>
440struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700441{
442 using self_t = T;
443 WebSocketRule& websocket()
444 {
Ed Tanous271584a2019-07-09 16:24:22 -0700445 self_t* self = static_cast<self_t*>(this);
446 WebSocketRule* p = new WebSocketRule(self->rule);
Ed Tanous9d192c72023-04-10 10:20:13 -0700447 p->privilegesSet = self->privilegesSet;
Ed Tanous271584a2019-07-09 16:24:22 -0700448 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700449 return *p;
450 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700451
V-Sanjana88ada3b2023-04-13 15:18:31 +0530452 SseSocketRule& serverSentEvent()
453 {
454 self_t* self = static_cast<self_t*>(this);
455 SseSocketRule* p = new SseSocketRule(self->rule);
456 self->ruleToUpgrade.reset(p);
457 return *p;
458 }
459
Ed Tanous1abe55e2018-09-05 08:30:59 -0700460 self_t& methods(boost::beast::http::verb method)
461 {
Ed Tanous271584a2019-07-09 16:24:22 -0700462 self_t* self = static_cast<self_t*>(this);
Ed Tanous2c9efc32022-07-31 22:08:26 -0700463 std::optional<HttpVerb> verb = httpVerbFromBoost(method);
464 if (verb)
465 {
466 self->methodsBitfield = 1U << static_cast<size_t>(*verb);
467 }
Ed Tanous271584a2019-07-09 16:24:22 -0700468 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700469 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700470
Ed Tanous1abe55e2018-09-05 08:30:59 -0700471 template <typename... MethodArgs>
Ed Tanous81ce6092020-12-17 16:54:55 +0000472 self_t& methods(boost::beast::http::verb method, MethodArgs... argsMethod)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700473 {
Ed Tanous271584a2019-07-09 16:24:22 -0700474 self_t* self = static_cast<self_t*>(this);
Ed Tanous81ce6092020-12-17 16:54:55 +0000475 methods(argsMethod...);
Ed Tanous2c9efc32022-07-31 22:08:26 -0700476 std::optional<HttpVerb> verb = httpVerbFromBoost(method);
477 if (verb)
478 {
479 self->methodsBitfield |= 1U << static_cast<size_t>(*verb);
480 }
Ed Tanous271584a2019-07-09 16:24:22 -0700481 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700482 }
Tanousf00032d2018-11-05 01:18:10 -0300483
Ed Tanous44e45182022-07-26 16:47:23 -0700484 self_t& notFound()
485 {
486 self_t* self = static_cast<self_t*>(this);
487 self->methodsBitfield = 1U << notFoundIndex;
488 return *self;
489 }
490
Ed Tanous759cf102022-07-31 16:36:52 -0700491 self_t& methodNotAllowed()
492 {
493 self_t* self = static_cast<self_t*>(this);
494 self->methodsBitfield = 1U << methodNotAllowedIndex;
495 return *self;
496 }
497
Ed Tanous432a8902021-06-14 15:28:56 -0700498 self_t& privileges(
499 const std::initializer_list<std::initializer_list<const char*>>& p)
Tanousf00032d2018-11-05 01:18:10 -0300500 {
Ed Tanous271584a2019-07-09 16:24:22 -0700501 self_t* self = static_cast<self_t*>(this);
Ed Tanous432a8902021-06-14 15:28:56 -0700502 for (const std::initializer_list<const char*>& privilege : p)
Tanousf00032d2018-11-05 01:18:10 -0300503 {
Ed Tanous271584a2019-07-09 16:24:22 -0700504 self->privilegesSet.emplace_back(privilege);
Tanousf00032d2018-11-05 01:18:10 -0300505 }
Ed Tanous271584a2019-07-09 16:24:22 -0700506 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300507 }
Ed Tanoused398212021-06-09 17:05:54 -0700508
509 template <size_t N, typename... MethodArgs>
510 self_t& privileges(const std::array<redfish::Privileges, N>& p)
511 {
512 self_t* self = static_cast<self_t*>(this);
513 for (const redfish::Privileges& privilege : p)
514 {
515 self->privilegesSet.emplace_back(privilege);
516 }
517 return *self;
518 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700519};
520
Ed Tanous1abe55e2018-09-05 08:30:59 -0700521class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
522{
523 public:
Patrick Williams89492a12023-05-10 07:51:34 -0500524 explicit DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700525
Ed Tanous1abe55e2018-09-05 08:30:59 -0700526 void validate() override
527 {
528 if (!erasedHandler)
529 {
Ed Tanous28f4b382023-04-10 10:20:56 -0700530 throw std::runtime_error("no handler for url " + rule);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700531 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700532 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700533
zhanghch058d1b46d2021-04-01 11:18:24 +0800534 void handle(const Request& req,
535 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800536 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700537 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800538 erasedHandler(req, asyncResp, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700539 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700540
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500541 template <typename Func>
542 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700543 {
Ed Tanousc867a832022-03-10 14:17:00 -0800544 using boost::callable_traits::args_t;
545 constexpr size_t arity = std::tuple_size<args_t<Func>>::value;
546 constexpr auto is = std::make_integer_sequence<unsigned, arity>{};
547 erasedHandler = wrap(std::move(f), is);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700548 }
549
550 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500551 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700552 // enable_if Arg1 != request
553
554 template <typename Func, unsigned... Indices>
zhanghch058d1b46d2021-04-01 11:18:24 +0800555 std::function<void(const Request&,
556 const std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous15a42df2023-02-09 18:08:23 -0800557 const std::vector<std::string>&)>
Ed Tanous104f09c2022-01-25 09:56:04 -0800558 wrap(Func f, std::integer_sequence<unsigned, Indices...> /*is*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700559 {
Ed Tanousc867a832022-03-10 14:17:00 -0800560 using function_t = crow::utility::FunctionTraits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700561
Ed Tanous1abe55e2018-09-05 08:30:59 -0700562 auto ret = detail::routing_handler_call_helper::Wrapped<
563 Func, typename function_t::template arg<Indices>...>();
564 ret.template set<typename function_t::template arg<Indices>...>(
565 std::move(f));
566 return ret;
567 }
568
Ed Tanous1abe55e2018-09-05 08:30:59 -0700569 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800570 std::function<void(const Request&,
571 const std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous15a42df2023-02-09 18:08:23 -0800572 const std::vector<std::string>&)>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700573 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700574};
575
576template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500577class TaggedRule :
578 public BaseRule,
579 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700580{
581 public:
582 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700583
Patrick Williams89492a12023-05-10 07:51:34 -0500584 explicit TaggedRule(const std::string& ruleIn) : BaseRule(ruleIn) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700585
Ed Tanous1abe55e2018-09-05 08:30:59 -0700586 void validate() override
587 {
588 if (!handler)
589 {
Ed Tanous28f4b382023-04-10 10:20:56 -0700590 throw std::runtime_error("no handler for url " + rule);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700591 }
592 }
593
594 template <typename Func>
Ed Tanous15a42df2023-02-09 18:08:23 -0800595 void operator()(Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700596 {
597 static_assert(
Ed Tanous7045c8d2017-04-03 10:04:37 -0700598 black_magic::CallHelper<
Ed Tanous15a42df2023-02-09 18:08:23 -0800599 Func, black_magic::S<crow::Request,
600 std::shared_ptr<bmcweb::AsyncResp>&,
601 Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700602 "Handler type is mismatched with URL parameters");
603 static_assert(
zhanghch058d1b46d2021-04-01 11:18:24 +0800604 std::is_same<
605 void,
606 decltype(f(std::declval<crow::Request>(),
607 std::declval<std::shared_ptr<bmcweb::AsyncResp>&>(),
608 std::declval<Args>()...))>::value,
Ed Tanous15a42df2023-02-09 18:08:23 -0800609 "Handler function with response argument should have void return type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700610
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800611 handler = std::forward<Func>(f);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700612 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700613
zhanghch058d1b46d2021-04-01 11:18:24 +0800614 void handle(const Request& req,
615 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800616 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700617 {
618 detail::routing_handler_call_helper::Call<
619 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
Ed Tanous15a42df2023-02-09 18:08:23 -0800620 0, black_magic::S<Args...>, black_magic::S<>>()(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700621 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800622 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700623 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700624
Ed Tanous1abe55e2018-09-05 08:30:59 -0700625 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800626 std::function<void(const crow::Request&,
627 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>
628 handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700629};
630
Ed Tanous1abe55e2018-09-05 08:30:59 -0700631class Trie
632{
633 public:
634 struct Node
635 {
636 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700637 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
638 paramChildrens{};
Ed Tanousa94ac612022-02-22 11:13:24 -0800639 using ChildMap = boost::container::flat_map<
640 std::string, unsigned, std::less<>,
641 std::vector<std::pair<std::string, unsigned>>>;
642 ChildMap children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700643
Ed Tanous1abe55e2018-09-05 08:30:59 -0700644 bool isSimpleNode() const
645 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800646 return ruleIndex == 0 &&
647 std::all_of(std::begin(paramChildrens),
648 std::end(paramChildrens),
649 [](size_t x) { return x == 0U; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700650 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700651 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700652
Patrick Williams89492a12023-05-10 07:51:34 -0500653 Trie() : nodes(1) {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700654
655 private:
656 void optimizeNode(Node* node)
657 {
Ed Tanous271584a2019-07-09 16:24:22 -0700658 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700659 {
Ed Tanousdbb59d42022-01-25 11:09:55 -0800660 if (x == 0U)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700661 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700662 continue;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700663 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700664 Node* child = &nodes[x];
665 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700666 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700667 if (node->children.empty())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700668 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700669 return;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700670 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 bool mergeWithChild = true;
Ed Tanousa94ac612022-02-22 11:13:24 -0800672 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673 {
674 Node* child = &nodes[kv.second];
675 if (!child->isSimpleNode())
676 {
677 mergeWithChild = false;
678 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700679 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700680 }
681 if (mergeWithChild)
682 {
Ed Tanousa94ac612022-02-22 11:13:24 -0800683 Node::ChildMap merged;
684 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685 {
686 Node* child = &nodes[kv.second];
Ed Tanousa94ac612022-02-22 11:13:24 -0800687 for (const Node::ChildMap::value_type& childKv :
Tanousf00032d2018-11-05 01:18:10 -0300688 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700689 {
690 merged[kv.first + childKv.first] = childKv.second;
691 }
692 }
693 node->children = std::move(merged);
694 optimizeNode(node);
695 }
696 else
697 {
Ed Tanousa94ac612022-02-22 11:13:24 -0800698 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700699 {
700 Node* child = &nodes[kv.second];
701 optimizeNode(child);
702 }
703 }
704 }
705
706 void optimize()
707 {
708 optimizeNode(head());
709 }
710
711 public:
712 void validate()
713 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700714 optimize();
715 }
716
Ed Tanous81ce6092020-12-17 16:54:55 +0000717 void findRouteIndexes(const std::string& reqUrl,
718 std::vector<unsigned>& routeIndexes,
Tanousf00032d2018-11-05 01:18:10 -0300719 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700720 {
721 if (node == nullptr)
722 {
723 node = head();
724 }
Ed Tanousa94ac612022-02-22 11:13:24 -0800725 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700726 {
727 const std::string& fragment = kv.first;
728 const Node* child = &nodes[kv.second];
Ed Tanous81ce6092020-12-17 16:54:55 +0000729 if (pos >= reqUrl.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700730 {
731 if (child->ruleIndex != 0 && fragment != "/")
732 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000733 routeIndexes.push_back(child->ruleIndex);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700734 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000735 findRouteIndexes(reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700736 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700737 }
738 else
739 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000740 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700741 {
Ed Tanous271584a2019-07-09 16:24:22 -0700742 findRouteIndexes(
Ed Tanous81ce6092020-12-17 16:54:55 +0000743 reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700744 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700745 }
746 }
747 }
748 }
749
Ed Tanous15a42df2023-02-09 18:08:23 -0800750 std::pair<unsigned, std::vector<std::string>>
751 find(const std::string_view reqUrl, const Node* node = nullptr,
752 size_t pos = 0, std::vector<std::string>* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800754 std::vector<std::string> empty;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700755 if (params == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700756 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700757 params = &empty;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700758 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700759
760 unsigned found{};
Ed Tanous15a42df2023-02-09 18:08:23 -0800761 std::vector<std::string> matchParams;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700762
763 if (node == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700764 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700765 node = head();
Ed Tanous3174e4d2020-10-07 11:41:22 -0700766 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000767 if (pos == reqUrl.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700768 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700769 return {node->ruleIndex, *params};
Ed Tanous3174e4d2020-10-07 11:41:22 -0700770 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700771
772 auto updateFound =
Ed Tanous15a42df2023-02-09 18:08:23 -0800773 [&found,
774 &matchParams](std::pair<unsigned, std::vector<std::string>>& ret) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700775 if (ret.first != 0U && (found == 0U || found > ret.first))
776 {
777 found = ret.first;
778 matchParams = std::move(ret.second);
779 }
780 };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700781
Ed Tanouse662eae2022-01-25 10:39:19 -0800782 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700783 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000784 size_t epos = pos;
Ed Tanous81ce6092020-12-17 16:54:55 +0000785 for (; epos < reqUrl.size(); epos++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700786 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000787 if (reqUrl[epos] == '/')
Ed Tanous3174e4d2020-10-07 11:41:22 -0700788 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789 break;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700790 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791 }
792
793 if (epos != pos)
794 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800795 params->emplace_back(reqUrl.substr(pos, epos - pos));
796 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000797 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700798 &nodes[node->paramChildrens[static_cast<size_t>(
799 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000800 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 updateFound(ret);
Ed Tanous15a42df2023-02-09 18:08:23 -0800802 params->pop_back();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700803 }
804 }
805
Ed Tanouse662eae2022-01-25 10:39:19 -0800806 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000808 size_t epos = reqUrl.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700809
810 if (epos != pos)
811 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800812 params->emplace_back(reqUrl.substr(pos, epos - pos));
813 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000814 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700815 &nodes[node->paramChildrens[static_cast<size_t>(
816 ParamType::PATH)]],
817 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700818 updateFound(ret);
Ed Tanous15a42df2023-02-09 18:08:23 -0800819 params->pop_back();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820 }
821 }
822
Ed Tanousa94ac612022-02-22 11:13:24 -0800823 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700824 {
825 const std::string& fragment = kv.first;
826 const Node* child = &nodes[kv.second];
827
Ed Tanous81ce6092020-12-17 16:54:55 +0000828 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700829 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800830 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000831 find(reqUrl, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700832 updateFound(ret);
833 }
834 }
835
836 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700837 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700838
839 void add(const std::string& url, unsigned ruleIndex)
840 {
Ed Tanous271584a2019-07-09 16:24:22 -0700841 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700842
843 for (unsigned i = 0; i < url.size(); i++)
844 {
845 char c = url[i];
846 if (c == '<')
847 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800848 constexpr static std::array<
849 std::pair<ParamType, std::string_view>, 3>
Tanousf00032d2018-11-05 01:18:10 -0300850 paramTraits = {{
Tanousf00032d2018-11-05 01:18:10 -0300851 {ParamType::STRING, "<str>"},
852 {ParamType::STRING, "<string>"},
853 {ParamType::PATH, "<path>"},
854 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700855
Ed Tanous15a42df2023-02-09 18:08:23 -0800856 for (const std::pair<ParamType, std::string_view>& x :
857 paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700858 {
Tanousf00032d2018-11-05 01:18:10 -0300859 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700860 {
Ed Tanous271584a2019-07-09 16:24:22 -0700861 size_t index = static_cast<size_t>(x.first);
Ed Tanouse662eae2022-01-25 10:39:19 -0800862 if (nodes[idx].paramChildrens[index] == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700863 {
Tanousf00032d2018-11-05 01:18:10 -0300864 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700865 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700866 }
Ed Tanous271584a2019-07-09 16:24:22 -0700867 idx = nodes[idx].paramChildrens[index];
868 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700869 break;
870 }
871 }
872
873 i--;
874 }
875 else
876 {
877 std::string piece(&c, 1);
Ed Tanouse662eae2022-01-25 10:39:19 -0800878 if (nodes[idx].children.count(piece) == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700879 {
Tanousf00032d2018-11-05 01:18:10 -0300880 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700881 nodes[idx].children.emplace(piece, newNodeIdx);
882 }
883 idx = nodes[idx].children[piece];
884 }
885 }
Ed Tanouse662eae2022-01-25 10:39:19 -0800886 if (nodes[idx].ruleIndex != 0U)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700887 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700888 throw std::runtime_error("handler already exists for " + url);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700889 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700890 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700891 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700892
Ed Tanous1abe55e2018-09-05 08:30:59 -0700893 private:
Ed Tanous271584a2019-07-09 16:24:22 -0700894 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700895 {
Ed Tanous271584a2019-07-09 16:24:22 -0700896 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700897 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800898 if (n->paramChildrens[i] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700899 {
900 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -0700901 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
902 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700903 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700904 case ParamType::STRING:
905 BMCWEB_LOG_DEBUG << "<str>";
906 break;
907 case ParamType::PATH:
908 BMCWEB_LOG_DEBUG << "<path>";
909 break;
Ed Tanous23a21a12020-07-25 04:45:05 +0000910 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -0700911 BMCWEB_LOG_DEBUG << "<ERROR>";
912 break;
913 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700914
Ed Tanous1abe55e2018-09-05 08:30:59 -0700915 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
916 }
917 }
Ed Tanousa94ac612022-02-22 11:13:24 -0800918 for (const Node::ChildMap::value_type& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700919 {
920 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -0700921 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -0700922 << kv.first;
923 debugNodePrint(&nodes[kv.second], level + 1);
924 }
925 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700926
Ed Tanous1abe55e2018-09-05 08:30:59 -0700927 public:
928 void debugPrint()
929 {
Ed Tanous271584a2019-07-09 16:24:22 -0700930 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700931 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700932
Ed Tanous1abe55e2018-09-05 08:30:59 -0700933 private:
934 const Node* head() const
935 {
936 return &nodes.front();
937 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700938
Ed Tanous1abe55e2018-09-05 08:30:59 -0700939 Node* head()
940 {
941 return &nodes.front();
942 }
943
944 unsigned newNode()
945 {
946 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -0700947 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700948 }
949
950 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700951};
952
Ed Tanous1abe55e2018-09-05 08:30:59 -0700953class Router
954{
955 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -0700956 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700957
Ed Tanous1abe55e2018-09-05 08:30:59 -0700958 DynamicRule& newRuleDynamic(const std::string& rule)
959 {
960 std::unique_ptr<DynamicRule> ruleObject =
961 std::make_unique<DynamicRule>(rule);
962 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -0300963 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -0700964
Ed Tanous1abe55e2018-09-05 08:30:59 -0700965 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700966 }
967
Ed Tanous1abe55e2018-09-05 08:30:59 -0700968 template <uint64_t N>
969 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
970 newRuleTagged(const std::string& rule)
971 {
972 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
973 TaggedRule>;
974 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
975 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -0300976 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700977
978 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700979 }
980
Tanousf00032d2018-11-05 01:18:10 -0300981 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700982 {
Tanousf00032d2018-11-05 01:18:10 -0300983 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700984 {
Tanousf00032d2018-11-05 01:18:10 -0300985 return;
986 }
Ed Tanous759cf102022-07-31 16:36:52 -0700987 for (size_t method = 0, methodBit = 1; method <= methodNotAllowedIndex;
Ed Tanous2c70f802020-09-28 14:29:23 -0700988 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -0300989 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800990 if ((ruleObject->methodsBitfield & methodBit) > 0U)
Tanousf00032d2018-11-05 01:18:10 -0300991 {
992 perMethods[method].rules.emplace_back(ruleObject);
993 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -0700994 rule, static_cast<unsigned>(
995 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -0300996 // directory case:
997 // request to `/about' url matches `/about/' rule
998 if (rule.size() > 2 && rule.back() == '/')
999 {
1000 perMethods[method].trie.add(
1001 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -07001002 static_cast<unsigned>(perMethods[method].rules.size() -
1003 1));
Tanousf00032d2018-11-05 01:18:10 -03001004 }
1005 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001006 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001007 }
1008
Ed Tanous1abe55e2018-09-05 08:30:59 -07001009 void validate()
1010 {
Tanousf00032d2018-11-05 01:18:10 -03001011 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001012 {
1013 if (rule)
1014 {
Tanousf00032d2018-11-05 01:18:10 -03001015 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001016 if (upgraded)
Ed Tanous3174e4d2020-10-07 11:41:22 -07001017 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001018 rule = std::move(upgraded);
Ed Tanous3174e4d2020-10-07 11:41:22 -07001019 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001020 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -03001021 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001022 }
1023 }
Tanousf00032d2018-11-05 01:18:10 -03001024 for (PerMethod& perMethod : perMethods)
1025 {
1026 perMethod.trie.validate();
1027 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001028 }
1029
Ed Tanous44e45182022-07-26 16:47:23 -07001030 struct FindRoute
1031 {
1032 BaseRule* rule = nullptr;
Ed Tanous15a42df2023-02-09 18:08:23 -08001033 std::vector<std::string> params;
Ed Tanous44e45182022-07-26 16:47:23 -07001034 };
1035
1036 struct FindRouteResponse
1037 {
1038 std::string allowHeader;
1039 FindRoute route;
1040 };
1041
Ed Tanous759cf102022-07-31 16:36:52 -07001042 FindRoute findRouteByIndex(std::string_view url, size_t index) const
1043 {
1044 FindRoute route;
1045 if (index >= perMethods.size())
1046 {
1047 BMCWEB_LOG_CRITICAL << "Bad index???";
1048 return route;
1049 }
1050 const PerMethod& perMethod = perMethods[index];
Ed Tanous15a42df2023-02-09 18:08:23 -08001051 std::pair<unsigned, std::vector<std::string>> found =
1052 perMethod.trie.find(url);
Ed Tanous759cf102022-07-31 16:36:52 -07001053 if (found.first >= perMethod.rules.size())
1054 {
1055 throw std::runtime_error("Trie internal structure corrupted!");
1056 }
1057 // Found a 404 route, switch that in
1058 if (found.first != 0U)
1059 {
1060 route.rule = perMethod.rules[found.first];
1061 route.params = std::move(found.second);
1062 }
1063 return route;
1064 }
1065
1066 FindRouteResponse findRoute(Request& req) const
Ed Tanous44e45182022-07-26 16:47:23 -07001067 {
1068 FindRouteResponse findRoute;
1069
Ed Tanous2c9efc32022-07-31 22:08:26 -07001070 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1071 if (!verb)
1072 {
1073 return findRoute;
1074 }
1075 size_t reqMethodIndex = static_cast<size_t>(*verb);
Ed Tanous44e45182022-07-26 16:47:23 -07001076 // Check to see if this url exists at any verb
1077 for (size_t perMethodIndex = 0; perMethodIndex <= maxVerbIndex;
1078 perMethodIndex++)
1079 {
1080 // Make sure it's safe to deference the array at that index
1081 static_assert(maxVerbIndex <
1082 std::tuple_size_v<decltype(perMethods)>);
Patrick Williams89492a12023-05-10 07:51:34 -05001083 FindRoute route = findRouteByIndex(req.url().encoded_path(),
1084 perMethodIndex);
Ed Tanous759cf102022-07-31 16:36:52 -07001085 if (route.rule == nullptr)
Ed Tanous44e45182022-07-26 16:47:23 -07001086 {
1087 continue;
1088 }
1089 if (!findRoute.allowHeader.empty())
1090 {
1091 findRoute.allowHeader += ", ";
1092 }
Ed Tanous2c9efc32022-07-31 22:08:26 -07001093 HttpVerb thisVerb = static_cast<HttpVerb>(perMethodIndex);
1094 findRoute.allowHeader += httpVerbToString(thisVerb);
Ed Tanous44e45182022-07-26 16:47:23 -07001095 if (perMethodIndex == reqMethodIndex)
1096 {
Ed Tanous759cf102022-07-31 16:36:52 -07001097 findRoute.route = route;
Ed Tanous44e45182022-07-26 16:47:23 -07001098 }
1099 }
1100 return findRoute;
1101 }
1102
Ninad Palsule3e72c202023-03-27 17:19:55 -05001103 // Populate session with user information.
1104 static bool
1105 populateUserInfo(Request& req,
1106 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1107 const dbus::utility::DBusPropertiesMap& userInfoMap)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001108 {
Ed Tanous3d183202023-03-10 09:21:58 -08001109 const std::string* userRolePtr = nullptr;
1110 const bool* remoteUser = nullptr;
1111 const bool* passwordExpired = nullptr;
Ninad Palsule3e72c202023-03-27 17:19:55 -05001112 const std::vector<std::string>* userGroups = nullptr;
Ed Tanous3d183202023-03-10 09:21:58 -08001113
1114 const bool success = sdbusplus::unpackPropertiesNoThrow(
1115 redfish::dbus_utils::UnpackErrorPrinter(), userInfoMap,
1116 "UserPrivilege", userRolePtr, "RemoteUser", remoteUser,
Ninad Palsule3e72c202023-03-27 17:19:55 -05001117 "UserPasswordExpired", passwordExpired, "UserGroups", userGroups);
Ed Tanous3d183202023-03-10 09:21:58 -08001118
1119 if (!success)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001120 {
Ninad Palsule3e72c202023-03-27 17:19:55 -05001121 BMCWEB_LOG_ERROR << "Failed to unpack user properties.";
Ed Tanous3d183202023-03-10 09:21:58 -08001122 asyncResp->res.result(
1123 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301124 return false;
Ed Tanous3d183202023-03-10 09:21:58 -08001125 }
1126
1127 if (userRolePtr != nullptr)
1128 {
Ninad Palsule3e72c202023-03-27 17:19:55 -05001129 req.session->userRole = *userRolePtr;
Ed Tanous3d183202023-03-10 09:21:58 -08001130 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1131 << " userRole = " << *userRolePtr;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001132 }
1133
1134 if (remoteUser == nullptr)
1135 {
1136 BMCWEB_LOG_ERROR << "RemoteUser property missing or wrong type";
1137 asyncResp->res.result(
1138 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301139 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001140 }
Ed Tanous3d183202023-03-10 09:21:58 -08001141 bool expired = false;
1142 if (passwordExpired == nullptr)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001143 {
1144 if (!*remoteUser)
1145 {
1146 BMCWEB_LOG_ERROR
1147 << "UserPasswordExpired property is expected for"
1148 " local user but is missing or wrong type";
1149 asyncResp->res.result(
1150 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301151 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001152 }
Ed Tanous3d183202023-03-10 09:21:58 -08001153 }
1154 else
1155 {
1156 expired = *passwordExpired;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001157 }
1158
Ed Tanouse1f5c162023-03-10 09:02:51 -08001159 // Set isConfigureSelfOnly based on D-Bus results. This
1160 // ignores the results from both pamAuthenticateUser and the
1161 // value from any previous use of this session.
Ed Tanous3d183202023-03-10 09:21:58 -08001162 req.session->isConfigureSelfOnly = expired;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001163
Ninad Palsule3e72c202023-03-27 17:19:55 -05001164 if (userGroups != nullptr)
1165 {
1166 // Populate session with user groups.
1167 for (const auto& userGroup : *userGroups)
1168 {
1169 req.session->userGroups.emplace_back(userGroup);
1170 }
1171 }
1172
1173 return true;
1174 }
1175
1176 static bool
1177 isUserPrivileged(Request& req,
1178 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1179 BaseRule& rule)
1180 {
1181 // Get the user's privileges from the role
1182 redfish::Privileges userPrivileges =
1183 redfish::getUserPrivileges(*req.session);
1184
Ed Tanouse1f5c162023-03-10 09:02:51 -08001185 // Modify privileges if isConfigureSelfOnly.
1186 if (req.session->isConfigureSelfOnly)
1187 {
1188 // Remove all privileges except ConfigureSelf
1189 userPrivileges = userPrivileges.intersection(
1190 redfish::Privileges{"ConfigureSelf"});
1191 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1192 }
1193
1194 if (!rule.checkPrivileges(userPrivileges))
1195 {
1196 asyncResp->res.result(boost::beast::http::status::forbidden);
1197 if (req.session->isConfigureSelfOnly)
1198 {
1199 redfish::messages::passwordChangeRequired(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001200 asyncResp->res,
1201 boost::urls::format(
1202 "/redfish/v1/AccountService/Accounts/{}",
1203 req.session->username));
Ed Tanouse1f5c162023-03-10 09:02:51 -08001204 }
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301205 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001206 }
1207
Ninad Palsule3e72c202023-03-27 17:19:55 -05001208 req.userRole = req.session->userRole;
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301209 return true;
1210 }
1211
1212 template <typename CallbackFn>
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001213 void afterGetUserInfo(Request& req,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301214 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1215 BaseRule& rule, CallbackFn&& callback,
1216 const boost::system::error_code& ec,
1217 const dbus::utility::DBusPropertiesMap& userInfoMap)
1218 {
1219 if (ec)
1220 {
1221 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
1222 asyncResp->res.result(
1223 boost::beast::http::status::internal_server_error);
1224 return;
1225 }
1226
Ninad Palsule3e72c202023-03-27 17:19:55 -05001227 if (!populateUserInfo(req, asyncResp, userInfoMap))
1228 {
1229 BMCWEB_LOG_ERROR << "Failed to populate user information";
1230 asyncResp->res.result(
1231 boost::beast::http::status::internal_server_error);
1232 return;
1233 }
1234
1235 if (!Router::isUserPrivileged(req, asyncResp, rule))
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301236 {
1237 // User is not privileged
1238 BMCWEB_LOG_ERROR << "Insufficient Privilege";
1239 asyncResp->res.result(boost::beast::http::status::forbidden);
1240 return;
1241 }
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001242 callback(req);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301243 }
1244
1245 template <typename CallbackFn>
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001246 void validatePrivilege(Request& req,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301247 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1248 BaseRule& rule, CallbackFn&& callback)
1249 {
Ed Tanous915d2d42023-03-15 13:09:34 -07001250 if (req.session == nullptr)
1251 {
1252 return;
1253 }
1254 std::string username = req.session->username;
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301255 crow::connections::systemBus->async_method_call(
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001256 [this, &req, asyncResp, &rule,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301257 callback(std::forward<CallbackFn>(callback))](
1258 const boost::system::error_code& ec,
1259 const dbus::utility::DBusPropertiesMap& userInfoMap) mutable {
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001260 afterGetUserInfo(req, asyncResp, rule,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301261 std::forward<CallbackFn>(callback), ec,
1262 userInfoMap);
1263 },
1264 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
Ed Tanous915d2d42023-03-15 13:09:34 -07001265 "xyz.openbmc_project.User.Manager", "GetUserInfo", username);
Ed Tanouse1f5c162023-03-10 09:02:51 -08001266 }
1267
Ed Tanous1abe55e2018-09-05 08:30:59 -07001268 template <typename Adaptor>
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301269 void handleUpgrade(Request& req,
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301270 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1271 Adaptor&& adaptor)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001272 {
Ed Tanous2c9efc32022-07-31 22:08:26 -07001273 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1274 if (!verb || static_cast<size_t>(*verb) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001275 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301276 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001277 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001278 }
Ed Tanous2c9efc32022-07-31 22:08:26 -07001279 PerMethod& perMethod = perMethods[static_cast<size_t>(*verb)];
Tanousf00032d2018-11-05 01:18:10 -03001280 Trie& trie = perMethod.trie;
1281 std::vector<BaseRule*>& rules = perMethod.rules;
1282
Ed Tanous15a42df2023-02-09 18:08:23 -08001283 const std::pair<unsigned, std::vector<std::string>>& found =
Ed Tanous39662a32023-02-06 15:09:46 -08001284 trie.find(req.url().encoded_path());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001285 unsigned ruleIndex = found.first;
Ed Tanouse662eae2022-01-25 10:39:19 -08001286 if (ruleIndex == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001287 {
Ed Tanous39662a32023-02-06 15:09:46 -08001288 BMCWEB_LOG_DEBUG << "Cannot match rules "
1289 << req.url().encoded_path();
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301290 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001291 return;
1292 }
1293
1294 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001295 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001296 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001297 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001298
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301299 BaseRule& rule = *rules[ruleIndex];
1300 size_t methods = rule.getMethods();
1301 if ((methods & (1U << static_cast<size_t>(*verb))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001302 {
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301303 BMCWEB_LOG_DEBUG
1304 << "Rule found but method mismatch: "
1305 << req.url().encoded_path() << " with " << req.methodString()
1306 << "(" << static_cast<uint32_t>(*verb) << ") / " << methods;
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301307 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001308 return;
1309 }
1310
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301311 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rule.rule << "' "
1312 << static_cast<uint32_t>(*verb) << " / " << methods;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001313
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301314 // TODO(ed) This should be able to use std::bind_front, but it doesn't
1315 // appear to work with the std::move on adaptor.
Ed Tanous915d2d42023-03-15 13:09:34 -07001316 validatePrivilege(
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001317 req, asyncResp, rule,
Ed Tanous915d2d42023-03-15 13:09:34 -07001318 [&rule, asyncResp, adaptor(std::forward<Adaptor>(adaptor))](
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001319 Request& thisReq) mutable {
Ed Tanous915d2d42023-03-15 13:09:34 -07001320 rule.handleUpgrade(thisReq, asyncResp, std::move(adaptor));
1321 });
Ed Tanous7045c8d2017-04-03 10:04:37 -07001322 }
1323
zhanghch058d1b46d2021-04-01 11:18:24 +08001324 void handle(Request& req,
1325 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001326 {
Ed Tanous2c9efc32022-07-31 22:08:26 -07001327 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1328 if (!verb || static_cast<size_t>(*verb) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001329 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001330 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001331 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001332 }
Ed Tanous44e45182022-07-26 16:47:23 -07001333
1334 FindRouteResponse foundRoute = findRoute(req);
1335
Ed Tanous759cf102022-07-31 16:36:52 -07001336 if (foundRoute.route.rule == nullptr)
Ed Tanous88a03c52022-03-14 10:16:07 -07001337 {
Ed Tanous759cf102022-07-31 16:36:52 -07001338 // Couldn't find a normal route with any verb, try looking for a 404
1339 // route
1340 if (foundRoute.allowHeader.empty())
Ed Tanous44e45182022-07-26 16:47:23 -07001341 {
Patrick Williams89492a12023-05-10 07:51:34 -05001342 foundRoute.route = findRouteByIndex(req.url().encoded_path(),
1343 notFoundIndex);
Ed Tanous759cf102022-07-31 16:36:52 -07001344 }
1345 else
1346 {
1347 // See if we have a method not allowed (405) handler
Ed Tanous39662a32023-02-06 15:09:46 -08001348 foundRoute.route = findRouteByIndex(req.url().encoded_path(),
1349 methodNotAllowedIndex);
Ed Tanous44e45182022-07-26 16:47:23 -07001350 }
1351 }
Ed Tanous759cf102022-07-31 16:36:52 -07001352
1353 // Fill in the allow header if it's valid
1354 if (!foundRoute.allowHeader.empty())
Ed Tanous44e45182022-07-26 16:47:23 -07001355 {
Ed Tanous88a03c52022-03-14 10:16:07 -07001356 asyncResp->res.addHeader(boost::beast::http::field::allow,
Ed Tanous44e45182022-07-26 16:47:23 -07001357 foundRoute.allowHeader);
Ed Tanous88a03c52022-03-14 10:16:07 -07001358 }
Tanousf00032d2018-11-05 01:18:10 -03001359
Ed Tanous44e45182022-07-26 16:47:23 -07001360 // If we couldn't find a real route or a 404 route, return a generic
1361 // response
1362 if (foundRoute.route.rule == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001363 {
Ed Tanous44e45182022-07-26 16:47:23 -07001364 if (foundRoute.allowHeader.empty())
1365 {
1366 asyncResp->res.result(boost::beast::http::status::not_found);
1367 }
1368 else
Ed Tanous2634dcd2019-03-26 09:28:06 -07001369 {
Ed Tanous88a03c52022-03-14 10:16:07 -07001370 asyncResp->res.result(
1371 boost::beast::http::status::method_not_allowed);
Ed Tanous2634dcd2019-03-26 09:28:06 -07001372 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001373 return;
1374 }
1375
Ed Tanous44e45182022-07-26 16:47:23 -07001376 BaseRule& rule = *foundRoute.route.rule;
Ed Tanous15a42df2023-02-09 18:08:23 -08001377 std::vector<std::string> params = std::move(foundRoute.route.params);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001378
Ed Tanous44e45182022-07-26 16:47:23 -07001379 BMCWEB_LOG_DEBUG << "Matched rule '" << rule.rule << "' "
Snehalatha Venkatesh1c99da02022-12-27 06:45:35 +00001380 << static_cast<uint32_t>(*verb) << " / "
Ed Tanous44e45182022-07-26 16:47:23 -07001381 << rule.getMethods();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001382
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001383 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001384 {
Ed Tanous44e45182022-07-26 16:47:23 -07001385 rule.handle(req, asyncResp, params);
James Feist7166bf02019-12-10 16:52:14 +00001386 return;
1387 }
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001388 validatePrivilege(req, asyncResp, rule,
1389 [&rule, asyncResp, params](Request& thisReq) mutable {
Ed Tanous915d2d42023-03-15 13:09:34 -07001390 rule.handle(thisReq, asyncResp, params);
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001391 });
Ed Tanous7045c8d2017-04-03 10:04:37 -07001392 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001393
Ed Tanous1abe55e2018-09-05 08:30:59 -07001394 void debugPrint()
1395 {
Ed Tanous271584a2019-07-09 16:24:22 -07001396 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001397 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001398 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1399 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001400 perMethods[i].trie.debugPrint();
1401 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001402 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001403
Ed Tanous1abe55e2018-09-05 08:30:59 -07001404 std::vector<const std::string*> getRoutes(const std::string& parent)
1405 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001406 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001407
1408 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001409 {
Tanousf00032d2018-11-05 01:18:10 -03001410 std::vector<unsigned> x;
1411 pm.trie.findRouteIndexes(parent, x);
1412 for (unsigned index : x)
1413 {
1414 ret.push_back(&pm.rules[index]->rule);
1415 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001416 }
1417 return ret;
1418 }
1419
1420 private:
Tanousf00032d2018-11-05 01:18:10 -03001421 struct PerMethod
1422 {
1423 std::vector<BaseRule*> rules;
1424 Trie trie;
Ed Tanous313a3c22022-03-14 09:27:38 -07001425 // rule index 0 has special meaning; preallocate it to avoid
Tanousf00032d2018-11-05 01:18:10 -03001426 // duplication.
Patrick Williams89492a12023-05-10 07:51:34 -05001427 PerMethod() : rules(1) {}
Tanousf00032d2018-11-05 01:18:10 -03001428 };
Ed Tanous888880a2020-08-24 13:48:50 -07001429
Ed Tanous759cf102022-07-31 16:36:52 -07001430 std::array<PerMethod, methodNotAllowedIndex + 1> perMethods;
Tanousf00032d2018-11-05 01:18:10 -03001431 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001432};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001433} // namespace crow