blob: 5bf6902e9c840823e36bad3ecae90e507bb9c2f1 [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:
Patrick Williams89492a12023-05-10 07:51:34 -050037 explicit BaseRule(const std::string& thisRule) : rule(thisRule) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070038
Ed Tanous0c0084a2019-10-24 15:57:51 -070039 virtual ~BaseRule() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -070040
Ed Tanousecd6a3a2022-01-07 09:18:40 -080041 BaseRule(const BaseRule&) = delete;
42 BaseRule(BaseRule&&) = delete;
43 BaseRule& operator=(const BaseRule&) = delete;
44 BaseRule& operator=(const BaseRule&&) = delete;
45
Ed Tanous1abe55e2018-09-05 08:30:59 -070046 virtual void validate() = 0;
47 std::unique_ptr<BaseRule> upgrade()
48 {
49 if (ruleToUpgrade)
Ed Tanous3174e4d2020-10-07 11:41:22 -070050 {
Ed Tanous1abe55e2018-09-05 08:30:59 -070051 return std::move(ruleToUpgrade);
Ed Tanous3174e4d2020-10-07 11:41:22 -070052 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070053 return {};
54 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070055
Ed Tanous104f09c2022-01-25 09:56:04 -080056 virtual void handle(const Request& /*req*/,
zhanghch058d1b46d2021-04-01 11:18:24 +080057 const std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous15a42df2023-02-09 18:08:23 -080058 const std::vector<std::string>&) = 0;
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +053059#ifndef BMCWEB_ENABLE_SSL
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053060 virtual void
61 handleUpgrade(const Request& /*req*/,
62 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
63 boost::asio::ip::tcp::socket&& /*adaptor*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -070064 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053065 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070066 }
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +053067#else
Ed Tanous104f09c2022-01-25 09:56:04 -080068 virtual void handleUpgrade(
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053069 const Request& /*req*/,
70 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous104f09c2022-01-25 09:56:04 -080071 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&& /*adaptor*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -070072 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053073 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070074 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070075#endif
76
Ed Tanous9eb808c2022-01-25 10:19:23 -080077 size_t getMethods() const
Ed Tanous1abe55e2018-09-05 08:30:59 -070078 {
79 return methodsBitfield;
80 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070081
Tanousf00032d2018-11-05 01:18:10 -030082 bool checkPrivileges(const redfish::Privileges& userPrivileges)
83 {
84 // If there are no privileges assigned, assume no privileges
85 // required
86 if (privilegesSet.empty())
87 {
88 return true;
89 }
90
91 for (const redfish::Privileges& requiredPrivileges : privilegesSet)
92 {
93 if (userPrivileges.isSupersetOf(requiredPrivileges))
94 {
95 return true;
96 }
97 }
98 return false;
99 }
100
Ed Tanous2c9efc32022-07-31 22:08:26 -0700101 size_t methodsBitfield{1 << static_cast<size_t>(HttpVerb::Get)};
Ed Tanous44e45182022-07-26 16:47:23 -0700102 static_assert(std::numeric_limits<decltype(methodsBitfield)>::digits >
Ed Tanous759cf102022-07-31 16:36:52 -0700103 methodNotAllowedIndex,
Ed Tanous44e45182022-07-26 16:47:23 -0700104 "Not enough bits to store bitfield");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700105
Tanousf00032d2018-11-05 01:18:10 -0300106 std::vector<redfish::Privileges> privilegesSet;
107
Ed Tanous1abe55e2018-09-05 08:30:59 -0700108 std::string rule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700109
Ed Tanous1abe55e2018-09-05 08:30:59 -0700110 std::unique_ptr<BaseRule> ruleToUpgrade;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700111
Ed Tanous1abe55e2018-09-05 08:30:59 -0700112 friend class Router;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500113 template <typename T>
114 friend struct RuleParameterTraits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700115};
116
Ed Tanous1abe55e2018-09-05 08:30:59 -0700117namespace detail
118{
119namespace routing_handler_call_helper
120{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500121template <typename T, int Pos>
122struct CallPair
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123{
124 using type = T;
125 static const int pos = Pos;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700126};
127
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500128template <typename H1>
129struct CallParams
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130{
131 H1& handler;
Ed Tanous15a42df2023-02-09 18:08:23 -0800132 const std::vector<std::string>& params;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700133 const Request& req;
zhanghch058d1b46d2021-04-01 11:18:24 +0800134 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700135};
136
Ed Tanous15a42df2023-02-09 18:08:23 -0800137template <typename F, int NString, typename S1, typename S2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700138struct Call
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500139{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700140
Ed Tanous15a42df2023-02-09 18:08:23 -0800141template <typename F, int NString, typename... Args1, typename... Args2>
142struct Call<F, NString, black_magic::S<std::string, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700143 black_magic::S<Args2...>>
144{
145 void operator()(F cparams)
146 {
147 using pushed = typename black_magic::S<Args2...>::template push_back<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700148 CallPair<std::string, NString>>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800149 Call<F, NString + 1, black_magic::S<Args1...>, pushed>()(cparams);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700150 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700151};
152
Ed Tanous15a42df2023-02-09 18:08:23 -0800153template <typename F, int NString, typename... Args1>
154struct Call<F, NString, black_magic::S<>, black_magic::S<Args1...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700155{
156 void operator()(F cparams)
157 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800158 cparams.handler(cparams.req, cparams.asyncResp,
159 cparams.params[Args1::pos]...);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700160 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700161};
162
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500163template <typename Func, typename... ArgsWrapped>
164struct Wrapped
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165{
166 template <typename... Args>
167 void set(
168 Func f,
169 typename std::enable_if<
170 !std::is_same<
171 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
172 const Request&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800173 int>::type /*enable*/
174 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700175 {
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800176 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800177 const Request&,
178 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
179 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700180 }
181
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500182 template <typename Req, typename... Args>
183 struct ReqHandlerWrapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700184 {
Patrick Williams89492a12023-05-10 07:51:34 -0500185 explicit ReqHandlerWrapper(Func fIn) : f(std::move(fIn)) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700186
zhanghch058d1b46d2021-04-01 11:18:24 +0800187 void operator()(const Request& req,
188 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
189 Args... args)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700190 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800191 asyncResp->res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700192 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700193
Ed Tanous1abe55e2018-09-05 08:30:59 -0700194 Func f;
195 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700196
Ed Tanous1abe55e2018-09-05 08:30:59 -0700197 template <typename... Args>
198 void set(
199 Func f,
200 typename std::enable_if<
201 std::is_same<
202 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
203 const Request&>::value &&
204 !std::is_same<typename std::tuple_element<
205 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800206 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800207 int>::type /*enable*/
208 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700209 {
210 handler = ReqHandlerWrapper<Args...>(std::move(f));
211 /*handler = (
212 [f = std::move(f)]
213 (const Request& req, Response& res, Args... args){
Ed Tanousde5c9f32019-03-26 09:17:55 -0700214 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700215 res.end();
216 });*/
217 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700218
Ed Tanous1abe55e2018-09-05 08:30:59 -0700219 template <typename... Args>
220 void set(
221 Func f,
222 typename std::enable_if<
223 std::is_same<
224 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
225 const Request&>::value &&
226 std::is_same<typename std::tuple_element<
227 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800228 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800229 int>::type /*enable*/
230 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700231 {
232 handler = std::move(f);
233 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700234
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500235 template <typename... Args>
236 struct HandlerTypeHelper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700237 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800238 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800239 const crow::Request& /*req*/,
240 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800241 using args_type = black_magic::S<Args...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700242 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700243
Ed Tanous1abe55e2018-09-05 08:30:59 -0700244 template <typename... Args>
245 struct HandlerTypeHelper<const Request&, Args...>
246 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800247 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800248 const crow::Request& /*req*/,
249 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800250 using args_type = black_magic::S<Args...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700251 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700252
Ed Tanous1abe55e2018-09-05 08:30:59 -0700253 template <typename... Args>
zhanghch058d1b46d2021-04-01 11:18:24 +0800254 struct HandlerTypeHelper<const Request&,
255 const std::shared_ptr<bmcweb::AsyncResp>&, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700256 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800257 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800258 const crow::Request& /*req*/,
259 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous15a42df2023-02-09 18:08:23 -0800260 using args_type = black_magic::S<Args...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700261 };
262
263 typename HandlerTypeHelper<ArgsWrapped...>::type handler;
264
zhanghch058d1b46d2021-04-01 11:18:24 +0800265 void operator()(const Request& req,
266 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800267 const std::vector<std::string>& params)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700268 {
269 detail::routing_handler_call_helper::Call<
270 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
Ed Tanous15a42df2023-02-09 18:08:23 -0800271 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700272 black_magic::S<>>()(
273 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800274 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700275 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700276};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700277} // namespace routing_handler_call_helper
278} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700279
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280class WebSocketRule : public BaseRule
281{
282 using self_t = WebSocketRule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700283
Ed Tanous1abe55e2018-09-05 08:30:59 -0700284 public:
Patrick Williams89492a12023-05-10 07:51:34 -0500285 explicit WebSocketRule(const std::string& ruleIn) : BaseRule(ruleIn) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700286
Patrick Williams89492a12023-05-10 07:51:34 -0500287 void validate() override {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700288
Ed Tanous104f09c2022-01-25 09:56:04 -0800289 void handle(const Request& /*req*/,
zhanghch058d1b46d2021-04-01 11:18:24 +0800290 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800291 const std::vector<std::string>& /*params*/) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700292 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800293 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700294 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700295
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +0530296#ifndef BMCWEB_ENABLE_SSL
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +0530297 void handleUpgrade(const Request& req,
298 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800299 boost::asio::ip::tcp::socket&& adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700300 {
Nan Zhou93c02022022-02-24 18:21:07 -0800301 BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
Ratan Gupta02453b12019-10-22 14:43:36 +0530302 std::shared_ptr<
303 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>
304 myConnection = std::make_shared<
305 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000306 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanous863c1c22022-02-21 21:33:06 -0800307 messageExHandler, closeHandler, errorHandler);
Ratan Gupta02453b12019-10-22 14:43:36 +0530308 myConnection->start();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700309 }
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +0530310#else
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +0530311 void handleUpgrade(const Request& req,
312 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800313 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
314 adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700315 {
Nan Zhou93c02022022-02-24 18:21:07 -0800316 BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
Ed Tanousceac6f72018-12-02 11:58:47 -0800317 std::shared_ptr<crow::websocket::ConnectionImpl<
318 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
319 myConnection = std::make_shared<crow::websocket::ConnectionImpl<
320 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000321 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanous863c1c22022-02-21 21:33:06 -0800322 messageExHandler, closeHandler, errorHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700323 myConnection->start();
324 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700325#endif
326
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500327 template <typename Func>
328 self_t& onopen(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700329 {
330 openHandler = f;
331 return *this;
332 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700333
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500334 template <typename Func>
335 self_t& onmessage(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700336 {
337 messageHandler = f;
338 return *this;
339 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700340
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500341 template <typename Func>
Ed Tanous863c1c22022-02-21 21:33:06 -0800342 self_t& onmessageex(Func f)
343 {
344 messageExHandler = f;
345 return *this;
346 }
347
348 template <typename Func>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500349 self_t& onclose(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700350 {
351 closeHandler = f;
352 return *this;
353 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700354
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500355 template <typename Func>
356 self_t& onerror(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700357 {
358 errorHandler = f;
359 return *this;
360 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700361
Ed Tanous1abe55e2018-09-05 08:30:59 -0700362 protected:
zhanghch0577726382021-10-21 14:07:57 +0800363 std::function<void(crow::websocket::Connection&)> openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700364 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
365 messageHandler;
Ed Tanous863c1c22022-02-21 21:33:06 -0800366 std::function<void(crow::websocket::Connection&, std::string_view,
367 crow::websocket::MessageType type,
368 std::function<void()>&& whenComplete)>
369 messageExHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700370 std::function<void(crow::websocket::Connection&, const std::string&)>
371 closeHandler;
372 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700373};
374
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500375template <typename T>
376struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700377{
378 using self_t = T;
379 WebSocketRule& websocket()
380 {
Ed Tanous271584a2019-07-09 16:24:22 -0700381 self_t* self = static_cast<self_t*>(this);
382 WebSocketRule* p = new WebSocketRule(self->rule);
Ed Tanous9d192c72023-04-10 10:20:13 -0700383 p->privilegesSet = self->privilegesSet;
Ed Tanous271584a2019-07-09 16:24:22 -0700384 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700385 return *p;
386 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700387
Ed Tanous1abe55e2018-09-05 08:30:59 -0700388 self_t& methods(boost::beast::http::verb method)
389 {
Ed Tanous271584a2019-07-09 16:24:22 -0700390 self_t* self = static_cast<self_t*>(this);
Ed Tanous2c9efc32022-07-31 22:08:26 -0700391 std::optional<HttpVerb> verb = httpVerbFromBoost(method);
392 if (verb)
393 {
394 self->methodsBitfield = 1U << static_cast<size_t>(*verb);
395 }
Ed Tanous271584a2019-07-09 16:24:22 -0700396 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700397 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700398
Ed Tanous1abe55e2018-09-05 08:30:59 -0700399 template <typename... MethodArgs>
Ed Tanous81ce6092020-12-17 16:54:55 +0000400 self_t& methods(boost::beast::http::verb method, MethodArgs... argsMethod)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700401 {
Ed Tanous271584a2019-07-09 16:24:22 -0700402 self_t* self = static_cast<self_t*>(this);
Ed Tanous81ce6092020-12-17 16:54:55 +0000403 methods(argsMethod...);
Ed Tanous2c9efc32022-07-31 22:08:26 -0700404 std::optional<HttpVerb> verb = httpVerbFromBoost(method);
405 if (verb)
406 {
407 self->methodsBitfield |= 1U << static_cast<size_t>(*verb);
408 }
Ed Tanous271584a2019-07-09 16:24:22 -0700409 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700410 }
Tanousf00032d2018-11-05 01:18:10 -0300411
Ed Tanous44e45182022-07-26 16:47:23 -0700412 self_t& notFound()
413 {
414 self_t* self = static_cast<self_t*>(this);
415 self->methodsBitfield = 1U << notFoundIndex;
416 return *self;
417 }
418
Ed Tanous759cf102022-07-31 16:36:52 -0700419 self_t& methodNotAllowed()
420 {
421 self_t* self = static_cast<self_t*>(this);
422 self->methodsBitfield = 1U << methodNotAllowedIndex;
423 return *self;
424 }
425
Ed Tanous432a8902021-06-14 15:28:56 -0700426 self_t& privileges(
427 const std::initializer_list<std::initializer_list<const char*>>& p)
Tanousf00032d2018-11-05 01:18:10 -0300428 {
Ed Tanous271584a2019-07-09 16:24:22 -0700429 self_t* self = static_cast<self_t*>(this);
Ed Tanous432a8902021-06-14 15:28:56 -0700430 for (const std::initializer_list<const char*>& privilege : p)
Tanousf00032d2018-11-05 01:18:10 -0300431 {
Ed Tanous271584a2019-07-09 16:24:22 -0700432 self->privilegesSet.emplace_back(privilege);
Tanousf00032d2018-11-05 01:18:10 -0300433 }
Ed Tanous271584a2019-07-09 16:24:22 -0700434 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300435 }
Ed Tanoused398212021-06-09 17:05:54 -0700436
437 template <size_t N, typename... MethodArgs>
438 self_t& privileges(const std::array<redfish::Privileges, N>& p)
439 {
440 self_t* self = static_cast<self_t*>(this);
441 for (const redfish::Privileges& privilege : p)
442 {
443 self->privilegesSet.emplace_back(privilege);
444 }
445 return *self;
446 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700447};
448
Ed Tanous1abe55e2018-09-05 08:30:59 -0700449class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
450{
451 public:
Patrick Williams89492a12023-05-10 07:51:34 -0500452 explicit DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700453
Ed Tanous1abe55e2018-09-05 08:30:59 -0700454 void validate() override
455 {
456 if (!erasedHandler)
457 {
Ed Tanous28f4b382023-04-10 10:20:56 -0700458 throw std::runtime_error("no handler for url " + rule);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700459 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700460 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700461
zhanghch058d1b46d2021-04-01 11:18:24 +0800462 void handle(const Request& req,
463 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800464 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700465 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800466 erasedHandler(req, asyncResp, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700467 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700468
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500469 template <typename Func>
470 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700471 {
Ed Tanousc867a832022-03-10 14:17:00 -0800472 using boost::callable_traits::args_t;
473 constexpr size_t arity = std::tuple_size<args_t<Func>>::value;
474 constexpr auto is = std::make_integer_sequence<unsigned, arity>{};
475 erasedHandler = wrap(std::move(f), is);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700476 }
477
478 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500479 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700480 // enable_if Arg1 != request
481
482 template <typename Func, unsigned... Indices>
zhanghch058d1b46d2021-04-01 11:18:24 +0800483 std::function<void(const Request&,
484 const std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous15a42df2023-02-09 18:08:23 -0800485 const std::vector<std::string>&)>
Ed Tanous104f09c2022-01-25 09:56:04 -0800486 wrap(Func f, std::integer_sequence<unsigned, Indices...> /*is*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700487 {
Ed Tanousc867a832022-03-10 14:17:00 -0800488 using function_t = crow::utility::FunctionTraits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700489
Ed Tanous1abe55e2018-09-05 08:30:59 -0700490 auto ret = detail::routing_handler_call_helper::Wrapped<
491 Func, typename function_t::template arg<Indices>...>();
492 ret.template set<typename function_t::template arg<Indices>...>(
493 std::move(f));
494 return ret;
495 }
496
Ed Tanous1abe55e2018-09-05 08:30:59 -0700497 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800498 std::function<void(const Request&,
499 const std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous15a42df2023-02-09 18:08:23 -0800500 const std::vector<std::string>&)>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700501 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700502};
503
504template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500505class TaggedRule :
506 public BaseRule,
507 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700508{
509 public:
510 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700511
Patrick Williams89492a12023-05-10 07:51:34 -0500512 explicit TaggedRule(const std::string& ruleIn) : BaseRule(ruleIn) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700513
Ed Tanous1abe55e2018-09-05 08:30:59 -0700514 void validate() override
515 {
516 if (!handler)
517 {
Ed Tanous28f4b382023-04-10 10:20:56 -0700518 throw std::runtime_error("no handler for url " + rule);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519 }
520 }
521
522 template <typename Func>
Ed Tanous15a42df2023-02-09 18:08:23 -0800523 void operator()(Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700524 {
525 static_assert(
Ed Tanous7045c8d2017-04-03 10:04:37 -0700526 black_magic::CallHelper<
Ed Tanous15a42df2023-02-09 18:08:23 -0800527 Func, black_magic::S<crow::Request,
528 std::shared_ptr<bmcweb::AsyncResp>&,
529 Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700530 "Handler type is mismatched with URL parameters");
531 static_assert(
zhanghch058d1b46d2021-04-01 11:18:24 +0800532 std::is_same<
533 void,
534 decltype(f(std::declval<crow::Request>(),
535 std::declval<std::shared_ptr<bmcweb::AsyncResp>&>(),
536 std::declval<Args>()...))>::value,
Ed Tanous15a42df2023-02-09 18:08:23 -0800537 "Handler function with response argument should have void return type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700538
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800539 handler = std::forward<Func>(f);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700540 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700541
zhanghch058d1b46d2021-04-01 11:18:24 +0800542 void handle(const Request& req,
543 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous15a42df2023-02-09 18:08:23 -0800544 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700545 {
546 detail::routing_handler_call_helper::Call<
547 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
Ed Tanous15a42df2023-02-09 18:08:23 -0800548 0, black_magic::S<Args...>, black_magic::S<>>()(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700549 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800550 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700551 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700552
Ed Tanous1abe55e2018-09-05 08:30:59 -0700553 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800554 std::function<void(const crow::Request&,
555 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>
556 handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700557};
558
Ed Tanous1abe55e2018-09-05 08:30:59 -0700559class Trie
560{
561 public:
562 struct Node
563 {
564 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700565 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
566 paramChildrens{};
Ed Tanousa94ac612022-02-22 11:13:24 -0800567 using ChildMap = boost::container::flat_map<
568 std::string, unsigned, std::less<>,
569 std::vector<std::pair<std::string, unsigned>>>;
570 ChildMap children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700571
Ed Tanous1abe55e2018-09-05 08:30:59 -0700572 bool isSimpleNode() const
573 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800574 return ruleIndex == 0 &&
575 std::all_of(std::begin(paramChildrens),
576 std::end(paramChildrens),
577 [](size_t x) { return x == 0U; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700578 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700579 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700580
Patrick Williams89492a12023-05-10 07:51:34 -0500581 Trie() : nodes(1) {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700582
583 private:
584 void optimizeNode(Node* node)
585 {
Ed Tanous271584a2019-07-09 16:24:22 -0700586 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700587 {
Ed Tanousdbb59d42022-01-25 11:09:55 -0800588 if (x == 0U)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700589 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700590 continue;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700591 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700592 Node* child = &nodes[x];
593 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700594 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700595 if (node->children.empty())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700596 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700597 return;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700598 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599 bool mergeWithChild = true;
Ed Tanousa94ac612022-02-22 11:13:24 -0800600 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700601 {
602 Node* child = &nodes[kv.second];
603 if (!child->isSimpleNode())
604 {
605 mergeWithChild = false;
606 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700607 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700608 }
609 if (mergeWithChild)
610 {
Ed Tanousa94ac612022-02-22 11:13:24 -0800611 Node::ChildMap merged;
612 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700613 {
614 Node* child = &nodes[kv.second];
Ed Tanousa94ac612022-02-22 11:13:24 -0800615 for (const Node::ChildMap::value_type& childKv :
Tanousf00032d2018-11-05 01:18:10 -0300616 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700617 {
618 merged[kv.first + childKv.first] = childKv.second;
619 }
620 }
621 node->children = std::move(merged);
622 optimizeNode(node);
623 }
624 else
625 {
Ed Tanousa94ac612022-02-22 11:13:24 -0800626 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700627 {
628 Node* child = &nodes[kv.second];
629 optimizeNode(child);
630 }
631 }
632 }
633
634 void optimize()
635 {
636 optimizeNode(head());
637 }
638
639 public:
640 void validate()
641 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700642 optimize();
643 }
644
Ed Tanous81ce6092020-12-17 16:54:55 +0000645 void findRouteIndexes(const std::string& reqUrl,
646 std::vector<unsigned>& routeIndexes,
Tanousf00032d2018-11-05 01:18:10 -0300647 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700648 {
649 if (node == nullptr)
650 {
651 node = head();
652 }
Ed Tanousa94ac612022-02-22 11:13:24 -0800653 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700654 {
655 const std::string& fragment = kv.first;
656 const Node* child = &nodes[kv.second];
Ed Tanous81ce6092020-12-17 16:54:55 +0000657 if (pos >= reqUrl.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700658 {
659 if (child->ruleIndex != 0 && fragment != "/")
660 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000661 routeIndexes.push_back(child->ruleIndex);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700662 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000663 findRouteIndexes(reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700664 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 }
666 else
667 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000668 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700669 {
Ed Tanous271584a2019-07-09 16:24:22 -0700670 findRouteIndexes(
Ed Tanous81ce6092020-12-17 16:54:55 +0000671 reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700672 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673 }
674 }
675 }
676 }
677
Ed Tanous15a42df2023-02-09 18:08:23 -0800678 std::pair<unsigned, std::vector<std::string>>
679 find(const std::string_view reqUrl, const Node* node = nullptr,
680 size_t pos = 0, std::vector<std::string>* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700681 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800682 std::vector<std::string> empty;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 if (params == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700684 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685 params = &empty;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700686 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700687
688 unsigned found{};
Ed Tanous15a42df2023-02-09 18:08:23 -0800689 std::vector<std::string> matchParams;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700690
691 if (node == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700692 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700693 node = head();
Ed Tanous3174e4d2020-10-07 11:41:22 -0700694 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000695 if (pos == reqUrl.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700696 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700697 return {node->ruleIndex, *params};
Ed Tanous3174e4d2020-10-07 11:41:22 -0700698 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700699
700 auto updateFound =
Ed Tanous15a42df2023-02-09 18:08:23 -0800701 [&found,
702 &matchParams](std::pair<unsigned, std::vector<std::string>>& ret) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700703 if (ret.first != 0U && (found == 0U || found > ret.first))
704 {
705 found = ret.first;
706 matchParams = std::move(ret.second);
707 }
708 };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700709
Ed Tanouse662eae2022-01-25 10:39:19 -0800710 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700711 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000712 size_t epos = pos;
Ed Tanous81ce6092020-12-17 16:54:55 +0000713 for (; epos < reqUrl.size(); epos++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700714 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000715 if (reqUrl[epos] == '/')
Ed Tanous3174e4d2020-10-07 11:41:22 -0700716 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700717 break;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700718 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700719 }
720
721 if (epos != pos)
722 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800723 params->emplace_back(reqUrl.substr(pos, epos - pos));
724 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000725 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700726 &nodes[node->paramChildrens[static_cast<size_t>(
727 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000728 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 updateFound(ret);
Ed Tanous15a42df2023-02-09 18:08:23 -0800730 params->pop_back();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700731 }
732 }
733
Ed Tanouse662eae2022-01-25 10:39:19 -0800734 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700735 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000736 size_t epos = reqUrl.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700737
738 if (epos != pos)
739 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800740 params->emplace_back(reqUrl.substr(pos, epos - pos));
741 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000742 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700743 &nodes[node->paramChildrens[static_cast<size_t>(
744 ParamType::PATH)]],
745 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 updateFound(ret);
Ed Tanous15a42df2023-02-09 18:08:23 -0800747 params->pop_back();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700748 }
749 }
750
Ed Tanousa94ac612022-02-22 11:13:24 -0800751 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752 {
753 const std::string& fragment = kv.first;
754 const Node* child = &nodes[kv.second];
755
Ed Tanous81ce6092020-12-17 16:54:55 +0000756 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700757 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800758 std::pair<unsigned, std::vector<std::string>> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000759 find(reqUrl, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700760 updateFound(ret);
761 }
762 }
763
764 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700765 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766
767 void add(const std::string& url, unsigned ruleIndex)
768 {
Ed Tanous271584a2019-07-09 16:24:22 -0700769 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700770
771 for (unsigned i = 0; i < url.size(); i++)
772 {
773 char c = url[i];
774 if (c == '<')
775 {
Ed Tanous15a42df2023-02-09 18:08:23 -0800776 constexpr static std::array<
777 std::pair<ParamType, std::string_view>, 3>
Tanousf00032d2018-11-05 01:18:10 -0300778 paramTraits = {{
Tanousf00032d2018-11-05 01:18:10 -0300779 {ParamType::STRING, "<str>"},
780 {ParamType::STRING, "<string>"},
781 {ParamType::PATH, "<path>"},
782 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700783
Ed Tanous15a42df2023-02-09 18:08:23 -0800784 for (const std::pair<ParamType, std::string_view>& x :
785 paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700786 {
Tanousf00032d2018-11-05 01:18:10 -0300787 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700788 {
Ed Tanous271584a2019-07-09 16:24:22 -0700789 size_t index = static_cast<size_t>(x.first);
Ed Tanouse662eae2022-01-25 10:39:19 -0800790 if (nodes[idx].paramChildrens[index] == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791 {
Tanousf00032d2018-11-05 01:18:10 -0300792 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700793 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700794 }
Ed Tanous271584a2019-07-09 16:24:22 -0700795 idx = nodes[idx].paramChildrens[index];
796 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700797 break;
798 }
799 }
800
801 i--;
802 }
803 else
804 {
805 std::string piece(&c, 1);
Ed Tanouse662eae2022-01-25 10:39:19 -0800806 if (nodes[idx].children.count(piece) == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807 {
Tanousf00032d2018-11-05 01:18:10 -0300808 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700809 nodes[idx].children.emplace(piece, newNodeIdx);
810 }
811 idx = nodes[idx].children[piece];
812 }
813 }
Ed Tanouse662eae2022-01-25 10:39:19 -0800814 if (nodes[idx].ruleIndex != 0U)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700815 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700816 throw std::runtime_error("handler already exists for " + url);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700817 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700818 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700819 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700820
Ed Tanous1abe55e2018-09-05 08:30:59 -0700821 private:
Ed Tanous271584a2019-07-09 16:24:22 -0700822 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700823 {
Ed Tanous271584a2019-07-09 16:24:22 -0700824 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800826 if (n->paramChildrens[i] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 {
828 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -0700829 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
830 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700831 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700832 case ParamType::STRING:
833 BMCWEB_LOG_DEBUG << "<str>";
834 break;
835 case ParamType::PATH:
836 BMCWEB_LOG_DEBUG << "<path>";
837 break;
Ed Tanous23a21a12020-07-25 04:45:05 +0000838 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -0700839 BMCWEB_LOG_DEBUG << "<ERROR>";
840 break;
841 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700842
Ed Tanous1abe55e2018-09-05 08:30:59 -0700843 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
844 }
845 }
Ed Tanousa94ac612022-02-22 11:13:24 -0800846 for (const Node::ChildMap::value_type& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700847 {
848 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -0700849 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -0700850 << kv.first;
851 debugNodePrint(&nodes[kv.second], level + 1);
852 }
853 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700854
Ed Tanous1abe55e2018-09-05 08:30:59 -0700855 public:
856 void debugPrint()
857 {
Ed Tanous271584a2019-07-09 16:24:22 -0700858 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700859 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700860
Ed Tanous1abe55e2018-09-05 08:30:59 -0700861 private:
862 const Node* head() const
863 {
864 return &nodes.front();
865 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700866
Ed Tanous1abe55e2018-09-05 08:30:59 -0700867 Node* head()
868 {
869 return &nodes.front();
870 }
871
872 unsigned newNode()
873 {
874 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -0700875 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700876 }
877
878 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700879};
880
Ed Tanous1abe55e2018-09-05 08:30:59 -0700881class Router
882{
883 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -0700884 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700885
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886 DynamicRule& newRuleDynamic(const std::string& rule)
887 {
888 std::unique_ptr<DynamicRule> ruleObject =
889 std::make_unique<DynamicRule>(rule);
890 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -0300891 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -0700892
Ed Tanous1abe55e2018-09-05 08:30:59 -0700893 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700894 }
895
Ed Tanous1abe55e2018-09-05 08:30:59 -0700896 template <uint64_t N>
897 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
898 newRuleTagged(const std::string& rule)
899 {
900 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
901 TaggedRule>;
902 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
903 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -0300904 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700905
906 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700907 }
908
Tanousf00032d2018-11-05 01:18:10 -0300909 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700910 {
Tanousf00032d2018-11-05 01:18:10 -0300911 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700912 {
Tanousf00032d2018-11-05 01:18:10 -0300913 return;
914 }
Ed Tanous759cf102022-07-31 16:36:52 -0700915 for (size_t method = 0, methodBit = 1; method <= methodNotAllowedIndex;
Ed Tanous2c70f802020-09-28 14:29:23 -0700916 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -0300917 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800918 if ((ruleObject->methodsBitfield & methodBit) > 0U)
Tanousf00032d2018-11-05 01:18:10 -0300919 {
920 perMethods[method].rules.emplace_back(ruleObject);
921 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -0700922 rule, static_cast<unsigned>(
923 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -0300924 // directory case:
925 // request to `/about' url matches `/about/' rule
926 if (rule.size() > 2 && rule.back() == '/')
927 {
928 perMethods[method].trie.add(
929 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -0700930 static_cast<unsigned>(perMethods[method].rules.size() -
931 1));
Tanousf00032d2018-11-05 01:18:10 -0300932 }
933 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700934 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700935 }
936
Ed Tanous1abe55e2018-09-05 08:30:59 -0700937 void validate()
938 {
Tanousf00032d2018-11-05 01:18:10 -0300939 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700940 {
941 if (rule)
942 {
Tanousf00032d2018-11-05 01:18:10 -0300943 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700944 if (upgraded)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700945 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700946 rule = std::move(upgraded);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700947 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700948 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -0300949 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700950 }
951 }
Tanousf00032d2018-11-05 01:18:10 -0300952 for (PerMethod& perMethod : perMethods)
953 {
954 perMethod.trie.validate();
955 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700956 }
957
Ed Tanous44e45182022-07-26 16:47:23 -0700958 struct FindRoute
959 {
960 BaseRule* rule = nullptr;
Ed Tanous15a42df2023-02-09 18:08:23 -0800961 std::vector<std::string> params;
Ed Tanous44e45182022-07-26 16:47:23 -0700962 };
963
964 struct FindRouteResponse
965 {
966 std::string allowHeader;
967 FindRoute route;
968 };
969
Ed Tanous759cf102022-07-31 16:36:52 -0700970 FindRoute findRouteByIndex(std::string_view url, size_t index) const
971 {
972 FindRoute route;
973 if (index >= perMethods.size())
974 {
975 BMCWEB_LOG_CRITICAL << "Bad index???";
976 return route;
977 }
978 const PerMethod& perMethod = perMethods[index];
Ed Tanous15a42df2023-02-09 18:08:23 -0800979 std::pair<unsigned, std::vector<std::string>> found =
980 perMethod.trie.find(url);
Ed Tanous759cf102022-07-31 16:36:52 -0700981 if (found.first >= perMethod.rules.size())
982 {
983 throw std::runtime_error("Trie internal structure corrupted!");
984 }
985 // Found a 404 route, switch that in
986 if (found.first != 0U)
987 {
988 route.rule = perMethod.rules[found.first];
989 route.params = std::move(found.second);
990 }
991 return route;
992 }
993
994 FindRouteResponse findRoute(Request& req) const
Ed Tanous44e45182022-07-26 16:47:23 -0700995 {
996 FindRouteResponse findRoute;
997
Ed Tanous2c9efc32022-07-31 22:08:26 -0700998 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
999 if (!verb)
1000 {
1001 return findRoute;
1002 }
1003 size_t reqMethodIndex = static_cast<size_t>(*verb);
Ed Tanous44e45182022-07-26 16:47:23 -07001004 // Check to see if this url exists at any verb
1005 for (size_t perMethodIndex = 0; perMethodIndex <= maxVerbIndex;
1006 perMethodIndex++)
1007 {
1008 // Make sure it's safe to deference the array at that index
1009 static_assert(maxVerbIndex <
1010 std::tuple_size_v<decltype(perMethods)>);
Patrick Williams89492a12023-05-10 07:51:34 -05001011 FindRoute route = findRouteByIndex(req.url().encoded_path(),
1012 perMethodIndex);
Ed Tanous759cf102022-07-31 16:36:52 -07001013 if (route.rule == nullptr)
Ed Tanous44e45182022-07-26 16:47:23 -07001014 {
1015 continue;
1016 }
1017 if (!findRoute.allowHeader.empty())
1018 {
1019 findRoute.allowHeader += ", ";
1020 }
Ed Tanous2c9efc32022-07-31 22:08:26 -07001021 HttpVerb thisVerb = static_cast<HttpVerb>(perMethodIndex);
1022 findRoute.allowHeader += httpVerbToString(thisVerb);
Ed Tanous44e45182022-07-26 16:47:23 -07001023 if (perMethodIndex == reqMethodIndex)
1024 {
Ed Tanous759cf102022-07-31 16:36:52 -07001025 findRoute.route = route;
Ed Tanous44e45182022-07-26 16:47:23 -07001026 }
1027 }
1028 return findRoute;
1029 }
1030
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301031 static bool isUserPrivileged(
1032 Request& req, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1033 BaseRule& rule, const dbus::utility::DBusPropertiesMap& userInfoMap)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001034 {
Ed Tanous3d183202023-03-10 09:21:58 -08001035 std::string userRole{};
1036 const std::string* userRolePtr = nullptr;
1037 const bool* remoteUser = nullptr;
1038 const bool* passwordExpired = nullptr;
1039
1040 const bool success = sdbusplus::unpackPropertiesNoThrow(
1041 redfish::dbus_utils::UnpackErrorPrinter(), userInfoMap,
1042 "UserPrivilege", userRolePtr, "RemoteUser", remoteUser,
1043 "UserPasswordExpired", passwordExpired);
1044
1045 if (!success)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001046 {
Ed Tanous3d183202023-03-10 09:21:58 -08001047 asyncResp->res.result(
1048 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301049 return false;
Ed Tanous3d183202023-03-10 09:21:58 -08001050 }
1051
1052 if (userRolePtr != nullptr)
1053 {
1054 userRole = *userRolePtr;
1055 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1056 << " userRole = " << *userRolePtr;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001057 }
1058
1059 if (remoteUser == nullptr)
1060 {
1061 BMCWEB_LOG_ERROR << "RemoteUser property missing or wrong type";
1062 asyncResp->res.result(
1063 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301064 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001065 }
Ed Tanous3d183202023-03-10 09:21:58 -08001066 bool expired = false;
1067 if (passwordExpired == nullptr)
Ed Tanouse1f5c162023-03-10 09:02:51 -08001068 {
1069 if (!*remoteUser)
1070 {
1071 BMCWEB_LOG_ERROR
1072 << "UserPasswordExpired property is expected for"
1073 " local user but is missing or wrong type";
1074 asyncResp->res.result(
1075 boost::beast::http::status::internal_server_error);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301076 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001077 }
Ed Tanous3d183202023-03-10 09:21:58 -08001078 }
1079 else
1080 {
1081 expired = *passwordExpired;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001082 }
1083
1084 // Get the user's privileges from the role
1085 redfish::Privileges userPrivileges =
1086 redfish::getUserPrivileges(userRole);
1087
1088 // Set isConfigureSelfOnly based on D-Bus results. This
1089 // ignores the results from both pamAuthenticateUser and the
1090 // value from any previous use of this session.
Ed Tanous3d183202023-03-10 09:21:58 -08001091 req.session->isConfigureSelfOnly = expired;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001092
1093 // Modify privileges if isConfigureSelfOnly.
1094 if (req.session->isConfigureSelfOnly)
1095 {
1096 // Remove all privileges except ConfigureSelf
1097 userPrivileges = userPrivileges.intersection(
1098 redfish::Privileges{"ConfigureSelf"});
1099 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1100 }
1101
1102 if (!rule.checkPrivileges(userPrivileges))
1103 {
1104 asyncResp->res.result(boost::beast::http::status::forbidden);
1105 if (req.session->isConfigureSelfOnly)
1106 {
1107 redfish::messages::passwordChangeRequired(
1108 asyncResp->res, crow::utility::urlFromPieces(
1109 "redfish", "v1", "AccountService",
1110 "Accounts", req.session->username));
1111 }
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301112 return false;
Ed Tanouse1f5c162023-03-10 09:02:51 -08001113 }
1114
1115 req.userRole = userRole;
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301116
1117 return true;
1118 }
1119
1120 template <typename CallbackFn>
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001121 void afterGetUserInfo(Request& req,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301122 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1123 BaseRule& rule, CallbackFn&& callback,
1124 const boost::system::error_code& ec,
1125 const dbus::utility::DBusPropertiesMap& userInfoMap)
1126 {
1127 if (ec)
1128 {
1129 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
1130 asyncResp->res.result(
1131 boost::beast::http::status::internal_server_error);
1132 return;
1133 }
1134
1135 if (!Router::isUserPrivileged(req, asyncResp, rule, userInfoMap))
1136 {
1137 // User is not privileged
1138 BMCWEB_LOG_ERROR << "Insufficient Privilege";
1139 asyncResp->res.result(boost::beast::http::status::forbidden);
1140 return;
1141 }
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001142 callback(req);
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301143 }
1144
1145 template <typename CallbackFn>
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001146 void validatePrivilege(Request& req,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301147 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1148 BaseRule& rule, CallbackFn&& callback)
1149 {
Ed Tanous915d2d42023-03-15 13:09:34 -07001150 if (req.session == nullptr)
1151 {
1152 return;
1153 }
1154 std::string username = req.session->username;
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301155 crow::connections::systemBus->async_method_call(
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001156 [this, &req, asyncResp, &rule,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301157 callback(std::forward<CallbackFn>(callback))](
1158 const boost::system::error_code& ec,
1159 const dbus::utility::DBusPropertiesMap& userInfoMap) mutable {
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001160 afterGetUserInfo(req, asyncResp, rule,
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301161 std::forward<CallbackFn>(callback), ec,
1162 userInfoMap);
1163 },
1164 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
Ed Tanous915d2d42023-03-15 13:09:34 -07001165 "xyz.openbmc_project.User.Manager", "GetUserInfo", username);
Ed Tanouse1f5c162023-03-10 09:02:51 -08001166 }
1167
Ed Tanous1abe55e2018-09-05 08:30:59 -07001168 template <typename Adaptor>
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301169 void handleUpgrade(Request& req,
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301170 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1171 Adaptor&& adaptor)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001172 {
Ed Tanous2c9efc32022-07-31 22:08:26 -07001173 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1174 if (!verb || static_cast<size_t>(*verb) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001175 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301176 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001177 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001178 }
Ed Tanous2c9efc32022-07-31 22:08:26 -07001179 PerMethod& perMethod = perMethods[static_cast<size_t>(*verb)];
Tanousf00032d2018-11-05 01:18:10 -03001180 Trie& trie = perMethod.trie;
1181 std::vector<BaseRule*>& rules = perMethod.rules;
1182
Ed Tanous15a42df2023-02-09 18:08:23 -08001183 const std::pair<unsigned, std::vector<std::string>>& found =
Ed Tanous39662a32023-02-06 15:09:46 -08001184 trie.find(req.url().encoded_path());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001185 unsigned ruleIndex = found.first;
Ed Tanouse662eae2022-01-25 10:39:19 -08001186 if (ruleIndex == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001187 {
Ed Tanous39662a32023-02-06 15:09:46 -08001188 BMCWEB_LOG_DEBUG << "Cannot match rules "
1189 << req.url().encoded_path();
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301190 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001191 return;
1192 }
1193
1194 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001195 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001196 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001197 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001198
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301199 BaseRule& rule = *rules[ruleIndex];
1200 size_t methods = rule.getMethods();
1201 if ((methods & (1U << static_cast<size_t>(*verb))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001202 {
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301203 BMCWEB_LOG_DEBUG
1204 << "Rule found but method mismatch: "
1205 << req.url().encoded_path() << " with " << req.methodString()
1206 << "(" << static_cast<uint32_t>(*verb) << ") / " << methods;
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +05301207 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001208 return;
1209 }
1210
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301211 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rule.rule << "' "
1212 << static_cast<uint32_t>(*verb) << " / " << methods;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001213
P Dheeraj Srujan Kumar7e9093e2021-09-18 01:19:04 +05301214 // TODO(ed) This should be able to use std::bind_front, but it doesn't
1215 // appear to work with the std::move on adaptor.
Ed Tanous915d2d42023-03-15 13:09:34 -07001216 validatePrivilege(
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001217 req, asyncResp, rule,
Ed Tanous915d2d42023-03-15 13:09:34 -07001218 [&rule, asyncResp, adaptor(std::forward<Adaptor>(adaptor))](
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001219 Request& thisReq) mutable {
Ed Tanous915d2d42023-03-15 13:09:34 -07001220 rule.handleUpgrade(thisReq, asyncResp, std::move(adaptor));
1221 });
Ed Tanous7045c8d2017-04-03 10:04:37 -07001222 }
1223
zhanghch058d1b46d2021-04-01 11:18:24 +08001224 void handle(Request& req,
1225 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001226 {
Ed Tanous2c9efc32022-07-31 22:08:26 -07001227 std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
1228 if (!verb || static_cast<size_t>(*verb) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001229 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001230 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001231 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001232 }
Ed Tanous44e45182022-07-26 16:47:23 -07001233
1234 FindRouteResponse foundRoute = findRoute(req);
1235
Ed Tanous759cf102022-07-31 16:36:52 -07001236 if (foundRoute.route.rule == nullptr)
Ed Tanous88a03c52022-03-14 10:16:07 -07001237 {
Ed Tanous759cf102022-07-31 16:36:52 -07001238 // Couldn't find a normal route with any verb, try looking for a 404
1239 // route
1240 if (foundRoute.allowHeader.empty())
Ed Tanous44e45182022-07-26 16:47:23 -07001241 {
Patrick Williams89492a12023-05-10 07:51:34 -05001242 foundRoute.route = findRouteByIndex(req.url().encoded_path(),
1243 notFoundIndex);
Ed Tanous759cf102022-07-31 16:36:52 -07001244 }
1245 else
1246 {
1247 // See if we have a method not allowed (405) handler
Ed Tanous39662a32023-02-06 15:09:46 -08001248 foundRoute.route = findRouteByIndex(req.url().encoded_path(),
1249 methodNotAllowedIndex);
Ed Tanous44e45182022-07-26 16:47:23 -07001250 }
1251 }
Ed Tanous759cf102022-07-31 16:36:52 -07001252
1253 // Fill in the allow header if it's valid
1254 if (!foundRoute.allowHeader.empty())
Ed Tanous44e45182022-07-26 16:47:23 -07001255 {
Ed Tanous88a03c52022-03-14 10:16:07 -07001256 asyncResp->res.addHeader(boost::beast::http::field::allow,
Ed Tanous44e45182022-07-26 16:47:23 -07001257 foundRoute.allowHeader);
Ed Tanous88a03c52022-03-14 10:16:07 -07001258 }
Tanousf00032d2018-11-05 01:18:10 -03001259
Ed Tanous44e45182022-07-26 16:47:23 -07001260 // If we couldn't find a real route or a 404 route, return a generic
1261 // response
1262 if (foundRoute.route.rule == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001263 {
Ed Tanous44e45182022-07-26 16:47:23 -07001264 if (foundRoute.allowHeader.empty())
1265 {
1266 asyncResp->res.result(boost::beast::http::status::not_found);
1267 }
1268 else
Ed Tanous2634dcd2019-03-26 09:28:06 -07001269 {
Ed Tanous88a03c52022-03-14 10:16:07 -07001270 asyncResp->res.result(
1271 boost::beast::http::status::method_not_allowed);
Ed Tanous2634dcd2019-03-26 09:28:06 -07001272 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001273 return;
1274 }
1275
Ed Tanous44e45182022-07-26 16:47:23 -07001276 BaseRule& rule = *foundRoute.route.rule;
Ed Tanous15a42df2023-02-09 18:08:23 -08001277 std::vector<std::string> params = std::move(foundRoute.route.params);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001278
Ed Tanous44e45182022-07-26 16:47:23 -07001279 BMCWEB_LOG_DEBUG << "Matched rule '" << rule.rule << "' "
Snehalatha Venkatesh1c99da02022-12-27 06:45:35 +00001280 << static_cast<uint32_t>(*verb) << " / "
Ed Tanous44e45182022-07-26 16:47:23 -07001281 << rule.getMethods();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001282
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001283 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001284 {
Ed Tanous44e45182022-07-26 16:47:23 -07001285 rule.handle(req, asyncResp, params);
James Feist7166bf02019-12-10 16:52:14 +00001286 return;
1287 }
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001288 validatePrivilege(req, asyncResp, rule,
1289 [&rule, asyncResp, params](Request& thisReq) mutable {
Ed Tanous915d2d42023-03-15 13:09:34 -07001290 rule.handle(thisReq, asyncResp, params);
Jonathan Domand3c8ce62023-03-21 18:17:06 -07001291 });
Ed Tanous7045c8d2017-04-03 10:04:37 -07001292 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001293
Ed Tanous1abe55e2018-09-05 08:30:59 -07001294 void debugPrint()
1295 {
Ed Tanous271584a2019-07-09 16:24:22 -07001296 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001297 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001298 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1299 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001300 perMethods[i].trie.debugPrint();
1301 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001302 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001303
Ed Tanous1abe55e2018-09-05 08:30:59 -07001304 std::vector<const std::string*> getRoutes(const std::string& parent)
1305 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001306 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001307
1308 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001309 {
Tanousf00032d2018-11-05 01:18:10 -03001310 std::vector<unsigned> x;
1311 pm.trie.findRouteIndexes(parent, x);
1312 for (unsigned index : x)
1313 {
1314 ret.push_back(&pm.rules[index]->rule);
1315 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001316 }
1317 return ret;
1318 }
1319
1320 private:
Tanousf00032d2018-11-05 01:18:10 -03001321 struct PerMethod
1322 {
1323 std::vector<BaseRule*> rules;
1324 Trie trie;
Ed Tanous313a3c22022-03-14 09:27:38 -07001325 // rule index 0 has special meaning; preallocate it to avoid
Tanousf00032d2018-11-05 01:18:10 -03001326 // duplication.
Patrick Williams89492a12023-05-10 07:51:34 -05001327 PerMethod() : rules(1) {}
Tanousf00032d2018-11-05 01:18:10 -03001328 };
Ed Tanous888880a2020-08-24 13:48:50 -07001329
Ed Tanous759cf102022-07-31 16:36:52 -07001330 std::array<PerMethod, methodNotAllowedIndex + 1> perMethods;
Tanousf00032d2018-11-05 01:18:10 -03001331 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001332};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001333} // namespace crow