blob: 250cd3354ea0f572fa446d2fa74a1071847f202f [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
2
Ed Tanous04e438c2020-10-03 08:06:26 -07003#include "common.hpp"
Ed Tanous168e20c2021-12-13 14:39:53 -08004#include "dbus_utility.hpp"
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06005#include "error_messages.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -07006#include "http_request.hpp"
7#include "http_response.hpp"
8#include "logging.hpp"
Tanousf00032d2018-11-05 01:18:10 -03009#include "privileges.hpp"
Ratan Gupta6f359562019-04-03 10:39:08 +053010#include "sessions.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -070011#include "utility.hpp"
12#include "websocket.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070013
Iwona Klimaszewskac0a1c8a2019-07-12 18:26:38 +020014#include <async_resp.hpp>
Tanousf00032d2018-11-05 01:18:10 -030015#include <boost/container/flat_map.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050016
Ed Tanouse0d918b2018-03-27 17:41:04 -070017#include <cerrno>
Ed Tanous7045c8d2017-04-03 10:04:37 -070018#include <cstdint>
Ed Tanouse0d918b2018-03-27 17:41:04 -070019#include <cstdlib>
Ed Tanous3dac7492017-08-02 13:46:20 -070020#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070021#include <memory>
22#include <tuple>
Ed Tanous7045c8d2017-04-03 10:04:37 -070023#include <utility>
24#include <vector>
Ed Tanous9140a672017-04-24 17:01:32 -070025
Ed Tanous1abe55e2018-09-05 08:30:59 -070026namespace crow
27{
Tanousf00032d2018-11-05 01:18:10 -030028
Ed Tanous1abe55e2018-09-05 08:30:59 -070029class BaseRule
30{
31 public:
Ed Tanousf23b7292020-10-15 09:41:17 -070032 BaseRule(const std::string& thisRule) : rule(thisRule)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050033 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070034
Ed Tanous0c0084a2019-10-24 15:57:51 -070035 virtual ~BaseRule() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -070036
Ed Tanousecd6a3a2022-01-07 09:18:40 -080037 BaseRule(const BaseRule&) = delete;
38 BaseRule(BaseRule&&) = delete;
39 BaseRule& operator=(const BaseRule&) = delete;
40 BaseRule& operator=(const BaseRule&&) = delete;
41
Ed Tanous1abe55e2018-09-05 08:30:59 -070042 virtual void validate() = 0;
43 std::unique_ptr<BaseRule> upgrade()
44 {
45 if (ruleToUpgrade)
Ed Tanous3174e4d2020-10-07 11:41:22 -070046 {
Ed Tanous1abe55e2018-09-05 08:30:59 -070047 return std::move(ruleToUpgrade);
Ed Tanous3174e4d2020-10-07 11:41:22 -070048 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070049 return {};
50 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070051
Ed Tanous104f09c2022-01-25 09:56:04 -080052 virtual void handle(const Request& /*req*/,
zhanghch058d1b46d2021-04-01 11:18:24 +080053 const std::shared_ptr<bmcweb::AsyncResp>&,
54 const RoutingParams&) = 0;
Ed Tanous104f09c2022-01-25 09:56:04 -080055 virtual void handleUpgrade(const Request& /*req*/, Response& res,
56 boost::asio::ip::tcp::socket&& /*adaptor*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -070057 {
Ed Tanousde5c9f32019-03-26 09:17:55 -070058 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070059 res.end();
60 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -070061#ifdef BMCWEB_ENABLE_SSL
Ed Tanous104f09c2022-01-25 09:56:04 -080062 virtual void handleUpgrade(
63 const Request& /*req*/, Response& res,
64 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&& /*adaptor*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -070065 {
Ed Tanousde5c9f32019-03-26 09:17:55 -070066 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 res.end();
68 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070069#endif
70
Ed Tanous9eb808c2022-01-25 10:19:23 -080071 size_t getMethods() const
Ed Tanous1abe55e2018-09-05 08:30:59 -070072 {
73 return methodsBitfield;
74 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070075
Tanousf00032d2018-11-05 01:18:10 -030076 bool checkPrivileges(const redfish::Privileges& userPrivileges)
77 {
78 // If there are no privileges assigned, assume no privileges
79 // required
80 if (privilegesSet.empty())
81 {
82 return true;
83 }
84
85 for (const redfish::Privileges& requiredPrivileges : privilegesSet)
86 {
87 if (userPrivileges.isSupersetOf(requiredPrivileges))
88 {
89 return true;
90 }
91 }
92 return false;
93 }
94
Ed Tanous271584a2019-07-09 16:24:22 -070095 size_t methodsBitfield{
96 1 << static_cast<size_t>(boost::beast::http::verb::get)};
Ed Tanous7045c8d2017-04-03 10:04:37 -070097
Tanousf00032d2018-11-05 01:18:10 -030098 std::vector<redfish::Privileges> privilegesSet;
99
Ed Tanous1abe55e2018-09-05 08:30:59 -0700100 std::string rule;
101 std::string nameStr;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700102
Ed Tanous1abe55e2018-09-05 08:30:59 -0700103 std::unique_ptr<BaseRule> ruleToUpgrade;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700104
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105 friend class Router;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500106 template <typename T>
107 friend struct RuleParameterTraits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700108};
109
Ed Tanous1abe55e2018-09-05 08:30:59 -0700110namespace detail
111{
112namespace routing_handler_call_helper
113{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500114template <typename T, int Pos>
115struct CallPair
Ed Tanous1abe55e2018-09-05 08:30:59 -0700116{
117 using type = T;
118 static const int pos = Pos;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700119};
120
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500121template <typename H1>
122struct CallParams
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123{
124 H1& handler;
125 const RoutingParams& params;
126 const Request& req;
zhanghch058d1b46d2021-04-01 11:18:24 +0800127 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700128};
129
130template <typename F, int NInt, int NUint, int NDouble, int NString,
131 typename S1, typename S2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700132struct Call
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500133{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700134
135template <typename F, int NInt, int NUint, int NDouble, int NString,
136 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700137struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<int64_t, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700138 black_magic::S<Args2...>>
139{
140 void operator()(F cparams)
141 {
142 using pushed = typename black_magic::S<Args2...>::template push_back<
143 CallPair<int64_t, NInt>>;
144 Call<F, NInt + 1, NUint, NDouble, NString, black_magic::S<Args1...>,
145 pushed>()(cparams);
146 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700147};
148
149template <typename F, int NInt, int NUint, int NDouble, int NString,
150 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700151struct Call<F, NInt, NUint, NDouble, NString,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700152 black_magic::S<uint64_t, Args1...>, black_magic::S<Args2...>>
153{
154 void operator()(F cparams)
155 {
156 using pushed = typename black_magic::S<Args2...>::template push_back<
157 CallPair<uint64_t, NUint>>;
158 Call<F, NInt, NUint + 1, NDouble, NString, black_magic::S<Args1...>,
159 pushed>()(cparams);
160 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700161};
162
163template <typename F, int NInt, int NUint, int NDouble, int NString,
164 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700165struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<double, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700166 black_magic::S<Args2...>>
167{
168 void operator()(F cparams)
169 {
170 using pushed = typename black_magic::S<Args2...>::template push_back<
171 CallPair<double, NDouble>>;
172 Call<F, NInt, NUint, NDouble + 1, NString, black_magic::S<Args1...>,
173 pushed>()(cparams);
174 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700175};
176
177template <typename F, int NInt, int NUint, int NDouble, int NString,
178 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700179struct Call<F, NInt, NUint, NDouble, NString,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700180 black_magic::S<std::string, Args1...>, black_magic::S<Args2...>>
181{
182 void operator()(F cparams)
183 {
184 using pushed = typename black_magic::S<Args2...>::template push_back<
185 CallPair<std::string, NString>>;
186 Call<F, NInt, NUint, NDouble, NString + 1, black_magic::S<Args1...>,
187 pushed>()(cparams);
188 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700189};
190
191template <typename F, int NInt, int NUint, int NDouble, int NString,
192 typename... Args1>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700193struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700194 black_magic::S<Args1...>>
195{
196 void operator()(F cparams)
197 {
198 cparams.handler(
zhanghch058d1b46d2021-04-01 11:18:24 +0800199 cparams.req, cparams.asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700200 cparams.params.template get<typename Args1::type>(Args1::pos)...);
201 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700202};
203
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500204template <typename Func, typename... ArgsWrapped>
205struct Wrapped
Ed Tanous1abe55e2018-09-05 08:30:59 -0700206{
207 template <typename... Args>
208 void set(
209 Func f,
210 typename std::enable_if<
211 !std::is_same<
212 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
213 const Request&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800214 int>::type /*enable*/
215 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700216 {
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800217 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800218 const Request&,
219 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
220 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700221 }
222
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500223 template <typename Req, typename... Args>
224 struct ReqHandlerWrapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700225 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000226 ReqHandlerWrapper(Func fIn) : f(std::move(fIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500227 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700228
zhanghch058d1b46d2021-04-01 11:18:24 +0800229 void operator()(const Request& req,
230 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
231 Args... args)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700232 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800233 asyncResp->res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700234 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700235
Ed Tanous1abe55e2018-09-05 08:30:59 -0700236 Func f;
237 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700238
Ed Tanous1abe55e2018-09-05 08:30:59 -0700239 template <typename... Args>
240 void set(
241 Func f,
242 typename std::enable_if<
243 std::is_same<
244 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
245 const Request&>::value &&
246 !std::is_same<typename std::tuple_element<
247 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800248 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800249 int>::type /*enable*/
250 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700251 {
252 handler = ReqHandlerWrapper<Args...>(std::move(f));
253 /*handler = (
254 [f = std::move(f)]
255 (const Request& req, Response& res, Args... args){
Ed Tanousde5c9f32019-03-26 09:17:55 -0700256 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700257 res.end();
258 });*/
259 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700260
Ed Tanous1abe55e2018-09-05 08:30:59 -0700261 template <typename... Args>
262 void set(
263 Func f,
264 typename std::enable_if<
265 std::is_same<
266 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
267 const Request&>::value &&
268 std::is_same<typename std::tuple_element<
269 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800270 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous104f09c2022-01-25 09:56:04 -0800271 int>::type /*enable*/
272 = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700273 {
274 handler = std::move(f);
275 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700276
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500277 template <typename... Args>
278 struct HandlerTypeHelper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700279 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800280 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800281 const crow::Request& /*req*/,
282 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700283 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&, Args...>
289 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800290 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800291 const crow::Request& /*req*/,
292 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700293 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700294 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700295 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700296
Ed Tanous1abe55e2018-09-05 08:30:59 -0700297 template <typename... Args>
zhanghch058d1b46d2021-04-01 11:18:24 +0800298 struct HandlerTypeHelper<const Request&,
299 const std::shared_ptr<bmcweb::AsyncResp>&, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700300 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800301 using type = std::function<void(
Ed Tanous104f09c2022-01-25 09:56:04 -0800302 const crow::Request& /*req*/,
303 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700304 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700305 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700306 };
307
308 typename HandlerTypeHelper<ArgsWrapped...>::type handler;
309
zhanghch058d1b46d2021-04-01 11:18:24 +0800310 void operator()(const Request& req,
311 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700312 const RoutingParams& params)
313 {
314 detail::routing_handler_call_helper::Call<
315 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
316 0, 0, 0, 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
317 black_magic::S<>>()(
318 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800319 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700320 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700321};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700322} // namespace routing_handler_call_helper
323} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700324
Ed Tanous1abe55e2018-09-05 08:30:59 -0700325class WebSocketRule : public BaseRule
326{
327 using self_t = WebSocketRule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700328
Ed Tanous1abe55e2018-09-05 08:30:59 -0700329 public:
Ed Tanousf23b7292020-10-15 09:41:17 -0700330 WebSocketRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500331 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700332
Ed Tanous1abe55e2018-09-05 08:30:59 -0700333 void validate() override
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500334 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700335
Ed Tanous104f09c2022-01-25 09:56:04 -0800336 void handle(const Request& /*req*/,
zhanghch058d1b46d2021-04-01 11:18:24 +0800337 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous104f09c2022-01-25 09:56:04 -0800338 const RoutingParams& /*params*/) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700339 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800340 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700341 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700342
Ed Tanous104f09c2022-01-25 09:56:04 -0800343 void handleUpgrade(const Request& req, Response& /*res*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800344 boost::asio::ip::tcp::socket&& adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700345 {
Nan Zhou93c02022022-02-24 18:21:07 -0800346 BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
Ratan Gupta02453b12019-10-22 14:43:36 +0530347 std::shared_ptr<
348 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>
349 myConnection = std::make_shared<
350 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000351 req, std::move(adaptor), openHandler, messageHandler,
Ratan Gupta02453b12019-10-22 14:43:36 +0530352 closeHandler, errorHandler);
353 myConnection->start();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700354 }
355#ifdef BMCWEB_ENABLE_SSL
Ed Tanous104f09c2022-01-25 09:56:04 -0800356 void handleUpgrade(const Request& req, Response& /*res*/,
Ed Tanousceac6f72018-12-02 11:58:47 -0800357 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
358 adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700359 {
Nan Zhou93c02022022-02-24 18:21:07 -0800360 BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
Ed Tanousceac6f72018-12-02 11:58:47 -0800361 std::shared_ptr<crow::websocket::ConnectionImpl<
362 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
363 myConnection = std::make_shared<crow::websocket::ConnectionImpl<
364 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000365 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanousceac6f72018-12-02 11:58:47 -0800366 closeHandler, errorHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700367 myConnection->start();
368 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700369#endif
370
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500371 template <typename Func>
372 self_t& onopen(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700373 {
374 openHandler = f;
375 return *this;
376 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700377
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500378 template <typename Func>
379 self_t& onmessage(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700380 {
381 messageHandler = f;
382 return *this;
383 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700384
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500385 template <typename Func>
386 self_t& onclose(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700387 {
388 closeHandler = f;
389 return *this;
390 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700391
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500392 template <typename Func>
393 self_t& onerror(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700394 {
395 errorHandler = f;
396 return *this;
397 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700398
Ed Tanous1abe55e2018-09-05 08:30:59 -0700399 protected:
Gunnar Millsccd584f2021-11-16 11:36:33 -0600400 std::function<void(crow::websocket::Connection&,
401 std::shared_ptr<bmcweb::AsyncResp>)>
402 openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700403 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
404 messageHandler;
405 std::function<void(crow::websocket::Connection&, const std::string&)>
406 closeHandler;
407 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700408};
409
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500410template <typename T>
411struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700412{
413 using self_t = T;
414 WebSocketRule& websocket()
415 {
Ed Tanous271584a2019-07-09 16:24:22 -0700416 self_t* self = static_cast<self_t*>(this);
417 WebSocketRule* p = new WebSocketRule(self->rule);
418 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700419 return *p;
420 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700421
Ed Tanousf23b7292020-10-15 09:41:17 -0700422 self_t& name(const std::string_view name) noexcept
Ed Tanous1abe55e2018-09-05 08:30:59 -0700423 {
Ed Tanous271584a2019-07-09 16:24:22 -0700424 self_t* self = static_cast<self_t*>(this);
Ed Tanousf23b7292020-10-15 09:41:17 -0700425 self->nameStr = name;
Ed Tanous271584a2019-07-09 16:24:22 -0700426 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700427 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700428
Ed Tanous1abe55e2018-09-05 08:30:59 -0700429 self_t& methods(boost::beast::http::verb method)
430 {
Ed Tanous271584a2019-07-09 16:24:22 -0700431 self_t* self = static_cast<self_t*>(this);
432 self->methodsBitfield = 1U << static_cast<size_t>(method);
433 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700434 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700435
Ed Tanous1abe55e2018-09-05 08:30:59 -0700436 template <typename... MethodArgs>
Ed Tanous81ce6092020-12-17 16:54:55 +0000437 self_t& methods(boost::beast::http::verb method, MethodArgs... argsMethod)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700438 {
Ed Tanous271584a2019-07-09 16:24:22 -0700439 self_t* self = static_cast<self_t*>(this);
Ed Tanous81ce6092020-12-17 16:54:55 +0000440 methods(argsMethod...);
Ed Tanous271584a2019-07-09 16:24:22 -0700441 self->methodsBitfield |= 1U << static_cast<size_t>(method);
442 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700443 }
Tanousf00032d2018-11-05 01:18:10 -0300444
Ed Tanous432a8902021-06-14 15:28:56 -0700445 self_t& privileges(
446 const std::initializer_list<std::initializer_list<const char*>>& p)
Tanousf00032d2018-11-05 01:18:10 -0300447 {
Ed Tanous271584a2019-07-09 16:24:22 -0700448 self_t* self = static_cast<self_t*>(this);
Ed Tanous432a8902021-06-14 15:28:56 -0700449 for (const std::initializer_list<const char*>& privilege : p)
Tanousf00032d2018-11-05 01:18:10 -0300450 {
Ed Tanous271584a2019-07-09 16:24:22 -0700451 self->privilegesSet.emplace_back(privilege);
Tanousf00032d2018-11-05 01:18:10 -0300452 }
Ed Tanous271584a2019-07-09 16:24:22 -0700453 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300454 }
Ed Tanoused398212021-06-09 17:05:54 -0700455
456 template <size_t N, typename... MethodArgs>
457 self_t& privileges(const std::array<redfish::Privileges, N>& p)
458 {
459 self_t* self = static_cast<self_t*>(this);
460 for (const redfish::Privileges& privilege : p)
461 {
462 self->privilegesSet.emplace_back(privilege);
463 }
464 return *self;
465 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700466};
467
Ed Tanous1abe55e2018-09-05 08:30:59 -0700468class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
469{
470 public:
Ed Tanousf23b7292020-10-15 09:41:17 -0700471 DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500472 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700473
Ed Tanous1abe55e2018-09-05 08:30:59 -0700474 void validate() override
475 {
476 if (!erasedHandler)
477 {
478 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
479 "no handler for url " + rule);
480 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700481 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700482
zhanghch058d1b46d2021-04-01 11:18:24 +0800483 void handle(const Request& req,
484 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700485 const RoutingParams& params) override
486 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800487 erasedHandler(req, asyncResp, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700488 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700489
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500490 template <typename Func>
491 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700492 {
493 using function_t = utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700494 erasedHandler =
Ed Tanous988403c2020-08-24 11:29:49 -0700495 wrap(std::move(f),
496 std::make_integer_sequence<unsigned, function_t::arity>{});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700497 }
498
499 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500500 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700501 // enable_if Arg1 != request
502
503 template <typename Func, unsigned... Indices>
zhanghch058d1b46d2021-04-01 11:18:24 +0800504 std::function<void(const Request&,
505 const std::shared_ptr<bmcweb::AsyncResp>&,
506 const RoutingParams&)>
Ed Tanous104f09c2022-01-25 09:56:04 -0800507 wrap(Func f, std::integer_sequence<unsigned, Indices...> /*is*/)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700508 {
Ed Tanous988403c2020-08-24 11:29:49 -0700509 using function_t = crow::utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700510
511 if (!black_magic::isParameterTagCompatible(
Ed Tanous988403c2020-08-24 11:29:49 -0700512 black_magic::getParameterTag(rule.c_str()),
513 black_magic::computeParameterTagFromArgsList<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700514 typename function_t::template arg<Indices>...>::value))
515 {
516 throw std::runtime_error("routeDynamic: Handler type is mismatched "
517 "with URL parameters: " +
518 rule);
519 }
520 auto ret = detail::routing_handler_call_helper::Wrapped<
521 Func, typename function_t::template arg<Indices>...>();
522 ret.template set<typename function_t::template arg<Indices>...>(
523 std::move(f));
524 return ret;
525 }
526
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500527 template <typename Func>
528 void operator()(std::string name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700529 {
530 nameStr = std::move(name);
531 (*this).template operator()<Func>(std::forward(f));
532 }
533
534 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800535 std::function<void(const Request&,
536 const std::shared_ptr<bmcweb::AsyncResp>&,
537 const RoutingParams&)>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700538 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700539};
540
541template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500542class TaggedRule :
543 public BaseRule,
544 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700545{
546 public:
547 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700548
Ed Tanousf23b7292020-10-15 09:41:17 -0700549 TaggedRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500550 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700551
Ed Tanous1abe55e2018-09-05 08:30:59 -0700552 void validate() override
553 {
554 if (!handler)
555 {
556 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
557 "no handler for url " + rule);
558 }
559 }
560
561 template <typename Func>
562 typename std::enable_if<
563 black_magic::CallHelper<Func, black_magic::S<Args...>>::value,
564 void>::type
565 operator()(Func&& f)
566 {
567 static_assert(
568 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
569 black_magic::CallHelper<
570 Func, black_magic::S<crow::Request, Args...>>::value,
571 "Handler type is mismatched with URL parameters");
572 static_assert(
573 !std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
574 "Handler function cannot have void return type; valid return "
575 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500576 "string, int, crow::response, nlohmann::json");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700577
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800578 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800579 const Request&,
580 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
581 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700582 }
583
584 template <typename Func>
585 typename std::enable_if<
586 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
Ed Tanous7045c8d2017-04-03 10:04:37 -0700587 black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700588 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700589 void>::type
590 operator()(Func&& f)
591 {
592 static_assert(
593 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
594 black_magic::CallHelper<
595 Func, black_magic::S<crow::Request, Args...>>::value,
596 "Handler type is mismatched with URL parameters");
597 static_assert(
598 !std::is_same<void, decltype(f(std::declval<crow::Request>(),
599 std::declval<Args>()...))>::value,
600 "Handler function cannot have void return type; valid return "
601 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500602 "string, int, crow::response,nlohmann::json");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700603
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800604 handler = [f = std::forward<Func>(f)](
zhanghch058d1b46d2021-04-01 11:18:24 +0800605 const crow::Request& req,
606 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
607 Args... args) { asyncResp->res.result(f(req, args...)); };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700608 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700609
Ed Tanous1abe55e2018-09-05 08:30:59 -0700610 template <typename Func>
611 typename std::enable_if<
612 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
613 !black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700614 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700615 void>::type
616 operator()(Func&& f)
617 {
618 static_assert(
619 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
620 black_magic::CallHelper<
621 Func, black_magic::S<crow::Request, Args...>>::value ||
622 black_magic::CallHelper<
zhanghch058d1b46d2021-04-01 11:18:24 +0800623 Func, black_magic::S<crow::Request,
624 std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700625 Args...>>::value,
626 "Handler type is mismatched with URL parameters");
627 static_assert(
zhanghch058d1b46d2021-04-01 11:18:24 +0800628 std::is_same<
629 void,
630 decltype(f(std::declval<crow::Request>(),
631 std::declval<std::shared_ptr<bmcweb::AsyncResp>&>(),
632 std::declval<Args>()...))>::value,
Tanousf00032d2018-11-05 01:18:10 -0300633 "Handler function with response argument should have void "
634 "return "
Ed Tanous1abe55e2018-09-05 08:30:59 -0700635 "type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700636
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800637 handler = std::forward<Func>(f);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700639
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500640 template <typename Func>
Ed Tanousf23b7292020-10-15 09:41:17 -0700641 void operator()(const std::string_view name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700642 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700643 nameStr = name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700644 (*this).template operator()<Func>(std::forward(f));
645 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700646
zhanghch058d1b46d2021-04-01 11:18:24 +0800647 void handle(const Request& req,
648 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700649 const RoutingParams& params) override
650 {
651 detail::routing_handler_call_helper::Call<
652 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
653 0, 0, 0, 0, black_magic::S<Args...>, black_magic::S<>>()(
654 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800655 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700656 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700657
Ed Tanous1abe55e2018-09-05 08:30:59 -0700658 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800659 std::function<void(const crow::Request&,
660 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>
661 handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700662};
663
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700664const int ruleSpecialRedirectSlash = 1;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700665
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666class Trie
667{
668 public:
669 struct Node
670 {
671 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700672 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
673 paramChildrens{};
Ed Tanousa94ac612022-02-22 11:13:24 -0800674 using ChildMap = boost::container::flat_map<
675 std::string, unsigned, std::less<>,
676 std::vector<std::pair<std::string, unsigned>>>;
677 ChildMap children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700678
Ed Tanous1abe55e2018-09-05 08:30:59 -0700679 bool isSimpleNode() const
680 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800681 return ruleIndex == 0 &&
682 std::all_of(std::begin(paramChildrens),
683 std::end(paramChildrens),
684 [](size_t x) { return x == 0U; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700685 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700686 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700687
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688 Trie() : nodes(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500689 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700690
691 private:
692 void optimizeNode(Node* node)
693 {
Ed Tanous271584a2019-07-09 16:24:22 -0700694 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700695 {
Ed Tanousdbb59d42022-01-25 11:09:55 -0800696 if (x == 0U)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700697 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700698 continue;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700699 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700700 Node* child = &nodes[x];
701 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700702 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700703 if (node->children.empty())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700704 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700705 return;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700706 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700707 bool mergeWithChild = true;
Ed Tanousa94ac612022-02-22 11:13:24 -0800708 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700709 {
710 Node* child = &nodes[kv.second];
711 if (!child->isSimpleNode())
712 {
713 mergeWithChild = false;
714 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700715 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700716 }
717 if (mergeWithChild)
718 {
Ed Tanousa94ac612022-02-22 11:13:24 -0800719 Node::ChildMap merged;
720 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700721 {
722 Node* child = &nodes[kv.second];
Ed Tanousa94ac612022-02-22 11:13:24 -0800723 for (const Node::ChildMap::value_type& childKv :
Tanousf00032d2018-11-05 01:18:10 -0300724 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700725 {
726 merged[kv.first + childKv.first] = childKv.second;
727 }
728 }
729 node->children = std::move(merged);
730 optimizeNode(node);
731 }
732 else
733 {
Ed Tanousa94ac612022-02-22 11:13:24 -0800734 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700735 {
736 Node* child = &nodes[kv.second];
737 optimizeNode(child);
738 }
739 }
740 }
741
742 void optimize()
743 {
744 optimizeNode(head());
745 }
746
747 public:
748 void validate()
749 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700750 optimize();
751 }
752
Ed Tanous81ce6092020-12-17 16:54:55 +0000753 void findRouteIndexes(const std::string& reqUrl,
754 std::vector<unsigned>& routeIndexes,
Tanousf00032d2018-11-05 01:18:10 -0300755 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 {
757 if (node == nullptr)
758 {
759 node = head();
760 }
Ed Tanousa94ac612022-02-22 11:13:24 -0800761 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700762 {
763 const std::string& fragment = kv.first;
764 const Node* child = &nodes[kv.second];
Ed Tanous81ce6092020-12-17 16:54:55 +0000765 if (pos >= reqUrl.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766 {
767 if (child->ruleIndex != 0 && fragment != "/")
768 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000769 routeIndexes.push_back(child->ruleIndex);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700770 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000771 findRouteIndexes(reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700772 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700773 }
774 else
775 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000776 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700777 {
Ed Tanous271584a2019-07-09 16:24:22 -0700778 findRouteIndexes(
Ed Tanous81ce6092020-12-17 16:54:55 +0000779 reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700780 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700781 }
782 }
783 }
784 }
785
786 std::pair<unsigned, RoutingParams>
Ed Tanous81ce6092020-12-17 16:54:55 +0000787 find(const std::string_view reqUrl, const Node* node = nullptr,
Ed Tanous271584a2019-07-09 16:24:22 -0700788 size_t pos = 0, RoutingParams* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789 {
790 RoutingParams empty;
791 if (params == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700792 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700793 params = &empty;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700794 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700795
796 unsigned found{};
797 RoutingParams matchParams;
798
799 if (node == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700800 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 node = head();
Ed Tanous3174e4d2020-10-07 11:41:22 -0700802 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000803 if (pos == reqUrl.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700804 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805 return {node->ruleIndex, *params};
Ed Tanous3174e4d2020-10-07 11:41:22 -0700806 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807
808 auto updateFound =
809 [&found, &matchParams](std::pair<unsigned, RoutingParams>& ret) {
Ed Tanouse662eae2022-01-25 10:39:19 -0800810 if (ret.first != 0U && (found == 0U || found > ret.first))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700811 {
812 found = ret.first;
813 matchParams = std::move(ret.second);
814 }
815 };
816
Ed Tanouse662eae2022-01-25 10:39:19 -0800817 if (node->paramChildrens[static_cast<size_t>(ParamType::INT)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700818 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000819 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820 if ((c >= '0' && c <= '9') || c == '+' || c == '-')
821 {
Ed Tanous543f4402022-01-06 13:12:53 -0800822 char* eptr = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700823 errno = 0;
824 long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000825 std::strtoll(reqUrl.data() + pos, &eptr, 10);
826 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 {
828 params->intParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000829 std::pair<unsigned, RoutingParams> ret =
830 find(reqUrl,
831 &nodes[node->paramChildrens[static_cast<size_t>(
832 ParamType::INT)]],
833 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700834 updateFound(ret);
835 params->intParams.pop_back();
836 }
837 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700838 }
839
Ed Tanouse662eae2022-01-25 10:39:19 -0800840 if (node->paramChildrens[static_cast<size_t>(ParamType::UINT)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000842 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700843 if ((c >= '0' && c <= '9') || c == '+')
844 {
Ed Tanous543f4402022-01-06 13:12:53 -0800845 char* eptr = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700846 errno = 0;
847 unsigned long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000848 std::strtoull(reqUrl.data() + pos, &eptr, 10);
849 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700850 {
851 params->uintParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000852 std::pair<unsigned, RoutingParams> ret =
853 find(reqUrl,
854 &nodes[node->paramChildrens[static_cast<size_t>(
855 ParamType::UINT)]],
856 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700857 updateFound(ret);
858 params->uintParams.pop_back();
859 }
860 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700861 }
862
Ed Tanouse662eae2022-01-25 10:39:19 -0800863 if (node->paramChildrens[static_cast<size_t>(ParamType::DOUBLE)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700864 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000865 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700866 if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
867 {
Ed Tanous543f4402022-01-06 13:12:53 -0800868 char* eptr = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700869 errno = 0;
Ed Tanous81ce6092020-12-17 16:54:55 +0000870 double value = std::strtod(reqUrl.data() + pos, &eptr);
871 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700872 {
873 params->doubleParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000874 std::pair<unsigned, RoutingParams> ret =
875 find(reqUrl,
876 &nodes[node->paramChildrens[static_cast<size_t>(
877 ParamType::DOUBLE)]],
878 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700879 updateFound(ret);
880 params->doubleParams.pop_back();
881 }
882 }
883 }
884
Ed Tanouse662eae2022-01-25 10:39:19 -0800885 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000887 size_t epos = pos;
Ed Tanous81ce6092020-12-17 16:54:55 +0000888 for (; epos < reqUrl.size(); epos++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700889 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000890 if (reqUrl[epos] == '/')
Ed Tanous3174e4d2020-10-07 11:41:22 -0700891 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700892 break;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700893 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700894 }
895
896 if (epos != pos)
897 {
898 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000899 reqUrl.substr(pos, epos - pos));
Tanousf00032d2018-11-05 01:18:10 -0300900 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000901 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700902 &nodes[node->paramChildrens[static_cast<size_t>(
903 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000904 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700905 updateFound(ret);
906 params->stringParams.pop_back();
907 }
908 }
909
Ed Tanouse662eae2022-01-25 10:39:19 -0800910 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700911 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000912 size_t epos = reqUrl.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700913
914 if (epos != pos)
915 {
916 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000917 reqUrl.substr(pos, epos - pos));
Ed Tanous271584a2019-07-09 16:24:22 -0700918 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000919 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700920 &nodes[node->paramChildrens[static_cast<size_t>(
921 ParamType::PATH)]],
922 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700923 updateFound(ret);
924 params->stringParams.pop_back();
925 }
926 }
927
Ed Tanousa94ac612022-02-22 11:13:24 -0800928 for (const Node::ChildMap::value_type& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700929 {
930 const std::string& fragment = kv.first;
931 const Node* child = &nodes[kv.second];
932
Ed Tanous81ce6092020-12-17 16:54:55 +0000933 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700934 {
Tanousf00032d2018-11-05 01:18:10 -0300935 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000936 find(reqUrl, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700937 updateFound(ret);
938 }
939 }
940
941 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700942 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700943
944 void add(const std::string& url, unsigned ruleIndex)
945 {
Ed Tanous271584a2019-07-09 16:24:22 -0700946 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700947
948 for (unsigned i = 0; i < url.size(); i++)
949 {
950 char c = url[i];
951 if (c == '<')
952 {
Tanousf00032d2018-11-05 01:18:10 -0300953 const static std::array<std::pair<ParamType, std::string>, 7>
954 paramTraits = {{
955 {ParamType::INT, "<int>"},
956 {ParamType::UINT, "<uint>"},
957 {ParamType::DOUBLE, "<float>"},
958 {ParamType::DOUBLE, "<double>"},
959 {ParamType::STRING, "<str>"},
960 {ParamType::STRING, "<string>"},
961 {ParamType::PATH, "<path>"},
962 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700963
Tanousf00032d2018-11-05 01:18:10 -0300964 for (const std::pair<ParamType, std::string>& x : paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700965 {
Tanousf00032d2018-11-05 01:18:10 -0300966 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700967 {
Ed Tanous271584a2019-07-09 16:24:22 -0700968 size_t index = static_cast<size_t>(x.first);
Ed Tanouse662eae2022-01-25 10:39:19 -0800969 if (nodes[idx].paramChildrens[index] == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700970 {
Tanousf00032d2018-11-05 01:18:10 -0300971 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700972 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700973 }
Ed Tanous271584a2019-07-09 16:24:22 -0700974 idx = nodes[idx].paramChildrens[index];
975 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700976 break;
977 }
978 }
979
980 i--;
981 }
982 else
983 {
984 std::string piece(&c, 1);
Ed Tanouse662eae2022-01-25 10:39:19 -0800985 if (nodes[idx].children.count(piece) == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700986 {
Tanousf00032d2018-11-05 01:18:10 -0300987 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700988 nodes[idx].children.emplace(piece, newNodeIdx);
989 }
990 idx = nodes[idx].children[piece];
991 }
992 }
Ed Tanouse662eae2022-01-25 10:39:19 -0800993 if (nodes[idx].ruleIndex != 0U)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700994 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700995 throw std::runtime_error("handler already exists for " + url);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700996 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700997 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700998 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700999
Ed Tanous1abe55e2018-09-05 08:30:59 -07001000 private:
Ed Tanous271584a2019-07-09 16:24:22 -07001001 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001002 {
Ed Tanous271584a2019-07-09 16:24:22 -07001003 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001004 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001005 if (n->paramChildrens[i] != 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001006 {
1007 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -07001008 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
1009 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001010 {
1011 case ParamType::INT:
1012 BMCWEB_LOG_DEBUG << "<int>";
1013 break;
1014 case ParamType::UINT:
1015 BMCWEB_LOG_DEBUG << "<uint>";
1016 break;
1017 case ParamType::DOUBLE:
1018 BMCWEB_LOG_DEBUG << "<float>";
1019 break;
1020 case ParamType::STRING:
1021 BMCWEB_LOG_DEBUG << "<str>";
1022 break;
1023 case ParamType::PATH:
1024 BMCWEB_LOG_DEBUG << "<path>";
1025 break;
Ed Tanous23a21a12020-07-25 04:45:05 +00001026 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -07001027 BMCWEB_LOG_DEBUG << "<ERROR>";
1028 break;
1029 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001030
Ed Tanous1abe55e2018-09-05 08:30:59 -07001031 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
1032 }
1033 }
Ed Tanousa94ac612022-02-22 11:13:24 -08001034 for (const Node::ChildMap::value_type& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001035 {
1036 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -07001037 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -07001038 << kv.first;
1039 debugNodePrint(&nodes[kv.second], level + 1);
1040 }
1041 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001042
Ed Tanous1abe55e2018-09-05 08:30:59 -07001043 public:
1044 void debugPrint()
1045 {
Ed Tanous271584a2019-07-09 16:24:22 -07001046 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001047 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001048
Ed Tanous1abe55e2018-09-05 08:30:59 -07001049 private:
1050 const Node* head() const
1051 {
1052 return &nodes.front();
1053 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001054
Ed Tanous1abe55e2018-09-05 08:30:59 -07001055 Node* head()
1056 {
1057 return &nodes.front();
1058 }
1059
1060 unsigned newNode()
1061 {
1062 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -07001063 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001064 }
1065
1066 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001067};
1068
Ed Tanous1abe55e2018-09-05 08:30:59 -07001069class Router
1070{
1071 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -07001072 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001073
Ed Tanous1abe55e2018-09-05 08:30:59 -07001074 DynamicRule& newRuleDynamic(const std::string& rule)
1075 {
1076 std::unique_ptr<DynamicRule> ruleObject =
1077 std::make_unique<DynamicRule>(rule);
1078 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001079 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -07001080
Ed Tanous1abe55e2018-09-05 08:30:59 -07001081 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001082 }
1083
Ed Tanous1abe55e2018-09-05 08:30:59 -07001084 template <uint64_t N>
1085 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
1086 newRuleTagged(const std::string& rule)
1087 {
1088 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
1089 TaggedRule>;
1090 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
1091 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001092 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001093
1094 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001095 }
1096
Tanousf00032d2018-11-05 01:18:10 -03001097 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001098 {
Tanousf00032d2018-11-05 01:18:10 -03001099 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001100 {
Tanousf00032d2018-11-05 01:18:10 -03001101 return;
1102 }
Ed Tanous888880a2020-08-24 13:48:50 -07001103 for (size_t method = 0, methodBit = 1; method < maxHttpVerbCount;
Ed Tanous2c70f802020-09-28 14:29:23 -07001104 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -03001105 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001106 if ((ruleObject->methodsBitfield & methodBit) > 0U)
Tanousf00032d2018-11-05 01:18:10 -03001107 {
1108 perMethods[method].rules.emplace_back(ruleObject);
1109 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -07001110 rule, static_cast<unsigned>(
1111 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -03001112 // directory case:
1113 // request to `/about' url matches `/about/' rule
1114 if (rule.size() > 2 && rule.back() == '/')
1115 {
1116 perMethods[method].trie.add(
1117 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -07001118 static_cast<unsigned>(perMethods[method].rules.size() -
1119 1));
Tanousf00032d2018-11-05 01:18:10 -03001120 }
1121 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001122 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001123 }
1124
Ed Tanous1abe55e2018-09-05 08:30:59 -07001125 void validate()
1126 {
Tanousf00032d2018-11-05 01:18:10 -03001127 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001128 {
1129 if (rule)
1130 {
Tanousf00032d2018-11-05 01:18:10 -03001131 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001132 if (upgraded)
Ed Tanous3174e4d2020-10-07 11:41:22 -07001133 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001134 rule = std::move(upgraded);
Ed Tanous3174e4d2020-10-07 11:41:22 -07001135 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001136 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -03001137 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001138 }
1139 }
Tanousf00032d2018-11-05 01:18:10 -03001140 for (PerMethod& perMethod : perMethods)
1141 {
1142 perMethod.trie.validate();
1143 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001144 }
1145
Ed Tanous1abe55e2018-09-05 08:30:59 -07001146 template <typename Adaptor>
1147 void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
1148 {
Ed Tanous271584a2019-07-09 16:24:22 -07001149 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001150 {
1151 res.result(boost::beast::http::status::not_found);
1152 res.end();
Tanousf00032d2018-11-05 01:18:10 -03001153 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001154 }
Tanousf00032d2018-11-05 01:18:10 -03001155
Ed Tanous271584a2019-07-09 16:24:22 -07001156 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001157 Trie& trie = perMethod.trie;
1158 std::vector<BaseRule*>& rules = perMethod.rules;
1159
1160 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001161 unsigned ruleIndex = found.first;
Ed Tanouse662eae2022-01-25 10:39:19 -08001162 if (ruleIndex == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001163 {
1164 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001165 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001166 res.end();
1167 return;
1168 }
1169
1170 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001171 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001172 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001173 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001174
1175 if (ruleIndex == ruleSpecialRedirectSlash)
1176 {
1177 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1178 << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001179 res.result(boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001180
1181 // TODO absolute url building
1182 if (req.getHeaderValue("Host").empty())
1183 {
1184 res.addHeader("Location", std::string(req.url) + "/");
1185 }
1186 else
1187 {
1188 res.addHeader(
1189 "Location",
1190 req.isSecure
1191 ? "https://"
1192 : "http://" + std::string(req.getHeaderValue("Host")) +
1193 std::string(req.url) + "/");
1194 }
1195 res.end();
1196 return;
1197 }
1198
Ed Tanous271584a2019-07-09 16:24:22 -07001199 if ((rules[ruleIndex]->getMethods() &
1200 (1U << static_cast<size_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001201 {
1202 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1203 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001204 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001205 << rules[ruleIndex]->getMethods();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001206 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001207 res.end();
1208 return;
1209 }
1210
1211 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rules[ruleIndex]->rule
Ed Tanous271584a2019-07-09 16:24:22 -07001212 << "' " << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001213 << rules[ruleIndex]->getMethods();
1214
1215 // any uncaught exceptions become 500s
1216 try
1217 {
Ed Tanousf94c4ec2022-01-06 12:44:41 -08001218 rules[ruleIndex]->handleUpgrade(req, res,
1219 std::forward<Adaptor>(adaptor));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001220 }
Patrick Williamsc5967042021-10-06 12:39:54 -05001221 catch (const std::exception& e)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001222 {
1223 BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001224 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001225 res.end();
1226 return;
1227 }
1228 catch (...)
1229 {
1230 BMCWEB_LOG_ERROR
1231 << "An uncaught exception occurred. The type was unknown "
1232 "so no information was available.";
Ed Tanousde5c9f32019-03-26 09:17:55 -07001233 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001234 res.end();
1235 return;
1236 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001237 }
1238
zhanghch058d1b46d2021-04-01 11:18:24 +08001239 void handle(Request& req,
1240 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001241 {
Ed Tanous271584a2019-07-09 16:24:22 -07001242 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001243 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001244 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001245 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001246 }
Ed Tanous271584a2019-07-09 16:24:22 -07001247 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001248 Trie& trie = perMethod.trie;
1249 std::vector<BaseRule*>& rules = perMethod.rules;
1250
1251 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001252
Ed Tanous1abe55e2018-09-05 08:30:59 -07001253 unsigned ruleIndex = found.first;
1254
Ed Tanouse662eae2022-01-25 10:39:19 -08001255 if (ruleIndex == 0U)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001256 {
Ed Tanous2634dcd2019-03-26 09:28:06 -07001257 // Check to see if this url exists at any verb
1258 for (const PerMethod& p : perMethods)
1259 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001260 const std::pair<unsigned, RoutingParams>& found2 =
Ed Tanous2634dcd2019-03-26 09:28:06 -07001261 p.trie.find(req.url);
Ed Tanous23a21a12020-07-25 04:45:05 +00001262 if (found2.first > 0)
Ed Tanous2634dcd2019-03-26 09:28:06 -07001263 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001264 asyncResp->res.result(
1265 boost::beast::http::status::method_not_allowed);
Ed Tanous2634dcd2019-03-26 09:28:06 -07001266 return;
1267 }
1268 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001269 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
zhanghch058d1b46d2021-04-01 11:18:24 +08001270 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001271 return;
1272 }
1273
1274 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001275 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001276 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001277 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001278
1279 if (ruleIndex == ruleSpecialRedirectSlash)
1280 {
1281 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1282 << req.url;
zhanghch058d1b46d2021-04-01 11:18:24 +08001283 asyncResp->res.result(
1284 boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001285
1286 // TODO absolute url building
1287 if (req.getHeaderValue("Host").empty())
1288 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001289 asyncResp->res.addHeader("Location",
1290 std::string(req.url) + "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001291 }
1292 else
1293 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001294 asyncResp->res.addHeader(
1295 "Location", (req.isSecure ? "https://" : "http://") +
1296 std::string(req.getHeaderValue("Host")) +
1297 std::string(req.url) + "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001298 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001299 return;
1300 }
1301
Ed Tanous271584a2019-07-09 16:24:22 -07001302 if ((rules[ruleIndex]->getMethods() &
1303 (1U << static_cast<uint32_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001304 {
1305 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1306 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001307 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001308 << rules[ruleIndex]->getMethods();
zhanghch058d1b46d2021-04-01 11:18:24 +08001309 asyncResp->res.result(
1310 boost::beast::http::status::method_not_allowed);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001311 return;
1312 }
1313
1314 BMCWEB_LOG_DEBUG << "Matched rule '" << rules[ruleIndex]->rule << "' "
Ed Tanous271584a2019-07-09 16:24:22 -07001315 << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001316 << rules[ruleIndex]->getMethods();
1317
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001318 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001319 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001320 rules[ruleIndex]->handle(req, asyncResp, found.second);
James Feist7166bf02019-12-10 16:52:14 +00001321 return;
1322 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001323
1324 crow::connections::systemBus->async_method_call(
Ed Tanous168e20c2021-12-13 14:39:53 -08001325 [&req, asyncResp, &rules, ruleIndex,
1326 found](const boost::system::error_code ec,
1327 const std::map<std::string, dbus::utility::DbusVariantType>&
1328 userInfo) {
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001329 if (ec)
1330 {
1331 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
zhanghch058d1b46d2021-04-01 11:18:24 +08001332 asyncResp->res.result(
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001333 boost::beast::http::status::internal_server_error);
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001334 return;
1335 }
1336
1337 const std::string* userRolePtr = nullptr;
1338 auto userInfoIter = userInfo.find("UserPrivilege");
1339 if (userInfoIter != userInfo.end())
1340 {
1341 userRolePtr =
1342 std::get_if<std::string>(&userInfoIter->second);
1343 }
1344
1345 std::string userRole{};
1346 if (userRolePtr != nullptr)
1347 {
1348 userRole = *userRolePtr;
1349 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1350 << " userRole = " << *userRolePtr;
1351 }
1352
Ed Tanous5dc924d2021-12-20 09:17:28 -08001353 const bool* remoteUserPtr = nullptr;
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001354 auto remoteUserIter = userInfo.find("RemoteUser");
1355 if (remoteUserIter != userInfo.end())
1356 {
1357 remoteUserPtr = std::get_if<bool>(&remoteUserIter->second);
1358 }
1359 if (remoteUserPtr == nullptr)
1360 {
1361 BMCWEB_LOG_ERROR
1362 << "RemoteUser property missing or wrong type";
zhanghch058d1b46d2021-04-01 11:18:24 +08001363 asyncResp->res.result(
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001364 boost::beast::http::status::internal_server_error);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001365 return;
1366 }
1367 bool remoteUser = *remoteUserPtr;
1368
1369 bool passwordExpired = false; // default for remote user
1370 if (!remoteUser)
1371 {
Ed Tanous5dc924d2021-12-20 09:17:28 -08001372 const bool* passwordExpiredPtr = nullptr;
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001373 auto passwordExpiredIter =
1374 userInfo.find("UserPasswordExpired");
1375 if (passwordExpiredIter != userInfo.end())
1376 {
1377 passwordExpiredPtr =
1378 std::get_if<bool>(&passwordExpiredIter->second);
1379 }
1380 if (passwordExpiredPtr != nullptr)
1381 {
1382 passwordExpired = *passwordExpiredPtr;
1383 }
1384 else
1385 {
1386 BMCWEB_LOG_ERROR
1387 << "UserPasswordExpired property is expected for"
1388 " local user but is missing or wrong type";
zhanghch058d1b46d2021-04-01 11:18:24 +08001389 asyncResp->res.result(
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001390 boost::beast::http::status::internal_server_error);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001391 return;
1392 }
1393 }
1394
Ed Tanous23a21a12020-07-25 04:45:05 +00001395 // Get the userprivileges from the role
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001396 redfish::Privileges userPrivileges =
1397 redfish::getUserPrivileges(userRole);
1398
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001399 // Set isConfigureSelfOnly based on D-Bus results. This
1400 // ignores the results from both pamAuthenticateUser and the
1401 // value from any previous use of this session.
1402 req.session->isConfigureSelfOnly = passwordExpired;
1403
Ed Tanous23a21a12020-07-25 04:45:05 +00001404 // Modifyprivileges if isConfigureSelfOnly.
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001405 if (req.session->isConfigureSelfOnly)
1406 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001407 // Remove allprivileges except ConfigureSelf
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001408 userPrivileges = userPrivileges.intersection(
1409 redfish::Privileges{"ConfigureSelf"});
1410 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1411 }
1412
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001413 if (!rules[ruleIndex]->checkPrivileges(userPrivileges))
1414 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001415 asyncResp->res.result(
1416 boost::beast::http::status::forbidden);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001417 if (req.session->isConfigureSelfOnly)
1418 {
1419 redfish::messages::passwordChangeRequired(
zhanghch058d1b46d2021-04-01 11:18:24 +08001420 asyncResp->res,
Ed Tanousace85d62021-10-26 12:45:59 -07001421 crow::utility::urlFromPieces(
1422 "redfish", "v1", "AccountService", "Accounts",
1423 req.session->username));
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001424 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001425 return;
1426 }
1427
1428 req.userRole = userRole;
zhanghch058d1b46d2021-04-01 11:18:24 +08001429 rules[ruleIndex]->handle(req, asyncResp, found.second);
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001430 },
1431 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1432 "xyz.openbmc_project.User.Manager", "GetUserInfo",
1433 req.session->username);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001434 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001435
Ed Tanous1abe55e2018-09-05 08:30:59 -07001436 void debugPrint()
1437 {
Ed Tanous271584a2019-07-09 16:24:22 -07001438 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001439 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001440 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1441 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001442 perMethods[i].trie.debugPrint();
1443 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001444 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001445
Ed Tanous1abe55e2018-09-05 08:30:59 -07001446 std::vector<const std::string*> getRoutes(const std::string& parent)
1447 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001448 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001449
1450 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001451 {
Tanousf00032d2018-11-05 01:18:10 -03001452 std::vector<unsigned> x;
1453 pm.trie.findRouteIndexes(parent, x);
1454 for (unsigned index : x)
1455 {
1456 ret.push_back(&pm.rules[index]->rule);
1457 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001458 }
1459 return ret;
1460 }
1461
1462 private:
Tanousf00032d2018-11-05 01:18:10 -03001463 struct PerMethod
1464 {
1465 std::vector<BaseRule*> rules;
1466 Trie trie;
1467 // rule index 0, 1 has special meaning; preallocate it to avoid
1468 // duplication.
1469 PerMethod() : rules(2)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001470 {}
Tanousf00032d2018-11-05 01:18:10 -03001471 };
Ed Tanous888880a2020-08-24 13:48:50 -07001472
1473 const static size_t maxHttpVerbCount =
Ed Tanouscc090442020-10-07 08:20:50 -07001474 static_cast<size_t>(boost::beast::http::verb::unlink);
Ed Tanous888880a2020-08-24 13:48:50 -07001475
Tanousf00032d2018-11-05 01:18:10 -03001476 std::array<PerMethod, maxHttpVerbCount> perMethods;
1477 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001478};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001479} // namespace crow