blob: 59fa6360fd758f0dcb17b56f10db08e3eb3c2114 [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)
Ed Tanous3174e4d2020-10-07 11:41:22 -070043 {
Ed Tanous1abe55e2018-09-05 08:30:59 -070044 return std::move(ruleToUpgrade);
Ed Tanous3174e4d2020-10-07 11:41:22 -070045 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070046 return {};
47 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070048
Ed Tanous1abe55e2018-09-05 08:30:59 -070049 virtual void handle(const Request&, Response&, 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;
122 Response& res;
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(
194 cparams.req, cparams.res,
195 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 {
Tanousf00032d2018-11-05 01:18:10 -0300211 handler = [f = std::move(f)](const Request&, Response& res,
212 Args... args) {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700213 res.result(f(args...));
Tanousf00032d2018-11-05 01:18:10 -0300214 res.end();
215 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700216 }
217
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500218 template <typename Req, typename... Args>
219 struct ReqHandlerWrapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700220 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000221 ReqHandlerWrapper(Func fIn) : f(std::move(fIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500222 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700223
Ed Tanous1abe55e2018-09-05 08:30:59 -0700224 void operator()(const Request& req, Response& res, Args... args)
225 {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700226 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700227 res.end();
228 }
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,
242 Response&>::value,
243 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,
263 Response&>::value,
264 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 {
272 using type =
273 std::function<void(const crow::Request&, crow::Response&, Args...)>;
274 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700275 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700276 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700277
Ed Tanous1abe55e2018-09-05 08:30:59 -0700278 template <typename... Args>
279 struct HandlerTypeHelper<const Request&, Args...>
280 {
281 using type =
282 std::function<void(const crow::Request&, crow::Response&, Args...)>;
283 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700284 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700285 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700286
Ed Tanous1abe55e2018-09-05 08:30:59 -0700287 template <typename... Args>
288 struct HandlerTypeHelper<const Request&, Response&, Args...>
289 {
290 using type =
291 std::function<void(const crow::Request&, crow::Response&, Args...)>;
292 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700293 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700294 };
295
296 typename HandlerTypeHelper<ArgsWrapped...>::type handler;
297
298 void operator()(const Request& req, Response& res,
299 const RoutingParams& params)
300 {
301 detail::routing_handler_call_helper::Call<
302 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
303 0, 0, 0, 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
304 black_magic::S<>>()(
305 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
306 handler, params, req, res});
307 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700308};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700309} // namespace routing_handler_call_helper
310} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700311
Ed Tanous1abe55e2018-09-05 08:30:59 -0700312class WebSocketRule : public BaseRule
313{
314 using self_t = WebSocketRule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700315
Ed Tanous1abe55e2018-09-05 08:30:59 -0700316 public:
Ed Tanous23a21a12020-07-25 04:45:05 +0000317 WebSocketRule(std::string ruleIn) : BaseRule(std::move(ruleIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500318 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700319
Ed Tanous1abe55e2018-09-05 08:30:59 -0700320 void validate() override
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500321 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700322
Ed Tanous1abe55e2018-09-05 08:30:59 -0700323 void handle(const Request&, Response& res, const RoutingParams&) override
324 {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700325 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700326 res.end();
327 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700328
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000329 void handleUpgrade(const Request& req, Response&,
Ed Tanousceac6f72018-12-02 11:58:47 -0800330 boost::asio::ip::tcp::socket&& adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700331 {
Ratan Gupta02453b12019-10-22 14:43:36 +0530332 std::shared_ptr<
333 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>
334 myConnection = std::make_shared<
335 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000336 req, std::move(adaptor), openHandler, messageHandler,
Ratan Gupta02453b12019-10-22 14:43:36 +0530337 closeHandler, errorHandler);
338 myConnection->start();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700339 }
340#ifdef BMCWEB_ENABLE_SSL
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000341 void handleUpgrade(const Request& req, Response&,
Ed Tanousceac6f72018-12-02 11:58:47 -0800342 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
343 adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700344 {
Ed Tanousceac6f72018-12-02 11:58:47 -0800345 std::shared_ptr<crow::websocket::ConnectionImpl<
346 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
347 myConnection = std::make_shared<crow::websocket::ConnectionImpl<
348 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000349 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanousceac6f72018-12-02 11:58:47 -0800350 closeHandler, errorHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700351 myConnection->start();
352 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700353#endif
354
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500355 template <typename Func>
356 self_t& onopen(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700357 {
358 openHandler = f;
359 return *this;
360 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700361
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500362 template <typename Func>
363 self_t& onmessage(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700364 {
365 messageHandler = f;
366 return *this;
367 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700368
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500369 template <typename Func>
370 self_t& onclose(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700371 {
372 closeHandler = f;
373 return *this;
374 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700375
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500376 template <typename Func>
377 self_t& onerror(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700378 {
379 errorHandler = f;
380 return *this;
381 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700382
Ed Tanous1abe55e2018-09-05 08:30:59 -0700383 protected:
Iwona Klimaszewskac0a1c8a2019-07-12 18:26:38 +0200384 std::function<void(crow::websocket::Connection&,
385 std::shared_ptr<bmcweb::AsyncResp>)>
386 openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700387 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
388 messageHandler;
389 std::function<void(crow::websocket::Connection&, const std::string&)>
390 closeHandler;
391 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700392};
393
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500394template <typename T>
395struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700396{
397 using self_t = T;
398 WebSocketRule& websocket()
399 {
Ed Tanous271584a2019-07-09 16:24:22 -0700400 self_t* self = static_cast<self_t*>(this);
401 WebSocketRule* p = new WebSocketRule(self->rule);
402 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700403 return *p;
404 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700405
Ed Tanousb5a76932020-09-29 16:16:58 -0700406 self_t& name(const std::string& name) noexcept
Ed Tanous1abe55e2018-09-05 08:30:59 -0700407 {
Ed Tanous271584a2019-07-09 16:24:22 -0700408 self_t* self = static_cast<self_t*>(this);
409 self->nameStr = std::move(name);
410 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700411 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700412
Ed Tanous1abe55e2018-09-05 08:30:59 -0700413 self_t& methods(boost::beast::http::verb method)
414 {
Ed Tanous271584a2019-07-09 16:24:22 -0700415 self_t* self = static_cast<self_t*>(this);
416 self->methodsBitfield = 1U << static_cast<size_t>(method);
417 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700418 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700419
Ed Tanous1abe55e2018-09-05 08:30:59 -0700420 template <typename... MethodArgs>
421 self_t& methods(boost::beast::http::verb method, MethodArgs... args_method)
422 {
Ed Tanous271584a2019-07-09 16:24:22 -0700423 self_t* self = static_cast<self_t*>(this);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700424 methods(args_method...);
Ed Tanous271584a2019-07-09 16:24:22 -0700425 self->methodsBitfield |= 1U << static_cast<size_t>(method);
426 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700427 }
Tanousf00032d2018-11-05 01:18:10 -0300428
429 template <typename... MethodArgs>
Ed Tanous23a21a12020-07-25 04:45:05 +0000430 self_t& privileges(std::initializer_list<const char*> l)
Tanousf00032d2018-11-05 01:18:10 -0300431 {
Ed Tanous271584a2019-07-09 16:24:22 -0700432 self_t* self = static_cast<self_t*>(this);
433 self->privilegesSet.emplace_back(l);
434 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300435 }
436
437 template <typename... MethodArgs>
Ed Tanous23a21a12020-07-25 04:45:05 +0000438 self_t& privileges(const std::vector<redfish::Privileges>& p)
Tanousf00032d2018-11-05 01:18:10 -0300439 {
Ed Tanous271584a2019-07-09 16:24:22 -0700440 self_t* self = static_cast<self_t*>(this);
Tanousf00032d2018-11-05 01:18:10 -0300441 for (const redfish::Privileges& privilege : p)
442 {
Ed Tanous271584a2019-07-09 16:24:22 -0700443 self->privilegesSet.emplace_back(privilege);
Tanousf00032d2018-11-05 01:18:10 -0300444 }
Ed Tanous271584a2019-07-09 16:24:22 -0700445 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300446 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700447};
448
Ed Tanous1abe55e2018-09-05 08:30:59 -0700449class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
450{
451 public:
Ed Tanous23a21a12020-07-25 04:45:05 +0000452 DynamicRule(std::string ruleIn) : BaseRule(std::move(ruleIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500453 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700454
Ed Tanous1abe55e2018-09-05 08:30:59 -0700455 void validate() override
456 {
457 if (!erasedHandler)
458 {
459 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
460 "no handler for url " + rule);
461 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700462 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700463
Ed Tanous1abe55e2018-09-05 08:30:59 -0700464 void handle(const Request& req, Response& res,
465 const RoutingParams& params) override
466 {
467 erasedHandler(req, res, params);
468 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700469
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500470 template <typename Func>
471 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700472 {
473 using function_t = utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700474 erasedHandler =
Ed Tanous988403c2020-08-24 11:29:49 -0700475 wrap(std::move(f),
476 std::make_integer_sequence<unsigned, function_t::arity>{});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700477 }
478
479 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500480 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481 // enable_if Arg1 != request
482
483 template <typename Func, unsigned... Indices>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700484 std::function<void(const Request&, Response&, const RoutingParams&)>
Ed Tanous988403c2020-08-24 11:29:49 -0700485 wrap(Func f, std::integer_sequence<unsigned, Indices...>)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700486 {
Ed Tanous988403c2020-08-24 11:29:49 -0700487 using function_t = crow::utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700488
489 if (!black_magic::isParameterTagCompatible(
Ed Tanous988403c2020-08-24 11:29:49 -0700490 black_magic::getParameterTag(rule.c_str()),
491 black_magic::computeParameterTagFromArgsList<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700492 typename function_t::template arg<Indices>...>::value))
493 {
494 throw std::runtime_error("routeDynamic: Handler type is mismatched "
495 "with URL parameters: " +
496 rule);
497 }
498 auto ret = detail::routing_handler_call_helper::Wrapped<
499 Func, typename function_t::template arg<Indices>...>();
500 ret.template set<typename function_t::template arg<Indices>...>(
501 std::move(f));
502 return ret;
503 }
504
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500505 template <typename Func>
506 void operator()(std::string name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700507 {
508 nameStr = std::move(name);
509 (*this).template operator()<Func>(std::forward(f));
510 }
511
512 private:
513 std::function<void(const Request&, Response&, const RoutingParams&)>
514 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700515};
516
517template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500518class TaggedRule :
519 public BaseRule,
520 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700521{
522 public:
523 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700524
Ed Tanousb5a76932020-09-29 16:16:58 -0700525 TaggedRule(const std::string& ruleIn) : BaseRule(std::move(ruleIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500526 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700527
Ed Tanous1abe55e2018-09-05 08:30:59 -0700528 void validate() override
529 {
530 if (!handler)
531 {
532 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
533 "no handler for url " + rule);
534 }
535 }
536
537 template <typename Func>
538 typename std::enable_if<
539 black_magic::CallHelper<Func, black_magic::S<Args...>>::value,
540 void>::type
541 operator()(Func&& f)
542 {
543 static_assert(
544 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
545 black_magic::CallHelper<
546 Func, black_magic::S<crow::Request, Args...>>::value,
547 "Handler type is mismatched with URL parameters");
548 static_assert(
549 !std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
550 "Handler function cannot have void return type; valid return "
551 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500552 "string, int, crow::response, nlohmann::json");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700553
554 handler = [f = std::move(f)](const Request&, Response& res,
555 Args... args) {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700556 res.result(f(args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700557 res.end();
558 };
559 }
560
561 template <typename Func>
562 typename std::enable_if<
563 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
Ed Tanous7045c8d2017-04-03 10:04:37 -0700564 black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700565 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700566 void>::type
567 operator()(Func&& f)
568 {
569 static_assert(
570 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
571 black_magic::CallHelper<
572 Func, black_magic::S<crow::Request, Args...>>::value,
573 "Handler type is mismatched with URL parameters");
574 static_assert(
575 !std::is_same<void, decltype(f(std::declval<crow::Request>(),
576 std::declval<Args>()...))>::value,
577 "Handler function cannot have void return type; valid return "
578 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500579 "string, int, crow::response,nlohmann::json");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700580
Ed Tanous1abe55e2018-09-05 08:30:59 -0700581 handler = [f = std::move(f)](const crow::Request& req,
582 crow::Response& res, Args... args) {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700583 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700584 res.end();
585 };
586 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700587
Ed Tanous1abe55e2018-09-05 08:30:59 -0700588 template <typename Func>
589 typename std::enable_if<
590 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
591 !black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700592 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700593 void>::type
594 operator()(Func&& f)
595 {
596 static_assert(
597 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
598 black_magic::CallHelper<
599 Func, black_magic::S<crow::Request, Args...>>::value ||
600 black_magic::CallHelper<
601 Func, black_magic::S<crow::Request, crow::Response&,
602 Args...>>::value,
603 "Handler type is mismatched with URL parameters");
604 static_assert(
605 std::is_same<void, decltype(f(std::declval<crow::Request>(),
606 std::declval<crow::Response&>(),
607 std::declval<Args>()...))>::value,
Tanousf00032d2018-11-05 01:18:10 -0300608 "Handler function with response argument should have void "
609 "return "
Ed Tanous1abe55e2018-09-05 08:30:59 -0700610 "type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700611
Ed Tanous1abe55e2018-09-05 08:30:59 -0700612 handler = std::move(f);
613 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700614
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500615 template <typename Func>
Ed Tanousb5a76932020-09-29 16:16:58 -0700616 void operator()(const std::string& name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700617 {
618 nameStr = std::move(name);
619 (*this).template operator()<Func>(std::forward(f));
620 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700621
Ed Tanous1abe55e2018-09-05 08:30:59 -0700622 void handle(const Request& req, Response& res,
623 const RoutingParams& params) override
624 {
625 detail::routing_handler_call_helper::Call<
626 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
627 0, 0, 0, 0, black_magic::S<Args...>, black_magic::S<>>()(
628 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
629 handler, params, req, res});
630 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700631
Ed Tanous1abe55e2018-09-05 08:30:59 -0700632 private:
633 std::function<void(const crow::Request&, crow::Response&, Args...)> handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700634};
635
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700636const int ruleSpecialRedirectSlash = 1;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700637
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638class Trie
639{
640 public:
641 struct Node
642 {
643 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700644 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
645 paramChildrens{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700646 boost::container::flat_map<std::string, unsigned> children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700647
Ed Tanous1abe55e2018-09-05 08:30:59 -0700648 bool isSimpleNode() const
649 {
650 return !ruleIndex && std::all_of(std::begin(paramChildrens),
651 std::end(paramChildrens),
Ed Tanous271584a2019-07-09 16:24:22 -0700652 [](size_t x) { return !x; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700653 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700654 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700655
Ed Tanous1abe55e2018-09-05 08:30:59 -0700656 Trie() : nodes(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500657 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700658
659 private:
660 void optimizeNode(Node* node)
661 {
Ed Tanous271584a2019-07-09 16:24:22 -0700662 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 {
664 if (!x)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700665 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 continue;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700667 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700668 Node* child = &nodes[x];
669 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700670 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 if (node->children.empty())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700672 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673 return;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700674 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700675 bool mergeWithChild = true;
Tanousf00032d2018-11-05 01:18:10 -0300676 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700677 {
678 Node* child = &nodes[kv.second];
679 if (!child->isSimpleNode())
680 {
681 mergeWithChild = false;
682 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700683 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700684 }
685 if (mergeWithChild)
686 {
687 decltype(node->children) merged;
Tanousf00032d2018-11-05 01:18:10 -0300688 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700689 {
690 Node* child = &nodes[kv.second];
Tanousf00032d2018-11-05 01:18:10 -0300691 for (const std::pair<std::string, unsigned>& childKv :
692 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700693 {
694 merged[kv.first + childKv.first] = childKv.second;
695 }
696 }
697 node->children = std::move(merged);
698 optimizeNode(node);
699 }
700 else
701 {
Tanousf00032d2018-11-05 01:18:10 -0300702 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700703 {
704 Node* child = &nodes[kv.second];
705 optimizeNode(child);
706 }
707 }
708 }
709
710 void optimize()
711 {
712 optimizeNode(head());
713 }
714
715 public:
716 void validate()
717 {
718 if (!head()->isSimpleNode())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700719 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700720 throw std::runtime_error(
721 "Internal error: Trie header should be simple!");
Ed Tanous3174e4d2020-10-07 11:41:22 -0700722 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700723 optimize();
724 }
725
726 void findRouteIndexes(const std::string& req_url,
727 std::vector<unsigned>& route_indexes,
Tanousf00032d2018-11-05 01:18:10 -0300728 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 {
730 if (node == nullptr)
731 {
732 node = head();
733 }
Tanousf00032d2018-11-05 01:18:10 -0300734 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700735 {
736 const std::string& fragment = kv.first;
737 const Node* child = &nodes[kv.second];
738 if (pos >= req_url.size())
739 {
740 if (child->ruleIndex != 0 && fragment != "/")
741 {
742 route_indexes.push_back(child->ruleIndex);
743 }
744 findRouteIndexes(req_url, route_indexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700745 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 }
747 else
748 {
749 if (req_url.compare(pos, fragment.size(), fragment) == 0)
750 {
Ed Tanous271584a2019-07-09 16:24:22 -0700751 findRouteIndexes(
752 req_url, route_indexes, child,
753 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700754 }
755 }
756 }
757 }
758
759 std::pair<unsigned, RoutingParams>
Ed Tanous39e77502019-03-04 17:35:53 -0800760 find(const std::string_view req_url, const Node* node = nullptr,
Ed Tanous271584a2019-07-09 16:24:22 -0700761 size_t pos = 0, RoutingParams* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700762 {
763 RoutingParams empty;
764 if (params == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700765 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766 params = &empty;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700767 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700768
769 unsigned found{};
770 RoutingParams matchParams;
771
772 if (node == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700773 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700774 node = head();
Ed Tanous3174e4d2020-10-07 11:41:22 -0700775 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700776 if (pos == req_url.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700777 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700778 return {node->ruleIndex, *params};
Ed Tanous3174e4d2020-10-07 11:41:22 -0700779 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700780
781 auto updateFound =
782 [&found, &matchParams](std::pair<unsigned, RoutingParams>& ret) {
783 if (ret.first && (!found || found > ret.first))
784 {
785 found = ret.first;
786 matchParams = std::move(ret.second);
787 }
788 };
789
Ed Tanous271584a2019-07-09 16:24:22 -0700790 if (node->paramChildrens[static_cast<size_t>(ParamType::INT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791 {
792 char c = req_url[pos];
793 if ((c >= '0' && c <= '9') || c == '+' || c == '-')
794 {
795 char* eptr;
796 errno = 0;
797 long long int value =
798 std::strtoll(req_url.data() + pos, &eptr, 10);
799 if (errno != ERANGE && eptr != req_url.data() + pos)
800 {
801 params->intParams.push_back(value);
Ed Tanous271584a2019-07-09 16:24:22 -0700802 std::pair<unsigned, RoutingParams> ret = find(
803 req_url,
804 &nodes[node->paramChildrens[static_cast<size_t>(
805 ParamType::INT)]],
806 static_cast<size_t>(eptr - req_url.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807 updateFound(ret);
808 params->intParams.pop_back();
809 }
810 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700811 }
812
Ed Tanous271584a2019-07-09 16:24:22 -0700813 if (node->paramChildrens[static_cast<size_t>(ParamType::UINT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700814 {
815 char c = req_url[pos];
816 if ((c >= '0' && c <= '9') || c == '+')
817 {
818 char* eptr;
819 errno = 0;
820 unsigned long long int value =
821 std::strtoull(req_url.data() + pos, &eptr, 10);
822 if (errno != ERANGE && eptr != req_url.data() + pos)
823 {
824 params->uintParams.push_back(value);
Ed Tanous271584a2019-07-09 16:24:22 -0700825 std::pair<unsigned, RoutingParams> ret = find(
826 req_url,
827 &nodes[node->paramChildrens[static_cast<size_t>(
828 ParamType::UINT)]],
829 static_cast<size_t>(eptr - req_url.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700830 updateFound(ret);
831 params->uintParams.pop_back();
832 }
833 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700834 }
835
Ed Tanous271584a2019-07-09 16:24:22 -0700836 if (node->paramChildrens[static_cast<size_t>(ParamType::DOUBLE)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700837 {
838 char c = req_url[pos];
839 if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
840 {
841 char* eptr;
842 errno = 0;
843 double value = std::strtod(req_url.data() + pos, &eptr);
844 if (errno != ERANGE && eptr != req_url.data() + pos)
845 {
846 params->doubleParams.push_back(value);
Tanousf00032d2018-11-05 01:18:10 -0300847 std::pair<unsigned, RoutingParams> ret = find(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700848 req_url,
Ed Tanous271584a2019-07-09 16:24:22 -0700849 &nodes[node->paramChildrens[static_cast<size_t>(
850 ParamType::DOUBLE)]],
851 static_cast<size_t>(eptr - req_url.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700852 updateFound(ret);
853 params->doubleParams.pop_back();
854 }
855 }
856 }
857
Ed Tanous271584a2019-07-09 16:24:22 -0700858 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700859 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000860 size_t epos = pos;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700861 for (; epos < req_url.size(); epos++)
862 {
863 if (req_url[epos] == '/')
Ed Tanous3174e4d2020-10-07 11:41:22 -0700864 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700865 break;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700866 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700867 }
868
869 if (epos != pos)
870 {
871 params->stringParams.emplace_back(
872 req_url.substr(pos, epos - pos));
Tanousf00032d2018-11-05 01:18:10 -0300873 std::pair<unsigned, RoutingParams> ret =
Ed Tanousb01bf292019-03-25 19:25:26 +0000874 find(req_url,
Ed Tanous271584a2019-07-09 16:24:22 -0700875 &nodes[node->paramChildrens[static_cast<size_t>(
876 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000877 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700878 updateFound(ret);
879 params->stringParams.pop_back();
880 }
881 }
882
Ed Tanous271584a2019-07-09 16:24:22 -0700883 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700884 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000885 size_t epos = req_url.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886
887 if (epos != pos)
888 {
889 params->stringParams.emplace_back(
890 req_url.substr(pos, epos - pos));
Ed Tanous271584a2019-07-09 16:24:22 -0700891 std::pair<unsigned, RoutingParams> ret =
892 find(req_url,
893 &nodes[node->paramChildrens[static_cast<size_t>(
894 ParamType::PATH)]],
895 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700896 updateFound(ret);
897 params->stringParams.pop_back();
898 }
899 }
900
Tanousf00032d2018-11-05 01:18:10 -0300901 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700902 {
903 const std::string& fragment = kv.first;
904 const Node* child = &nodes[kv.second];
905
906 if (req_url.compare(pos, fragment.size(), fragment) == 0)
907 {
Tanousf00032d2018-11-05 01:18:10 -0300908 std::pair<unsigned, RoutingParams> ret =
909 find(req_url, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700910 updateFound(ret);
911 }
912 }
913
914 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700915 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700916
917 void add(const std::string& url, unsigned ruleIndex)
918 {
Ed Tanous271584a2019-07-09 16:24:22 -0700919 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700920
921 for (unsigned i = 0; i < url.size(); i++)
922 {
923 char c = url[i];
924 if (c == '<')
925 {
Tanousf00032d2018-11-05 01:18:10 -0300926 const static std::array<std::pair<ParamType, std::string>, 7>
927 paramTraits = {{
928 {ParamType::INT, "<int>"},
929 {ParamType::UINT, "<uint>"},
930 {ParamType::DOUBLE, "<float>"},
931 {ParamType::DOUBLE, "<double>"},
932 {ParamType::STRING, "<str>"},
933 {ParamType::STRING, "<string>"},
934 {ParamType::PATH, "<path>"},
935 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700936
Tanousf00032d2018-11-05 01:18:10 -0300937 for (const std::pair<ParamType, std::string>& x : paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700938 {
Tanousf00032d2018-11-05 01:18:10 -0300939 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700940 {
Ed Tanous271584a2019-07-09 16:24:22 -0700941 size_t index = static_cast<size_t>(x.first);
942 if (!nodes[idx].paramChildrens[index])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700943 {
Tanousf00032d2018-11-05 01:18:10 -0300944 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700945 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700946 }
Ed Tanous271584a2019-07-09 16:24:22 -0700947 idx = nodes[idx].paramChildrens[index];
948 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700949 break;
950 }
951 }
952
953 i--;
954 }
955 else
956 {
957 std::string piece(&c, 1);
958 if (!nodes[idx].children.count(piece))
959 {
Tanousf00032d2018-11-05 01:18:10 -0300960 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700961 nodes[idx].children.emplace(piece, newNodeIdx);
962 }
963 idx = nodes[idx].children[piece];
964 }
965 }
966 if (nodes[idx].ruleIndex)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700967 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700968 throw std::runtime_error("handler already exists for " + url);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700969 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700970 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700971 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700972
Ed Tanous1abe55e2018-09-05 08:30:59 -0700973 private:
Ed Tanous271584a2019-07-09 16:24:22 -0700974 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700975 {
Ed Tanous271584a2019-07-09 16:24:22 -0700976 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700977 {
978 if (n->paramChildrens[i])
979 {
980 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -0700981 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
982 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700983 {
984 case ParamType::INT:
985 BMCWEB_LOG_DEBUG << "<int>";
986 break;
987 case ParamType::UINT:
988 BMCWEB_LOG_DEBUG << "<uint>";
989 break;
990 case ParamType::DOUBLE:
991 BMCWEB_LOG_DEBUG << "<float>";
992 break;
993 case ParamType::STRING:
994 BMCWEB_LOG_DEBUG << "<str>";
995 break;
996 case ParamType::PATH:
997 BMCWEB_LOG_DEBUG << "<path>";
998 break;
Ed Tanous23a21a12020-07-25 04:45:05 +0000999 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -07001000 BMCWEB_LOG_DEBUG << "<ERROR>";
1001 break;
1002 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001003
Ed Tanous1abe55e2018-09-05 08:30:59 -07001004 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
1005 }
1006 }
Tanousf00032d2018-11-05 01:18:10 -03001007 for (const std::pair<std::string, unsigned>& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001008 {
1009 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -07001010 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -07001011 << kv.first;
1012 debugNodePrint(&nodes[kv.second], level + 1);
1013 }
1014 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001015
Ed Tanous1abe55e2018-09-05 08:30:59 -07001016 public:
1017 void debugPrint()
1018 {
Ed Tanous271584a2019-07-09 16:24:22 -07001019 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001020 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001021
Ed Tanous1abe55e2018-09-05 08:30:59 -07001022 private:
1023 const Node* head() const
1024 {
1025 return &nodes.front();
1026 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001027
Ed Tanous1abe55e2018-09-05 08:30:59 -07001028 Node* head()
1029 {
1030 return &nodes.front();
1031 }
1032
1033 unsigned newNode()
1034 {
1035 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -07001036 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001037 }
1038
1039 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001040};
1041
Ed Tanous1abe55e2018-09-05 08:30:59 -07001042class Router
1043{
1044 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -07001045 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001046
Ed Tanous1abe55e2018-09-05 08:30:59 -07001047 DynamicRule& newRuleDynamic(const std::string& rule)
1048 {
1049 std::unique_ptr<DynamicRule> ruleObject =
1050 std::make_unique<DynamicRule>(rule);
1051 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001052 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -07001053
Ed Tanous1abe55e2018-09-05 08:30:59 -07001054 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001055 }
1056
Ed Tanous1abe55e2018-09-05 08:30:59 -07001057 template <uint64_t N>
1058 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
1059 newRuleTagged(const std::string& rule)
1060 {
1061 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
1062 TaggedRule>;
1063 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
1064 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001065 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001066
1067 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001068 }
1069
Tanousf00032d2018-11-05 01:18:10 -03001070 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001071 {
Tanousf00032d2018-11-05 01:18:10 -03001072 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001073 {
Tanousf00032d2018-11-05 01:18:10 -03001074 return;
1075 }
Ed Tanous888880a2020-08-24 13:48:50 -07001076 for (size_t method = 0, methodBit = 1; method < maxHttpVerbCount;
Ed Tanous2c70f802020-09-28 14:29:23 -07001077 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -03001078 {
Ed Tanous2c70f802020-09-28 14:29:23 -07001079 if (ruleObject->methodsBitfield & methodBit)
Tanousf00032d2018-11-05 01:18:10 -03001080 {
1081 perMethods[method].rules.emplace_back(ruleObject);
1082 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -07001083 rule, static_cast<unsigned>(
1084 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -03001085 // directory case:
1086 // request to `/about' url matches `/about/' rule
1087 if (rule.size() > 2 && rule.back() == '/')
1088 {
1089 perMethods[method].trie.add(
1090 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -07001091 static_cast<unsigned>(perMethods[method].rules.size() -
1092 1));
Tanousf00032d2018-11-05 01:18:10 -03001093 }
1094 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001095 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001096 }
1097
Ed Tanous1abe55e2018-09-05 08:30:59 -07001098 void validate()
1099 {
Tanousf00032d2018-11-05 01:18:10 -03001100 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001101 {
1102 if (rule)
1103 {
Tanousf00032d2018-11-05 01:18:10 -03001104 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001105 if (upgraded)
Ed Tanous3174e4d2020-10-07 11:41:22 -07001106 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001107 rule = std::move(upgraded);
Ed Tanous3174e4d2020-10-07 11:41:22 -07001108 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001109 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -03001110 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001111 }
1112 }
Tanousf00032d2018-11-05 01:18:10 -03001113 for (PerMethod& perMethod : perMethods)
1114 {
1115 perMethod.trie.validate();
1116 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001117 }
1118
Ed Tanous1abe55e2018-09-05 08:30:59 -07001119 template <typename Adaptor>
1120 void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
1121 {
Ed Tanous271584a2019-07-09 16:24:22 -07001122 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001123 {
1124 res.result(boost::beast::http::status::not_found);
1125 res.end();
Tanousf00032d2018-11-05 01:18:10 -03001126 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001127 }
Tanousf00032d2018-11-05 01:18:10 -03001128
Ed Tanous271584a2019-07-09 16:24:22 -07001129 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001130 Trie& trie = perMethod.trie;
1131 std::vector<BaseRule*>& rules = perMethod.rules;
1132
1133 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001134 unsigned ruleIndex = found.first;
1135 if (!ruleIndex)
1136 {
1137 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001138 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001139 res.end();
1140 return;
1141 }
1142
1143 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001144 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001145 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001146 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001147
1148 if (ruleIndex == ruleSpecialRedirectSlash)
1149 {
1150 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1151 << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001152 res.result(boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001153
1154 // TODO absolute url building
1155 if (req.getHeaderValue("Host").empty())
1156 {
1157 res.addHeader("Location", std::string(req.url) + "/");
1158 }
1159 else
1160 {
1161 res.addHeader(
1162 "Location",
1163 req.isSecure
1164 ? "https://"
1165 : "http://" + std::string(req.getHeaderValue("Host")) +
1166 std::string(req.url) + "/");
1167 }
1168 res.end();
1169 return;
1170 }
1171
Ed Tanous271584a2019-07-09 16:24:22 -07001172 if ((rules[ruleIndex]->getMethods() &
1173 (1U << static_cast<size_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001174 {
1175 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1176 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001177 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001178 << rules[ruleIndex]->getMethods();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001179 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001180 res.end();
1181 return;
1182 }
1183
1184 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rules[ruleIndex]->rule
Ed Tanous271584a2019-07-09 16:24:22 -07001185 << "' " << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001186 << rules[ruleIndex]->getMethods();
1187
1188 // any uncaught exceptions become 500s
1189 try
1190 {
1191 rules[ruleIndex]->handleUpgrade(req, res, std::move(adaptor));
1192 }
1193 catch (std::exception& e)
1194 {
1195 BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001196 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001197 res.end();
1198 return;
1199 }
1200 catch (...)
1201 {
1202 BMCWEB_LOG_ERROR
1203 << "An uncaught exception occurred. The type was unknown "
1204 "so no information was available.";
Ed Tanousde5c9f32019-03-26 09:17:55 -07001205 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001206 res.end();
1207 return;
1208 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001209 }
1210
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001211 void handle(Request& req, Response& res)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001212 {
Ed Tanous271584a2019-07-09 16:24:22 -07001213 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001214 {
1215 res.result(boost::beast::http::status::not_found);
1216 res.end();
Tanousf00032d2018-11-05 01:18:10 -03001217 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001218 }
Ed Tanous271584a2019-07-09 16:24:22 -07001219 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001220 Trie& trie = perMethod.trie;
1221 std::vector<BaseRule*>& rules = perMethod.rules;
1222
1223 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001224
Ed Tanous1abe55e2018-09-05 08:30:59 -07001225 unsigned ruleIndex = found.first;
1226
1227 if (!ruleIndex)
1228 {
Ed Tanous2634dcd2019-03-26 09:28:06 -07001229 // Check to see if this url exists at any verb
1230 for (const PerMethod& p : perMethods)
1231 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001232 const std::pair<unsigned, RoutingParams>& found2 =
Ed Tanous2634dcd2019-03-26 09:28:06 -07001233 p.trie.find(req.url);
Ed Tanous23a21a12020-07-25 04:45:05 +00001234 if (found2.first > 0)
Ed Tanous2634dcd2019-03-26 09:28:06 -07001235 {
1236 res.result(boost::beast::http::status::method_not_allowed);
1237 res.end();
1238 return;
1239 }
1240 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001241 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
1242 res.result(boost::beast::http::status::not_found);
1243 res.end();
1244 return;
1245 }
1246
1247 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001248 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001249 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001250 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001251
1252 if (ruleIndex == ruleSpecialRedirectSlash)
1253 {
1254 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1255 << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001256 res.result(boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001257
1258 // TODO absolute url building
1259 if (req.getHeaderValue("Host").empty())
1260 {
1261 res.addHeader("Location", std::string(req.url) + "/");
1262 }
1263 else
1264 {
1265 res.addHeader("Location",
1266 (req.isSecure ? "https://" : "http://") +
1267 std::string(req.getHeaderValue("Host")) +
1268 std::string(req.url) + "/");
1269 }
1270 res.end();
1271 return;
1272 }
1273
Ed Tanous271584a2019-07-09 16:24:22 -07001274 if ((rules[ruleIndex]->getMethods() &
1275 (1U << static_cast<uint32_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001276 {
1277 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1278 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001279 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001280 << rules[ruleIndex]->getMethods();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001281 res.result(boost::beast::http::status::method_not_allowed);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001282 res.end();
1283 return;
1284 }
1285
1286 BMCWEB_LOG_DEBUG << "Matched rule '" << rules[ruleIndex]->rule << "' "
Ed Tanous271584a2019-07-09 16:24:22 -07001287 << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001288 << rules[ruleIndex]->getMethods();
1289
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001290 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001291 {
1292 rules[ruleIndex]->handle(req, res, found.second);
James Feist7166bf02019-12-10 16:52:14 +00001293 return;
1294 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001295
1296 crow::connections::systemBus->async_method_call(
1297 [&req, &res, &rules, ruleIndex, found](
1298 const boost::system::error_code ec,
1299 std::map<std::string, std::variant<bool, std::string,
1300 std::vector<std::string>>>
1301 userInfo) {
1302 if (ec)
1303 {
1304 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
1305 res.result(
1306 boost::beast::http::status::internal_server_error);
1307 res.end();
1308 return;
1309 }
1310
1311 const std::string* userRolePtr = nullptr;
1312 auto userInfoIter = userInfo.find("UserPrivilege");
1313 if (userInfoIter != userInfo.end())
1314 {
1315 userRolePtr =
1316 std::get_if<std::string>(&userInfoIter->second);
1317 }
1318
1319 std::string userRole{};
1320 if (userRolePtr != nullptr)
1321 {
1322 userRole = *userRolePtr;
1323 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1324 << " userRole = " << *userRolePtr;
1325 }
1326
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001327 bool* remoteUserPtr = nullptr;
1328 auto remoteUserIter = userInfo.find("RemoteUser");
1329 if (remoteUserIter != userInfo.end())
1330 {
1331 remoteUserPtr = std::get_if<bool>(&remoteUserIter->second);
1332 }
1333 if (remoteUserPtr == nullptr)
1334 {
1335 BMCWEB_LOG_ERROR
1336 << "RemoteUser property missing or wrong type";
1337 res.result(
1338 boost::beast::http::status::internal_server_error);
1339 res.end();
1340 return;
1341 }
1342 bool remoteUser = *remoteUserPtr;
1343
1344 bool passwordExpired = false; // default for remote user
1345 if (!remoteUser)
1346 {
1347 bool* passwordExpiredPtr = nullptr;
1348 auto passwordExpiredIter =
1349 userInfo.find("UserPasswordExpired");
1350 if (passwordExpiredIter != userInfo.end())
1351 {
1352 passwordExpiredPtr =
1353 std::get_if<bool>(&passwordExpiredIter->second);
1354 }
1355 if (passwordExpiredPtr != nullptr)
1356 {
1357 passwordExpired = *passwordExpiredPtr;
1358 }
1359 else
1360 {
1361 BMCWEB_LOG_ERROR
1362 << "UserPasswordExpired property is expected for"
1363 " local user but is missing or wrong type";
1364 res.result(
1365 boost::beast::http::status::internal_server_error);
1366 res.end();
1367 return;
1368 }
1369 }
1370
Ed Tanous23a21a12020-07-25 04:45:05 +00001371 // Get the userprivileges from the role
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001372 redfish::Privileges userPrivileges =
1373 redfish::getUserPrivileges(userRole);
1374
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001375 // Set isConfigureSelfOnly based on D-Bus results. This
1376 // ignores the results from both pamAuthenticateUser and the
1377 // value from any previous use of this session.
1378 req.session->isConfigureSelfOnly = passwordExpired;
1379
Ed Tanous23a21a12020-07-25 04:45:05 +00001380 // Modifyprivileges if isConfigureSelfOnly.
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001381 if (req.session->isConfigureSelfOnly)
1382 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001383 // Remove allprivileges except ConfigureSelf
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001384 userPrivileges = userPrivileges.intersection(
1385 redfish::Privileges{"ConfigureSelf"});
1386 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1387 }
1388
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001389 if (!rules[ruleIndex]->checkPrivileges(userPrivileges))
1390 {
1391 res.result(boost::beast::http::status::forbidden);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001392 if (req.session->isConfigureSelfOnly)
1393 {
1394 redfish::messages::passwordChangeRequired(
1395 res, "/redfish/v1/AccountService/Accounts/" +
1396 req.session->username);
1397 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001398 res.end();
1399 return;
1400 }
1401
1402 req.userRole = userRole;
1403
1404 rules[ruleIndex]->handle(req, res, found.second);
1405 },
1406 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1407 "xyz.openbmc_project.User.Manager", "GetUserInfo",
1408 req.session->username);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001409 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001410
Ed Tanous1abe55e2018-09-05 08:30:59 -07001411 void debugPrint()
1412 {
Ed Tanous271584a2019-07-09 16:24:22 -07001413 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001414 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001415 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1416 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001417 perMethods[i].trie.debugPrint();
1418 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001419 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001420
Ed Tanous1abe55e2018-09-05 08:30:59 -07001421 std::vector<const std::string*> getRoutes(const std::string& parent)
1422 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001423 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001424
1425 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001426 {
Tanousf00032d2018-11-05 01:18:10 -03001427 std::vector<unsigned> x;
1428 pm.trie.findRouteIndexes(parent, x);
1429 for (unsigned index : x)
1430 {
1431 ret.push_back(&pm.rules[index]->rule);
1432 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001433 }
1434 return ret;
1435 }
1436
1437 private:
Tanousf00032d2018-11-05 01:18:10 -03001438 struct PerMethod
1439 {
1440 std::vector<BaseRule*> rules;
1441 Trie trie;
1442 // rule index 0, 1 has special meaning; preallocate it to avoid
1443 // duplication.
1444 PerMethod() : rules(2)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001445 {}
Tanousf00032d2018-11-05 01:18:10 -03001446 };
Ed Tanous888880a2020-08-24 13:48:50 -07001447
1448 const static size_t maxHttpVerbCount =
Ed Tanouscc090442020-10-07 08:20:50 -07001449 static_cast<size_t>(boost::beast::http::verb::unlink);
Ed Tanous888880a2020-08-24 13:48:50 -07001450
Tanousf00032d2018-11-05 01:18:10 -03001451 std::array<PerMethod, maxHttpVerbCount> perMethods;
1452 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001453};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001454} // namespace crow