blob: b49e15ea146050c4d2435b5f913a8f8283df582c [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
2
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003#include "common.h"
4#include "http_request.h"
5#include "http_response.h"
6#include "logging.h"
7#include "utility.h"
8#include "websocket.h"
9
Joseph Reynolds3bf4e632020-02-06 14:44:32 -060010#include "error_messages.hpp"
Tanousf00032d2018-11-05 01:18:10 -030011#include "privileges.hpp"
Ratan Gupta6f359562019-04-03 10:39:08 +053012#include "sessions.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>
16#include <boost/container/small_vector.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070017#include <boost/lexical_cast.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050018
Ed Tanouse0d918b2018-03-27 17:41:04 -070019#include <cerrno>
Ed Tanous7045c8d2017-04-03 10:04:37 -070020#include <cstdint>
Ed Tanouse0d918b2018-03-27 17:41:04 -070021#include <cstdlib>
Ed Tanous3dac7492017-08-02 13:46:20 -070022#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070023#include <memory>
24#include <tuple>
Ed Tanous7045c8d2017-04-03 10:04:37 -070025#include <utility>
26#include <vector>
Ed Tanous9140a672017-04-24 17:01:32 -070027
Ed Tanous1abe55e2018-09-05 08:30:59 -070028namespace crow
29{
Tanousf00032d2018-11-05 01:18:10 -030030
Ed Tanous1abe55e2018-09-05 08:30:59 -070031class BaseRule
32{
33 public:
Tanousf00032d2018-11-05 01:18:10 -030034 BaseRule(std::string thisRule) : rule(std::move(thisRule))
Gunnar Mills1214b7e2020-06-04 10:11:30 -050035 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070036
Ed Tanous0c0084a2019-10-24 15:57:51 -070037 virtual ~BaseRule() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -070038
Ed Tanous1abe55e2018-09-05 08:30:59 -070039 virtual void validate() = 0;
40 std::unique_ptr<BaseRule> upgrade()
41 {
42 if (ruleToUpgrade)
43 return std::move(ruleToUpgrade);
44 return {};
45 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070046
Ed Tanous1abe55e2018-09-05 08:30:59 -070047 virtual void handle(const Request&, Response&, const RoutingParams&) = 0;
Ed Tanousceac6f72018-12-02 11:58:47 -080048 virtual void handleUpgrade(const Request&, Response& res,
49 boost::asio::ip::tcp::socket&&)
Ed Tanous1abe55e2018-09-05 08:30:59 -070050 {
Ed Tanousde5c9f32019-03-26 09:17:55 -070051 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070052 res.end();
53 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -070054#ifdef BMCWEB_ENABLE_SSL
Ed Tanousceac6f72018-12-02 11:58:47 -080055 virtual void
56 handleUpgrade(const Request&, Response& res,
57 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&)
Ed Tanous1abe55e2018-09-05 08:30:59 -070058 {
Ed Tanousde5c9f32019-03-26 09:17:55 -070059 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070060 res.end();
61 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070062#endif
63
Ed Tanous271584a2019-07-09 16:24:22 -070064 size_t getMethods()
Ed Tanous1abe55e2018-09-05 08:30:59 -070065 {
66 return methodsBitfield;
67 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070068
Tanousf00032d2018-11-05 01:18:10 -030069 bool checkPrivileges(const redfish::Privileges& userPrivileges)
70 {
71 // If there are no privileges assigned, assume no privileges
72 // required
73 if (privilegesSet.empty())
74 {
75 return true;
76 }
77
78 for (const redfish::Privileges& requiredPrivileges : privilegesSet)
79 {
80 if (userPrivileges.isSupersetOf(requiredPrivileges))
81 {
82 return true;
83 }
84 }
85 return false;
86 }
87
Ed Tanous271584a2019-07-09 16:24:22 -070088 size_t methodsBitfield{
89 1 << static_cast<size_t>(boost::beast::http::verb::get)};
Ed Tanous7045c8d2017-04-03 10:04:37 -070090
Tanousf00032d2018-11-05 01:18:10 -030091 std::vector<redfish::Privileges> privilegesSet;
92
Ed Tanous1abe55e2018-09-05 08:30:59 -070093 std::string rule;
94 std::string nameStr;
Ed Tanous7045c8d2017-04-03 10:04:37 -070095
Ed Tanous1abe55e2018-09-05 08:30:59 -070096 std::unique_ptr<BaseRule> ruleToUpgrade;
Ed Tanous7045c8d2017-04-03 10:04:37 -070097
Ed Tanous1abe55e2018-09-05 08:30:59 -070098 friend class Router;
Gunnar Mills1214b7e2020-06-04 10:11:30 -050099 template <typename T>
100 friend struct RuleParameterTraits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700101};
102
Ed Tanous1abe55e2018-09-05 08:30:59 -0700103namespace detail
104{
105namespace routing_handler_call_helper
106{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500107template <typename T, int Pos>
108struct CallPair
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109{
110 using type = T;
111 static const int pos = Pos;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700112};
113
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500114template <typename H1>
115struct CallParams
Ed Tanous1abe55e2018-09-05 08:30:59 -0700116{
117 H1& handler;
118 const RoutingParams& params;
119 const Request& req;
120 Response& res;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700121};
122
123template <typename F, int NInt, int NUint, int NDouble, int NString,
124 typename S1, typename S2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700125struct Call
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500126{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700127
128template <typename F, int NInt, int NUint, int NDouble, int NString,
129 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700130struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<int64_t, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700131 black_magic::S<Args2...>>
132{
133 void operator()(F cparams)
134 {
135 using pushed = typename black_magic::S<Args2...>::template push_back<
136 CallPair<int64_t, NInt>>;
137 Call<F, NInt + 1, NUint, NDouble, NString, black_magic::S<Args1...>,
138 pushed>()(cparams);
139 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700140};
141
142template <typename F, int NInt, int NUint, int NDouble, int NString,
143 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700144struct Call<F, NInt, NUint, NDouble, NString,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700145 black_magic::S<uint64_t, Args1...>, black_magic::S<Args2...>>
146{
147 void operator()(F cparams)
148 {
149 using pushed = typename black_magic::S<Args2...>::template push_back<
150 CallPair<uint64_t, NUint>>;
151 Call<F, NInt, NUint + 1, NDouble, NString, black_magic::S<Args1...>,
152 pushed>()(cparams);
153 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700154};
155
156template <typename F, int NInt, int NUint, int NDouble, int NString,
157 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700158struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<double, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700159 black_magic::S<Args2...>>
160{
161 void operator()(F cparams)
162 {
163 using pushed = typename black_magic::S<Args2...>::template push_back<
164 CallPair<double, NDouble>>;
165 Call<F, NInt, NUint, NDouble + 1, NString, black_magic::S<Args1...>,
166 pushed>()(cparams);
167 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700168};
169
170template <typename F, int NInt, int NUint, int NDouble, int NString,
171 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700172struct Call<F, NInt, NUint, NDouble, NString,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700173 black_magic::S<std::string, Args1...>, black_magic::S<Args2...>>
174{
175 void operator()(F cparams)
176 {
177 using pushed = typename black_magic::S<Args2...>::template push_back<
178 CallPair<std::string, NString>>;
179 Call<F, NInt, NUint, NDouble, NString + 1, black_magic::S<Args1...>,
180 pushed>()(cparams);
181 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700182};
183
184template <typename F, int NInt, int NUint, int NDouble, int NString,
185 typename... Args1>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700186struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700187 black_magic::S<Args1...>>
188{
189 void operator()(F cparams)
190 {
191 cparams.handler(
192 cparams.req, cparams.res,
193 cparams.params.template get<typename Args1::type>(Args1::pos)...);
194 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700195};
196
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500197template <typename Func, typename... ArgsWrapped>
198struct Wrapped
Ed Tanous1abe55e2018-09-05 08:30:59 -0700199{
200 template <typename... Args>
201 void set(
202 Func f,
203 typename std::enable_if<
204 !std::is_same<
205 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
206 const Request&>::value,
207 int>::type = 0)
208 {
Tanousf00032d2018-11-05 01:18:10 -0300209 handler = [f = std::move(f)](const Request&, Response& res,
210 Args... args) {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700211 res.result(f(args...));
Tanousf00032d2018-11-05 01:18:10 -0300212 res.end();
213 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700214 }
215
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500216 template <typename Req, typename... Args>
217 struct ReqHandlerWrapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700218 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000219 ReqHandlerWrapper(Func fIn) : f(std::move(fIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500220 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700221
Ed Tanous1abe55e2018-09-05 08:30:59 -0700222 void operator()(const Request& req, Response& res, Args... args)
223 {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700224 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700225 res.end();
226 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700227
Ed Tanous1abe55e2018-09-05 08:30:59 -0700228 Func f;
229 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700230
Ed Tanous1abe55e2018-09-05 08:30:59 -0700231 template <typename... Args>
232 void set(
233 Func f,
234 typename std::enable_if<
235 std::is_same<
236 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
237 const Request&>::value &&
238 !std::is_same<typename std::tuple_element<
239 1, std::tuple<Args..., void, void>>::type,
240 Response&>::value,
241 int>::type = 0)
242 {
243 handler = ReqHandlerWrapper<Args...>(std::move(f));
244 /*handler = (
245 [f = std::move(f)]
246 (const Request& req, Response& res, Args... args){
Ed Tanousde5c9f32019-03-26 09:17:55 -0700247 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700248 res.end();
249 });*/
250 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700251
Ed Tanous1abe55e2018-09-05 08:30:59 -0700252 template <typename... Args>
253 void set(
254 Func f,
255 typename std::enable_if<
256 std::is_same<
257 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
258 const Request&>::value &&
259 std::is_same<typename std::tuple_element<
260 1, std::tuple<Args..., void, void>>::type,
261 Response&>::value,
262 int>::type = 0)
263 {
264 handler = std::move(f);
265 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700266
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500267 template <typename... Args>
268 struct HandlerTypeHelper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700269 {
270 using type =
271 std::function<void(const crow::Request&, crow::Response&, Args...)>;
272 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700273 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700274 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700275
Ed Tanous1abe55e2018-09-05 08:30:59 -0700276 template <typename... Args>
277 struct HandlerTypeHelper<const Request&, Args...>
278 {
279 using type =
280 std::function<void(const crow::Request&, crow::Response&, Args...)>;
281 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700282 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700283 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700284
Ed Tanous1abe55e2018-09-05 08:30:59 -0700285 template <typename... Args>
286 struct HandlerTypeHelper<const Request&, Response&, Args...>
287 {
288 using type =
289 std::function<void(const crow::Request&, crow::Response&, Args...)>;
290 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700291 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700292 };
293
294 typename HandlerTypeHelper<ArgsWrapped...>::type handler;
295
296 void operator()(const Request& req, Response& res,
297 const RoutingParams& params)
298 {
299 detail::routing_handler_call_helper::Call<
300 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
301 0, 0, 0, 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
302 black_magic::S<>>()(
303 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
304 handler, params, req, res});
305 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700306};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700307} // namespace routing_handler_call_helper
308} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700309
Ed Tanous1abe55e2018-09-05 08:30:59 -0700310class WebSocketRule : public BaseRule
311{
312 using self_t = WebSocketRule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700313
Ed Tanous1abe55e2018-09-05 08:30:59 -0700314 public:
Ed Tanous23a21a12020-07-25 04:45:05 +0000315 WebSocketRule(std::string ruleIn) : BaseRule(std::move(ruleIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500316 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700317
Ed Tanous1abe55e2018-09-05 08:30:59 -0700318 void validate() override
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500319 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700320
Ed Tanous1abe55e2018-09-05 08:30:59 -0700321 void handle(const Request&, Response& res, const RoutingParams&) override
322 {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700323 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700324 res.end();
325 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700326
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000327 void handleUpgrade(const Request& req, Response&,
Ed Tanousceac6f72018-12-02 11:58:47 -0800328 boost::asio::ip::tcp::socket&& adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700329 {
Ratan Gupta02453b12019-10-22 14:43:36 +0530330 std::shared_ptr<
331 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>
332 myConnection = std::make_shared<
333 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000334 req, std::move(adaptor), openHandler, messageHandler,
Ratan Gupta02453b12019-10-22 14:43:36 +0530335 closeHandler, errorHandler);
336 myConnection->start();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700337 }
338#ifdef BMCWEB_ENABLE_SSL
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000339 void handleUpgrade(const Request& req, Response&,
Ed Tanousceac6f72018-12-02 11:58:47 -0800340 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
341 adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700342 {
Ed Tanousceac6f72018-12-02 11:58:47 -0800343 std::shared_ptr<crow::websocket::ConnectionImpl<
344 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
345 myConnection = std::make_shared<crow::websocket::ConnectionImpl<
346 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000347 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanousceac6f72018-12-02 11:58:47 -0800348 closeHandler, errorHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700349 myConnection->start();
350 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700351#endif
352
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500353 template <typename Func>
354 self_t& onopen(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700355 {
356 openHandler = f;
357 return *this;
358 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700359
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500360 template <typename Func>
361 self_t& onmessage(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700362 {
363 messageHandler = f;
364 return *this;
365 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700366
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500367 template <typename Func>
368 self_t& onclose(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700369 {
370 closeHandler = f;
371 return *this;
372 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700373
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500374 template <typename Func>
375 self_t& onerror(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700376 {
377 errorHandler = f;
378 return *this;
379 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700380
Ed Tanous1abe55e2018-09-05 08:30:59 -0700381 protected:
Iwona Klimaszewskac0a1c8a2019-07-12 18:26:38 +0200382 std::function<void(crow::websocket::Connection&,
383 std::shared_ptr<bmcweb::AsyncResp>)>
384 openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700385 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
386 messageHandler;
387 std::function<void(crow::websocket::Connection&, const std::string&)>
388 closeHandler;
389 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700390};
391
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500392template <typename T>
393struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700394{
395 using self_t = T;
396 WebSocketRule& websocket()
397 {
Ed Tanous271584a2019-07-09 16:24:22 -0700398 self_t* self = static_cast<self_t*>(this);
399 WebSocketRule* p = new WebSocketRule(self->rule);
400 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700401 return *p;
402 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700403
Ed Tanous1abe55e2018-09-05 08:30:59 -0700404 self_t& name(std::string name) noexcept
405 {
Ed Tanous271584a2019-07-09 16:24:22 -0700406 self_t* self = static_cast<self_t*>(this);
407 self->nameStr = std::move(name);
408 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700409 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700410
Ed Tanous1abe55e2018-09-05 08:30:59 -0700411 self_t& methods(boost::beast::http::verb method)
412 {
Ed Tanous271584a2019-07-09 16:24:22 -0700413 self_t* self = static_cast<self_t*>(this);
414 self->methodsBitfield = 1U << static_cast<size_t>(method);
415 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700416 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700417
Ed Tanous1abe55e2018-09-05 08:30:59 -0700418 template <typename... MethodArgs>
419 self_t& methods(boost::beast::http::verb method, MethodArgs... args_method)
420 {
Ed Tanous271584a2019-07-09 16:24:22 -0700421 self_t* self = static_cast<self_t*>(this);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700422 methods(args_method...);
Ed Tanous271584a2019-07-09 16:24:22 -0700423 self->methodsBitfield |= 1U << static_cast<size_t>(method);
424 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700425 }
Tanousf00032d2018-11-05 01:18:10 -0300426
427 template <typename... MethodArgs>
Ed Tanous23a21a12020-07-25 04:45:05 +0000428 self_t& privileges(std::initializer_list<const char*> l)
Tanousf00032d2018-11-05 01:18:10 -0300429 {
Ed Tanous271584a2019-07-09 16:24:22 -0700430 self_t* self = static_cast<self_t*>(this);
431 self->privilegesSet.emplace_back(l);
432 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300433 }
434
435 template <typename... MethodArgs>
Ed Tanous23a21a12020-07-25 04:45:05 +0000436 self_t& privileges(const std::vector<redfish::Privileges>& p)
Tanousf00032d2018-11-05 01:18:10 -0300437 {
Ed Tanous271584a2019-07-09 16:24:22 -0700438 self_t* self = static_cast<self_t*>(this);
Tanousf00032d2018-11-05 01:18:10 -0300439 for (const redfish::Privileges& privilege : p)
440 {
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 Tanous7045c8d2017-04-03 10:04:37 -0700445};
446
Ed Tanous1abe55e2018-09-05 08:30:59 -0700447class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
448{
449 public:
Ed Tanous23a21a12020-07-25 04:45:05 +0000450 DynamicRule(std::string ruleIn) : BaseRule(std::move(ruleIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500451 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700452
Ed Tanous1abe55e2018-09-05 08:30:59 -0700453 void validate() override
454 {
455 if (!erasedHandler)
456 {
457 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
458 "no handler for url " + rule);
459 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700460 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700461
Ed Tanous1abe55e2018-09-05 08:30:59 -0700462 void handle(const Request& req, Response& res,
463 const RoutingParams& params) override
464 {
465 erasedHandler(req, res, params);
466 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700467
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500468 template <typename Func>
469 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700470 {
471 using function_t = utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700472 erasedHandler =
Ed Tanous988403c2020-08-24 11:29:49 -0700473 wrap(std::move(f),
474 std::make_integer_sequence<unsigned, function_t::arity>{});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700475 }
476
477 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500478 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479 // enable_if Arg1 != request
480
481 template <typename Func, unsigned... Indices>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700482 std::function<void(const Request&, Response&, const RoutingParams&)>
Ed Tanous988403c2020-08-24 11:29:49 -0700483 wrap(Func f, std::integer_sequence<unsigned, Indices...>)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700484 {
Ed Tanous988403c2020-08-24 11:29:49 -0700485 using function_t = crow::utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700486
487 if (!black_magic::isParameterTagCompatible(
Ed Tanous988403c2020-08-24 11:29:49 -0700488 black_magic::getParameterTag(rule.c_str()),
489 black_magic::computeParameterTagFromArgsList<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700490 typename function_t::template arg<Indices>...>::value))
491 {
492 throw std::runtime_error("routeDynamic: Handler type is mismatched "
493 "with URL parameters: " +
494 rule);
495 }
496 auto ret = detail::routing_handler_call_helper::Wrapped<
497 Func, typename function_t::template arg<Indices>...>();
498 ret.template set<typename function_t::template arg<Indices>...>(
499 std::move(f));
500 return ret;
501 }
502
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500503 template <typename Func>
504 void operator()(std::string name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700505 {
506 nameStr = std::move(name);
507 (*this).template operator()<Func>(std::forward(f));
508 }
509
510 private:
511 std::function<void(const Request&, Response&, const RoutingParams&)>
512 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700513};
514
515template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500516class TaggedRule :
517 public BaseRule,
518 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519{
520 public:
521 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700522
Ed Tanous271584a2019-07-09 16:24:22 -0700523 TaggedRule(std::string ruleIn) : BaseRule(std::move(ruleIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500524 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700525
Ed Tanous1abe55e2018-09-05 08:30:59 -0700526 void validate() override
527 {
528 if (!handler)
529 {
530 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
531 "no handler for url " + rule);
532 }
533 }
534
535 template <typename Func>
536 typename std::enable_if<
537 black_magic::CallHelper<Func, black_magic::S<Args...>>::value,
538 void>::type
539 operator()(Func&& f)
540 {
541 static_assert(
542 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
543 black_magic::CallHelper<
544 Func, black_magic::S<crow::Request, Args...>>::value,
545 "Handler type is mismatched with URL parameters");
546 static_assert(
547 !std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
548 "Handler function cannot have void return type; valid return "
549 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500550 "string, int, crow::response, nlohmann::json");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700551
552 handler = [f = std::move(f)](const Request&, Response& res,
553 Args... args) {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700554 res.result(f(args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700555 res.end();
556 };
557 }
558
559 template <typename Func>
560 typename std::enable_if<
561 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
Ed Tanous7045c8d2017-04-03 10:04:37 -0700562 black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700563 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700564 void>::type
565 operator()(Func&& f)
566 {
567 static_assert(
568 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
569 black_magic::CallHelper<
570 Func, black_magic::S<crow::Request, Args...>>::value,
571 "Handler type is mismatched with URL parameters");
572 static_assert(
573 !std::is_same<void, decltype(f(std::declval<crow::Request>(),
574 std::declval<Args>()...))>::value,
575 "Handler function cannot have void return type; valid return "
576 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500577 "string, int, crow::response,nlohmann::json");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700578
Ed Tanous1abe55e2018-09-05 08:30:59 -0700579 handler = [f = std::move(f)](const crow::Request& req,
580 crow::Response& res, Args... args) {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700581 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700582 res.end();
583 };
584 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700585
Ed Tanous1abe55e2018-09-05 08:30:59 -0700586 template <typename Func>
587 typename std::enable_if<
588 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
589 !black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700590 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700591 void>::type
592 operator()(Func&& f)
593 {
594 static_assert(
595 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
596 black_magic::CallHelper<
597 Func, black_magic::S<crow::Request, Args...>>::value ||
598 black_magic::CallHelper<
599 Func, black_magic::S<crow::Request, crow::Response&,
600 Args...>>::value,
601 "Handler type is mismatched with URL parameters");
602 static_assert(
603 std::is_same<void, decltype(f(std::declval<crow::Request>(),
604 std::declval<crow::Response&>(),
605 std::declval<Args>()...))>::value,
Tanousf00032d2018-11-05 01:18:10 -0300606 "Handler function with response argument should have void "
607 "return "
Ed Tanous1abe55e2018-09-05 08:30:59 -0700608 "type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700609
Ed Tanous1abe55e2018-09-05 08:30:59 -0700610 handler = std::move(f);
611 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700612
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500613 template <typename Func>
614 void operator()(std::string name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700615 {
616 nameStr = std::move(name);
617 (*this).template operator()<Func>(std::forward(f));
618 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700619
Ed Tanous1abe55e2018-09-05 08:30:59 -0700620 void handle(const Request& req, Response& res,
621 const RoutingParams& params) override
622 {
623 detail::routing_handler_call_helper::Call<
624 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
625 0, 0, 0, 0, black_magic::S<Args...>, black_magic::S<>>()(
626 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
627 handler, params, req, res});
628 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700629
Ed Tanous1abe55e2018-09-05 08:30:59 -0700630 private:
631 std::function<void(const crow::Request&, crow::Response&, Args...)> handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700632};
633
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700634const int ruleSpecialRedirectSlash = 1;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700635
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636class Trie
637{
638 public:
639 struct Node
640 {
641 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700642 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
643 paramChildrens{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700644 boost::container::flat_map<std::string, unsigned> children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700645
Ed Tanous1abe55e2018-09-05 08:30:59 -0700646 bool isSimpleNode() const
647 {
648 return !ruleIndex && std::all_of(std::begin(paramChildrens),
649 std::end(paramChildrens),
Ed Tanous271584a2019-07-09 16:24:22 -0700650 [](size_t x) { return !x; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700651 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700652 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700653
Ed Tanous1abe55e2018-09-05 08:30:59 -0700654 Trie() : nodes(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500655 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700656
657 private:
658 void optimizeNode(Node* node)
659 {
Ed Tanous271584a2019-07-09 16:24:22 -0700660 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700661 {
662 if (!x)
663 continue;
664 Node* child = &nodes[x];
665 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700666 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700667 if (node->children.empty())
668 return;
669 bool mergeWithChild = true;
Tanousf00032d2018-11-05 01:18:10 -0300670 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 {
672 Node* child = &nodes[kv.second];
673 if (!child->isSimpleNode())
674 {
675 mergeWithChild = false;
676 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700677 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700678 }
679 if (mergeWithChild)
680 {
681 decltype(node->children) merged;
Tanousf00032d2018-11-05 01:18:10 -0300682 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 {
684 Node* child = &nodes[kv.second];
Tanousf00032d2018-11-05 01:18:10 -0300685 for (const std::pair<std::string, unsigned>& childKv :
686 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700687 {
688 merged[kv.first + childKv.first] = childKv.second;
689 }
690 }
691 node->children = std::move(merged);
692 optimizeNode(node);
693 }
694 else
695 {
Tanousf00032d2018-11-05 01:18:10 -0300696 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700697 {
698 Node* child = &nodes[kv.second];
699 optimizeNode(child);
700 }
701 }
702 }
703
704 void optimize()
705 {
706 optimizeNode(head());
707 }
708
709 public:
710 void validate()
711 {
712 if (!head()->isSimpleNode())
713 throw std::runtime_error(
714 "Internal error: Trie header should be simple!");
715 optimize();
716 }
717
718 void findRouteIndexes(const std::string& req_url,
719 std::vector<unsigned>& route_indexes,
Tanousf00032d2018-11-05 01:18:10 -0300720 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700721 {
722 if (node == nullptr)
723 {
724 node = head();
725 }
Tanousf00032d2018-11-05 01:18:10 -0300726 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700727 {
728 const std::string& fragment = kv.first;
729 const Node* child = &nodes[kv.second];
730 if (pos >= req_url.size())
731 {
732 if (child->ruleIndex != 0 && fragment != "/")
733 {
734 route_indexes.push_back(child->ruleIndex);
735 }
736 findRouteIndexes(req_url, route_indexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700737 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700738 }
739 else
740 {
741 if (req_url.compare(pos, fragment.size(), fragment) == 0)
742 {
Ed Tanous271584a2019-07-09 16:24:22 -0700743 findRouteIndexes(
744 req_url, route_indexes, child,
745 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 }
747 }
748 }
749 }
750
751 std::pair<unsigned, RoutingParams>
Ed Tanous39e77502019-03-04 17:35:53 -0800752 find(const std::string_view req_url, const Node* node = nullptr,
Ed Tanous271584a2019-07-09 16:24:22 -0700753 size_t pos = 0, RoutingParams* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700754 {
755 RoutingParams empty;
756 if (params == nullptr)
757 params = &empty;
758
759 unsigned found{};
760 RoutingParams matchParams;
761
762 if (node == nullptr)
763 node = head();
764 if (pos == req_url.size())
765 return {node->ruleIndex, *params};
766
767 auto updateFound =
768 [&found, &matchParams](std::pair<unsigned, RoutingParams>& ret) {
769 if (ret.first && (!found || found > ret.first))
770 {
771 found = ret.first;
772 matchParams = std::move(ret.second);
773 }
774 };
775
Ed Tanous271584a2019-07-09 16:24:22 -0700776 if (node->paramChildrens[static_cast<size_t>(ParamType::INT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700777 {
778 char c = req_url[pos];
779 if ((c >= '0' && c <= '9') || c == '+' || c == '-')
780 {
781 char* eptr;
782 errno = 0;
783 long long int value =
784 std::strtoll(req_url.data() + pos, &eptr, 10);
785 if (errno != ERANGE && eptr != req_url.data() + pos)
786 {
787 params->intParams.push_back(value);
Ed Tanous271584a2019-07-09 16:24:22 -0700788 std::pair<unsigned, RoutingParams> ret = find(
789 req_url,
790 &nodes[node->paramChildrens[static_cast<size_t>(
791 ParamType::INT)]],
792 static_cast<size_t>(eptr - req_url.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700793 updateFound(ret);
794 params->intParams.pop_back();
795 }
796 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700797 }
798
Ed Tanous271584a2019-07-09 16:24:22 -0700799 if (node->paramChildrens[static_cast<size_t>(ParamType::UINT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700800 {
801 char c = req_url[pos];
802 if ((c >= '0' && c <= '9') || c == '+')
803 {
804 char* eptr;
805 errno = 0;
806 unsigned long long int value =
807 std::strtoull(req_url.data() + pos, &eptr, 10);
808 if (errno != ERANGE && eptr != req_url.data() + pos)
809 {
810 params->uintParams.push_back(value);
Ed Tanous271584a2019-07-09 16:24:22 -0700811 std::pair<unsigned, RoutingParams> ret = find(
812 req_url,
813 &nodes[node->paramChildrens[static_cast<size_t>(
814 ParamType::UINT)]],
815 static_cast<size_t>(eptr - req_url.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700816 updateFound(ret);
817 params->uintParams.pop_back();
818 }
819 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700820 }
821
Ed Tanous271584a2019-07-09 16:24:22 -0700822 if (node->paramChildrens[static_cast<size_t>(ParamType::DOUBLE)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700823 {
824 char c = req_url[pos];
825 if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
826 {
827 char* eptr;
828 errno = 0;
829 double value = std::strtod(req_url.data() + pos, &eptr);
830 if (errno != ERANGE && eptr != req_url.data() + pos)
831 {
832 params->doubleParams.push_back(value);
Tanousf00032d2018-11-05 01:18:10 -0300833 std::pair<unsigned, RoutingParams> ret = find(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700834 req_url,
Ed Tanous271584a2019-07-09 16:24:22 -0700835 &nodes[node->paramChildrens[static_cast<size_t>(
836 ParamType::DOUBLE)]],
837 static_cast<size_t>(eptr - req_url.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700838 updateFound(ret);
839 params->doubleParams.pop_back();
840 }
841 }
842 }
843
Ed Tanous271584a2019-07-09 16:24:22 -0700844 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700845 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000846 size_t epos = pos;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700847 for (; epos < req_url.size(); epos++)
848 {
849 if (req_url[epos] == '/')
850 break;
851 }
852
853 if (epos != pos)
854 {
855 params->stringParams.emplace_back(
856 req_url.substr(pos, epos - pos));
Tanousf00032d2018-11-05 01:18:10 -0300857 std::pair<unsigned, RoutingParams> ret =
Ed Tanousb01bf292019-03-25 19:25:26 +0000858 find(req_url,
Ed Tanous271584a2019-07-09 16:24:22 -0700859 &nodes[node->paramChildrens[static_cast<size_t>(
860 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000861 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700862 updateFound(ret);
863 params->stringParams.pop_back();
864 }
865 }
866
Ed Tanous271584a2019-07-09 16:24:22 -0700867 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700868 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000869 size_t epos = req_url.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700870
871 if (epos != pos)
872 {
873 params->stringParams.emplace_back(
874 req_url.substr(pos, epos - pos));
Ed Tanous271584a2019-07-09 16:24:22 -0700875 std::pair<unsigned, RoutingParams> ret =
876 find(req_url,
877 &nodes[node->paramChildrens[static_cast<size_t>(
878 ParamType::PATH)]],
879 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700880 updateFound(ret);
881 params->stringParams.pop_back();
882 }
883 }
884
Tanousf00032d2018-11-05 01:18:10 -0300885 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886 {
887 const std::string& fragment = kv.first;
888 const Node* child = &nodes[kv.second];
889
890 if (req_url.compare(pos, fragment.size(), fragment) == 0)
891 {
Tanousf00032d2018-11-05 01:18:10 -0300892 std::pair<unsigned, RoutingParams> ret =
893 find(req_url, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700894 updateFound(ret);
895 }
896 }
897
898 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700899 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700900
901 void add(const std::string& url, unsigned ruleIndex)
902 {
Ed Tanous271584a2019-07-09 16:24:22 -0700903 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700904
905 for (unsigned i = 0; i < url.size(); i++)
906 {
907 char c = url[i];
908 if (c == '<')
909 {
Tanousf00032d2018-11-05 01:18:10 -0300910 const static std::array<std::pair<ParamType, std::string>, 7>
911 paramTraits = {{
912 {ParamType::INT, "<int>"},
913 {ParamType::UINT, "<uint>"},
914 {ParamType::DOUBLE, "<float>"},
915 {ParamType::DOUBLE, "<double>"},
916 {ParamType::STRING, "<str>"},
917 {ParamType::STRING, "<string>"},
918 {ParamType::PATH, "<path>"},
919 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700920
Tanousf00032d2018-11-05 01:18:10 -0300921 for (const std::pair<ParamType, std::string>& x : paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700922 {
Tanousf00032d2018-11-05 01:18:10 -0300923 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700924 {
Ed Tanous271584a2019-07-09 16:24:22 -0700925 size_t index = static_cast<size_t>(x.first);
926 if (!nodes[idx].paramChildrens[index])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700927 {
Tanousf00032d2018-11-05 01:18:10 -0300928 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700929 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700930 }
Ed Tanous271584a2019-07-09 16:24:22 -0700931 idx = nodes[idx].paramChildrens[index];
932 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700933 break;
934 }
935 }
936
937 i--;
938 }
939 else
940 {
941 std::string piece(&c, 1);
942 if (!nodes[idx].children.count(piece))
943 {
Tanousf00032d2018-11-05 01:18:10 -0300944 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700945 nodes[idx].children.emplace(piece, newNodeIdx);
946 }
947 idx = nodes[idx].children[piece];
948 }
949 }
950 if (nodes[idx].ruleIndex)
951 throw std::runtime_error("handler already exists for " + url);
952 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700953 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700954
Ed Tanous1abe55e2018-09-05 08:30:59 -0700955 private:
Ed Tanous271584a2019-07-09 16:24:22 -0700956 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700957 {
Ed Tanous271584a2019-07-09 16:24:22 -0700958 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700959 {
960 if (n->paramChildrens[i])
961 {
962 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -0700963 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
964 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700965 {
966 case ParamType::INT:
967 BMCWEB_LOG_DEBUG << "<int>";
968 break;
969 case ParamType::UINT:
970 BMCWEB_LOG_DEBUG << "<uint>";
971 break;
972 case ParamType::DOUBLE:
973 BMCWEB_LOG_DEBUG << "<float>";
974 break;
975 case ParamType::STRING:
976 BMCWEB_LOG_DEBUG << "<str>";
977 break;
978 case ParamType::PATH:
979 BMCWEB_LOG_DEBUG << "<path>";
980 break;
Ed Tanous23a21a12020-07-25 04:45:05 +0000981 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -0700982 BMCWEB_LOG_DEBUG << "<ERROR>";
983 break;
984 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700985
Ed Tanous1abe55e2018-09-05 08:30:59 -0700986 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
987 }
988 }
Tanousf00032d2018-11-05 01:18:10 -0300989 for (const std::pair<std::string, unsigned>& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700990 {
991 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -0700992 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -0700993 << kv.first;
994 debugNodePrint(&nodes[kv.second], level + 1);
995 }
996 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700997
Ed Tanous1abe55e2018-09-05 08:30:59 -0700998 public:
999 void debugPrint()
1000 {
Ed Tanous271584a2019-07-09 16:24:22 -07001001 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001002 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001003
Ed Tanous1abe55e2018-09-05 08:30:59 -07001004 private:
1005 const Node* head() const
1006 {
1007 return &nodes.front();
1008 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001009
Ed Tanous1abe55e2018-09-05 08:30:59 -07001010 Node* head()
1011 {
1012 return &nodes.front();
1013 }
1014
1015 unsigned newNode()
1016 {
1017 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -07001018 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001019 }
1020
1021 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001022};
1023
Ed Tanous1abe55e2018-09-05 08:30:59 -07001024class Router
1025{
1026 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -07001027 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001028
Ed Tanous1abe55e2018-09-05 08:30:59 -07001029 DynamicRule& newRuleDynamic(const std::string& rule)
1030 {
1031 std::unique_ptr<DynamicRule> ruleObject =
1032 std::make_unique<DynamicRule>(rule);
1033 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001034 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -07001035
Ed Tanous1abe55e2018-09-05 08:30:59 -07001036 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001037 }
1038
Ed Tanous1abe55e2018-09-05 08:30:59 -07001039 template <uint64_t N>
1040 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
1041 newRuleTagged(const std::string& rule)
1042 {
1043 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
1044 TaggedRule>;
1045 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
1046 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001047 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001048
1049 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001050 }
1051
Tanousf00032d2018-11-05 01:18:10 -03001052 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001053 {
Tanousf00032d2018-11-05 01:18:10 -03001054 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001055 {
Tanousf00032d2018-11-05 01:18:10 -03001056 return;
1057 }
Ed Tanous888880a2020-08-24 13:48:50 -07001058 for (size_t method = 0, methodBit = 1; method < maxHttpVerbCount;
Ed Tanous2c70f802020-09-28 14:29:23 -07001059 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -03001060 {
Ed Tanous2c70f802020-09-28 14:29:23 -07001061 if (ruleObject->methodsBitfield & methodBit)
Tanousf00032d2018-11-05 01:18:10 -03001062 {
1063 perMethods[method].rules.emplace_back(ruleObject);
1064 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -07001065 rule, static_cast<unsigned>(
1066 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -03001067 // directory case:
1068 // request to `/about' url matches `/about/' rule
1069 if (rule.size() > 2 && rule.back() == '/')
1070 {
1071 perMethods[method].trie.add(
1072 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -07001073 static_cast<unsigned>(perMethods[method].rules.size() -
1074 1));
Tanousf00032d2018-11-05 01:18:10 -03001075 }
1076 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001077 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001078 }
1079
Ed Tanous1abe55e2018-09-05 08:30:59 -07001080 void validate()
1081 {
Tanousf00032d2018-11-05 01:18:10 -03001082 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001083 {
1084 if (rule)
1085 {
Tanousf00032d2018-11-05 01:18:10 -03001086 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001087 if (upgraded)
1088 rule = std::move(upgraded);
1089 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -03001090 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001091 }
1092 }
Tanousf00032d2018-11-05 01:18:10 -03001093 for (PerMethod& perMethod : perMethods)
1094 {
1095 perMethod.trie.validate();
1096 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001097 }
1098
Ed Tanous1abe55e2018-09-05 08:30:59 -07001099 template <typename Adaptor>
1100 void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
1101 {
Ed Tanous271584a2019-07-09 16:24:22 -07001102 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001103 {
1104 res.result(boost::beast::http::status::not_found);
1105 res.end();
Tanousf00032d2018-11-05 01:18:10 -03001106 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001107 }
Tanousf00032d2018-11-05 01:18:10 -03001108
Ed Tanous271584a2019-07-09 16:24:22 -07001109 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001110 Trie& trie = perMethod.trie;
1111 std::vector<BaseRule*>& rules = perMethod.rules;
1112
1113 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001114 unsigned ruleIndex = found.first;
1115 if (!ruleIndex)
1116 {
1117 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001118 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001119 res.end();
1120 return;
1121 }
1122
1123 if (ruleIndex >= rules.size())
1124 throw std::runtime_error("Trie internal structure corrupted!");
1125
1126 if (ruleIndex == ruleSpecialRedirectSlash)
1127 {
1128 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1129 << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001130 res.result(boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001131
1132 // TODO absolute url building
1133 if (req.getHeaderValue("Host").empty())
1134 {
1135 res.addHeader("Location", std::string(req.url) + "/");
1136 }
1137 else
1138 {
1139 res.addHeader(
1140 "Location",
1141 req.isSecure
1142 ? "https://"
1143 : "http://" + std::string(req.getHeaderValue("Host")) +
1144 std::string(req.url) + "/");
1145 }
1146 res.end();
1147 return;
1148 }
1149
Ed Tanous271584a2019-07-09 16:24:22 -07001150 if ((rules[ruleIndex]->getMethods() &
1151 (1U << static_cast<size_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001152 {
1153 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1154 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001155 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001156 << rules[ruleIndex]->getMethods();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001157 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001158 res.end();
1159 return;
1160 }
1161
1162 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rules[ruleIndex]->rule
Ed Tanous271584a2019-07-09 16:24:22 -07001163 << "' " << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001164 << rules[ruleIndex]->getMethods();
1165
1166 // any uncaught exceptions become 500s
1167 try
1168 {
1169 rules[ruleIndex]->handleUpgrade(req, res, std::move(adaptor));
1170 }
1171 catch (std::exception& e)
1172 {
1173 BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001174 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001175 res.end();
1176 return;
1177 }
1178 catch (...)
1179 {
1180 BMCWEB_LOG_ERROR
1181 << "An uncaught exception occurred. The type was unknown "
1182 "so no information was available.";
Ed Tanousde5c9f32019-03-26 09:17:55 -07001183 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001184 res.end();
1185 return;
1186 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001187 }
1188
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001189 void handle(Request& req, Response& res)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001190 {
Ed Tanous271584a2019-07-09 16:24:22 -07001191 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001192 {
1193 res.result(boost::beast::http::status::not_found);
1194 res.end();
Tanousf00032d2018-11-05 01:18:10 -03001195 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001196 }
Ed Tanous271584a2019-07-09 16:24:22 -07001197 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001198 Trie& trie = perMethod.trie;
1199 std::vector<BaseRule*>& rules = perMethod.rules;
1200
1201 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001202
Ed Tanous1abe55e2018-09-05 08:30:59 -07001203 unsigned ruleIndex = found.first;
1204
1205 if (!ruleIndex)
1206 {
Ed Tanous2634dcd2019-03-26 09:28:06 -07001207 // Check to see if this url exists at any verb
1208 for (const PerMethod& p : perMethods)
1209 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001210 const std::pair<unsigned, RoutingParams>& found2 =
Ed Tanous2634dcd2019-03-26 09:28:06 -07001211 p.trie.find(req.url);
Ed Tanous23a21a12020-07-25 04:45:05 +00001212 if (found2.first > 0)
Ed Tanous2634dcd2019-03-26 09:28:06 -07001213 {
1214 res.result(boost::beast::http::status::method_not_allowed);
1215 res.end();
1216 return;
1217 }
1218 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001219 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
1220 res.result(boost::beast::http::status::not_found);
1221 res.end();
1222 return;
1223 }
1224
1225 if (ruleIndex >= rules.size())
1226 throw std::runtime_error("Trie internal structure corrupted!");
1227
1228 if (ruleIndex == ruleSpecialRedirectSlash)
1229 {
1230 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1231 << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001232 res.result(boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001233
1234 // TODO absolute url building
1235 if (req.getHeaderValue("Host").empty())
1236 {
1237 res.addHeader("Location", std::string(req.url) + "/");
1238 }
1239 else
1240 {
1241 res.addHeader("Location",
1242 (req.isSecure ? "https://" : "http://") +
1243 std::string(req.getHeaderValue("Host")) +
1244 std::string(req.url) + "/");
1245 }
1246 res.end();
1247 return;
1248 }
1249
Ed Tanous271584a2019-07-09 16:24:22 -07001250 if ((rules[ruleIndex]->getMethods() &
1251 (1U << static_cast<uint32_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001252 {
1253 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1254 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001255 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001256 << rules[ruleIndex]->getMethods();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001257 res.result(boost::beast::http::status::method_not_allowed);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001258 res.end();
1259 return;
1260 }
1261
1262 BMCWEB_LOG_DEBUG << "Matched rule '" << rules[ruleIndex]->rule << "' "
Ed Tanous271584a2019-07-09 16:24:22 -07001263 << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001264 << rules[ruleIndex]->getMethods();
1265
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001266 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001267 {
1268 rules[ruleIndex]->handle(req, res, found.second);
James Feist7166bf02019-12-10 16:52:14 +00001269 return;
1270 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001271
1272 crow::connections::systemBus->async_method_call(
1273 [&req, &res, &rules, ruleIndex, found](
1274 const boost::system::error_code ec,
1275 std::map<std::string, std::variant<bool, std::string,
1276 std::vector<std::string>>>
1277 userInfo) {
1278 if (ec)
1279 {
1280 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
1281 res.result(
1282 boost::beast::http::status::internal_server_error);
1283 res.end();
1284 return;
1285 }
1286
1287 const std::string* userRolePtr = nullptr;
1288 auto userInfoIter = userInfo.find("UserPrivilege");
1289 if (userInfoIter != userInfo.end())
1290 {
1291 userRolePtr =
1292 std::get_if<std::string>(&userInfoIter->second);
1293 }
1294
1295 std::string userRole{};
1296 if (userRolePtr != nullptr)
1297 {
1298 userRole = *userRolePtr;
1299 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1300 << " userRole = " << *userRolePtr;
1301 }
1302
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001303 bool* remoteUserPtr = nullptr;
1304 auto remoteUserIter = userInfo.find("RemoteUser");
1305 if (remoteUserIter != userInfo.end())
1306 {
1307 remoteUserPtr = std::get_if<bool>(&remoteUserIter->second);
1308 }
1309 if (remoteUserPtr == nullptr)
1310 {
1311 BMCWEB_LOG_ERROR
1312 << "RemoteUser property missing or wrong type";
1313 res.result(
1314 boost::beast::http::status::internal_server_error);
1315 res.end();
1316 return;
1317 }
1318 bool remoteUser = *remoteUserPtr;
1319
1320 bool passwordExpired = false; // default for remote user
1321 if (!remoteUser)
1322 {
1323 bool* passwordExpiredPtr = nullptr;
1324 auto passwordExpiredIter =
1325 userInfo.find("UserPasswordExpired");
1326 if (passwordExpiredIter != userInfo.end())
1327 {
1328 passwordExpiredPtr =
1329 std::get_if<bool>(&passwordExpiredIter->second);
1330 }
1331 if (passwordExpiredPtr != nullptr)
1332 {
1333 passwordExpired = *passwordExpiredPtr;
1334 }
1335 else
1336 {
1337 BMCWEB_LOG_ERROR
1338 << "UserPasswordExpired property is expected for"
1339 " local user but is missing or wrong type";
1340 res.result(
1341 boost::beast::http::status::internal_server_error);
1342 res.end();
1343 return;
1344 }
1345 }
1346
Ed Tanous23a21a12020-07-25 04:45:05 +00001347 // Get the userprivileges from the role
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001348 redfish::Privileges userPrivileges =
1349 redfish::getUserPrivileges(userRole);
1350
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001351 // Set isConfigureSelfOnly based on D-Bus results. This
1352 // ignores the results from both pamAuthenticateUser and the
1353 // value from any previous use of this session.
1354 req.session->isConfigureSelfOnly = passwordExpired;
1355
Ed Tanous23a21a12020-07-25 04:45:05 +00001356 // Modifyprivileges if isConfigureSelfOnly.
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001357 if (req.session->isConfigureSelfOnly)
1358 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001359 // Remove allprivileges except ConfigureSelf
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001360 userPrivileges = userPrivileges.intersection(
1361 redfish::Privileges{"ConfigureSelf"});
1362 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1363 }
1364
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001365 if (!rules[ruleIndex]->checkPrivileges(userPrivileges))
1366 {
1367 res.result(boost::beast::http::status::forbidden);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001368 if (req.session->isConfigureSelfOnly)
1369 {
1370 redfish::messages::passwordChangeRequired(
1371 res, "/redfish/v1/AccountService/Accounts/" +
1372 req.session->username);
1373 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001374 res.end();
1375 return;
1376 }
1377
1378 req.userRole = userRole;
1379
1380 rules[ruleIndex]->handle(req, res, found.second);
1381 },
1382 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1383 "xyz.openbmc_project.User.Manager", "GetUserInfo",
1384 req.session->username);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001385 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001386
Ed Tanous1abe55e2018-09-05 08:30:59 -07001387 void debugPrint()
1388 {
Ed Tanous271584a2019-07-09 16:24:22 -07001389 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001390 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001391 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1392 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001393 perMethods[i].trie.debugPrint();
1394 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001395 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001396
Ed Tanous1abe55e2018-09-05 08:30:59 -07001397 std::vector<const std::string*> getRoutes(const std::string& parent)
1398 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001399 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001400
1401 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001402 {
Tanousf00032d2018-11-05 01:18:10 -03001403 std::vector<unsigned> x;
1404 pm.trie.findRouteIndexes(parent, x);
1405 for (unsigned index : x)
1406 {
1407 ret.push_back(&pm.rules[index]->rule);
1408 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001409 }
1410 return ret;
1411 }
1412
1413 private:
Tanousf00032d2018-11-05 01:18:10 -03001414 struct PerMethod
1415 {
1416 std::vector<BaseRule*> rules;
1417 Trie trie;
1418 // rule index 0, 1 has special meaning; preallocate it to avoid
1419 // duplication.
1420 PerMethod() : rules(2)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001421 {}
Tanousf00032d2018-11-05 01:18:10 -03001422 };
Ed Tanous888880a2020-08-24 13:48:50 -07001423
1424 const static size_t maxHttpVerbCount =
Ed Tanouscc090442020-10-07 08:20:50 -07001425 static_cast<size_t>(boost::beast::http::verb::unlink);
Ed Tanous888880a2020-08-24 13:48:50 -07001426
Tanousf00032d2018-11-05 01:18:10 -03001427 std::array<PerMethod, maxHttpVerbCount> perMethods;
1428 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001429};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001430} // namespace crow