blob: 06f2a091ba8dc3315ba4a661d086b53482352ada [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
2
Ed Tanous04e438c2020-10-03 08:06:26 -07003#include "common.hpp"
Ed Tanous168e20c2021-12-13 14:39:53 -08004#include "dbus_utility.hpp"
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06005#include "error_messages.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -07006#include "http_request.hpp"
7#include "http_response.hpp"
8#include "logging.hpp"
Tanousf00032d2018-11-05 01:18:10 -03009#include "privileges.hpp"
Ratan Gupta6f359562019-04-03 10:39:08 +053010#include "sessions.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -070011#include "utility.hpp"
12#include "websocket.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070013
Iwona Klimaszewskac0a1c8a2019-07-12 18:26:38 +020014#include <async_resp.hpp>
Tanousf00032d2018-11-05 01:18:10 -030015#include <boost/container/flat_map.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050016
Ed Tanouse0d918b2018-03-27 17:41:04 -070017#include <cerrno>
Ed Tanous7045c8d2017-04-03 10:04:37 -070018#include <cstdint>
Ed Tanouse0d918b2018-03-27 17:41:04 -070019#include <cstdlib>
Ed Tanous3dac7492017-08-02 13:46:20 -070020#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070021#include <memory>
22#include <tuple>
Ed Tanous7045c8d2017-04-03 10:04:37 -070023#include <utility>
24#include <vector>
Ed Tanous9140a672017-04-24 17:01:32 -070025
Ed Tanous1abe55e2018-09-05 08:30:59 -070026namespace crow
27{
Tanousf00032d2018-11-05 01:18:10 -030028
Ed Tanous1abe55e2018-09-05 08:30:59 -070029class BaseRule
30{
31 public:
Ed Tanousf23b7292020-10-15 09:41:17 -070032 BaseRule(const std::string& thisRule) : rule(thisRule)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050033 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070034
Ed Tanous0c0084a2019-10-24 15:57:51 -070035 virtual ~BaseRule() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -070036
Ed Tanous1abe55e2018-09-05 08:30:59 -070037 virtual void validate() = 0;
38 std::unique_ptr<BaseRule> upgrade()
39 {
40 if (ruleToUpgrade)
Ed Tanous3174e4d2020-10-07 11:41:22 -070041 {
Ed Tanous1abe55e2018-09-05 08:30:59 -070042 return std::move(ruleToUpgrade);
Ed Tanous3174e4d2020-10-07 11:41:22 -070043 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070044 return {};
45 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070046
zhanghch058d1b46d2021-04-01 11:18:24 +080047 virtual void handle(const Request&,
48 const std::shared_ptr<bmcweb::AsyncResp>&,
49 const RoutingParams&) = 0;
Ed Tanousceac6f72018-12-02 11:58:47 -080050 virtual void handleUpgrade(const Request&, Response& res,
51 boost::asio::ip::tcp::socket&&)
Ed Tanous1abe55e2018-09-05 08:30:59 -070052 {
Ed Tanousde5c9f32019-03-26 09:17:55 -070053 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070054 res.end();
55 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -070056#ifdef BMCWEB_ENABLE_SSL
Ed Tanousceac6f72018-12-02 11:58:47 -080057 virtual void
58 handleUpgrade(const Request&, Response& res,
59 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&)
Ed Tanous1abe55e2018-09-05 08:30:59 -070060 {
Ed Tanousde5c9f32019-03-26 09:17:55 -070061 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070062 res.end();
63 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070064#endif
65
Ed Tanous271584a2019-07-09 16:24:22 -070066 size_t getMethods()
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 {
68 return methodsBitfield;
69 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070070
Tanousf00032d2018-11-05 01:18:10 -030071 bool checkPrivileges(const redfish::Privileges& userPrivileges)
72 {
73 // If there are no privileges assigned, assume no privileges
74 // required
75 if (privilegesSet.empty())
76 {
77 return true;
78 }
79
80 for (const redfish::Privileges& requiredPrivileges : privilegesSet)
81 {
82 if (userPrivileges.isSupersetOf(requiredPrivileges))
83 {
84 return true;
85 }
86 }
87 return false;
88 }
89
Ed Tanous271584a2019-07-09 16:24:22 -070090 size_t methodsBitfield{
91 1 << static_cast<size_t>(boost::beast::http::verb::get)};
Ed Tanous7045c8d2017-04-03 10:04:37 -070092
Tanousf00032d2018-11-05 01:18:10 -030093 std::vector<redfish::Privileges> privilegesSet;
94
Ed Tanous1abe55e2018-09-05 08:30:59 -070095 std::string rule;
96 std::string nameStr;
Ed Tanous7045c8d2017-04-03 10:04:37 -070097
Ed Tanous1abe55e2018-09-05 08:30:59 -070098 std::unique_ptr<BaseRule> ruleToUpgrade;
Ed Tanous7045c8d2017-04-03 10:04:37 -070099
Ed Tanous1abe55e2018-09-05 08:30:59 -0700100 friend class Router;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500101 template <typename T>
102 friend struct RuleParameterTraits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700103};
104
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105namespace detail
106{
107namespace routing_handler_call_helper
108{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500109template <typename T, int Pos>
110struct CallPair
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111{
112 using type = T;
113 static const int pos = Pos;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700114};
115
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500116template <typename H1>
117struct CallParams
Ed Tanous1abe55e2018-09-05 08:30:59 -0700118{
119 H1& handler;
120 const RoutingParams& params;
121 const Request& req;
zhanghch058d1b46d2021-04-01 11:18:24 +0800122 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700123};
124
125template <typename F, int NInt, int NUint, int NDouble, int NString,
126 typename S1, typename S2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700127struct Call
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500128{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700129
130template <typename F, int NInt, int NUint, int NDouble, int NString,
131 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700132struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<int64_t, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700133 black_magic::S<Args2...>>
134{
135 void operator()(F cparams)
136 {
137 using pushed = typename black_magic::S<Args2...>::template push_back<
138 CallPair<int64_t, NInt>>;
139 Call<F, NInt + 1, NUint, NDouble, NString, black_magic::S<Args1...>,
140 pushed>()(cparams);
141 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700142};
143
144template <typename F, int NInt, int NUint, int NDouble, int NString,
145 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700146struct Call<F, NInt, NUint, NDouble, NString,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700147 black_magic::S<uint64_t, Args1...>, black_magic::S<Args2...>>
148{
149 void operator()(F cparams)
150 {
151 using pushed = typename black_magic::S<Args2...>::template push_back<
152 CallPair<uint64_t, NUint>>;
153 Call<F, NInt, NUint + 1, NDouble, NString, black_magic::S<Args1...>,
154 pushed>()(cparams);
155 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700156};
157
158template <typename F, int NInt, int NUint, int NDouble, int NString,
159 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700160struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<double, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700161 black_magic::S<Args2...>>
162{
163 void operator()(F cparams)
164 {
165 using pushed = typename black_magic::S<Args2...>::template push_back<
166 CallPair<double, NDouble>>;
167 Call<F, NInt, NUint, NDouble + 1, NString, black_magic::S<Args1...>,
168 pushed>()(cparams);
169 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700170};
171
172template <typename F, int NInt, int NUint, int NDouble, int NString,
173 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700174struct Call<F, NInt, NUint, NDouble, NString,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700175 black_magic::S<std::string, Args1...>, black_magic::S<Args2...>>
176{
177 void operator()(F cparams)
178 {
179 using pushed = typename black_magic::S<Args2...>::template push_back<
180 CallPair<std::string, NString>>;
181 Call<F, NInt, NUint, NDouble, NString + 1, black_magic::S<Args1...>,
182 pushed>()(cparams);
183 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700184};
185
186template <typename F, int NInt, int NUint, int NDouble, int NString,
187 typename... Args1>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700188struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700189 black_magic::S<Args1...>>
190{
191 void operator()(F cparams)
192 {
193 cparams.handler(
zhanghch058d1b46d2021-04-01 11:18:24 +0800194 cparams.req, cparams.asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700195 cparams.params.template get<typename Args1::type>(Args1::pos)...);
196 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700197};
198
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500199template <typename Func, typename... ArgsWrapped>
200struct Wrapped
Ed Tanous1abe55e2018-09-05 08:30:59 -0700201{
202 template <typename... Args>
203 void set(
204 Func f,
205 typename std::enable_if<
206 !std::is_same<
207 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
208 const Request&>::value,
209 int>::type = 0)
210 {
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800211 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800212 const Request&,
213 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
214 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700215 }
216
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500217 template <typename Req, typename... Args>
218 struct ReqHandlerWrapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700219 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000220 ReqHandlerWrapper(Func fIn) : f(std::move(fIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500221 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700222
zhanghch058d1b46d2021-04-01 11:18:24 +0800223 void operator()(const Request& req,
224 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
225 Args... args)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700226 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800227 asyncResp->res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700228 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700229
Ed Tanous1abe55e2018-09-05 08:30:59 -0700230 Func f;
231 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700232
Ed Tanous1abe55e2018-09-05 08:30:59 -0700233 template <typename... Args>
234 void set(
235 Func f,
236 typename std::enable_if<
237 std::is_same<
238 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
239 const Request&>::value &&
240 !std::is_same<typename std::tuple_element<
241 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800242 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700243 int>::type = 0)
244 {
245 handler = ReqHandlerWrapper<Args...>(std::move(f));
246 /*handler = (
247 [f = std::move(f)]
248 (const Request& req, Response& res, Args... args){
Ed Tanousde5c9f32019-03-26 09:17:55 -0700249 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700250 res.end();
251 });*/
252 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700253
Ed Tanous1abe55e2018-09-05 08:30:59 -0700254 template <typename... Args>
255 void set(
256 Func f,
257 typename std::enable_if<
258 std::is_same<
259 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
260 const Request&>::value &&
261 std::is_same<typename std::tuple_element<
262 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800263 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700264 int>::type = 0)
265 {
266 handler = std::move(f);
267 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700268
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500269 template <typename... Args>
270 struct HandlerTypeHelper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700271 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800272 using type = std::function<void(
273 const crow::Request&, const std::shared_ptr<bmcweb::AsyncResp>&,
274 Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700275 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700276 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700277 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700278
Ed Tanous1abe55e2018-09-05 08:30:59 -0700279 template <typename... Args>
280 struct HandlerTypeHelper<const Request&, Args...>
281 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800282 using type = std::function<void(
283 const crow::Request&, const std::shared_ptr<bmcweb::AsyncResp>&,
284 Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700285 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700286 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700287 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700288
Ed Tanous1abe55e2018-09-05 08:30:59 -0700289 template <typename... Args>
zhanghch058d1b46d2021-04-01 11:18:24 +0800290 struct HandlerTypeHelper<const Request&,
291 const std::shared_ptr<bmcweb::AsyncResp>&, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700292 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800293 using type = std::function<void(
294 const crow::Request&, const std::shared_ptr<bmcweb::AsyncResp>&,
295 Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700296 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700297 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700298 };
299
300 typename HandlerTypeHelper<ArgsWrapped...>::type handler;
301
zhanghch058d1b46d2021-04-01 11:18:24 +0800302 void operator()(const Request& req,
303 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700304 const RoutingParams& params)
305 {
306 detail::routing_handler_call_helper::Call<
307 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
308 0, 0, 0, 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
309 black_magic::S<>>()(
310 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800311 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700312 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700313};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700314} // namespace routing_handler_call_helper
315} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700316
Ed Tanous1abe55e2018-09-05 08:30:59 -0700317class WebSocketRule : public BaseRule
318{
319 using self_t = WebSocketRule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700320
Ed Tanous1abe55e2018-09-05 08:30:59 -0700321 public:
Ed Tanousf23b7292020-10-15 09:41:17 -0700322 WebSocketRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500323 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700324
Ed Tanous1abe55e2018-09-05 08:30:59 -0700325 void validate() override
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500326 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700327
zhanghch058d1b46d2021-04-01 11:18:24 +0800328 void handle(const Request&,
329 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
330 const RoutingParams&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700331 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800332 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700333 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700334
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000335 void handleUpgrade(const Request& req, Response&,
Ed Tanousceac6f72018-12-02 11:58:47 -0800336 boost::asio::ip::tcp::socket&& adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700337 {
Ratan Gupta02453b12019-10-22 14:43:36 +0530338 std::shared_ptr<
339 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>
340 myConnection = std::make_shared<
341 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000342 req, std::move(adaptor), openHandler, messageHandler,
Ratan Gupta02453b12019-10-22 14:43:36 +0530343 closeHandler, errorHandler);
344 myConnection->start();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700345 }
346#ifdef BMCWEB_ENABLE_SSL
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000347 void handleUpgrade(const Request& req, Response&,
Ed Tanousceac6f72018-12-02 11:58:47 -0800348 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
349 adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700350 {
Ed Tanousceac6f72018-12-02 11:58:47 -0800351 std::shared_ptr<crow::websocket::ConnectionImpl<
352 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
353 myConnection = std::make_shared<crow::websocket::ConnectionImpl<
354 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000355 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanousceac6f72018-12-02 11:58:47 -0800356 closeHandler, errorHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700357 myConnection->start();
358 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700359#endif
360
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500361 template <typename Func>
362 self_t& onopen(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700363 {
364 openHandler = f;
365 return *this;
366 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700367
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500368 template <typename Func>
369 self_t& onmessage(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700370 {
371 messageHandler = f;
372 return *this;
373 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700374
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500375 template <typename Func>
376 self_t& onclose(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700377 {
378 closeHandler = f;
379 return *this;
380 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700381
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500382 template <typename Func>
383 self_t& onerror(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700384 {
385 errorHandler = f;
386 return *this;
387 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700388
Ed Tanous1abe55e2018-09-05 08:30:59 -0700389 protected:
Gunnar Millsccd584f2021-11-16 11:36:33 -0600390 std::function<void(crow::websocket::Connection&,
391 std::shared_ptr<bmcweb::AsyncResp>)>
392 openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700393 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
394 messageHandler;
395 std::function<void(crow::websocket::Connection&, const std::string&)>
396 closeHandler;
397 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700398};
399
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500400template <typename T>
401struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700402{
403 using self_t = T;
404 WebSocketRule& websocket()
405 {
Ed Tanous271584a2019-07-09 16:24:22 -0700406 self_t* self = static_cast<self_t*>(this);
407 WebSocketRule* p = new WebSocketRule(self->rule);
408 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700409 return *p;
410 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700411
Ed Tanousf23b7292020-10-15 09:41:17 -0700412 self_t& name(const std::string_view name) noexcept
Ed Tanous1abe55e2018-09-05 08:30:59 -0700413 {
Ed Tanous271584a2019-07-09 16:24:22 -0700414 self_t* self = static_cast<self_t*>(this);
Ed Tanousf23b7292020-10-15 09:41:17 -0700415 self->nameStr = name;
Ed Tanous271584a2019-07-09 16:24:22 -0700416 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700417 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700418
Ed Tanous1abe55e2018-09-05 08:30:59 -0700419 self_t& methods(boost::beast::http::verb method)
420 {
Ed Tanous271584a2019-07-09 16:24:22 -0700421 self_t* self = static_cast<self_t*>(this);
422 self->methodsBitfield = 1U << static_cast<size_t>(method);
423 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700424 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700425
Ed Tanous1abe55e2018-09-05 08:30:59 -0700426 template <typename... MethodArgs>
Ed Tanous81ce6092020-12-17 16:54:55 +0000427 self_t& methods(boost::beast::http::verb method, MethodArgs... argsMethod)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700428 {
Ed Tanous271584a2019-07-09 16:24:22 -0700429 self_t* self = static_cast<self_t*>(this);
Ed Tanous81ce6092020-12-17 16:54:55 +0000430 methods(argsMethod...);
Ed Tanous271584a2019-07-09 16:24:22 -0700431 self->methodsBitfield |= 1U << static_cast<size_t>(method);
432 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700433 }
Tanousf00032d2018-11-05 01:18:10 -0300434
Ed Tanous432a8902021-06-14 15:28:56 -0700435 self_t& privileges(
436 const std::initializer_list<std::initializer_list<const char*>>& p)
Tanousf00032d2018-11-05 01:18:10 -0300437 {
Ed Tanous271584a2019-07-09 16:24:22 -0700438 self_t* self = static_cast<self_t*>(this);
Ed Tanous432a8902021-06-14 15:28:56 -0700439 for (const std::initializer_list<const char*>& privilege : p)
Tanousf00032d2018-11-05 01:18:10 -0300440 {
Ed Tanous271584a2019-07-09 16:24:22 -0700441 self->privilegesSet.emplace_back(privilege);
Tanousf00032d2018-11-05 01:18:10 -0300442 }
Ed Tanous271584a2019-07-09 16:24:22 -0700443 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300444 }
Ed Tanoused398212021-06-09 17:05:54 -0700445
446 template <size_t N, typename... MethodArgs>
447 self_t& privileges(const std::array<redfish::Privileges, N>& p)
448 {
449 self_t* self = static_cast<self_t*>(this);
450 for (const redfish::Privileges& privilege : p)
451 {
452 self->privilegesSet.emplace_back(privilege);
453 }
454 return *self;
455 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700456};
457
Ed Tanous1abe55e2018-09-05 08:30:59 -0700458class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
459{
460 public:
Ed Tanousf23b7292020-10-15 09:41:17 -0700461 DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500462 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700463
Ed Tanous1abe55e2018-09-05 08:30:59 -0700464 void validate() override
465 {
466 if (!erasedHandler)
467 {
468 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
469 "no handler for url " + rule);
470 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700471 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700472
zhanghch058d1b46d2021-04-01 11:18:24 +0800473 void handle(const Request& req,
474 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700475 const RoutingParams& params) override
476 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800477 erasedHandler(req, asyncResp, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700478 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700479
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500480 template <typename Func>
481 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700482 {
483 using function_t = utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700484 erasedHandler =
Ed Tanous988403c2020-08-24 11:29:49 -0700485 wrap(std::move(f),
486 std::make_integer_sequence<unsigned, function_t::arity>{});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700487 }
488
489 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500490 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700491 // enable_if Arg1 != request
492
493 template <typename Func, unsigned... Indices>
zhanghch058d1b46d2021-04-01 11:18:24 +0800494 std::function<void(const Request&,
495 const std::shared_ptr<bmcweb::AsyncResp>&,
496 const RoutingParams&)>
Ed Tanous988403c2020-08-24 11:29:49 -0700497 wrap(Func f, std::integer_sequence<unsigned, Indices...>)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700498 {
Ed Tanous988403c2020-08-24 11:29:49 -0700499 using function_t = crow::utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700500
501 if (!black_magic::isParameterTagCompatible(
Ed Tanous988403c2020-08-24 11:29:49 -0700502 black_magic::getParameterTag(rule.c_str()),
503 black_magic::computeParameterTagFromArgsList<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700504 typename function_t::template arg<Indices>...>::value))
505 {
506 throw std::runtime_error("routeDynamic: Handler type is mismatched "
507 "with URL parameters: " +
508 rule);
509 }
510 auto ret = detail::routing_handler_call_helper::Wrapped<
511 Func, typename function_t::template arg<Indices>...>();
512 ret.template set<typename function_t::template arg<Indices>...>(
513 std::move(f));
514 return ret;
515 }
516
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500517 template <typename Func>
518 void operator()(std::string name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519 {
520 nameStr = std::move(name);
521 (*this).template operator()<Func>(std::forward(f));
522 }
523
524 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800525 std::function<void(const Request&,
526 const std::shared_ptr<bmcweb::AsyncResp>&,
527 const RoutingParams&)>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700528 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700529};
530
531template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500532class TaggedRule :
533 public BaseRule,
534 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700535{
536 public:
537 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700538
Ed Tanousf23b7292020-10-15 09:41:17 -0700539 TaggedRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500540 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700541
Ed Tanous1abe55e2018-09-05 08:30:59 -0700542 void validate() override
543 {
544 if (!handler)
545 {
546 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
547 "no handler for url " + rule);
548 }
549 }
550
551 template <typename Func>
552 typename std::enable_if<
553 black_magic::CallHelper<Func, black_magic::S<Args...>>::value,
554 void>::type
555 operator()(Func&& f)
556 {
557 static_assert(
558 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
559 black_magic::CallHelper<
560 Func, black_magic::S<crow::Request, Args...>>::value,
561 "Handler type is mismatched with URL parameters");
562 static_assert(
563 !std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
564 "Handler function cannot have void return type; valid return "
565 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500566 "string, int, crow::response, nlohmann::json");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700567
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800568 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800569 const Request&,
570 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
571 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700572 }
573
574 template <typename Func>
575 typename std::enable_if<
576 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
Ed Tanous7045c8d2017-04-03 10:04:37 -0700577 black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700578 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700579 void>::type
580 operator()(Func&& f)
581 {
582 static_assert(
583 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
584 black_magic::CallHelper<
585 Func, black_magic::S<crow::Request, Args...>>::value,
586 "Handler type is mismatched with URL parameters");
587 static_assert(
588 !std::is_same<void, decltype(f(std::declval<crow::Request>(),
589 std::declval<Args>()...))>::value,
590 "Handler function cannot have void return type; valid return "
591 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500592 "string, int, crow::response,nlohmann::json");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700593
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800594 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800595 const crow::Request& req,
596 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
597 Args... args) { asyncResp->res.result(f(req, args...)); };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700598 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700599
Ed Tanous1abe55e2018-09-05 08:30:59 -0700600 template <typename Func>
601 typename std::enable_if<
602 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
603 !black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700604 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700605 void>::type
606 operator()(Func&& f)
607 {
608 static_assert(
609 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
610 black_magic::CallHelper<
611 Func, black_magic::S<crow::Request, Args...>>::value ||
612 black_magic::CallHelper<
zhanghch058d1b46d2021-04-01 11:18:24 +0800613 Func, black_magic::S<crow::Request,
614 std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700615 Args...>>::value,
616 "Handler type is mismatched with URL parameters");
617 static_assert(
zhanghch058d1b46d2021-04-01 11:18:24 +0800618 std::is_same<
619 void,
620 decltype(f(std::declval<crow::Request>(),
621 std::declval<std::shared_ptr<bmcweb::AsyncResp>&>(),
622 std::declval<Args>()...))>::value,
Tanousf00032d2018-11-05 01:18:10 -0300623 "Handler function with response argument should have void "
624 "return "
Ed Tanous1abe55e2018-09-05 08:30:59 -0700625 "type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700626
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800627 handler = std::forward<Func>(f);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700629
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500630 template <typename Func>
Ed Tanousf23b7292020-10-15 09:41:17 -0700631 void operator()(const std::string_view name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700632 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700633 nameStr = name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700634 (*this).template operator()<Func>(std::forward(f));
635 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700636
zhanghch058d1b46d2021-04-01 11:18:24 +0800637 void handle(const Request& req,
638 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700639 const RoutingParams& params) override
640 {
641 detail::routing_handler_call_helper::Call<
642 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
643 0, 0, 0, 0, black_magic::S<Args...>, black_magic::S<>>()(
644 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800645 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700646 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700647
Ed Tanous1abe55e2018-09-05 08:30:59 -0700648 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800649 std::function<void(const crow::Request&,
650 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>
651 handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700652};
653
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700654const int ruleSpecialRedirectSlash = 1;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700655
Ed Tanous1abe55e2018-09-05 08:30:59 -0700656class Trie
657{
658 public:
659 struct Node
660 {
661 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700662 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
663 paramChildrens{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700664 boost::container::flat_map<std::string, unsigned> children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700665
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 bool isSimpleNode() const
667 {
668 return !ruleIndex && std::all_of(std::begin(paramChildrens),
669 std::end(paramChildrens),
Ed Tanous271584a2019-07-09 16:24:22 -0700670 [](size_t x) { return !x; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700671 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700672 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700673
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 Trie() : nodes(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500675 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700676
677 private:
678 void optimizeNode(Node* node)
679 {
Ed Tanous271584a2019-07-09 16:24:22 -0700680 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700681 {
682 if (!x)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700683 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700684 continue;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700685 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700686 Node* child = &nodes[x];
687 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700688 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700689 if (node->children.empty())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700690 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700691 return;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700692 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700693 bool mergeWithChild = true;
Tanousf00032d2018-11-05 01:18:10 -0300694 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700695 {
696 Node* child = &nodes[kv.second];
697 if (!child->isSimpleNode())
698 {
699 mergeWithChild = false;
700 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700701 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700702 }
703 if (mergeWithChild)
704 {
705 decltype(node->children) merged;
Tanousf00032d2018-11-05 01:18:10 -0300706 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700707 {
708 Node* child = &nodes[kv.second];
Tanousf00032d2018-11-05 01:18:10 -0300709 for (const std::pair<std::string, unsigned>& childKv :
710 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700711 {
712 merged[kv.first + childKv.first] = childKv.second;
713 }
714 }
715 node->children = std::move(merged);
716 optimizeNode(node);
717 }
718 else
719 {
Tanousf00032d2018-11-05 01:18:10 -0300720 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700721 {
722 Node* child = &nodes[kv.second];
723 optimizeNode(child);
724 }
725 }
726 }
727
728 void optimize()
729 {
730 optimizeNode(head());
731 }
732
733 public:
734 void validate()
735 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700736 optimize();
737 }
738
Ed Tanous81ce6092020-12-17 16:54:55 +0000739 void findRouteIndexes(const std::string& reqUrl,
740 std::vector<unsigned>& routeIndexes,
Tanousf00032d2018-11-05 01:18:10 -0300741 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700742 {
743 if (node == nullptr)
744 {
745 node = head();
746 }
Tanousf00032d2018-11-05 01:18:10 -0300747 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700748 {
749 const std::string& fragment = kv.first;
750 const Node* child = &nodes[kv.second];
Ed Tanous81ce6092020-12-17 16:54:55 +0000751 if (pos >= reqUrl.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752 {
753 if (child->ruleIndex != 0 && fragment != "/")
754 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000755 routeIndexes.push_back(child->ruleIndex);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000757 findRouteIndexes(reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700758 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700759 }
760 else
761 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000762 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700763 {
Ed Tanous271584a2019-07-09 16:24:22 -0700764 findRouteIndexes(
Ed Tanous81ce6092020-12-17 16:54:55 +0000765 reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700766 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700767 }
768 }
769 }
770 }
771
772 std::pair<unsigned, RoutingParams>
Ed Tanous81ce6092020-12-17 16:54:55 +0000773 find(const std::string_view reqUrl, const Node* node = nullptr,
Ed Tanous271584a2019-07-09 16:24:22 -0700774 size_t pos = 0, RoutingParams* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700775 {
776 RoutingParams empty;
777 if (params == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700778 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700779 params = &empty;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700780 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700781
782 unsigned found{};
783 RoutingParams matchParams;
784
785 if (node == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700786 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 node = head();
Ed Tanous3174e4d2020-10-07 11:41:22 -0700788 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000789 if (pos == reqUrl.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700790 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791 return {node->ruleIndex, *params};
Ed Tanous3174e4d2020-10-07 11:41:22 -0700792 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700793
794 auto updateFound =
795 [&found, &matchParams](std::pair<unsigned, RoutingParams>& ret) {
796 if (ret.first && (!found || found > ret.first))
797 {
798 found = ret.first;
799 matchParams = std::move(ret.second);
800 }
801 };
802
Ed Tanous271584a2019-07-09 16:24:22 -0700803 if (node->paramChildrens[static_cast<size_t>(ParamType::INT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700804 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000805 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700806 if ((c >= '0' && c <= '9') || c == '+' || c == '-')
807 {
Ed Tanous543f4402022-01-06 13:12:53 -0800808 char* eptr = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700809 errno = 0;
810 long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000811 std::strtoll(reqUrl.data() + pos, &eptr, 10);
812 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700813 {
814 params->intParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000815 std::pair<unsigned, RoutingParams> ret =
816 find(reqUrl,
817 &nodes[node->paramChildrens[static_cast<size_t>(
818 ParamType::INT)]],
819 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820 updateFound(ret);
821 params->intParams.pop_back();
822 }
823 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700824 }
825
Ed Tanous271584a2019-07-09 16:24:22 -0700826 if (node->paramChildrens[static_cast<size_t>(ParamType::UINT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000828 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700829 if ((c >= '0' && c <= '9') || c == '+')
830 {
Ed Tanous543f4402022-01-06 13:12:53 -0800831 char* eptr = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700832 errno = 0;
833 unsigned long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000834 std::strtoull(reqUrl.data() + pos, &eptr, 10);
835 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700836 {
837 params->uintParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000838 std::pair<unsigned, RoutingParams> ret =
839 find(reqUrl,
840 &nodes[node->paramChildrens[static_cast<size_t>(
841 ParamType::UINT)]],
842 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700843 updateFound(ret);
844 params->uintParams.pop_back();
845 }
846 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700847 }
848
Ed Tanous271584a2019-07-09 16:24:22 -0700849 if (node->paramChildrens[static_cast<size_t>(ParamType::DOUBLE)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700850 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000851 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700852 if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
853 {
Ed Tanous543f4402022-01-06 13:12:53 -0800854 char* eptr = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700855 errno = 0;
Ed Tanous81ce6092020-12-17 16:54:55 +0000856 double value = std::strtod(reqUrl.data() + pos, &eptr);
857 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700858 {
859 params->doubleParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000860 std::pair<unsigned, RoutingParams> ret =
861 find(reqUrl,
862 &nodes[node->paramChildrens[static_cast<size_t>(
863 ParamType::DOUBLE)]],
864 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700865 updateFound(ret);
866 params->doubleParams.pop_back();
867 }
868 }
869 }
870
Ed Tanous271584a2019-07-09 16:24:22 -0700871 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700872 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000873 size_t epos = pos;
Ed Tanous81ce6092020-12-17 16:54:55 +0000874 for (; epos < reqUrl.size(); epos++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700875 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000876 if (reqUrl[epos] == '/')
Ed Tanous3174e4d2020-10-07 11:41:22 -0700877 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700878 break;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700879 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700880 }
881
882 if (epos != pos)
883 {
884 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000885 reqUrl.substr(pos, epos - pos));
Tanousf00032d2018-11-05 01:18:10 -0300886 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000887 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700888 &nodes[node->paramChildrens[static_cast<size_t>(
889 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000890 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700891 updateFound(ret);
892 params->stringParams.pop_back();
893 }
894 }
895
Ed Tanous271584a2019-07-09 16:24:22 -0700896 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700897 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000898 size_t epos = reqUrl.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700899
900 if (epos != pos)
901 {
902 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000903 reqUrl.substr(pos, epos - pos));
Ed Tanous271584a2019-07-09 16:24:22 -0700904 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000905 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700906 &nodes[node->paramChildrens[static_cast<size_t>(
907 ParamType::PATH)]],
908 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700909 updateFound(ret);
910 params->stringParams.pop_back();
911 }
912 }
913
Tanousf00032d2018-11-05 01:18:10 -0300914 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700915 {
916 const std::string& fragment = kv.first;
917 const Node* child = &nodes[kv.second];
918
Ed Tanous81ce6092020-12-17 16:54:55 +0000919 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700920 {
Tanousf00032d2018-11-05 01:18:10 -0300921 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000922 find(reqUrl, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700923 updateFound(ret);
924 }
925 }
926
927 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700928 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700929
930 void add(const std::string& url, unsigned ruleIndex)
931 {
Ed Tanous271584a2019-07-09 16:24:22 -0700932 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700933
934 for (unsigned i = 0; i < url.size(); i++)
935 {
936 char c = url[i];
937 if (c == '<')
938 {
Tanousf00032d2018-11-05 01:18:10 -0300939 const static std::array<std::pair<ParamType, std::string>, 7>
940 paramTraits = {{
941 {ParamType::INT, "<int>"},
942 {ParamType::UINT, "<uint>"},
943 {ParamType::DOUBLE, "<float>"},
944 {ParamType::DOUBLE, "<double>"},
945 {ParamType::STRING, "<str>"},
946 {ParamType::STRING, "<string>"},
947 {ParamType::PATH, "<path>"},
948 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700949
Tanousf00032d2018-11-05 01:18:10 -0300950 for (const std::pair<ParamType, std::string>& x : paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700951 {
Tanousf00032d2018-11-05 01:18:10 -0300952 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700953 {
Ed Tanous271584a2019-07-09 16:24:22 -0700954 size_t index = static_cast<size_t>(x.first);
955 if (!nodes[idx].paramChildrens[index])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700956 {
Tanousf00032d2018-11-05 01:18:10 -0300957 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700958 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700959 }
Ed Tanous271584a2019-07-09 16:24:22 -0700960 idx = nodes[idx].paramChildrens[index];
961 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700962 break;
963 }
964 }
965
966 i--;
967 }
968 else
969 {
970 std::string piece(&c, 1);
971 if (!nodes[idx].children.count(piece))
972 {
Tanousf00032d2018-11-05 01:18:10 -0300973 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700974 nodes[idx].children.emplace(piece, newNodeIdx);
975 }
976 idx = nodes[idx].children[piece];
977 }
978 }
979 if (nodes[idx].ruleIndex)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700980 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700981 throw std::runtime_error("handler already exists for " + url);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700982 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700983 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700984 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700985
Ed Tanous1abe55e2018-09-05 08:30:59 -0700986 private:
Ed Tanous271584a2019-07-09 16:24:22 -0700987 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700988 {
Ed Tanous271584a2019-07-09 16:24:22 -0700989 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700990 {
991 if (n->paramChildrens[i])
992 {
993 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -0700994 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
995 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700996 {
997 case ParamType::INT:
998 BMCWEB_LOG_DEBUG << "<int>";
999 break;
1000 case ParamType::UINT:
1001 BMCWEB_LOG_DEBUG << "<uint>";
1002 break;
1003 case ParamType::DOUBLE:
1004 BMCWEB_LOG_DEBUG << "<float>";
1005 break;
1006 case ParamType::STRING:
1007 BMCWEB_LOG_DEBUG << "<str>";
1008 break;
1009 case ParamType::PATH:
1010 BMCWEB_LOG_DEBUG << "<path>";
1011 break;
Ed Tanous23a21a12020-07-25 04:45:05 +00001012 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -07001013 BMCWEB_LOG_DEBUG << "<ERROR>";
1014 break;
1015 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001016
Ed Tanous1abe55e2018-09-05 08:30:59 -07001017 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
1018 }
1019 }
Tanousf00032d2018-11-05 01:18:10 -03001020 for (const std::pair<std::string, unsigned>& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001021 {
1022 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -07001023 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -07001024 << kv.first;
1025 debugNodePrint(&nodes[kv.second], level + 1);
1026 }
1027 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001028
Ed Tanous1abe55e2018-09-05 08:30:59 -07001029 public:
1030 void debugPrint()
1031 {
Ed Tanous271584a2019-07-09 16:24:22 -07001032 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001033 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001034
Ed Tanous1abe55e2018-09-05 08:30:59 -07001035 private:
1036 const Node* head() const
1037 {
1038 return &nodes.front();
1039 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001040
Ed Tanous1abe55e2018-09-05 08:30:59 -07001041 Node* head()
1042 {
1043 return &nodes.front();
1044 }
1045
1046 unsigned newNode()
1047 {
1048 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -07001049 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001050 }
1051
1052 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001053};
1054
Ed Tanous1abe55e2018-09-05 08:30:59 -07001055class Router
1056{
1057 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -07001058 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001059
Ed Tanous1abe55e2018-09-05 08:30:59 -07001060 DynamicRule& newRuleDynamic(const std::string& rule)
1061 {
1062 std::unique_ptr<DynamicRule> ruleObject =
1063 std::make_unique<DynamicRule>(rule);
1064 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001065 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -07001066
Ed Tanous1abe55e2018-09-05 08:30:59 -07001067 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001068 }
1069
Ed Tanous1abe55e2018-09-05 08:30:59 -07001070 template <uint64_t N>
1071 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
1072 newRuleTagged(const std::string& rule)
1073 {
1074 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
1075 TaggedRule>;
1076 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
1077 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001078 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001079
1080 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001081 }
1082
Tanousf00032d2018-11-05 01:18:10 -03001083 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001084 {
Tanousf00032d2018-11-05 01:18:10 -03001085 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001086 {
Tanousf00032d2018-11-05 01:18:10 -03001087 return;
1088 }
Ed Tanous888880a2020-08-24 13:48:50 -07001089 for (size_t method = 0, methodBit = 1; method < maxHttpVerbCount;
Ed Tanous2c70f802020-09-28 14:29:23 -07001090 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -03001091 {
Ed Tanous2c70f802020-09-28 14:29:23 -07001092 if (ruleObject->methodsBitfield & methodBit)
Tanousf00032d2018-11-05 01:18:10 -03001093 {
1094 perMethods[method].rules.emplace_back(ruleObject);
1095 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -07001096 rule, static_cast<unsigned>(
1097 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -03001098 // directory case:
1099 // request to `/about' url matches `/about/' rule
1100 if (rule.size() > 2 && rule.back() == '/')
1101 {
1102 perMethods[method].trie.add(
1103 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -07001104 static_cast<unsigned>(perMethods[method].rules.size() -
1105 1));
Tanousf00032d2018-11-05 01:18:10 -03001106 }
1107 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001108 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001109 }
1110
Ed Tanous1abe55e2018-09-05 08:30:59 -07001111 void validate()
1112 {
Tanousf00032d2018-11-05 01:18:10 -03001113 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001114 {
1115 if (rule)
1116 {
Tanousf00032d2018-11-05 01:18:10 -03001117 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001118 if (upgraded)
Ed Tanous3174e4d2020-10-07 11:41:22 -07001119 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001120 rule = std::move(upgraded);
Ed Tanous3174e4d2020-10-07 11:41:22 -07001121 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001122 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -03001123 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001124 }
1125 }
Tanousf00032d2018-11-05 01:18:10 -03001126 for (PerMethod& perMethod : perMethods)
1127 {
1128 perMethod.trie.validate();
1129 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001130 }
1131
Ed Tanous1abe55e2018-09-05 08:30:59 -07001132 template <typename Adaptor>
1133 void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
1134 {
Ed Tanous271584a2019-07-09 16:24:22 -07001135 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001136 {
1137 res.result(boost::beast::http::status::not_found);
1138 res.end();
Tanousf00032d2018-11-05 01:18:10 -03001139 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001140 }
Tanousf00032d2018-11-05 01:18:10 -03001141
Ed Tanous271584a2019-07-09 16:24:22 -07001142 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001143 Trie& trie = perMethod.trie;
1144 std::vector<BaseRule*>& rules = perMethod.rules;
1145
1146 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001147 unsigned ruleIndex = found.first;
1148 if (!ruleIndex)
1149 {
1150 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001151 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001152 res.end();
1153 return;
1154 }
1155
1156 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001157 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001158 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001159 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001160
1161 if (ruleIndex == ruleSpecialRedirectSlash)
1162 {
1163 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1164 << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001165 res.result(boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001166
1167 // TODO absolute url building
1168 if (req.getHeaderValue("Host").empty())
1169 {
1170 res.addHeader("Location", std::string(req.url) + "/");
1171 }
1172 else
1173 {
1174 res.addHeader(
1175 "Location",
1176 req.isSecure
1177 ? "https://"
1178 : "http://" + std::string(req.getHeaderValue("Host")) +
1179 std::string(req.url) + "/");
1180 }
1181 res.end();
1182 return;
1183 }
1184
Ed Tanous271584a2019-07-09 16:24:22 -07001185 if ((rules[ruleIndex]->getMethods() &
1186 (1U << static_cast<size_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001187 {
1188 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1189 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001190 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001191 << rules[ruleIndex]->getMethods();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001192 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001193 res.end();
1194 return;
1195 }
1196
1197 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rules[ruleIndex]->rule
Ed Tanous271584a2019-07-09 16:24:22 -07001198 << "' " << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001199 << rules[ruleIndex]->getMethods();
1200
1201 // any uncaught exceptions become 500s
1202 try
1203 {
Ed Tanousf94c4ec2022-01-06 12:44:41 -08001204 rules[ruleIndex]->handleUpgrade(req, res,
1205 std::forward<Adaptor>(adaptor));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001206 }
Patrick Williamsc5967042021-10-06 12:39:54 -05001207 catch (const std::exception& e)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001208 {
1209 BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001210 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001211 res.end();
1212 return;
1213 }
1214 catch (...)
1215 {
1216 BMCWEB_LOG_ERROR
1217 << "An uncaught exception occurred. The type was unknown "
1218 "so no information was available.";
Ed Tanousde5c9f32019-03-26 09:17:55 -07001219 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001220 res.end();
1221 return;
1222 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001223 }
1224
zhanghch058d1b46d2021-04-01 11:18:24 +08001225 void handle(Request& req,
1226 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001227 {
Ed Tanous271584a2019-07-09 16:24:22 -07001228 if (static_cast<size_t>(req.method()) >= 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 Tanous271584a2019-07-09 16:24:22 -07001233 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001234 Trie& trie = perMethod.trie;
1235 std::vector<BaseRule*>& rules = perMethod.rules;
1236
1237 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001238
Ed Tanous1abe55e2018-09-05 08:30:59 -07001239 unsigned ruleIndex = found.first;
1240
1241 if (!ruleIndex)
1242 {
Ed Tanous2634dcd2019-03-26 09:28:06 -07001243 // Check to see if this url exists at any verb
1244 for (const PerMethod& p : perMethods)
1245 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001246 const std::pair<unsigned, RoutingParams>& found2 =
Ed Tanous2634dcd2019-03-26 09:28:06 -07001247 p.trie.find(req.url);
Ed Tanous23a21a12020-07-25 04:45:05 +00001248 if (found2.first > 0)
Ed Tanous2634dcd2019-03-26 09:28:06 -07001249 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001250 asyncResp->res.result(
1251 boost::beast::http::status::method_not_allowed);
Ed Tanous2634dcd2019-03-26 09:28:06 -07001252 return;
1253 }
1254 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001255 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
zhanghch058d1b46d2021-04-01 11:18:24 +08001256 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001257 return;
1258 }
1259
1260 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001261 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001262 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001263 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001264
1265 if (ruleIndex == ruleSpecialRedirectSlash)
1266 {
1267 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1268 << req.url;
zhanghch058d1b46d2021-04-01 11:18:24 +08001269 asyncResp->res.result(
1270 boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001271
1272 // TODO absolute url building
1273 if (req.getHeaderValue("Host").empty())
1274 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001275 asyncResp->res.addHeader("Location",
1276 std::string(req.url) + "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001277 }
1278 else
1279 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001280 asyncResp->res.addHeader(
1281 "Location", (req.isSecure ? "https://" : "http://") +
1282 std::string(req.getHeaderValue("Host")) +
1283 std::string(req.url) + "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001284 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001285 return;
1286 }
1287
Ed Tanous271584a2019-07-09 16:24:22 -07001288 if ((rules[ruleIndex]->getMethods() &
1289 (1U << static_cast<uint32_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001290 {
1291 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1292 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001293 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001294 << rules[ruleIndex]->getMethods();
zhanghch058d1b46d2021-04-01 11:18:24 +08001295 asyncResp->res.result(
1296 boost::beast::http::status::method_not_allowed);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001297 return;
1298 }
1299
1300 BMCWEB_LOG_DEBUG << "Matched rule '" << rules[ruleIndex]->rule << "' "
Ed Tanous271584a2019-07-09 16:24:22 -07001301 << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001302 << rules[ruleIndex]->getMethods();
1303
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001304 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001305 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001306 rules[ruleIndex]->handle(req, asyncResp, found.second);
James Feist7166bf02019-12-10 16:52:14 +00001307 return;
1308 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001309
1310 crow::connections::systemBus->async_method_call(
Ed Tanous168e20c2021-12-13 14:39:53 -08001311 [&req, asyncResp, &rules, ruleIndex,
1312 found](const boost::system::error_code ec,
1313 const std::map<std::string, dbus::utility::DbusVariantType>&
1314 userInfo) {
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001315 if (ec)
1316 {
1317 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
zhanghch058d1b46d2021-04-01 11:18:24 +08001318 asyncResp->res.result(
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001319 boost::beast::http::status::internal_server_error);
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001320 return;
1321 }
1322
1323 const std::string* userRolePtr = nullptr;
1324 auto userInfoIter = userInfo.find("UserPrivilege");
1325 if (userInfoIter != userInfo.end())
1326 {
1327 userRolePtr =
1328 std::get_if<std::string>(&userInfoIter->second);
1329 }
1330
1331 std::string userRole{};
1332 if (userRolePtr != nullptr)
1333 {
1334 userRole = *userRolePtr;
1335 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1336 << " userRole = " << *userRolePtr;
1337 }
1338
Ed Tanous5dc924d2021-12-20 09:17:28 -08001339 const bool* remoteUserPtr = nullptr;
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001340 auto remoteUserIter = userInfo.find("RemoteUser");
1341 if (remoteUserIter != userInfo.end())
1342 {
1343 remoteUserPtr = std::get_if<bool>(&remoteUserIter->second);
1344 }
1345 if (remoteUserPtr == nullptr)
1346 {
1347 BMCWEB_LOG_ERROR
1348 << "RemoteUser property missing or wrong type";
zhanghch058d1b46d2021-04-01 11:18:24 +08001349 asyncResp->res.result(
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001350 boost::beast::http::status::internal_server_error);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001351 return;
1352 }
1353 bool remoteUser = *remoteUserPtr;
1354
1355 bool passwordExpired = false; // default for remote user
1356 if (!remoteUser)
1357 {
Ed Tanous5dc924d2021-12-20 09:17:28 -08001358 const bool* passwordExpiredPtr = nullptr;
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001359 auto passwordExpiredIter =
1360 userInfo.find("UserPasswordExpired");
1361 if (passwordExpiredIter != userInfo.end())
1362 {
1363 passwordExpiredPtr =
1364 std::get_if<bool>(&passwordExpiredIter->second);
1365 }
1366 if (passwordExpiredPtr != nullptr)
1367 {
1368 passwordExpired = *passwordExpiredPtr;
1369 }
1370 else
1371 {
1372 BMCWEB_LOG_ERROR
1373 << "UserPasswordExpired property is expected for"
1374 " local user but is missing or wrong type";
zhanghch058d1b46d2021-04-01 11:18:24 +08001375 asyncResp->res.result(
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001376 boost::beast::http::status::internal_server_error);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001377 return;
1378 }
1379 }
1380
Ed Tanous23a21a12020-07-25 04:45:05 +00001381 // Get the userprivileges from the role
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001382 redfish::Privileges userPrivileges =
1383 redfish::getUserPrivileges(userRole);
1384
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001385 // Set isConfigureSelfOnly based on D-Bus results. This
1386 // ignores the results from both pamAuthenticateUser and the
1387 // value from any previous use of this session.
1388 req.session->isConfigureSelfOnly = passwordExpired;
1389
Ed Tanous23a21a12020-07-25 04:45:05 +00001390 // Modifyprivileges if isConfigureSelfOnly.
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001391 if (req.session->isConfigureSelfOnly)
1392 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001393 // Remove allprivileges except ConfigureSelf
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001394 userPrivileges = userPrivileges.intersection(
1395 redfish::Privileges{"ConfigureSelf"});
1396 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1397 }
1398
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001399 if (!rules[ruleIndex]->checkPrivileges(userPrivileges))
1400 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001401 asyncResp->res.result(
1402 boost::beast::http::status::forbidden);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001403 if (req.session->isConfigureSelfOnly)
1404 {
1405 redfish::messages::passwordChangeRequired(
zhanghch058d1b46d2021-04-01 11:18:24 +08001406 asyncResp->res,
1407 "/redfish/v1/AccountService/Accounts/" +
1408 req.session->username);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001409 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001410 return;
1411 }
1412
1413 req.userRole = userRole;
zhanghch058d1b46d2021-04-01 11:18:24 +08001414 rules[ruleIndex]->handle(req, asyncResp, found.second);
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001415 },
1416 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1417 "xyz.openbmc_project.User.Manager", "GetUserInfo",
1418 req.session->username);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001419 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001420
Ed Tanous1abe55e2018-09-05 08:30:59 -07001421 void debugPrint()
1422 {
Ed Tanous271584a2019-07-09 16:24:22 -07001423 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001424 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001425 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1426 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001427 perMethods[i].trie.debugPrint();
1428 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001429 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001430
Ed Tanous1abe55e2018-09-05 08:30:59 -07001431 std::vector<const std::string*> getRoutes(const std::string& parent)
1432 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001433 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001434
1435 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001436 {
Tanousf00032d2018-11-05 01:18:10 -03001437 std::vector<unsigned> x;
1438 pm.trie.findRouteIndexes(parent, x);
1439 for (unsigned index : x)
1440 {
1441 ret.push_back(&pm.rules[index]->rule);
1442 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001443 }
1444 return ret;
1445 }
1446
1447 private:
Tanousf00032d2018-11-05 01:18:10 -03001448 struct PerMethod
1449 {
1450 std::vector<BaseRule*> rules;
1451 Trie trie;
1452 // rule index 0, 1 has special meaning; preallocate it to avoid
1453 // duplication.
1454 PerMethod() : rules(2)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001455 {}
Tanousf00032d2018-11-05 01:18:10 -03001456 };
Ed Tanous888880a2020-08-24 13:48:50 -07001457
1458 const static size_t maxHttpVerbCount =
Ed Tanouscc090442020-10-07 08:20:50 -07001459 static_cast<size_t>(boost::beast::http::verb::unlink);
Ed Tanous888880a2020-08-24 13:48:50 -07001460
Tanousf00032d2018-11-05 01:18:10 -03001461 std::array<PerMethod, maxHttpVerbCount> perMethods;
1462 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001463};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001464} // namespace crow