blob: 5d9c8e307cc0ae191cd717ea15d803d8a49374f9 [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
2
Ed Tanous04e438c2020-10-03 08:06:26 -07003#include "common.hpp"
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06004#include "error_messages.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -07005#include "http_request.hpp"
6#include "http_response.hpp"
7#include "logging.hpp"
Tanousf00032d2018-11-05 01:18:10 -03008#include "privileges.hpp"
Ratan Gupta6f359562019-04-03 10:39:08 +05309#include "sessions.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -070010#include "utility.hpp"
11#include "websocket.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070012
Iwona Klimaszewskac0a1c8a2019-07-12 18:26:38 +020013#include <async_resp.hpp>
Tanousf00032d2018-11-05 01:18:10 -030014#include <boost/container/flat_map.hpp>
15#include <boost/container/small_vector.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070016#include <boost/lexical_cast.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050017
Ed Tanouse0d918b2018-03-27 17:41:04 -070018#include <cerrno>
Ed Tanous7045c8d2017-04-03 10:04:37 -070019#include <cstdint>
Ed Tanouse0d918b2018-03-27 17:41:04 -070020#include <cstdlib>
Ed Tanous3dac7492017-08-02 13:46:20 -070021#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070022#include <memory>
23#include <tuple>
Ed Tanous7045c8d2017-04-03 10:04:37 -070024#include <utility>
25#include <vector>
Ed Tanous9140a672017-04-24 17:01:32 -070026
Ed Tanous1abe55e2018-09-05 08:30:59 -070027namespace crow
28{
Tanousf00032d2018-11-05 01:18:10 -030029
Ed Tanous1abe55e2018-09-05 08:30:59 -070030class BaseRule
31{
32 public:
Ed Tanousf23b7292020-10-15 09:41:17 -070033 BaseRule(const std::string& thisRule) : rule(thisRule)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050034 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070035
Ed Tanous0c0084a2019-10-24 15:57:51 -070036 virtual ~BaseRule() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -070037
Ed Tanous1abe55e2018-09-05 08:30:59 -070038 virtual void validate() = 0;
39 std::unique_ptr<BaseRule> upgrade()
40 {
41 if (ruleToUpgrade)
Ed Tanous3174e4d2020-10-07 11:41:22 -070042 {
Ed Tanous1abe55e2018-09-05 08:30:59 -070043 return std::move(ruleToUpgrade);
Ed Tanous3174e4d2020-10-07 11:41:22 -070044 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070045 return {};
46 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070047
zhanghch058d1b46d2021-04-01 11:18:24 +080048 virtual void handle(const Request&,
49 const std::shared_ptr<bmcweb::AsyncResp>&,
50 const RoutingParams&) = 0;
Ed Tanousceac6f72018-12-02 11:58:47 -080051 virtual void handleUpgrade(const Request&, Response& res,
52 boost::asio::ip::tcp::socket&&)
Ed Tanous1abe55e2018-09-05 08:30:59 -070053 {
Ed Tanousde5c9f32019-03-26 09:17:55 -070054 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070055 res.end();
56 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -070057#ifdef BMCWEB_ENABLE_SSL
Ed Tanousceac6f72018-12-02 11:58:47 -080058 virtual void
59 handleUpgrade(const Request&, Response& res,
60 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&)
Ed Tanous1abe55e2018-09-05 08:30:59 -070061 {
Ed Tanousde5c9f32019-03-26 09:17:55 -070062 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070063 res.end();
64 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070065#endif
66
Ed Tanous271584a2019-07-09 16:24:22 -070067 size_t getMethods()
Ed Tanous1abe55e2018-09-05 08:30:59 -070068 {
69 return methodsBitfield;
70 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070071
Tanousf00032d2018-11-05 01:18:10 -030072 bool checkPrivileges(const redfish::Privileges& userPrivileges)
73 {
74 // If there are no privileges assigned, assume no privileges
75 // required
76 if (privilegesSet.empty())
77 {
78 return true;
79 }
80
81 for (const redfish::Privileges& requiredPrivileges : privilegesSet)
82 {
83 if (userPrivileges.isSupersetOf(requiredPrivileges))
84 {
85 return true;
86 }
87 }
88 return false;
89 }
90
Ed Tanous271584a2019-07-09 16:24:22 -070091 size_t methodsBitfield{
92 1 << static_cast<size_t>(boost::beast::http::verb::get)};
Ed Tanous7045c8d2017-04-03 10:04:37 -070093
Tanousf00032d2018-11-05 01:18:10 -030094 std::vector<redfish::Privileges> privilegesSet;
95
Ed Tanous1abe55e2018-09-05 08:30:59 -070096 std::string rule;
97 std::string nameStr;
Ed Tanous7045c8d2017-04-03 10:04:37 -070098
Ed Tanous1abe55e2018-09-05 08:30:59 -070099 std::unique_ptr<BaseRule> ruleToUpgrade;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700100
Ed Tanous1abe55e2018-09-05 08:30:59 -0700101 friend class Router;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500102 template <typename T>
103 friend struct RuleParameterTraits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700104};
105
Ed Tanous1abe55e2018-09-05 08:30:59 -0700106namespace detail
107{
108namespace routing_handler_call_helper
109{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500110template <typename T, int Pos>
111struct CallPair
Ed Tanous1abe55e2018-09-05 08:30:59 -0700112{
113 using type = T;
114 static const int pos = Pos;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700115};
116
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500117template <typename H1>
118struct CallParams
Ed Tanous1abe55e2018-09-05 08:30:59 -0700119{
120 H1& handler;
121 const RoutingParams& params;
122 const Request& req;
zhanghch058d1b46d2021-04-01 11:18:24 +0800123 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700124};
125
126template <typename F, int NInt, int NUint, int NDouble, int NString,
127 typename S1, typename S2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128struct Call
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500129{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700130
131template <typename F, int NInt, int NUint, int NDouble, int NString,
132 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700133struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<int64_t, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700134 black_magic::S<Args2...>>
135{
136 void operator()(F cparams)
137 {
138 using pushed = typename black_magic::S<Args2...>::template push_back<
139 CallPair<int64_t, NInt>>;
140 Call<F, NInt + 1, NUint, NDouble, NString, black_magic::S<Args1...>,
141 pushed>()(cparams);
142 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700143};
144
145template <typename F, int NInt, int NUint, int NDouble, int NString,
146 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700147struct Call<F, NInt, NUint, NDouble, NString,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700148 black_magic::S<uint64_t, Args1...>, black_magic::S<Args2...>>
149{
150 void operator()(F cparams)
151 {
152 using pushed = typename black_magic::S<Args2...>::template push_back<
153 CallPair<uint64_t, NUint>>;
154 Call<F, NInt, NUint + 1, NDouble, NString, black_magic::S<Args1...>,
155 pushed>()(cparams);
156 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700157};
158
159template <typename F, int NInt, int NUint, int NDouble, int NString,
160 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700161struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<double, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700162 black_magic::S<Args2...>>
163{
164 void operator()(F cparams)
165 {
166 using pushed = typename black_magic::S<Args2...>::template push_back<
167 CallPair<double, NDouble>>;
168 Call<F, NInt, NUint, NDouble + 1, NString, black_magic::S<Args1...>,
169 pushed>()(cparams);
170 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700171};
172
173template <typename F, int NInt, int NUint, int NDouble, int NString,
174 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700175struct Call<F, NInt, NUint, NDouble, NString,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700176 black_magic::S<std::string, Args1...>, black_magic::S<Args2...>>
177{
178 void operator()(F cparams)
179 {
180 using pushed = typename black_magic::S<Args2...>::template push_back<
181 CallPair<std::string, NString>>;
182 Call<F, NInt, NUint, NDouble, NString + 1, black_magic::S<Args1...>,
183 pushed>()(cparams);
184 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700185};
186
187template <typename F, int NInt, int NUint, int NDouble, int NString,
188 typename... Args1>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700189struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700190 black_magic::S<Args1...>>
191{
192 void operator()(F cparams)
193 {
194 cparams.handler(
zhanghch058d1b46d2021-04-01 11:18:24 +0800195 cparams.req, cparams.asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700196 cparams.params.template get<typename Args1::type>(Args1::pos)...);
197 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700198};
199
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500200template <typename Func, typename... ArgsWrapped>
201struct Wrapped
Ed Tanous1abe55e2018-09-05 08:30:59 -0700202{
203 template <typename... Args>
204 void set(
205 Func f,
206 typename std::enable_if<
207 !std::is_same<
208 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
209 const Request&>::value,
210 int>::type = 0)
211 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800212 handler = [f = std::move(f)](
213 const Request&,
214 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
215 Args... args) { asyncResp->res.result(f(args...)); };
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
zhanghch058d1b46d2021-04-01 11:18:24 +0800224 void operator()(const Request& req,
225 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
226 Args... args)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700227 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800228 asyncResp->res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700229 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700230
Ed Tanous1abe55e2018-09-05 08:30:59 -0700231 Func f;
232 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700233
Ed Tanous1abe55e2018-09-05 08:30:59 -0700234 template <typename... Args>
235 void set(
236 Func f,
237 typename std::enable_if<
238 std::is_same<
239 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
240 const Request&>::value &&
241 !std::is_same<typename std::tuple_element<
242 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800243 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700244 int>::type = 0)
245 {
246 handler = ReqHandlerWrapper<Args...>(std::move(f));
247 /*handler = (
248 [f = std::move(f)]
249 (const Request& req, Response& res, Args... args){
Ed Tanousde5c9f32019-03-26 09:17:55 -0700250 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700251 res.end();
252 });*/
253 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700254
Ed Tanous1abe55e2018-09-05 08:30:59 -0700255 template <typename... Args>
256 void set(
257 Func f,
258 typename std::enable_if<
259 std::is_same<
260 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
261 const Request&>::value &&
262 std::is_same<typename std::tuple_element<
263 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800264 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700265 int>::type = 0)
266 {
267 handler = std::move(f);
268 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700269
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500270 template <typename... Args>
271 struct HandlerTypeHelper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700272 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800273 using type = std::function<void(
274 const crow::Request&, const std::shared_ptr<bmcweb::AsyncResp>&,
275 Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700276 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700277 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700278 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700279
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280 template <typename... Args>
281 struct HandlerTypeHelper<const Request&, Args...>
282 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800283 using type = std::function<void(
284 const crow::Request&, const std::shared_ptr<bmcweb::AsyncResp>&,
285 Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700286 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700287 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700288 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700289
Ed Tanous1abe55e2018-09-05 08:30:59 -0700290 template <typename... Args>
zhanghch058d1b46d2021-04-01 11:18:24 +0800291 struct HandlerTypeHelper<const Request&,
292 const std::shared_ptr<bmcweb::AsyncResp>&, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700293 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800294 using type = std::function<void(
295 const crow::Request&, const std::shared_ptr<bmcweb::AsyncResp>&,
296 Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700297 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700298 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700299 };
300
301 typename HandlerTypeHelper<ArgsWrapped...>::type handler;
302
zhanghch058d1b46d2021-04-01 11:18:24 +0800303 void operator()(const Request& req,
304 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700305 const RoutingParams& params)
306 {
307 detail::routing_handler_call_helper::Call<
308 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
309 0, 0, 0, 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
310 black_magic::S<>>()(
311 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800312 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700313 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700314};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700315} // namespace routing_handler_call_helper
316} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700317
Ed Tanous1abe55e2018-09-05 08:30:59 -0700318class WebSocketRule : public BaseRule
319{
320 using self_t = WebSocketRule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700321
Ed Tanous1abe55e2018-09-05 08:30:59 -0700322 public:
Ed Tanousf23b7292020-10-15 09:41:17 -0700323 WebSocketRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500324 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700325
Ed Tanous1abe55e2018-09-05 08:30:59 -0700326 void validate() override
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500327 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700328
zhanghch058d1b46d2021-04-01 11:18:24 +0800329 void handle(const Request&,
330 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
331 const RoutingParams&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700332 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800333 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700334 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700335
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000336 void handleUpgrade(const Request& req, Response&,
Ed Tanousceac6f72018-12-02 11:58:47 -0800337 boost::asio::ip::tcp::socket&& adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700338 {
Ratan Gupta02453b12019-10-22 14:43:36 +0530339 std::shared_ptr<
340 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>
341 myConnection = std::make_shared<
342 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000343 req, std::move(adaptor), openHandler, messageHandler,
Ratan Gupta02453b12019-10-22 14:43:36 +0530344 closeHandler, errorHandler);
345 myConnection->start();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700346 }
347#ifdef BMCWEB_ENABLE_SSL
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000348 void handleUpgrade(const Request& req, Response&,
Ed Tanousceac6f72018-12-02 11:58:47 -0800349 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
350 adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700351 {
Ed Tanousceac6f72018-12-02 11:58:47 -0800352 std::shared_ptr<crow::websocket::ConnectionImpl<
353 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
354 myConnection = std::make_shared<crow::websocket::ConnectionImpl<
355 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000356 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanousceac6f72018-12-02 11:58:47 -0800357 closeHandler, errorHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700358 myConnection->start();
359 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700360#endif
361
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500362 template <typename Func>
363 self_t& onopen(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700364 {
365 openHandler = 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& onmessage(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700371 {
372 messageHandler = 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& onclose(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700378 {
379 closeHandler = f;
380 return *this;
381 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700382
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500383 template <typename Func>
384 self_t& onerror(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700385 {
386 errorHandler = f;
387 return *this;
388 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700389
Ed Tanous1abe55e2018-09-05 08:30:59 -0700390 protected:
Iwona Klimaszewskac0a1c8a2019-07-12 18:26:38 +0200391 std::function<void(crow::websocket::Connection&,
392 std::shared_ptr<bmcweb::AsyncResp>)>
393 openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700394 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
395 messageHandler;
396 std::function<void(crow::websocket::Connection&, const std::string&)>
397 closeHandler;
398 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700399};
400
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500401template <typename T>
402struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700403{
404 using self_t = T;
405 WebSocketRule& websocket()
406 {
Ed Tanous271584a2019-07-09 16:24:22 -0700407 self_t* self = static_cast<self_t*>(this);
408 WebSocketRule* p = new WebSocketRule(self->rule);
409 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700410 return *p;
411 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700412
Ed Tanousf23b7292020-10-15 09:41:17 -0700413 self_t& name(const std::string_view name) noexcept
Ed Tanous1abe55e2018-09-05 08:30:59 -0700414 {
Ed Tanous271584a2019-07-09 16:24:22 -0700415 self_t* self = static_cast<self_t*>(this);
Ed Tanousf23b7292020-10-15 09:41:17 -0700416 self->nameStr = name;
Ed Tanous271584a2019-07-09 16:24:22 -0700417 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 self_t& methods(boost::beast::http::verb method)
421 {
Ed Tanous271584a2019-07-09 16:24:22 -0700422 self_t* self = static_cast<self_t*>(this);
423 self->methodsBitfield = 1U << static_cast<size_t>(method);
424 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700425 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700426
Ed Tanous1abe55e2018-09-05 08:30:59 -0700427 template <typename... MethodArgs>
Ed Tanous81ce6092020-12-17 16:54:55 +0000428 self_t& methods(boost::beast::http::verb method, MethodArgs... argsMethod)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700429 {
Ed Tanous271584a2019-07-09 16:24:22 -0700430 self_t* self = static_cast<self_t*>(this);
Ed Tanous81ce6092020-12-17 16:54:55 +0000431 methods(argsMethod...);
Ed Tanous271584a2019-07-09 16:24:22 -0700432 self->methodsBitfield |= 1U << static_cast<size_t>(method);
433 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700434 }
Tanousf00032d2018-11-05 01:18:10 -0300435
Ed Tanous432a8902021-06-14 15:28:56 -0700436 self_t& privileges(
437 const std::initializer_list<std::initializer_list<const char*>>& p)
Tanousf00032d2018-11-05 01:18:10 -0300438 {
Ed Tanous271584a2019-07-09 16:24:22 -0700439 self_t* self = static_cast<self_t*>(this);
Ed Tanous432a8902021-06-14 15:28:56 -0700440 for (const std::initializer_list<const char*>& privilege : p)
Tanousf00032d2018-11-05 01:18:10 -0300441 {
Ed Tanous271584a2019-07-09 16:24:22 -0700442 self->privilegesSet.emplace_back(privilege);
Tanousf00032d2018-11-05 01:18:10 -0300443 }
Ed Tanous271584a2019-07-09 16:24:22 -0700444 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300445 }
Ed Tanoused398212021-06-09 17:05:54 -0700446
447 template <size_t N, typename... MethodArgs>
448 self_t& privileges(const std::array<redfish::Privileges, N>& p)
449 {
450 self_t* self = static_cast<self_t*>(this);
451 for (const redfish::Privileges& privilege : p)
452 {
453 self->privilegesSet.emplace_back(privilege);
454 }
455 return *self;
456 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700457};
458
Ed Tanous1abe55e2018-09-05 08:30:59 -0700459class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
460{
461 public:
Ed Tanousf23b7292020-10-15 09:41:17 -0700462 DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500463 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700464
Ed Tanous1abe55e2018-09-05 08:30:59 -0700465 void validate() override
466 {
467 if (!erasedHandler)
468 {
469 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
470 "no handler for url " + rule);
471 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700472 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700473
zhanghch058d1b46d2021-04-01 11:18:24 +0800474 void handle(const Request& req,
475 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700476 const RoutingParams& params) override
477 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800478 erasedHandler(req, asyncResp, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700480
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500481 template <typename Func>
482 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700483 {
484 using function_t = utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700485 erasedHandler =
Ed Tanous988403c2020-08-24 11:29:49 -0700486 wrap(std::move(f),
487 std::make_integer_sequence<unsigned, function_t::arity>{});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700488 }
489
490 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500491 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700492 // enable_if Arg1 != request
493
494 template <typename Func, unsigned... Indices>
zhanghch058d1b46d2021-04-01 11:18:24 +0800495 std::function<void(const Request&,
496 const std::shared_ptr<bmcweb::AsyncResp>&,
497 const RoutingParams&)>
Ed Tanous988403c2020-08-24 11:29:49 -0700498 wrap(Func f, std::integer_sequence<unsigned, Indices...>)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700499 {
Ed Tanous988403c2020-08-24 11:29:49 -0700500 using function_t = crow::utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700501
502 if (!black_magic::isParameterTagCompatible(
Ed Tanous988403c2020-08-24 11:29:49 -0700503 black_magic::getParameterTag(rule.c_str()),
504 black_magic::computeParameterTagFromArgsList<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700505 typename function_t::template arg<Indices>...>::value))
506 {
507 throw std::runtime_error("routeDynamic: Handler type is mismatched "
508 "with URL parameters: " +
509 rule);
510 }
511 auto ret = detail::routing_handler_call_helper::Wrapped<
512 Func, typename function_t::template arg<Indices>...>();
513 ret.template set<typename function_t::template arg<Indices>...>(
514 std::move(f));
515 return ret;
516 }
517
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500518 template <typename Func>
519 void operator()(std::string name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520 {
521 nameStr = std::move(name);
522 (*this).template operator()<Func>(std::forward(f));
523 }
524
525 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800526 std::function<void(const Request&,
527 const std::shared_ptr<bmcweb::AsyncResp>&,
528 const RoutingParams&)>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700529 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700530};
531
532template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500533class TaggedRule :
534 public BaseRule,
535 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536{
537 public:
538 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700539
Ed Tanousf23b7292020-10-15 09:41:17 -0700540 TaggedRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500541 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700542
Ed Tanous1abe55e2018-09-05 08:30:59 -0700543 void validate() override
544 {
545 if (!handler)
546 {
547 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
548 "no handler for url " + rule);
549 }
550 }
551
552 template <typename Func>
553 typename std::enable_if<
554 black_magic::CallHelper<Func, black_magic::S<Args...>>::value,
555 void>::type
556 operator()(Func&& f)
557 {
558 static_assert(
559 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
560 black_magic::CallHelper<
561 Func, black_magic::S<crow::Request, Args...>>::value,
562 "Handler type is mismatched with URL parameters");
563 static_assert(
564 !std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
565 "Handler function cannot have void return type; valid return "
566 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500567 "string, int, crow::response, nlohmann::json");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700568
zhanghch058d1b46d2021-04-01 11:18:24 +0800569 handler = [f = std::move(f)](
570 const Request&,
571 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
572 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700573 }
574
575 template <typename Func>
576 typename std::enable_if<
577 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
Ed Tanous7045c8d2017-04-03 10:04:37 -0700578 black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700579 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700580 void>::type
581 operator()(Func&& f)
582 {
583 static_assert(
584 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
585 black_magic::CallHelper<
586 Func, black_magic::S<crow::Request, Args...>>::value,
587 "Handler type is mismatched with URL parameters");
588 static_assert(
589 !std::is_same<void, decltype(f(std::declval<crow::Request>(),
590 std::declval<Args>()...))>::value,
591 "Handler function cannot have void return type; valid return "
592 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500593 "string, int, crow::response,nlohmann::json");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700594
zhanghch058d1b46d2021-04-01 11:18:24 +0800595 handler = [f = std::move(f)](
596 const crow::Request& req,
597 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
598 Args... args) { asyncResp->res.result(f(req, args...)); };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700600
Ed Tanous1abe55e2018-09-05 08:30:59 -0700601 template <typename Func>
602 typename std::enable_if<
603 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
604 !black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700605 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700606 void>::type
607 operator()(Func&& f)
608 {
609 static_assert(
610 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
611 black_magic::CallHelper<
612 Func, black_magic::S<crow::Request, Args...>>::value ||
613 black_magic::CallHelper<
zhanghch058d1b46d2021-04-01 11:18:24 +0800614 Func, black_magic::S<crow::Request,
615 std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700616 Args...>>::value,
617 "Handler type is mismatched with URL parameters");
618 static_assert(
zhanghch058d1b46d2021-04-01 11:18:24 +0800619 std::is_same<
620 void,
621 decltype(f(std::declval<crow::Request>(),
622 std::declval<std::shared_ptr<bmcweb::AsyncResp>&>(),
623 std::declval<Args>()...))>::value,
Tanousf00032d2018-11-05 01:18:10 -0300624 "Handler function with response argument should have void "
625 "return "
Ed Tanous1abe55e2018-09-05 08:30:59 -0700626 "type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700627
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 handler = std::move(f);
629 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700630
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500631 template <typename Func>
Ed Tanousf23b7292020-10-15 09:41:17 -0700632 void operator()(const std::string_view name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700633 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700634 nameStr = name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700635 (*this).template operator()<Func>(std::forward(f));
636 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700637
zhanghch058d1b46d2021-04-01 11:18:24 +0800638 void handle(const Request& req,
639 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700640 const RoutingParams& params) override
641 {
642 detail::routing_handler_call_helper::Call<
643 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
644 0, 0, 0, 0, black_magic::S<Args...>, black_magic::S<>>()(
645 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800646 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700647 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700648
Ed Tanous1abe55e2018-09-05 08:30:59 -0700649 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800650 std::function<void(const crow::Request&,
651 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>
652 handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700653};
654
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700655const int ruleSpecialRedirectSlash = 1;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700656
Ed Tanous1abe55e2018-09-05 08:30:59 -0700657class Trie
658{
659 public:
660 struct Node
661 {
662 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700663 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
664 paramChildrens{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 boost::container::flat_map<std::string, unsigned> children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700666
Ed Tanous1abe55e2018-09-05 08:30:59 -0700667 bool isSimpleNode() const
668 {
669 return !ruleIndex && std::all_of(std::begin(paramChildrens),
670 std::end(paramChildrens),
Ed Tanous271584a2019-07-09 16:24:22 -0700671 [](size_t x) { return !x; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700672 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700673 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700674
Ed Tanous1abe55e2018-09-05 08:30:59 -0700675 Trie() : nodes(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500676 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700677
678 private:
679 void optimizeNode(Node* node)
680 {
Ed Tanous271584a2019-07-09 16:24:22 -0700681 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700682 {
683 if (!x)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700684 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685 continue;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700686 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700687 Node* child = &nodes[x];
688 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700689 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700690 if (node->children.empty())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700691 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 return;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700693 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700694 bool mergeWithChild = true;
Tanousf00032d2018-11-05 01:18:10 -0300695 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700696 {
697 Node* child = &nodes[kv.second];
698 if (!child->isSimpleNode())
699 {
700 mergeWithChild = false;
701 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700702 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700703 }
704 if (mergeWithChild)
705 {
706 decltype(node->children) merged;
Tanousf00032d2018-11-05 01:18:10 -0300707 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700708 {
709 Node* child = &nodes[kv.second];
Tanousf00032d2018-11-05 01:18:10 -0300710 for (const std::pair<std::string, unsigned>& childKv :
711 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712 {
713 merged[kv.first + childKv.first] = childKv.second;
714 }
715 }
716 node->children = std::move(merged);
717 optimizeNode(node);
718 }
719 else
720 {
Tanousf00032d2018-11-05 01:18:10 -0300721 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700722 {
723 Node* child = &nodes[kv.second];
724 optimizeNode(child);
725 }
726 }
727 }
728
729 void optimize()
730 {
731 optimizeNode(head());
732 }
733
734 public:
735 void validate()
736 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700737 optimize();
738 }
739
Ed Tanous81ce6092020-12-17 16:54:55 +0000740 void findRouteIndexes(const std::string& reqUrl,
741 std::vector<unsigned>& routeIndexes,
Tanousf00032d2018-11-05 01:18:10 -0300742 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700743 {
744 if (node == nullptr)
745 {
746 node = head();
747 }
Tanousf00032d2018-11-05 01:18:10 -0300748 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700749 {
750 const std::string& fragment = kv.first;
751 const Node* child = &nodes[kv.second];
Ed Tanous81ce6092020-12-17 16:54:55 +0000752 if (pos >= reqUrl.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 {
754 if (child->ruleIndex != 0 && fragment != "/")
755 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000756 routeIndexes.push_back(child->ruleIndex);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700757 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000758 findRouteIndexes(reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700759 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700760 }
761 else
762 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000763 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 {
Ed Tanous271584a2019-07-09 16:24:22 -0700765 findRouteIndexes(
Ed Tanous81ce6092020-12-17 16:54:55 +0000766 reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700767 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700768 }
769 }
770 }
771 }
772
773 std::pair<unsigned, RoutingParams>
Ed Tanous81ce6092020-12-17 16:54:55 +0000774 find(const std::string_view reqUrl, const Node* node = nullptr,
Ed Tanous271584a2019-07-09 16:24:22 -0700775 size_t pos = 0, RoutingParams* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700776 {
777 RoutingParams empty;
778 if (params == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700779 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700780 params = &empty;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700781 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700782
783 unsigned found{};
784 RoutingParams matchParams;
785
786 if (node == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700787 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700788 node = head();
Ed Tanous3174e4d2020-10-07 11:41:22 -0700789 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000790 if (pos == reqUrl.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700791 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700792 return {node->ruleIndex, *params};
Ed Tanous3174e4d2020-10-07 11:41:22 -0700793 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700794
795 auto updateFound =
796 [&found, &matchParams](std::pair<unsigned, RoutingParams>& ret) {
797 if (ret.first && (!found || found > ret.first))
798 {
799 found = ret.first;
800 matchParams = std::move(ret.second);
801 }
802 };
803
Ed Tanous271584a2019-07-09 16:24:22 -0700804 if (node->paramChildrens[static_cast<size_t>(ParamType::INT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000806 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807 if ((c >= '0' && c <= '9') || c == '+' || c == '-')
808 {
809 char* eptr;
810 errno = 0;
811 long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000812 std::strtoll(reqUrl.data() + pos, &eptr, 10);
813 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700814 {
815 params->intParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000816 std::pair<unsigned, RoutingParams> ret =
817 find(reqUrl,
818 &nodes[node->paramChildrens[static_cast<size_t>(
819 ParamType::INT)]],
820 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700821 updateFound(ret);
822 params->intParams.pop_back();
823 }
824 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700825 }
826
Ed Tanous271584a2019-07-09 16:24:22 -0700827 if (node->paramChildrens[static_cast<size_t>(ParamType::UINT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000829 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700830 if ((c >= '0' && c <= '9') || c == '+')
831 {
832 char* eptr;
833 errno = 0;
834 unsigned long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000835 std::strtoull(reqUrl.data() + pos, &eptr, 10);
836 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700837 {
838 params->uintParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000839 std::pair<unsigned, RoutingParams> ret =
840 find(reqUrl,
841 &nodes[node->paramChildrens[static_cast<size_t>(
842 ParamType::UINT)]],
843 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700844 updateFound(ret);
845 params->uintParams.pop_back();
846 }
847 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700848 }
849
Ed Tanous271584a2019-07-09 16:24:22 -0700850 if (node->paramChildrens[static_cast<size_t>(ParamType::DOUBLE)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000852 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700853 if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
854 {
855 char* eptr;
856 errno = 0;
Ed Tanous81ce6092020-12-17 16:54:55 +0000857 double value = std::strtod(reqUrl.data() + pos, &eptr);
858 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700859 {
860 params->doubleParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000861 std::pair<unsigned, RoutingParams> ret =
862 find(reqUrl,
863 &nodes[node->paramChildrens[static_cast<size_t>(
864 ParamType::DOUBLE)]],
865 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700866 updateFound(ret);
867 params->doubleParams.pop_back();
868 }
869 }
870 }
871
Ed Tanous271584a2019-07-09 16:24:22 -0700872 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700873 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000874 size_t epos = pos;
Ed Tanous81ce6092020-12-17 16:54:55 +0000875 for (; epos < reqUrl.size(); epos++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700876 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000877 if (reqUrl[epos] == '/')
Ed Tanous3174e4d2020-10-07 11:41:22 -0700878 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700879 break;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700880 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700881 }
882
883 if (epos != pos)
884 {
885 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000886 reqUrl.substr(pos, epos - pos));
Tanousf00032d2018-11-05 01:18:10 -0300887 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000888 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700889 &nodes[node->paramChildrens[static_cast<size_t>(
890 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000891 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700892 updateFound(ret);
893 params->stringParams.pop_back();
894 }
895 }
896
Ed Tanous271584a2019-07-09 16:24:22 -0700897 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700898 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000899 size_t epos = reqUrl.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700900
901 if (epos != pos)
902 {
903 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000904 reqUrl.substr(pos, epos - pos));
Ed Tanous271584a2019-07-09 16:24:22 -0700905 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000906 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700907 &nodes[node->paramChildrens[static_cast<size_t>(
908 ParamType::PATH)]],
909 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700910 updateFound(ret);
911 params->stringParams.pop_back();
912 }
913 }
914
Tanousf00032d2018-11-05 01:18:10 -0300915 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700916 {
917 const std::string& fragment = kv.first;
918 const Node* child = &nodes[kv.second];
919
Ed Tanous81ce6092020-12-17 16:54:55 +0000920 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700921 {
Tanousf00032d2018-11-05 01:18:10 -0300922 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000923 find(reqUrl, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700924 updateFound(ret);
925 }
926 }
927
928 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700929 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700930
931 void add(const std::string& url, unsigned ruleIndex)
932 {
Ed Tanous271584a2019-07-09 16:24:22 -0700933 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700934
935 for (unsigned i = 0; i < url.size(); i++)
936 {
937 char c = url[i];
938 if (c == '<')
939 {
Tanousf00032d2018-11-05 01:18:10 -0300940 const static std::array<std::pair<ParamType, std::string>, 7>
941 paramTraits = {{
942 {ParamType::INT, "<int>"},
943 {ParamType::UINT, "<uint>"},
944 {ParamType::DOUBLE, "<float>"},
945 {ParamType::DOUBLE, "<double>"},
946 {ParamType::STRING, "<str>"},
947 {ParamType::STRING, "<string>"},
948 {ParamType::PATH, "<path>"},
949 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700950
Tanousf00032d2018-11-05 01:18:10 -0300951 for (const std::pair<ParamType, std::string>& x : paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700952 {
Tanousf00032d2018-11-05 01:18:10 -0300953 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700954 {
Ed Tanous271584a2019-07-09 16:24:22 -0700955 size_t index = static_cast<size_t>(x.first);
956 if (!nodes[idx].paramChildrens[index])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700957 {
Tanousf00032d2018-11-05 01:18:10 -0300958 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700959 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700960 }
Ed Tanous271584a2019-07-09 16:24:22 -0700961 idx = nodes[idx].paramChildrens[index];
962 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700963 break;
964 }
965 }
966
967 i--;
968 }
969 else
970 {
971 std::string piece(&c, 1);
972 if (!nodes[idx].children.count(piece))
973 {
Tanousf00032d2018-11-05 01:18:10 -0300974 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700975 nodes[idx].children.emplace(piece, newNodeIdx);
976 }
977 idx = nodes[idx].children[piece];
978 }
979 }
980 if (nodes[idx].ruleIndex)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700981 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700982 throw std::runtime_error("handler already exists for " + url);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700983 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700984 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700985 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700986
Ed Tanous1abe55e2018-09-05 08:30:59 -0700987 private:
Ed Tanous271584a2019-07-09 16:24:22 -0700988 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700989 {
Ed Tanous271584a2019-07-09 16:24:22 -0700990 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700991 {
992 if (n->paramChildrens[i])
993 {
994 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -0700995 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
996 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700997 {
998 case ParamType::INT:
999 BMCWEB_LOG_DEBUG << "<int>";
1000 break;
1001 case ParamType::UINT:
1002 BMCWEB_LOG_DEBUG << "<uint>";
1003 break;
1004 case ParamType::DOUBLE:
1005 BMCWEB_LOG_DEBUG << "<float>";
1006 break;
1007 case ParamType::STRING:
1008 BMCWEB_LOG_DEBUG << "<str>";
1009 break;
1010 case ParamType::PATH:
1011 BMCWEB_LOG_DEBUG << "<path>";
1012 break;
Ed Tanous23a21a12020-07-25 04:45:05 +00001013 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -07001014 BMCWEB_LOG_DEBUG << "<ERROR>";
1015 break;
1016 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001017
Ed Tanous1abe55e2018-09-05 08:30:59 -07001018 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
1019 }
1020 }
Tanousf00032d2018-11-05 01:18:10 -03001021 for (const std::pair<std::string, unsigned>& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001022 {
1023 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -07001024 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -07001025 << kv.first;
1026 debugNodePrint(&nodes[kv.second], level + 1);
1027 }
1028 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001029
Ed Tanous1abe55e2018-09-05 08:30:59 -07001030 public:
1031 void debugPrint()
1032 {
Ed Tanous271584a2019-07-09 16:24:22 -07001033 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001034 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001035
Ed Tanous1abe55e2018-09-05 08:30:59 -07001036 private:
1037 const Node* head() const
1038 {
1039 return &nodes.front();
1040 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001041
Ed Tanous1abe55e2018-09-05 08:30:59 -07001042 Node* head()
1043 {
1044 return &nodes.front();
1045 }
1046
1047 unsigned newNode()
1048 {
1049 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -07001050 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001051 }
1052
1053 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001054};
1055
Ed Tanous1abe55e2018-09-05 08:30:59 -07001056class Router
1057{
1058 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -07001059 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001060
Ed Tanous1abe55e2018-09-05 08:30:59 -07001061 DynamicRule& newRuleDynamic(const std::string& rule)
1062 {
1063 std::unique_ptr<DynamicRule> ruleObject =
1064 std::make_unique<DynamicRule>(rule);
1065 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001066 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -07001067
Ed Tanous1abe55e2018-09-05 08:30:59 -07001068 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001069 }
1070
Ed Tanous1abe55e2018-09-05 08:30:59 -07001071 template <uint64_t N>
1072 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
1073 newRuleTagged(const std::string& rule)
1074 {
1075 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
1076 TaggedRule>;
1077 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
1078 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001079 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001080
1081 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001082 }
1083
Tanousf00032d2018-11-05 01:18:10 -03001084 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001085 {
Tanousf00032d2018-11-05 01:18:10 -03001086 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001087 {
Tanousf00032d2018-11-05 01:18:10 -03001088 return;
1089 }
Ed Tanous888880a2020-08-24 13:48:50 -07001090 for (size_t method = 0, methodBit = 1; method < maxHttpVerbCount;
Ed Tanous2c70f802020-09-28 14:29:23 -07001091 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -03001092 {
Ed Tanous2c70f802020-09-28 14:29:23 -07001093 if (ruleObject->methodsBitfield & methodBit)
Tanousf00032d2018-11-05 01:18:10 -03001094 {
1095 perMethods[method].rules.emplace_back(ruleObject);
1096 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -07001097 rule, static_cast<unsigned>(
1098 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -03001099 // directory case:
1100 // request to `/about' url matches `/about/' rule
1101 if (rule.size() > 2 && rule.back() == '/')
1102 {
1103 perMethods[method].trie.add(
1104 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -07001105 static_cast<unsigned>(perMethods[method].rules.size() -
1106 1));
Tanousf00032d2018-11-05 01:18:10 -03001107 }
1108 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001109 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001110 }
1111
Ed Tanous1abe55e2018-09-05 08:30:59 -07001112 void validate()
1113 {
Tanousf00032d2018-11-05 01:18:10 -03001114 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001115 {
1116 if (rule)
1117 {
Tanousf00032d2018-11-05 01:18:10 -03001118 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001119 if (upgraded)
Ed Tanous3174e4d2020-10-07 11:41:22 -07001120 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001121 rule = std::move(upgraded);
Ed Tanous3174e4d2020-10-07 11:41:22 -07001122 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001123 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -03001124 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001125 }
1126 }
Tanousf00032d2018-11-05 01:18:10 -03001127 for (PerMethod& perMethod : perMethods)
1128 {
1129 perMethod.trie.validate();
1130 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001131 }
1132
Ed Tanous1abe55e2018-09-05 08:30:59 -07001133 template <typename Adaptor>
1134 void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
1135 {
Ed Tanous271584a2019-07-09 16:24:22 -07001136 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001137 {
1138 res.result(boost::beast::http::status::not_found);
1139 res.end();
Tanousf00032d2018-11-05 01:18:10 -03001140 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001141 }
Tanousf00032d2018-11-05 01:18:10 -03001142
Ed Tanous271584a2019-07-09 16:24:22 -07001143 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001144 Trie& trie = perMethod.trie;
1145 std::vector<BaseRule*>& rules = perMethod.rules;
1146
1147 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001148 unsigned ruleIndex = found.first;
1149 if (!ruleIndex)
1150 {
1151 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001152 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001153 res.end();
1154 return;
1155 }
1156
1157 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001158 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001159 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001160 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001161
1162 if (ruleIndex == ruleSpecialRedirectSlash)
1163 {
1164 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1165 << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001166 res.result(boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001167
1168 // TODO absolute url building
1169 if (req.getHeaderValue("Host").empty())
1170 {
1171 res.addHeader("Location", std::string(req.url) + "/");
1172 }
1173 else
1174 {
1175 res.addHeader(
1176 "Location",
1177 req.isSecure
1178 ? "https://"
1179 : "http://" + std::string(req.getHeaderValue("Host")) +
1180 std::string(req.url) + "/");
1181 }
1182 res.end();
1183 return;
1184 }
1185
Ed Tanous271584a2019-07-09 16:24:22 -07001186 if ((rules[ruleIndex]->getMethods() &
1187 (1U << static_cast<size_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001188 {
1189 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1190 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001191 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001192 << rules[ruleIndex]->getMethods();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001193 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001194 res.end();
1195 return;
1196 }
1197
1198 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rules[ruleIndex]->rule
Ed Tanous271584a2019-07-09 16:24:22 -07001199 << "' " << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001200 << rules[ruleIndex]->getMethods();
1201
1202 // any uncaught exceptions become 500s
1203 try
1204 {
1205 rules[ruleIndex]->handleUpgrade(req, res, std::move(adaptor));
1206 }
Patrick Williamsc5967042021-10-06 12:39:54 -05001207 catch (const std::exception& e)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001208 {
1209 BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001210 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001211 res.end();
1212 return;
1213 }
1214 catch (...)
1215 {
1216 BMCWEB_LOG_ERROR
1217 << "An uncaught exception occurred. The type was unknown "
1218 "so no information was available.";
Ed Tanousde5c9f32019-03-26 09:17:55 -07001219 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001220 res.end();
1221 return;
1222 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001223 }
1224
zhanghch058d1b46d2021-04-01 11:18:24 +08001225 void handle(Request& req,
1226 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001227 {
Ed Tanous271584a2019-07-09 16:24:22 -07001228 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001229 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001230 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001231 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001232 }
Ed Tanous271584a2019-07-09 16:24:22 -07001233 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001234 Trie& trie = perMethod.trie;
1235 std::vector<BaseRule*>& rules = perMethod.rules;
1236
1237 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001238
Ed Tanous1abe55e2018-09-05 08:30:59 -07001239 unsigned ruleIndex = found.first;
1240
1241 if (!ruleIndex)
1242 {
Ed Tanous2634dcd2019-03-26 09:28:06 -07001243 // Check to see if this url exists at any verb
1244 for (const PerMethod& p : perMethods)
1245 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001246 const std::pair<unsigned, RoutingParams>& found2 =
Ed Tanous2634dcd2019-03-26 09:28:06 -07001247 p.trie.find(req.url);
Ed Tanous23a21a12020-07-25 04:45:05 +00001248 if (found2.first > 0)
Ed Tanous2634dcd2019-03-26 09:28:06 -07001249 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001250 asyncResp->res.result(
1251 boost::beast::http::status::method_not_allowed);
Ed Tanous2634dcd2019-03-26 09:28:06 -07001252 return;
1253 }
1254 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001255 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
zhanghch058d1b46d2021-04-01 11:18:24 +08001256 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001257 return;
1258 }
1259
1260 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001261 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001262 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001263 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001264
1265 if (ruleIndex == ruleSpecialRedirectSlash)
1266 {
1267 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1268 << req.url;
zhanghch058d1b46d2021-04-01 11:18:24 +08001269 asyncResp->res.result(
1270 boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001271
1272 // TODO absolute url building
1273 if (req.getHeaderValue("Host").empty())
1274 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001275 asyncResp->res.addHeader("Location",
1276 std::string(req.url) + "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001277 }
1278 else
1279 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001280 asyncResp->res.addHeader(
1281 "Location", (req.isSecure ? "https://" : "http://") +
1282 std::string(req.getHeaderValue("Host")) +
1283 std::string(req.url) + "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001284 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001285 return;
1286 }
1287
Ed Tanous271584a2019-07-09 16:24:22 -07001288 if ((rules[ruleIndex]->getMethods() &
1289 (1U << static_cast<uint32_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001290 {
1291 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1292 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001293 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001294 << rules[ruleIndex]->getMethods();
zhanghch058d1b46d2021-04-01 11:18:24 +08001295 asyncResp->res.result(
1296 boost::beast::http::status::method_not_allowed);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001297 return;
1298 }
1299
1300 BMCWEB_LOG_DEBUG << "Matched rule '" << rules[ruleIndex]->rule << "' "
Ed Tanous271584a2019-07-09 16:24:22 -07001301 << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001302 << rules[ruleIndex]->getMethods();
1303
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001304 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001305 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001306 rules[ruleIndex]->handle(req, asyncResp, found.second);
James Feist7166bf02019-12-10 16:52:14 +00001307 return;
1308 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001309
1310 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001311 [&req, asyncResp, &rules, ruleIndex, found](
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001312 const boost::system::error_code ec,
1313 std::map<std::string, std::variant<bool, std::string,
1314 std::vector<std::string>>>
1315 userInfo) {
1316 if (ec)
1317 {
1318 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
zhanghch058d1b46d2021-04-01 11:18:24 +08001319 asyncResp->res.result(
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001320 boost::beast::http::status::internal_server_error);
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001321 return;
1322 }
1323
1324 const std::string* userRolePtr = nullptr;
1325 auto userInfoIter = userInfo.find("UserPrivilege");
1326 if (userInfoIter != userInfo.end())
1327 {
1328 userRolePtr =
1329 std::get_if<std::string>(&userInfoIter->second);
1330 }
1331
1332 std::string userRole{};
1333 if (userRolePtr != nullptr)
1334 {
1335 userRole = *userRolePtr;
1336 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1337 << " userRole = " << *userRolePtr;
1338 }
1339
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001340 bool* remoteUserPtr = nullptr;
1341 auto remoteUserIter = userInfo.find("RemoteUser");
1342 if (remoteUserIter != userInfo.end())
1343 {
1344 remoteUserPtr = std::get_if<bool>(&remoteUserIter->second);
1345 }
1346 if (remoteUserPtr == nullptr)
1347 {
1348 BMCWEB_LOG_ERROR
1349 << "RemoteUser property missing or wrong type";
zhanghch058d1b46d2021-04-01 11:18:24 +08001350 asyncResp->res.result(
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001351 boost::beast::http::status::internal_server_error);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001352 return;
1353 }
1354 bool remoteUser = *remoteUserPtr;
1355
1356 bool passwordExpired = false; // default for remote user
1357 if (!remoteUser)
1358 {
1359 bool* passwordExpiredPtr = nullptr;
1360 auto passwordExpiredIter =
1361 userInfo.find("UserPasswordExpired");
1362 if (passwordExpiredIter != userInfo.end())
1363 {
1364 passwordExpiredPtr =
1365 std::get_if<bool>(&passwordExpiredIter->second);
1366 }
1367 if (passwordExpiredPtr != nullptr)
1368 {
1369 passwordExpired = *passwordExpiredPtr;
1370 }
1371 else
1372 {
1373 BMCWEB_LOG_ERROR
1374 << "UserPasswordExpired property is expected for"
1375 " local user but is missing or wrong type";
zhanghch058d1b46d2021-04-01 11:18:24 +08001376 asyncResp->res.result(
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001377 boost::beast::http::status::internal_server_error);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001378 return;
1379 }
1380 }
1381
Ed Tanous23a21a12020-07-25 04:45:05 +00001382 // Get the userprivileges from the role
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001383 redfish::Privileges userPrivileges =
1384 redfish::getUserPrivileges(userRole);
1385
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001386 // Set isConfigureSelfOnly based on D-Bus results. This
1387 // ignores the results from both pamAuthenticateUser and the
1388 // value from any previous use of this session.
1389 req.session->isConfigureSelfOnly = passwordExpired;
1390
Ed Tanous23a21a12020-07-25 04:45:05 +00001391 // Modifyprivileges if isConfigureSelfOnly.
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001392 if (req.session->isConfigureSelfOnly)
1393 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001394 // Remove allprivileges except ConfigureSelf
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001395 userPrivileges = userPrivileges.intersection(
1396 redfish::Privileges{"ConfigureSelf"});
1397 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1398 }
1399
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001400 if (!rules[ruleIndex]->checkPrivileges(userPrivileges))
1401 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001402 asyncResp->res.result(
1403 boost::beast::http::status::forbidden);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001404 if (req.session->isConfigureSelfOnly)
1405 {
1406 redfish::messages::passwordChangeRequired(
zhanghch058d1b46d2021-04-01 11:18:24 +08001407 asyncResp->res,
1408 "/redfish/v1/AccountService/Accounts/" +
1409 req.session->username);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001410 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001411 return;
1412 }
1413
1414 req.userRole = userRole;
zhanghch058d1b46d2021-04-01 11:18:24 +08001415 rules[ruleIndex]->handle(req, asyncResp, found.second);
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001416 },
1417 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1418 "xyz.openbmc_project.User.Manager", "GetUserInfo",
1419 req.session->username);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001420 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001421
Ed Tanous1abe55e2018-09-05 08:30:59 -07001422 void debugPrint()
1423 {
Ed Tanous271584a2019-07-09 16:24:22 -07001424 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001425 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001426 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1427 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001428 perMethods[i].trie.debugPrint();
1429 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001430 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001431
Ed Tanous1abe55e2018-09-05 08:30:59 -07001432 std::vector<const std::string*> getRoutes(const std::string& parent)
1433 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001434 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001435
1436 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001437 {
Tanousf00032d2018-11-05 01:18:10 -03001438 std::vector<unsigned> x;
1439 pm.trie.findRouteIndexes(parent, x);
1440 for (unsigned index : x)
1441 {
1442 ret.push_back(&pm.rules[index]->rule);
1443 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001444 }
1445 return ret;
1446 }
1447
1448 private:
Tanousf00032d2018-11-05 01:18:10 -03001449 struct PerMethod
1450 {
1451 std::vector<BaseRule*> rules;
1452 Trie trie;
1453 // rule index 0, 1 has special meaning; preallocate it to avoid
1454 // duplication.
1455 PerMethod() : rules(2)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001456 {}
Tanousf00032d2018-11-05 01:18:10 -03001457 };
Ed Tanous888880a2020-08-24 13:48:50 -07001458
1459 const static size_t maxHttpVerbCount =
Ed Tanouscc090442020-10-07 08:20:50 -07001460 static_cast<size_t>(boost::beast::http::verb::unlink);
Ed Tanous888880a2020-08-24 13:48:50 -07001461
Tanousf00032d2018-11-05 01:18:10 -03001462 std::array<PerMethod, maxHttpVerbCount> perMethods;
1463 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001464};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001465} // namespace crow