blob: abb1d437439d60818acbc12463814fd4fa5d448f [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>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050015
Ed Tanouse0d918b2018-03-27 17:41:04 -070016#include <cerrno>
Ed Tanous7045c8d2017-04-03 10:04:37 -070017#include <cstdint>
Ed Tanouse0d918b2018-03-27 17:41:04 -070018#include <cstdlib>
Ed Tanous3dac7492017-08-02 13:46:20 -070019#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070020#include <memory>
21#include <tuple>
Ed Tanous7045c8d2017-04-03 10:04:37 -070022#include <utility>
23#include <vector>
Ed Tanous9140a672017-04-24 17:01:32 -070024
Ed Tanous1abe55e2018-09-05 08:30:59 -070025namespace crow
26{
Tanousf00032d2018-11-05 01:18:10 -030027
Ed Tanous1abe55e2018-09-05 08:30:59 -070028class BaseRule
29{
30 public:
Ed Tanousf23b7292020-10-15 09:41:17 -070031 BaseRule(const std::string& thisRule) : rule(thisRule)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050032 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070033
Ed Tanous0c0084a2019-10-24 15:57:51 -070034 virtual ~BaseRule() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -070035
Ed Tanous1abe55e2018-09-05 08:30:59 -070036 virtual void validate() = 0;
37 std::unique_ptr<BaseRule> upgrade()
38 {
39 if (ruleToUpgrade)
Ed Tanous3174e4d2020-10-07 11:41:22 -070040 {
Ed Tanous1abe55e2018-09-05 08:30:59 -070041 return std::move(ruleToUpgrade);
Ed Tanous3174e4d2020-10-07 11:41:22 -070042 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070043 return {};
44 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070045
zhanghch058d1b46d2021-04-01 11:18:24 +080046 virtual void handle(const Request&,
47 const std::shared_ptr<bmcweb::AsyncResp>&,
48 const RoutingParams&) = 0;
Ed Tanousceac6f72018-12-02 11:58:47 -080049 virtual void handleUpgrade(const Request&, Response& res,
50 boost::asio::ip::tcp::socket&&)
Ed Tanous1abe55e2018-09-05 08:30:59 -070051 {
Ed Tanousde5c9f32019-03-26 09:17:55 -070052 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070053 res.end();
54 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -070055#ifdef BMCWEB_ENABLE_SSL
Ed Tanousceac6f72018-12-02 11:58:47 -080056 virtual void
57 handleUpgrade(const Request&, Response& res,
58 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&)
Ed Tanous1abe55e2018-09-05 08:30:59 -070059 {
Ed Tanousde5c9f32019-03-26 09:17:55 -070060 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -070061 res.end();
62 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070063#endif
64
Ed Tanous271584a2019-07-09 16:24:22 -070065 size_t getMethods()
Ed Tanous1abe55e2018-09-05 08:30:59 -070066 {
67 return methodsBitfield;
68 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070069
Tanousf00032d2018-11-05 01:18:10 -030070 bool checkPrivileges(const redfish::Privileges& userPrivileges)
71 {
72 // If there are no privileges assigned, assume no privileges
73 // required
74 if (privilegesSet.empty())
75 {
76 return true;
77 }
78
79 for (const redfish::Privileges& requiredPrivileges : privilegesSet)
80 {
81 if (userPrivileges.isSupersetOf(requiredPrivileges))
82 {
83 return true;
84 }
85 }
86 return false;
87 }
88
Ed Tanous271584a2019-07-09 16:24:22 -070089 size_t methodsBitfield{
90 1 << static_cast<size_t>(boost::beast::http::verb::get)};
Ed Tanous7045c8d2017-04-03 10:04:37 -070091
Tanousf00032d2018-11-05 01:18:10 -030092 std::vector<redfish::Privileges> privilegesSet;
93
Ed Tanous1abe55e2018-09-05 08:30:59 -070094 std::string rule;
95 std::string nameStr;
Ed Tanous7045c8d2017-04-03 10:04:37 -070096
Ed Tanous1abe55e2018-09-05 08:30:59 -070097 std::unique_ptr<BaseRule> ruleToUpgrade;
Ed Tanous7045c8d2017-04-03 10:04:37 -070098
Ed Tanous1abe55e2018-09-05 08:30:59 -070099 friend class Router;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500100 template <typename T>
101 friend struct RuleParameterTraits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700102};
103
Ed Tanous1abe55e2018-09-05 08:30:59 -0700104namespace detail
105{
106namespace routing_handler_call_helper
107{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500108template <typename T, int Pos>
109struct CallPair
Ed Tanous1abe55e2018-09-05 08:30:59 -0700110{
111 using type = T;
112 static const int pos = Pos;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700113};
114
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500115template <typename H1>
116struct CallParams
Ed Tanous1abe55e2018-09-05 08:30:59 -0700117{
118 H1& handler;
119 const RoutingParams& params;
120 const Request& req;
zhanghch058d1b46d2021-04-01 11:18:24 +0800121 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700122};
123
124template <typename F, int NInt, int NUint, int NDouble, int NString,
125 typename S1, typename S2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700126struct Call
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500127{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700128
129template <typename F, int NInt, int NUint, int NDouble, int NString,
130 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700131struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<int64_t, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700132 black_magic::S<Args2...>>
133{
134 void operator()(F cparams)
135 {
136 using pushed = typename black_magic::S<Args2...>::template push_back<
137 CallPair<int64_t, NInt>>;
138 Call<F, NInt + 1, NUint, NDouble, NString, black_magic::S<Args1...>,
139 pushed>()(cparams);
140 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700141};
142
143template <typename F, int NInt, int NUint, int NDouble, int NString,
144 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700145struct Call<F, NInt, NUint, NDouble, NString,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700146 black_magic::S<uint64_t, Args1...>, black_magic::S<Args2...>>
147{
148 void operator()(F cparams)
149 {
150 using pushed = typename black_magic::S<Args2...>::template push_back<
151 CallPair<uint64_t, NUint>>;
152 Call<F, NInt, NUint + 1, NDouble, NString, black_magic::S<Args1...>,
153 pushed>()(cparams);
154 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700155};
156
157template <typename F, int NInt, int NUint, int NDouble, int NString,
158 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700159struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<double, Args1...>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700160 black_magic::S<Args2...>>
161{
162 void operator()(F cparams)
163 {
164 using pushed = typename black_magic::S<Args2...>::template push_back<
165 CallPair<double, NDouble>>;
166 Call<F, NInt, NUint, NDouble + 1, NString, black_magic::S<Args1...>,
167 pushed>()(cparams);
168 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700169};
170
171template <typename F, int NInt, int NUint, int NDouble, int NString,
172 typename... Args1, typename... Args2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700173struct Call<F, NInt, NUint, NDouble, NString,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700174 black_magic::S<std::string, Args1...>, black_magic::S<Args2...>>
175{
176 void operator()(F cparams)
177 {
178 using pushed = typename black_magic::S<Args2...>::template push_back<
179 CallPair<std::string, NString>>;
180 Call<F, NInt, NUint, NDouble, NString + 1, black_magic::S<Args1...>,
181 pushed>()(cparams);
182 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700183};
184
185template <typename F, int NInt, int NUint, int NDouble, int NString,
186 typename... Args1>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700187struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<>,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700188 black_magic::S<Args1...>>
189{
190 void operator()(F cparams)
191 {
192 cparams.handler(
zhanghch058d1b46d2021-04-01 11:18:24 +0800193 cparams.req, cparams.asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700194 cparams.params.template get<typename Args1::type>(Args1::pos)...);
195 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700196};
197
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500198template <typename Func, typename... ArgsWrapped>
199struct Wrapped
Ed Tanous1abe55e2018-09-05 08:30:59 -0700200{
201 template <typename... Args>
202 void set(
203 Func f,
204 typename std::enable_if<
205 !std::is_same<
206 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
207 const Request&>::value,
208 int>::type = 0)
209 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800210 handler = [f = std::move(f)](
211 const Request&,
212 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
213 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700214 }
215
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500216 template <typename Req, typename... Args>
217 struct ReqHandlerWrapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700218 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000219 ReqHandlerWrapper(Func fIn) : f(std::move(fIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500220 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700221
zhanghch058d1b46d2021-04-01 11:18:24 +0800222 void operator()(const Request& req,
223 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
224 Args... args)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700225 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800226 asyncResp->res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700227 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700228
Ed Tanous1abe55e2018-09-05 08:30:59 -0700229 Func f;
230 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700231
Ed Tanous1abe55e2018-09-05 08:30:59 -0700232 template <typename... Args>
233 void set(
234 Func f,
235 typename std::enable_if<
236 std::is_same<
237 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
238 const Request&>::value &&
239 !std::is_same<typename std::tuple_element<
240 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800241 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700242 int>::type = 0)
243 {
244 handler = ReqHandlerWrapper<Args...>(std::move(f));
245 /*handler = (
246 [f = std::move(f)]
247 (const Request& req, Response& res, Args... args){
Ed Tanousde5c9f32019-03-26 09:17:55 -0700248 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700249 res.end();
250 });*/
251 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700252
Ed Tanous1abe55e2018-09-05 08:30:59 -0700253 template <typename... Args>
254 void set(
255 Func f,
256 typename std::enable_if<
257 std::is_same<
258 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
259 const Request&>::value &&
260 std::is_same<typename std::tuple_element<
261 1, std::tuple<Args..., void, void>>::type,
zhanghch058d1b46d2021-04-01 11:18:24 +0800262 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700263 int>::type = 0)
264 {
265 handler = std::move(f);
266 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700267
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500268 template <typename... Args>
269 struct HandlerTypeHelper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700270 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800271 using type = std::function<void(
272 const crow::Request&, const std::shared_ptr<bmcweb::AsyncResp>&,
273 Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700274 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700275 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700276 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700277
Ed Tanous1abe55e2018-09-05 08:30:59 -0700278 template <typename... Args>
279 struct HandlerTypeHelper<const Request&, Args...>
280 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800281 using type = std::function<void(
282 const crow::Request&, const std::shared_ptr<bmcweb::AsyncResp>&,
283 Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700284 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700285 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700286 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700287
Ed Tanous1abe55e2018-09-05 08:30:59 -0700288 template <typename... Args>
zhanghch058d1b46d2021-04-01 11:18:24 +0800289 struct HandlerTypeHelper<const Request&,
290 const std::shared_ptr<bmcweb::AsyncResp>&, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700291 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800292 using type = std::function<void(
293 const crow::Request&, const std::shared_ptr<bmcweb::AsyncResp>&,
294 Args...)>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700295 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700296 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700297 };
298
299 typename HandlerTypeHelper<ArgsWrapped...>::type handler;
300
zhanghch058d1b46d2021-04-01 11:18:24 +0800301 void operator()(const Request& req,
302 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700303 const RoutingParams& params)
304 {
305 detail::routing_handler_call_helper::Call<
306 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
307 0, 0, 0, 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
308 black_magic::S<>>()(
309 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800310 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700311 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700312};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700313} // namespace routing_handler_call_helper
314} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700315
Ed Tanous1abe55e2018-09-05 08:30:59 -0700316class WebSocketRule : public BaseRule
317{
318 using self_t = WebSocketRule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700319
Ed Tanous1abe55e2018-09-05 08:30:59 -0700320 public:
Ed Tanousf23b7292020-10-15 09:41:17 -0700321 WebSocketRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500322 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700323
Ed Tanous1abe55e2018-09-05 08:30:59 -0700324 void validate() override
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500325 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700326
zhanghch058d1b46d2021-04-01 11:18:24 +0800327 void handle(const Request&,
328 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
329 const RoutingParams&) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700330 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800331 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700332 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700333
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000334 void handleUpgrade(const Request& req, Response&,
Ed Tanousceac6f72018-12-02 11:58:47 -0800335 boost::asio::ip::tcp::socket&& adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700336 {
Ratan Gupta02453b12019-10-22 14:43:36 +0530337 std::shared_ptr<
338 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>
339 myConnection = std::make_shared<
340 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000341 req, std::move(adaptor), openHandler, messageHandler,
Ratan Gupta02453b12019-10-22 14:43:36 +0530342 closeHandler, errorHandler);
343 myConnection->start();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700344 }
345#ifdef BMCWEB_ENABLE_SSL
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000346 void handleUpgrade(const Request& req, Response&,
Ed Tanousceac6f72018-12-02 11:58:47 -0800347 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
348 adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700349 {
Ed Tanousceac6f72018-12-02 11:58:47 -0800350 std::shared_ptr<crow::websocket::ConnectionImpl<
351 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
352 myConnection = std::make_shared<crow::websocket::ConnectionImpl<
353 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000354 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanousceac6f72018-12-02 11:58:47 -0800355 closeHandler, errorHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700356 myConnection->start();
357 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700358#endif
359
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500360 template <typename Func>
361 self_t& onopen(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700362 {
363 openHandler = f;
364 return *this;
365 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700366
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500367 template <typename Func>
368 self_t& onmessage(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700369 {
370 messageHandler = f;
371 return *this;
372 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700373
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500374 template <typename Func>
375 self_t& onclose(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700376 {
377 closeHandler = f;
378 return *this;
379 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700380
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500381 template <typename Func>
382 self_t& onerror(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700383 {
384 errorHandler = f;
385 return *this;
386 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700387
Ed Tanous1abe55e2018-09-05 08:30:59 -0700388 protected:
zhanghch050f3d3a02021-10-21 14:07:57 +0800389 std::function<void(crow::websocket::Connection&)> openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700390 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
391 messageHandler;
392 std::function<void(crow::websocket::Connection&, const std::string&)>
393 closeHandler;
394 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700395};
396
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500397template <typename T>
398struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700399{
400 using self_t = T;
401 WebSocketRule& websocket()
402 {
Ed Tanous271584a2019-07-09 16:24:22 -0700403 self_t* self = static_cast<self_t*>(this);
404 WebSocketRule* p = new WebSocketRule(self->rule);
405 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700406 return *p;
407 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700408
Ed Tanousf23b7292020-10-15 09:41:17 -0700409 self_t& name(const std::string_view name) noexcept
Ed Tanous1abe55e2018-09-05 08:30:59 -0700410 {
Ed Tanous271584a2019-07-09 16:24:22 -0700411 self_t* self = static_cast<self_t*>(this);
Ed Tanousf23b7292020-10-15 09:41:17 -0700412 self->nameStr = name;
Ed Tanous271584a2019-07-09 16:24:22 -0700413 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700414 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700415
Ed Tanous1abe55e2018-09-05 08:30:59 -0700416 self_t& methods(boost::beast::http::verb method)
417 {
Ed Tanous271584a2019-07-09 16:24:22 -0700418 self_t* self = static_cast<self_t*>(this);
419 self->methodsBitfield = 1U << static_cast<size_t>(method);
420 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700421 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700422
Ed Tanous1abe55e2018-09-05 08:30:59 -0700423 template <typename... MethodArgs>
Ed Tanous81ce6092020-12-17 16:54:55 +0000424 self_t& methods(boost::beast::http::verb method, MethodArgs... argsMethod)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700425 {
Ed Tanous271584a2019-07-09 16:24:22 -0700426 self_t* self = static_cast<self_t*>(this);
Ed Tanous81ce6092020-12-17 16:54:55 +0000427 methods(argsMethod...);
Ed Tanous271584a2019-07-09 16:24:22 -0700428 self->methodsBitfield |= 1U << static_cast<size_t>(method);
429 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700430 }
Tanousf00032d2018-11-05 01:18:10 -0300431
Ed Tanous432a8902021-06-14 15:28:56 -0700432 self_t& privileges(
433 const std::initializer_list<std::initializer_list<const char*>>& p)
Tanousf00032d2018-11-05 01:18:10 -0300434 {
Ed Tanous271584a2019-07-09 16:24:22 -0700435 self_t* self = static_cast<self_t*>(this);
Ed Tanous432a8902021-06-14 15:28:56 -0700436 for (const std::initializer_list<const char*>& privilege : p)
Tanousf00032d2018-11-05 01:18:10 -0300437 {
Ed Tanous271584a2019-07-09 16:24:22 -0700438 self->privilegesSet.emplace_back(privilege);
Tanousf00032d2018-11-05 01:18:10 -0300439 }
Ed Tanous271584a2019-07-09 16:24:22 -0700440 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300441 }
Ed Tanoused398212021-06-09 17:05:54 -0700442
443 template <size_t N, typename... MethodArgs>
444 self_t& privileges(const std::array<redfish::Privileges, N>& p)
445 {
446 self_t* self = static_cast<self_t*>(this);
447 for (const redfish::Privileges& privilege : p)
448 {
449 self->privilegesSet.emplace_back(privilege);
450 }
451 return *self;
452 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700453};
454
Ed Tanous1abe55e2018-09-05 08:30:59 -0700455class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
456{
457 public:
Ed Tanousf23b7292020-10-15 09:41:17 -0700458 DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500459 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700460
Ed Tanous1abe55e2018-09-05 08:30:59 -0700461 void validate() override
462 {
463 if (!erasedHandler)
464 {
465 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
466 "no handler for url " + rule);
467 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700468 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700469
zhanghch058d1b46d2021-04-01 11:18:24 +0800470 void handle(const Request& req,
471 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700472 const RoutingParams& params) override
473 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800474 erasedHandler(req, asyncResp, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700475 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700476
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500477 template <typename Func>
478 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479 {
480 using function_t = utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481 erasedHandler =
Ed Tanous988403c2020-08-24 11:29:49 -0700482 wrap(std::move(f),
483 std::make_integer_sequence<unsigned, function_t::arity>{});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700484 }
485
486 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500487 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700488 // enable_if Arg1 != request
489
490 template <typename Func, unsigned... Indices>
zhanghch058d1b46d2021-04-01 11:18:24 +0800491 std::function<void(const Request&,
492 const std::shared_ptr<bmcweb::AsyncResp>&,
493 const RoutingParams&)>
Ed Tanous988403c2020-08-24 11:29:49 -0700494 wrap(Func f, std::integer_sequence<unsigned, Indices...>)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700495 {
Ed Tanous988403c2020-08-24 11:29:49 -0700496 using function_t = crow::utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700497
498 if (!black_magic::isParameterTagCompatible(
Ed Tanous988403c2020-08-24 11:29:49 -0700499 black_magic::getParameterTag(rule.c_str()),
500 black_magic::computeParameterTagFromArgsList<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700501 typename function_t::template arg<Indices>...>::value))
502 {
503 throw std::runtime_error("routeDynamic: Handler type is mismatched "
504 "with URL parameters: " +
505 rule);
506 }
507 auto ret = detail::routing_handler_call_helper::Wrapped<
508 Func, typename function_t::template arg<Indices>...>();
509 ret.template set<typename function_t::template arg<Indices>...>(
510 std::move(f));
511 return ret;
512 }
513
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500514 template <typename Func>
515 void operator()(std::string name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700516 {
517 nameStr = std::move(name);
518 (*this).template operator()<Func>(std::forward(f));
519 }
520
521 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800522 std::function<void(const Request&,
523 const std::shared_ptr<bmcweb::AsyncResp>&,
524 const RoutingParams&)>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700525 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700526};
527
528template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500529class TaggedRule :
530 public BaseRule,
531 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700532{
533 public:
534 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700535
Ed Tanousf23b7292020-10-15 09:41:17 -0700536 TaggedRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500537 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700538
Ed Tanous1abe55e2018-09-05 08:30:59 -0700539 void validate() override
540 {
541 if (!handler)
542 {
543 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
544 "no handler for url " + rule);
545 }
546 }
547
548 template <typename Func>
549 typename std::enable_if<
550 black_magic::CallHelper<Func, black_magic::S<Args...>>::value,
551 void>::type
552 operator()(Func&& f)
553 {
554 static_assert(
555 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
556 black_magic::CallHelper<
557 Func, black_magic::S<crow::Request, Args...>>::value,
558 "Handler type is mismatched with URL parameters");
559 static_assert(
560 !std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
561 "Handler function cannot have void return type; valid return "
562 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500563 "string, int, crow::response, nlohmann::json");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700564
zhanghch058d1b46d2021-04-01 11:18:24 +0800565 handler = [f = std::move(f)](
566 const Request&,
567 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
568 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700569 }
570
571 template <typename Func>
572 typename std::enable_if<
573 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
Ed Tanous7045c8d2017-04-03 10:04:37 -0700574 black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700575 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700576 void>::type
577 operator()(Func&& f)
578 {
579 static_assert(
580 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
581 black_magic::CallHelper<
582 Func, black_magic::S<crow::Request, Args...>>::value,
583 "Handler type is mismatched with URL parameters");
584 static_assert(
585 !std::is_same<void, decltype(f(std::declval<crow::Request>(),
586 std::declval<Args>()...))>::value,
587 "Handler function cannot have void return type; valid return "
588 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500589 "string, int, crow::response,nlohmann::json");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700590
zhanghch058d1b46d2021-04-01 11:18:24 +0800591 handler = [f = std::move(f)](
592 const crow::Request& req,
593 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
594 Args... args) { asyncResp->res.result(f(req, args...)); };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700595 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700596
Ed Tanous1abe55e2018-09-05 08:30:59 -0700597 template <typename Func>
598 typename std::enable_if<
599 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
600 !black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700601 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700602 void>::type
603 operator()(Func&& f)
604 {
605 static_assert(
606 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
607 black_magic::CallHelper<
608 Func, black_magic::S<crow::Request, Args...>>::value ||
609 black_magic::CallHelper<
zhanghch058d1b46d2021-04-01 11:18:24 +0800610 Func, black_magic::S<crow::Request,
611 std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700612 Args...>>::value,
613 "Handler type is mismatched with URL parameters");
614 static_assert(
zhanghch058d1b46d2021-04-01 11:18:24 +0800615 std::is_same<
616 void,
617 decltype(f(std::declval<crow::Request>(),
618 std::declval<std::shared_ptr<bmcweb::AsyncResp>&>(),
619 std::declval<Args>()...))>::value,
Tanousf00032d2018-11-05 01:18:10 -0300620 "Handler function with response argument should have void "
621 "return "
Ed Tanous1abe55e2018-09-05 08:30:59 -0700622 "type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700623
Ed Tanous1abe55e2018-09-05 08:30:59 -0700624 handler = std::move(f);
625 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700626
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500627 template <typename Func>
Ed Tanousf23b7292020-10-15 09:41:17 -0700628 void operator()(const std::string_view name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700629 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700630 nameStr = name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700631 (*this).template operator()<Func>(std::forward(f));
632 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700633
zhanghch058d1b46d2021-04-01 11:18:24 +0800634 void handle(const Request& req,
635 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636 const RoutingParams& params) override
637 {
638 detail::routing_handler_call_helper::Call<
639 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
640 0, 0, 0, 0, black_magic::S<Args...>, black_magic::S<>>()(
641 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800642 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700643 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700644
Ed Tanous1abe55e2018-09-05 08:30:59 -0700645 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800646 std::function<void(const crow::Request&,
647 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>
648 handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700649};
650
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700651const int ruleSpecialRedirectSlash = 1;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700652
Ed Tanous1abe55e2018-09-05 08:30:59 -0700653class Trie
654{
655 public:
656 struct Node
657 {
658 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700659 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
660 paramChildrens{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700661 boost::container::flat_map<std::string, unsigned> children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700662
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 bool isSimpleNode() const
664 {
665 return !ruleIndex && std::all_of(std::begin(paramChildrens),
666 std::end(paramChildrens),
Ed Tanous271584a2019-07-09 16:24:22 -0700667 [](size_t x) { return !x; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700668 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700669 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700670
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 Trie() : nodes(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500672 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673
674 private:
675 void optimizeNode(Node* node)
676 {
Ed Tanous271584a2019-07-09 16:24:22 -0700677 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700678 {
679 if (!x)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700680 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700681 continue;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700682 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 Node* child = &nodes[x];
684 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700685 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700686 if (node->children.empty())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700687 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688 return;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700689 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700690 bool mergeWithChild = true;
Tanousf00032d2018-11-05 01:18:10 -0300691 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 {
693 Node* child = &nodes[kv.second];
694 if (!child->isSimpleNode())
695 {
696 mergeWithChild = false;
697 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700698 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700699 }
700 if (mergeWithChild)
701 {
702 decltype(node->children) merged;
Tanousf00032d2018-11-05 01:18:10 -0300703 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700704 {
705 Node* child = &nodes[kv.second];
Tanousf00032d2018-11-05 01:18:10 -0300706 for (const std::pair<std::string, unsigned>& childKv :
707 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700708 {
709 merged[kv.first + childKv.first] = childKv.second;
710 }
711 }
712 node->children = std::move(merged);
713 optimizeNode(node);
714 }
715 else
716 {
Tanousf00032d2018-11-05 01:18:10 -0300717 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700718 {
719 Node* child = &nodes[kv.second];
720 optimizeNode(child);
721 }
722 }
723 }
724
725 void optimize()
726 {
727 optimizeNode(head());
728 }
729
730 public:
731 void validate()
732 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700733 optimize();
734 }
735
Ed Tanous81ce6092020-12-17 16:54:55 +0000736 void findRouteIndexes(const std::string& reqUrl,
737 std::vector<unsigned>& routeIndexes,
Tanousf00032d2018-11-05 01:18:10 -0300738 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700739 {
740 if (node == nullptr)
741 {
742 node = head();
743 }
Tanousf00032d2018-11-05 01:18:10 -0300744 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700745 {
746 const std::string& fragment = kv.first;
747 const Node* child = &nodes[kv.second];
Ed Tanous81ce6092020-12-17 16:54:55 +0000748 if (pos >= reqUrl.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700749 {
750 if (child->ruleIndex != 0 && fragment != "/")
751 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000752 routeIndexes.push_back(child->ruleIndex);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000754 findRouteIndexes(reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700755 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 }
757 else
758 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000759 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700760 {
Ed Tanous271584a2019-07-09 16:24:22 -0700761 findRouteIndexes(
Ed Tanous81ce6092020-12-17 16:54:55 +0000762 reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700763 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 }
765 }
766 }
767 }
768
769 std::pair<unsigned, RoutingParams>
Ed Tanous81ce6092020-12-17 16:54:55 +0000770 find(const std::string_view reqUrl, const Node* node = nullptr,
Ed Tanous271584a2019-07-09 16:24:22 -0700771 size_t pos = 0, RoutingParams* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700772 {
773 RoutingParams empty;
774 if (params == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700775 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700776 params = &empty;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700777 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700778
779 unsigned found{};
780 RoutingParams matchParams;
781
782 if (node == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700783 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700784 node = head();
Ed Tanous3174e4d2020-10-07 11:41:22 -0700785 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000786 if (pos == reqUrl.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700787 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700788 return {node->ruleIndex, *params};
Ed Tanous3174e4d2020-10-07 11:41:22 -0700789 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700790
791 auto updateFound =
792 [&found, &matchParams](std::pair<unsigned, RoutingParams>& ret) {
793 if (ret.first && (!found || found > ret.first))
794 {
795 found = ret.first;
796 matchParams = std::move(ret.second);
797 }
798 };
799
Ed Tanous271584a2019-07-09 16:24:22 -0700800 if (node->paramChildrens[static_cast<size_t>(ParamType::INT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000802 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700803 if ((c >= '0' && c <= '9') || c == '+' || c == '-')
804 {
805 char* eptr;
806 errno = 0;
807 long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000808 std::strtoll(reqUrl.data() + pos, &eptr, 10);
809 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700810 {
811 params->intParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000812 std::pair<unsigned, RoutingParams> ret =
813 find(reqUrl,
814 &nodes[node->paramChildrens[static_cast<size_t>(
815 ParamType::INT)]],
816 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700817 updateFound(ret);
818 params->intParams.pop_back();
819 }
820 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700821 }
822
Ed Tanous271584a2019-07-09 16:24:22 -0700823 if (node->paramChildrens[static_cast<size_t>(ParamType::UINT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700824 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000825 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700826 if ((c >= '0' && c <= '9') || c == '+')
827 {
828 char* eptr;
829 errno = 0;
830 unsigned long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000831 std::strtoull(reqUrl.data() + pos, &eptr, 10);
832 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 {
834 params->uintParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000835 std::pair<unsigned, RoutingParams> ret =
836 find(reqUrl,
837 &nodes[node->paramChildrens[static_cast<size_t>(
838 ParamType::UINT)]],
839 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700840 updateFound(ret);
841 params->uintParams.pop_back();
842 }
843 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700844 }
845
Ed Tanous271584a2019-07-09 16:24:22 -0700846 if (node->paramChildrens[static_cast<size_t>(ParamType::DOUBLE)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700847 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000848 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700849 if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
850 {
851 char* eptr;
852 errno = 0;
Ed Tanous81ce6092020-12-17 16:54:55 +0000853 double value = std::strtod(reqUrl.data() + pos, &eptr);
854 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700855 {
856 params->doubleParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000857 std::pair<unsigned, RoutingParams> ret =
858 find(reqUrl,
859 &nodes[node->paramChildrens[static_cast<size_t>(
860 ParamType::DOUBLE)]],
861 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700862 updateFound(ret);
863 params->doubleParams.pop_back();
864 }
865 }
866 }
867
Ed Tanous271584a2019-07-09 16:24:22 -0700868 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700869 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000870 size_t epos = pos;
Ed Tanous81ce6092020-12-17 16:54:55 +0000871 for (; epos < reqUrl.size(); epos++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700872 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000873 if (reqUrl[epos] == '/')
Ed Tanous3174e4d2020-10-07 11:41:22 -0700874 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700875 break;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700876 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700877 }
878
879 if (epos != pos)
880 {
881 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000882 reqUrl.substr(pos, epos - pos));
Tanousf00032d2018-11-05 01:18:10 -0300883 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000884 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700885 &nodes[node->paramChildrens[static_cast<size_t>(
886 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000887 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700888 updateFound(ret);
889 params->stringParams.pop_back();
890 }
891 }
892
Ed Tanous271584a2019-07-09 16:24:22 -0700893 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700894 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000895 size_t epos = reqUrl.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700896
897 if (epos != pos)
898 {
899 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000900 reqUrl.substr(pos, epos - pos));
Ed Tanous271584a2019-07-09 16:24:22 -0700901 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000902 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700903 &nodes[node->paramChildrens[static_cast<size_t>(
904 ParamType::PATH)]],
905 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700906 updateFound(ret);
907 params->stringParams.pop_back();
908 }
909 }
910
Tanousf00032d2018-11-05 01:18:10 -0300911 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700912 {
913 const std::string& fragment = kv.first;
914 const Node* child = &nodes[kv.second];
915
Ed Tanous81ce6092020-12-17 16:54:55 +0000916 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700917 {
Tanousf00032d2018-11-05 01:18:10 -0300918 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000919 find(reqUrl, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700920 updateFound(ret);
921 }
922 }
923
924 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700925 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700926
927 void add(const std::string& url, unsigned ruleIndex)
928 {
Ed Tanous271584a2019-07-09 16:24:22 -0700929 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700930
931 for (unsigned i = 0; i < url.size(); i++)
932 {
933 char c = url[i];
934 if (c == '<')
935 {
Tanousf00032d2018-11-05 01:18:10 -0300936 const static std::array<std::pair<ParamType, std::string>, 7>
937 paramTraits = {{
938 {ParamType::INT, "<int>"},
939 {ParamType::UINT, "<uint>"},
940 {ParamType::DOUBLE, "<float>"},
941 {ParamType::DOUBLE, "<double>"},
942 {ParamType::STRING, "<str>"},
943 {ParamType::STRING, "<string>"},
944 {ParamType::PATH, "<path>"},
945 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700946
Tanousf00032d2018-11-05 01:18:10 -0300947 for (const std::pair<ParamType, std::string>& x : paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700948 {
Tanousf00032d2018-11-05 01:18:10 -0300949 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700950 {
Ed Tanous271584a2019-07-09 16:24:22 -0700951 size_t index = static_cast<size_t>(x.first);
952 if (!nodes[idx].paramChildrens[index])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700953 {
Tanousf00032d2018-11-05 01:18:10 -0300954 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700955 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700956 }
Ed Tanous271584a2019-07-09 16:24:22 -0700957 idx = nodes[idx].paramChildrens[index];
958 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700959 break;
960 }
961 }
962
963 i--;
964 }
965 else
966 {
967 std::string piece(&c, 1);
968 if (!nodes[idx].children.count(piece))
969 {
Tanousf00032d2018-11-05 01:18:10 -0300970 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700971 nodes[idx].children.emplace(piece, newNodeIdx);
972 }
973 idx = nodes[idx].children[piece];
974 }
975 }
976 if (nodes[idx].ruleIndex)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700977 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700978 throw std::runtime_error("handler already exists for " + url);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700979 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700980 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700981 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700982
Ed Tanous1abe55e2018-09-05 08:30:59 -0700983 private:
Ed Tanous271584a2019-07-09 16:24:22 -0700984 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700985 {
Ed Tanous271584a2019-07-09 16:24:22 -0700986 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700987 {
988 if (n->paramChildrens[i])
989 {
990 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -0700991 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
992 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700993 {
994 case ParamType::INT:
995 BMCWEB_LOG_DEBUG << "<int>";
996 break;
997 case ParamType::UINT:
998 BMCWEB_LOG_DEBUG << "<uint>";
999 break;
1000 case ParamType::DOUBLE:
1001 BMCWEB_LOG_DEBUG << "<float>";
1002 break;
1003 case ParamType::STRING:
1004 BMCWEB_LOG_DEBUG << "<str>";
1005 break;
1006 case ParamType::PATH:
1007 BMCWEB_LOG_DEBUG << "<path>";
1008 break;
Ed Tanous23a21a12020-07-25 04:45:05 +00001009 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -07001010 BMCWEB_LOG_DEBUG << "<ERROR>";
1011 break;
1012 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001013
Ed Tanous1abe55e2018-09-05 08:30:59 -07001014 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
1015 }
1016 }
Tanousf00032d2018-11-05 01:18:10 -03001017 for (const std::pair<std::string, unsigned>& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001018 {
1019 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -07001020 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -07001021 << kv.first;
1022 debugNodePrint(&nodes[kv.second], level + 1);
1023 }
1024 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001025
Ed Tanous1abe55e2018-09-05 08:30:59 -07001026 public:
1027 void debugPrint()
1028 {
Ed Tanous271584a2019-07-09 16:24:22 -07001029 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001030 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001031
Ed Tanous1abe55e2018-09-05 08:30:59 -07001032 private:
1033 const Node* head() const
1034 {
1035 return &nodes.front();
1036 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001037
Ed Tanous1abe55e2018-09-05 08:30:59 -07001038 Node* head()
1039 {
1040 return &nodes.front();
1041 }
1042
1043 unsigned newNode()
1044 {
1045 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -07001046 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001047 }
1048
1049 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001050};
1051
Ed Tanous1abe55e2018-09-05 08:30:59 -07001052class Router
1053{
1054 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -07001055 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001056
Ed Tanous1abe55e2018-09-05 08:30:59 -07001057 DynamicRule& newRuleDynamic(const std::string& rule)
1058 {
1059 std::unique_ptr<DynamicRule> ruleObject =
1060 std::make_unique<DynamicRule>(rule);
1061 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001062 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -07001063
Ed Tanous1abe55e2018-09-05 08:30:59 -07001064 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001065 }
1066
Ed Tanous1abe55e2018-09-05 08:30:59 -07001067 template <uint64_t N>
1068 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
1069 newRuleTagged(const std::string& rule)
1070 {
1071 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
1072 TaggedRule>;
1073 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
1074 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001075 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001076
1077 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001078 }
1079
Tanousf00032d2018-11-05 01:18:10 -03001080 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001081 {
Tanousf00032d2018-11-05 01:18:10 -03001082 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001083 {
Tanousf00032d2018-11-05 01:18:10 -03001084 return;
1085 }
Ed Tanous888880a2020-08-24 13:48:50 -07001086 for (size_t method = 0, methodBit = 1; method < maxHttpVerbCount;
Ed Tanous2c70f802020-09-28 14:29:23 -07001087 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -03001088 {
Ed Tanous2c70f802020-09-28 14:29:23 -07001089 if (ruleObject->methodsBitfield & methodBit)
Tanousf00032d2018-11-05 01:18:10 -03001090 {
1091 perMethods[method].rules.emplace_back(ruleObject);
1092 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -07001093 rule, static_cast<unsigned>(
1094 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -03001095 // directory case:
1096 // request to `/about' url matches `/about/' rule
1097 if (rule.size() > 2 && rule.back() == '/')
1098 {
1099 perMethods[method].trie.add(
1100 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -07001101 static_cast<unsigned>(perMethods[method].rules.size() -
1102 1));
Tanousf00032d2018-11-05 01:18:10 -03001103 }
1104 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001105 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001106 }
1107
Ed Tanous1abe55e2018-09-05 08:30:59 -07001108 void validate()
1109 {
Tanousf00032d2018-11-05 01:18:10 -03001110 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001111 {
1112 if (rule)
1113 {
Tanousf00032d2018-11-05 01:18:10 -03001114 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001115 if (upgraded)
Ed Tanous3174e4d2020-10-07 11:41:22 -07001116 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001117 rule = std::move(upgraded);
Ed Tanous3174e4d2020-10-07 11:41:22 -07001118 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001119 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -03001120 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001121 }
1122 }
Tanousf00032d2018-11-05 01:18:10 -03001123 for (PerMethod& perMethod : perMethods)
1124 {
1125 perMethod.trie.validate();
1126 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001127 }
1128
Ed Tanous1abe55e2018-09-05 08:30:59 -07001129 template <typename Adaptor>
1130 void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
1131 {
Ed Tanous271584a2019-07-09 16:24:22 -07001132 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001133 {
1134 res.result(boost::beast::http::status::not_found);
1135 res.end();
Tanousf00032d2018-11-05 01:18:10 -03001136 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001137 }
Tanousf00032d2018-11-05 01:18:10 -03001138
Ed Tanous271584a2019-07-09 16:24:22 -07001139 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001140 Trie& trie = perMethod.trie;
1141 std::vector<BaseRule*>& rules = perMethod.rules;
1142
1143 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001144 unsigned ruleIndex = found.first;
1145 if (!ruleIndex)
1146 {
1147 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001148 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001149 res.end();
1150 return;
1151 }
1152
1153 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001154 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001155 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001156 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001157
1158 if (ruleIndex == ruleSpecialRedirectSlash)
1159 {
1160 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1161 << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001162 res.result(boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001163
1164 // TODO absolute url building
1165 if (req.getHeaderValue("Host").empty())
1166 {
1167 res.addHeader("Location", std::string(req.url) + "/");
1168 }
1169 else
1170 {
1171 res.addHeader(
1172 "Location",
1173 req.isSecure
1174 ? "https://"
1175 : "http://" + std::string(req.getHeaderValue("Host")) +
1176 std::string(req.url) + "/");
1177 }
1178 res.end();
1179 return;
1180 }
1181
Ed Tanous271584a2019-07-09 16:24:22 -07001182 if ((rules[ruleIndex]->getMethods() &
1183 (1U << static_cast<size_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001184 {
1185 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1186 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001187 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001188 << rules[ruleIndex]->getMethods();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001189 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001190 res.end();
1191 return;
1192 }
1193
1194 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rules[ruleIndex]->rule
Ed Tanous271584a2019-07-09 16:24:22 -07001195 << "' " << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001196 << rules[ruleIndex]->getMethods();
1197
1198 // any uncaught exceptions become 500s
1199 try
1200 {
1201 rules[ruleIndex]->handleUpgrade(req, res, std::move(adaptor));
1202 }
Patrick Williamsc5967042021-10-06 12:39:54 -05001203 catch (const std::exception& e)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001204 {
1205 BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001206 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001207 res.end();
1208 return;
1209 }
1210 catch (...)
1211 {
1212 BMCWEB_LOG_ERROR
1213 << "An uncaught exception occurred. The type was unknown "
1214 "so no information was available.";
Ed Tanousde5c9f32019-03-26 09:17:55 -07001215 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001216 res.end();
1217 return;
1218 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001219 }
1220
zhanghch058d1b46d2021-04-01 11:18:24 +08001221 void handle(Request& req,
1222 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001223 {
Ed Tanous271584a2019-07-09 16:24:22 -07001224 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001225 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001226 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001227 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001228 }
Ed Tanous271584a2019-07-09 16:24:22 -07001229 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001230 Trie& trie = perMethod.trie;
1231 std::vector<BaseRule*>& rules = perMethod.rules;
1232
1233 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001234
Ed Tanous1abe55e2018-09-05 08:30:59 -07001235 unsigned ruleIndex = found.first;
1236
1237 if (!ruleIndex)
1238 {
Ed Tanous2634dcd2019-03-26 09:28:06 -07001239 // Check to see if this url exists at any verb
1240 for (const PerMethod& p : perMethods)
1241 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001242 const std::pair<unsigned, RoutingParams>& found2 =
Ed Tanous2634dcd2019-03-26 09:28:06 -07001243 p.trie.find(req.url);
Ed Tanous23a21a12020-07-25 04:45:05 +00001244 if (found2.first > 0)
Ed Tanous2634dcd2019-03-26 09:28:06 -07001245 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001246 asyncResp->res.result(
1247 boost::beast::http::status::method_not_allowed);
Ed Tanous2634dcd2019-03-26 09:28:06 -07001248 return;
1249 }
1250 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001251 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
zhanghch058d1b46d2021-04-01 11:18:24 +08001252 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001253 return;
1254 }
1255
1256 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001257 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001258 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001259 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001260
1261 if (ruleIndex == ruleSpecialRedirectSlash)
1262 {
1263 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1264 << req.url;
zhanghch058d1b46d2021-04-01 11:18:24 +08001265 asyncResp->res.result(
1266 boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001267
1268 // TODO absolute url building
1269 if (req.getHeaderValue("Host").empty())
1270 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001271 asyncResp->res.addHeader("Location",
1272 std::string(req.url) + "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001273 }
1274 else
1275 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001276 asyncResp->res.addHeader(
1277 "Location", (req.isSecure ? "https://" : "http://") +
1278 std::string(req.getHeaderValue("Host")) +
1279 std::string(req.url) + "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001280 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001281 return;
1282 }
1283
Ed Tanous271584a2019-07-09 16:24:22 -07001284 if ((rules[ruleIndex]->getMethods() &
1285 (1U << static_cast<uint32_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001286 {
1287 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1288 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001289 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001290 << rules[ruleIndex]->getMethods();
zhanghch058d1b46d2021-04-01 11:18:24 +08001291 asyncResp->res.result(
1292 boost::beast::http::status::method_not_allowed);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001293 return;
1294 }
1295
1296 BMCWEB_LOG_DEBUG << "Matched rule '" << rules[ruleIndex]->rule << "' "
Ed Tanous271584a2019-07-09 16:24:22 -07001297 << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001298 << rules[ruleIndex]->getMethods();
1299
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001300 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001301 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001302 rules[ruleIndex]->handle(req, asyncResp, found.second);
James Feist7166bf02019-12-10 16:52:14 +00001303 return;
1304 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001305
1306 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001307 [&req, asyncResp, &rules, ruleIndex, found](
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001308 const boost::system::error_code ec,
1309 std::map<std::string, std::variant<bool, std::string,
1310 std::vector<std::string>>>
1311 userInfo) {
1312 if (ec)
1313 {
1314 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
zhanghch058d1b46d2021-04-01 11:18:24 +08001315 asyncResp->res.result(
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001316 boost::beast::http::status::internal_server_error);
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001317 return;
1318 }
1319
1320 const std::string* userRolePtr = nullptr;
1321 auto userInfoIter = userInfo.find("UserPrivilege");
1322 if (userInfoIter != userInfo.end())
1323 {
1324 userRolePtr =
1325 std::get_if<std::string>(&userInfoIter->second);
1326 }
1327
1328 std::string userRole{};
1329 if (userRolePtr != nullptr)
1330 {
1331 userRole = *userRolePtr;
1332 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1333 << " userRole = " << *userRolePtr;
1334 }
1335
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001336 bool* remoteUserPtr = nullptr;
1337 auto remoteUserIter = userInfo.find("RemoteUser");
1338 if (remoteUserIter != userInfo.end())
1339 {
1340 remoteUserPtr = std::get_if<bool>(&remoteUserIter->second);
1341 }
1342 if (remoteUserPtr == nullptr)
1343 {
1344 BMCWEB_LOG_ERROR
1345 << "RemoteUser property missing or wrong type";
zhanghch058d1b46d2021-04-01 11:18:24 +08001346 asyncResp->res.result(
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001347 boost::beast::http::status::internal_server_error);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001348 return;
1349 }
1350 bool remoteUser = *remoteUserPtr;
1351
1352 bool passwordExpired = false; // default for remote user
1353 if (!remoteUser)
1354 {
1355 bool* passwordExpiredPtr = nullptr;
1356 auto passwordExpiredIter =
1357 userInfo.find("UserPasswordExpired");
1358 if (passwordExpiredIter != userInfo.end())
1359 {
1360 passwordExpiredPtr =
1361 std::get_if<bool>(&passwordExpiredIter->second);
1362 }
1363 if (passwordExpiredPtr != nullptr)
1364 {
1365 passwordExpired = *passwordExpiredPtr;
1366 }
1367 else
1368 {
1369 BMCWEB_LOG_ERROR
1370 << "UserPasswordExpired property is expected for"
1371 " local user but is missing or wrong type";
zhanghch058d1b46d2021-04-01 11:18:24 +08001372 asyncResp->res.result(
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001373 boost::beast::http::status::internal_server_error);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001374 return;
1375 }
1376 }
1377
Ed Tanous23a21a12020-07-25 04:45:05 +00001378 // Get the userprivileges from the role
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001379 redfish::Privileges userPrivileges =
1380 redfish::getUserPrivileges(userRole);
1381
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001382 // Set isConfigureSelfOnly based on D-Bus results. This
1383 // ignores the results from both pamAuthenticateUser and the
1384 // value from any previous use of this session.
1385 req.session->isConfigureSelfOnly = passwordExpired;
1386
Ed Tanous23a21a12020-07-25 04:45:05 +00001387 // Modifyprivileges if isConfigureSelfOnly.
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001388 if (req.session->isConfigureSelfOnly)
1389 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001390 // Remove allprivileges except ConfigureSelf
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001391 userPrivileges = userPrivileges.intersection(
1392 redfish::Privileges{"ConfigureSelf"});
1393 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1394 }
1395
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001396 if (!rules[ruleIndex]->checkPrivileges(userPrivileges))
1397 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001398 asyncResp->res.result(
1399 boost::beast::http::status::forbidden);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001400 if (req.session->isConfigureSelfOnly)
1401 {
1402 redfish::messages::passwordChangeRequired(
zhanghch058d1b46d2021-04-01 11:18:24 +08001403 asyncResp->res,
1404 "/redfish/v1/AccountService/Accounts/" +
1405 req.session->username);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001406 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001407 return;
1408 }
1409
1410 req.userRole = userRole;
zhanghch058d1b46d2021-04-01 11:18:24 +08001411 rules[ruleIndex]->handle(req, asyncResp, found.second);
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001412 },
1413 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1414 "xyz.openbmc_project.User.Manager", "GetUserInfo",
1415 req.session->username);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001416 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001417
Ed Tanous1abe55e2018-09-05 08:30:59 -07001418 void debugPrint()
1419 {
Ed Tanous271584a2019-07-09 16:24:22 -07001420 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001421 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001422 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1423 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001424 perMethods[i].trie.debugPrint();
1425 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001426 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001427
Ed Tanous1abe55e2018-09-05 08:30:59 -07001428 std::vector<const std::string*> getRoutes(const std::string& parent)
1429 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001430 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001431
1432 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001433 {
Tanousf00032d2018-11-05 01:18:10 -03001434 std::vector<unsigned> x;
1435 pm.trie.findRouteIndexes(parent, x);
1436 for (unsigned index : x)
1437 {
1438 ret.push_back(&pm.rules[index]->rule);
1439 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001440 }
1441 return ret;
1442 }
1443
1444 private:
Tanousf00032d2018-11-05 01:18:10 -03001445 struct PerMethod
1446 {
1447 std::vector<BaseRule*> rules;
1448 Trie trie;
1449 // rule index 0, 1 has special meaning; preallocate it to avoid
1450 // duplication.
1451 PerMethod() : rules(2)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001452 {}
Tanousf00032d2018-11-05 01:18:10 -03001453 };
Ed Tanous888880a2020-08-24 13:48:50 -07001454
1455 const static size_t maxHttpVerbCount =
Ed Tanouscc090442020-10-07 08:20:50 -07001456 static_cast<size_t>(boost::beast::http::verb::unlink);
Ed Tanous888880a2020-08-24 13:48:50 -07001457
Tanousf00032d2018-11-05 01:18:10 -03001458 std::array<PerMethod, maxHttpVerbCount> perMethods;
1459 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001460};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001461} // namespace crow