blob: 0a0dc747520ab6abf0a40240b029ce3a843c8628 [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:
Gunnar Millsccd584f2021-11-16 11:36:33 -0600389 std::function<void(crow::websocket::Connection&,
390 std::shared_ptr<bmcweb::AsyncResp>)>
391 openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700392 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
393 messageHandler;
394 std::function<void(crow::websocket::Connection&, const std::string&)>
395 closeHandler;
396 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700397};
398
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500399template <typename T>
400struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700401{
402 using self_t = T;
403 WebSocketRule& websocket()
404 {
Ed Tanous271584a2019-07-09 16:24:22 -0700405 self_t* self = static_cast<self_t*>(this);
406 WebSocketRule* p = new WebSocketRule(self->rule);
407 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700408 return *p;
409 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700410
Ed Tanousf23b7292020-10-15 09:41:17 -0700411 self_t& name(const std::string_view name) noexcept
Ed Tanous1abe55e2018-09-05 08:30:59 -0700412 {
Ed Tanous271584a2019-07-09 16:24:22 -0700413 self_t* self = static_cast<self_t*>(this);
Ed Tanousf23b7292020-10-15 09:41:17 -0700414 self->nameStr = name;
Ed Tanous271584a2019-07-09 16:24:22 -0700415 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700416 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700417
Ed Tanous1abe55e2018-09-05 08:30:59 -0700418 self_t& methods(boost::beast::http::verb method)
419 {
Ed Tanous271584a2019-07-09 16:24:22 -0700420 self_t* self = static_cast<self_t*>(this);
421 self->methodsBitfield = 1U << static_cast<size_t>(method);
422 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700423 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700424
Ed Tanous1abe55e2018-09-05 08:30:59 -0700425 template <typename... MethodArgs>
Ed Tanous81ce6092020-12-17 16:54:55 +0000426 self_t& methods(boost::beast::http::verb method, MethodArgs... argsMethod)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700427 {
Ed Tanous271584a2019-07-09 16:24:22 -0700428 self_t* self = static_cast<self_t*>(this);
Ed Tanous81ce6092020-12-17 16:54:55 +0000429 methods(argsMethod...);
Ed Tanous271584a2019-07-09 16:24:22 -0700430 self->methodsBitfield |= 1U << static_cast<size_t>(method);
431 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700432 }
Tanousf00032d2018-11-05 01:18:10 -0300433
Ed Tanous432a8902021-06-14 15:28:56 -0700434 self_t& privileges(
435 const std::initializer_list<std::initializer_list<const char*>>& p)
Tanousf00032d2018-11-05 01:18:10 -0300436 {
Ed Tanous271584a2019-07-09 16:24:22 -0700437 self_t* self = static_cast<self_t*>(this);
Ed Tanous432a8902021-06-14 15:28:56 -0700438 for (const std::initializer_list<const char*>& privilege : p)
Tanousf00032d2018-11-05 01:18:10 -0300439 {
Ed Tanous271584a2019-07-09 16:24:22 -0700440 self->privilegesSet.emplace_back(privilege);
Tanousf00032d2018-11-05 01:18:10 -0300441 }
Ed Tanous271584a2019-07-09 16:24:22 -0700442 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300443 }
Ed Tanoused398212021-06-09 17:05:54 -0700444
445 template <size_t N, typename... MethodArgs>
446 self_t& privileges(const std::array<redfish::Privileges, N>& p)
447 {
448 self_t* self = static_cast<self_t*>(this);
449 for (const redfish::Privileges& privilege : p)
450 {
451 self->privilegesSet.emplace_back(privilege);
452 }
453 return *self;
454 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700455};
456
Ed Tanous1abe55e2018-09-05 08:30:59 -0700457class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
458{
459 public:
Ed Tanousf23b7292020-10-15 09:41:17 -0700460 DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500461 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700462
Ed Tanous1abe55e2018-09-05 08:30:59 -0700463 void validate() override
464 {
465 if (!erasedHandler)
466 {
467 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
468 "no handler for url " + rule);
469 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700470 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700471
zhanghch058d1b46d2021-04-01 11:18:24 +0800472 void handle(const Request& req,
473 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700474 const RoutingParams& params) override
475 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800476 erasedHandler(req, asyncResp, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700477 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700478
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500479 template <typename Func>
480 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481 {
482 using function_t = utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700483 erasedHandler =
Ed Tanous988403c2020-08-24 11:29:49 -0700484 wrap(std::move(f),
485 std::make_integer_sequence<unsigned, function_t::arity>{});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700486 }
487
488 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500489 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700490 // enable_if Arg1 != request
491
492 template <typename Func, unsigned... Indices>
zhanghch058d1b46d2021-04-01 11:18:24 +0800493 std::function<void(const Request&,
494 const std::shared_ptr<bmcweb::AsyncResp>&,
495 const RoutingParams&)>
Ed Tanous988403c2020-08-24 11:29:49 -0700496 wrap(Func f, std::integer_sequence<unsigned, Indices...>)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700497 {
Ed Tanous988403c2020-08-24 11:29:49 -0700498 using function_t = crow::utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700499
500 if (!black_magic::isParameterTagCompatible(
Ed Tanous988403c2020-08-24 11:29:49 -0700501 black_magic::getParameterTag(rule.c_str()),
502 black_magic::computeParameterTagFromArgsList<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503 typename function_t::template arg<Indices>...>::value))
504 {
505 throw std::runtime_error("routeDynamic: Handler type is mismatched "
506 "with URL parameters: " +
507 rule);
508 }
509 auto ret = detail::routing_handler_call_helper::Wrapped<
510 Func, typename function_t::template arg<Indices>...>();
511 ret.template set<typename function_t::template arg<Indices>...>(
512 std::move(f));
513 return ret;
514 }
515
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500516 template <typename Func>
517 void operator()(std::string name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700518 {
519 nameStr = std::move(name);
520 (*this).template operator()<Func>(std::forward(f));
521 }
522
523 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800524 std::function<void(const Request&,
525 const std::shared_ptr<bmcweb::AsyncResp>&,
526 const RoutingParams&)>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700527 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700528};
529
530template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500531class TaggedRule :
532 public BaseRule,
533 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700534{
535 public:
536 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700537
Ed Tanousf23b7292020-10-15 09:41:17 -0700538 TaggedRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500539 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700540
Ed Tanous1abe55e2018-09-05 08:30:59 -0700541 void validate() override
542 {
543 if (!handler)
544 {
545 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
546 "no handler for url " + rule);
547 }
548 }
549
550 template <typename Func>
551 typename std::enable_if<
552 black_magic::CallHelper<Func, black_magic::S<Args...>>::value,
553 void>::type
554 operator()(Func&& f)
555 {
556 static_assert(
557 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
558 black_magic::CallHelper<
559 Func, black_magic::S<crow::Request, Args...>>::value,
560 "Handler type is mismatched with URL parameters");
561 static_assert(
562 !std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
563 "Handler function cannot have void return type; valid return "
564 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500565 "string, int, crow::response, nlohmann::json");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700566
zhanghch058d1b46d2021-04-01 11:18:24 +0800567 handler = [f = std::move(f)](
568 const Request&,
569 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
570 Args... args) { asyncResp->res.result(f(args...)); };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700571 }
572
573 template <typename Func>
574 typename std::enable_if<
575 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
Ed Tanous7045c8d2017-04-03 10:04:37 -0700576 black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700577 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700578 void>::type
579 operator()(Func&& f)
580 {
581 static_assert(
582 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
583 black_magic::CallHelper<
584 Func, black_magic::S<crow::Request, Args...>>::value,
585 "Handler type is mismatched with URL parameters");
586 static_assert(
587 !std::is_same<void, decltype(f(std::declval<crow::Request>(),
588 std::declval<Args>()...))>::value,
589 "Handler function cannot have void return type; valid return "
590 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500591 "string, int, crow::response,nlohmann::json");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700592
zhanghch058d1b46d2021-04-01 11:18:24 +0800593 handler = [f = std::move(f)](
594 const crow::Request& req,
595 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
596 Args... args) { asyncResp->res.result(f(req, args...)); };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700597 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700598
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599 template <typename Func>
600 typename std::enable_if<
601 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
602 !black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700603 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700604 void>::type
605 operator()(Func&& f)
606 {
607 static_assert(
608 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
609 black_magic::CallHelper<
610 Func, black_magic::S<crow::Request, Args...>>::value ||
611 black_magic::CallHelper<
zhanghch058d1b46d2021-04-01 11:18:24 +0800612 Func, black_magic::S<crow::Request,
613 std::shared_ptr<bmcweb::AsyncResp>&,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700614 Args...>>::value,
615 "Handler type is mismatched with URL parameters");
616 static_assert(
zhanghch058d1b46d2021-04-01 11:18:24 +0800617 std::is_same<
618 void,
619 decltype(f(std::declval<crow::Request>(),
620 std::declval<std::shared_ptr<bmcweb::AsyncResp>&>(),
621 std::declval<Args>()...))>::value,
Tanousf00032d2018-11-05 01:18:10 -0300622 "Handler function with response argument should have void "
623 "return "
Ed Tanous1abe55e2018-09-05 08:30:59 -0700624 "type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700625
Ed Tanous1abe55e2018-09-05 08:30:59 -0700626 handler = std::move(f);
627 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700628
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500629 template <typename Func>
Ed Tanousf23b7292020-10-15 09:41:17 -0700630 void operator()(const std::string_view name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700631 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700632 nameStr = name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700633 (*this).template operator()<Func>(std::forward(f));
634 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700635
zhanghch058d1b46d2021-04-01 11:18:24 +0800636 void handle(const Request& req,
637 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638 const RoutingParams& params) override
639 {
640 detail::routing_handler_call_helper::Call<
641 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
642 0, 0, 0, 0, black_magic::S<Args...>, black_magic::S<>>()(
643 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
zhanghch058d1b46d2021-04-01 11:18:24 +0800644 handler, params, req, asyncResp});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700645 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700646
Ed Tanous1abe55e2018-09-05 08:30:59 -0700647 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800648 std::function<void(const crow::Request&,
649 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>
650 handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700651};
652
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700653const int ruleSpecialRedirectSlash = 1;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700654
Ed Tanous1abe55e2018-09-05 08:30:59 -0700655class Trie
656{
657 public:
658 struct Node
659 {
660 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700661 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
662 paramChildrens{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 boost::container::flat_map<std::string, unsigned> children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700664
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 bool isSimpleNode() const
666 {
667 return !ruleIndex && std::all_of(std::begin(paramChildrens),
668 std::end(paramChildrens),
Ed Tanous271584a2019-07-09 16:24:22 -0700669 [](size_t x) { return !x; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700670 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700671 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700672
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673 Trie() : nodes(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500674 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700675
676 private:
677 void optimizeNode(Node* node)
678 {
Ed Tanous271584a2019-07-09 16:24:22 -0700679 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700680 {
681 if (!x)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700682 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 continue;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700684 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685 Node* child = &nodes[x];
686 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700687 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688 if (node->children.empty())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700689 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700690 return;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700691 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 bool mergeWithChild = true;
Tanousf00032d2018-11-05 01:18:10 -0300693 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700694 {
695 Node* child = &nodes[kv.second];
696 if (!child->isSimpleNode())
697 {
698 mergeWithChild = false;
699 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700700 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700701 }
702 if (mergeWithChild)
703 {
704 decltype(node->children) merged;
Tanousf00032d2018-11-05 01:18:10 -0300705 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700706 {
707 Node* child = &nodes[kv.second];
Tanousf00032d2018-11-05 01:18:10 -0300708 for (const std::pair<std::string, unsigned>& childKv :
709 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700710 {
711 merged[kv.first + childKv.first] = childKv.second;
712 }
713 }
714 node->children = std::move(merged);
715 optimizeNode(node);
716 }
717 else
718 {
Tanousf00032d2018-11-05 01:18:10 -0300719 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700720 {
721 Node* child = &nodes[kv.second];
722 optimizeNode(child);
723 }
724 }
725 }
726
727 void optimize()
728 {
729 optimizeNode(head());
730 }
731
732 public:
733 void validate()
734 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700735 optimize();
736 }
737
Ed Tanous81ce6092020-12-17 16:54:55 +0000738 void findRouteIndexes(const std::string& reqUrl,
739 std::vector<unsigned>& routeIndexes,
Tanousf00032d2018-11-05 01:18:10 -0300740 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700741 {
742 if (node == nullptr)
743 {
744 node = head();
745 }
Tanousf00032d2018-11-05 01:18:10 -0300746 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700747 {
748 const std::string& fragment = kv.first;
749 const Node* child = &nodes[kv.second];
Ed Tanous81ce6092020-12-17 16:54:55 +0000750 if (pos >= reqUrl.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700751 {
752 if (child->ruleIndex != 0 && fragment != "/")
753 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000754 routeIndexes.push_back(child->ruleIndex);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700755 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000756 findRouteIndexes(reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700757 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700758 }
759 else
760 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000761 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700762 {
Ed Tanous271584a2019-07-09 16:24:22 -0700763 findRouteIndexes(
Ed Tanous81ce6092020-12-17 16:54:55 +0000764 reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700765 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766 }
767 }
768 }
769 }
770
771 std::pair<unsigned, RoutingParams>
Ed Tanous81ce6092020-12-17 16:54:55 +0000772 find(const std::string_view reqUrl, const Node* node = nullptr,
Ed Tanous271584a2019-07-09 16:24:22 -0700773 size_t pos = 0, RoutingParams* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700774 {
775 RoutingParams empty;
776 if (params == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700777 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700778 params = &empty;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700779 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700780
781 unsigned found{};
782 RoutingParams matchParams;
783
784 if (node == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700785 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700786 node = head();
Ed Tanous3174e4d2020-10-07 11:41:22 -0700787 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000788 if (pos == reqUrl.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700789 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700790 return {node->ruleIndex, *params};
Ed Tanous3174e4d2020-10-07 11:41:22 -0700791 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700792
793 auto updateFound =
794 [&found, &matchParams](std::pair<unsigned, RoutingParams>& ret) {
795 if (ret.first && (!found || found > ret.first))
796 {
797 found = ret.first;
798 matchParams = std::move(ret.second);
799 }
800 };
801
Ed Tanous271584a2019-07-09 16:24:22 -0700802 if (node->paramChildrens[static_cast<size_t>(ParamType::INT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700803 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000804 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805 if ((c >= '0' && c <= '9') || c == '+' || c == '-')
806 {
807 char* eptr;
808 errno = 0;
809 long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000810 std::strtoll(reqUrl.data() + pos, &eptr, 10);
811 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700812 {
813 params->intParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000814 std::pair<unsigned, RoutingParams> ret =
815 find(reqUrl,
816 &nodes[node->paramChildrens[static_cast<size_t>(
817 ParamType::INT)]],
818 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700819 updateFound(ret);
820 params->intParams.pop_back();
821 }
822 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700823 }
824
Ed Tanous271584a2019-07-09 16:24:22 -0700825 if (node->paramChildrens[static_cast<size_t>(ParamType::UINT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700826 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000827 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828 if ((c >= '0' && c <= '9') || c == '+')
829 {
830 char* eptr;
831 errno = 0;
832 unsigned long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000833 std::strtoull(reqUrl.data() + pos, &eptr, 10);
834 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700835 {
836 params->uintParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000837 std::pair<unsigned, RoutingParams> ret =
838 find(reqUrl,
839 &nodes[node->paramChildrens[static_cast<size_t>(
840 ParamType::UINT)]],
841 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700842 updateFound(ret);
843 params->uintParams.pop_back();
844 }
845 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700846 }
847
Ed Tanous271584a2019-07-09 16:24:22 -0700848 if (node->paramChildrens[static_cast<size_t>(ParamType::DOUBLE)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700849 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000850 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
852 {
853 char* eptr;
854 errno = 0;
Ed Tanous81ce6092020-12-17 16:54:55 +0000855 double value = std::strtod(reqUrl.data() + pos, &eptr);
856 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700857 {
858 params->doubleParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000859 std::pair<unsigned, RoutingParams> ret =
860 find(reqUrl,
861 &nodes[node->paramChildrens[static_cast<size_t>(
862 ParamType::DOUBLE)]],
863 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700864 updateFound(ret);
865 params->doubleParams.pop_back();
866 }
867 }
868 }
869
Ed Tanous271584a2019-07-09 16:24:22 -0700870 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700871 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000872 size_t epos = pos;
Ed Tanous81ce6092020-12-17 16:54:55 +0000873 for (; epos < reqUrl.size(); epos++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700874 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000875 if (reqUrl[epos] == '/')
Ed Tanous3174e4d2020-10-07 11:41:22 -0700876 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700877 break;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700878 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700879 }
880
881 if (epos != pos)
882 {
883 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000884 reqUrl.substr(pos, epos - pos));
Tanousf00032d2018-11-05 01:18:10 -0300885 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000886 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700887 &nodes[node->paramChildrens[static_cast<size_t>(
888 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000889 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700890 updateFound(ret);
891 params->stringParams.pop_back();
892 }
893 }
894
Ed Tanous271584a2019-07-09 16:24:22 -0700895 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700896 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000897 size_t epos = reqUrl.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700898
899 if (epos != pos)
900 {
901 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000902 reqUrl.substr(pos, epos - pos));
Ed Tanous271584a2019-07-09 16:24:22 -0700903 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000904 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700905 &nodes[node->paramChildrens[static_cast<size_t>(
906 ParamType::PATH)]],
907 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700908 updateFound(ret);
909 params->stringParams.pop_back();
910 }
911 }
912
Tanousf00032d2018-11-05 01:18:10 -0300913 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700914 {
915 const std::string& fragment = kv.first;
916 const Node* child = &nodes[kv.second];
917
Ed Tanous81ce6092020-12-17 16:54:55 +0000918 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700919 {
Tanousf00032d2018-11-05 01:18:10 -0300920 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000921 find(reqUrl, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700922 updateFound(ret);
923 }
924 }
925
926 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700927 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700928
929 void add(const std::string& url, unsigned ruleIndex)
930 {
Ed Tanous271584a2019-07-09 16:24:22 -0700931 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700932
933 for (unsigned i = 0; i < url.size(); i++)
934 {
935 char c = url[i];
936 if (c == '<')
937 {
Tanousf00032d2018-11-05 01:18:10 -0300938 const static std::array<std::pair<ParamType, std::string>, 7>
939 paramTraits = {{
940 {ParamType::INT, "<int>"},
941 {ParamType::UINT, "<uint>"},
942 {ParamType::DOUBLE, "<float>"},
943 {ParamType::DOUBLE, "<double>"},
944 {ParamType::STRING, "<str>"},
945 {ParamType::STRING, "<string>"},
946 {ParamType::PATH, "<path>"},
947 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700948
Tanousf00032d2018-11-05 01:18:10 -0300949 for (const std::pair<ParamType, std::string>& x : paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700950 {
Tanousf00032d2018-11-05 01:18:10 -0300951 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700952 {
Ed Tanous271584a2019-07-09 16:24:22 -0700953 size_t index = static_cast<size_t>(x.first);
954 if (!nodes[idx].paramChildrens[index])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700955 {
Tanousf00032d2018-11-05 01:18:10 -0300956 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700957 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700958 }
Ed Tanous271584a2019-07-09 16:24:22 -0700959 idx = nodes[idx].paramChildrens[index];
960 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700961 break;
962 }
963 }
964
965 i--;
966 }
967 else
968 {
969 std::string piece(&c, 1);
970 if (!nodes[idx].children.count(piece))
971 {
Tanousf00032d2018-11-05 01:18:10 -0300972 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700973 nodes[idx].children.emplace(piece, newNodeIdx);
974 }
975 idx = nodes[idx].children[piece];
976 }
977 }
978 if (nodes[idx].ruleIndex)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700979 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700980 throw std::runtime_error("handler already exists for " + url);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700981 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700982 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700983 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700984
Ed Tanous1abe55e2018-09-05 08:30:59 -0700985 private:
Ed Tanous271584a2019-07-09 16:24:22 -0700986 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700987 {
Ed Tanous271584a2019-07-09 16:24:22 -0700988 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700989 {
990 if (n->paramChildrens[i])
991 {
992 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -0700993 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
994 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700995 {
996 case ParamType::INT:
997 BMCWEB_LOG_DEBUG << "<int>";
998 break;
999 case ParamType::UINT:
1000 BMCWEB_LOG_DEBUG << "<uint>";
1001 break;
1002 case ParamType::DOUBLE:
1003 BMCWEB_LOG_DEBUG << "<float>";
1004 break;
1005 case ParamType::STRING:
1006 BMCWEB_LOG_DEBUG << "<str>";
1007 break;
1008 case ParamType::PATH:
1009 BMCWEB_LOG_DEBUG << "<path>";
1010 break;
Ed Tanous23a21a12020-07-25 04:45:05 +00001011 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -07001012 BMCWEB_LOG_DEBUG << "<ERROR>";
1013 break;
1014 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001015
Ed Tanous1abe55e2018-09-05 08:30:59 -07001016 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
1017 }
1018 }
Tanousf00032d2018-11-05 01:18:10 -03001019 for (const std::pair<std::string, unsigned>& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001020 {
1021 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -07001022 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -07001023 << kv.first;
1024 debugNodePrint(&nodes[kv.second], level + 1);
1025 }
1026 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001027
Ed Tanous1abe55e2018-09-05 08:30:59 -07001028 public:
1029 void debugPrint()
1030 {
Ed Tanous271584a2019-07-09 16:24:22 -07001031 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001032 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001033
Ed Tanous1abe55e2018-09-05 08:30:59 -07001034 private:
1035 const Node* head() const
1036 {
1037 return &nodes.front();
1038 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001039
Ed Tanous1abe55e2018-09-05 08:30:59 -07001040 Node* head()
1041 {
1042 return &nodes.front();
1043 }
1044
1045 unsigned newNode()
1046 {
1047 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -07001048 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001049 }
1050
1051 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001052};
1053
Ed Tanous1abe55e2018-09-05 08:30:59 -07001054class Router
1055{
1056 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -07001057 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001058
Ed Tanous1abe55e2018-09-05 08:30:59 -07001059 DynamicRule& newRuleDynamic(const std::string& rule)
1060 {
1061 std::unique_ptr<DynamicRule> ruleObject =
1062 std::make_unique<DynamicRule>(rule);
1063 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001064 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -07001065
Ed Tanous1abe55e2018-09-05 08:30:59 -07001066 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001067 }
1068
Ed Tanous1abe55e2018-09-05 08:30:59 -07001069 template <uint64_t N>
1070 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
1071 newRuleTagged(const std::string& rule)
1072 {
1073 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
1074 TaggedRule>;
1075 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
1076 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001077 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001078
1079 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001080 }
1081
Tanousf00032d2018-11-05 01:18:10 -03001082 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001083 {
Tanousf00032d2018-11-05 01:18:10 -03001084 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001085 {
Tanousf00032d2018-11-05 01:18:10 -03001086 return;
1087 }
Ed Tanous888880a2020-08-24 13:48:50 -07001088 for (size_t method = 0, methodBit = 1; method < maxHttpVerbCount;
Ed Tanous2c70f802020-09-28 14:29:23 -07001089 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -03001090 {
Ed Tanous2c70f802020-09-28 14:29:23 -07001091 if (ruleObject->methodsBitfield & methodBit)
Tanousf00032d2018-11-05 01:18:10 -03001092 {
1093 perMethods[method].rules.emplace_back(ruleObject);
1094 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -07001095 rule, static_cast<unsigned>(
1096 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -03001097 // directory case:
1098 // request to `/about' url matches `/about/' rule
1099 if (rule.size() > 2 && rule.back() == '/')
1100 {
1101 perMethods[method].trie.add(
1102 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -07001103 static_cast<unsigned>(perMethods[method].rules.size() -
1104 1));
Tanousf00032d2018-11-05 01:18:10 -03001105 }
1106 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001107 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001108 }
1109
Ed Tanous1abe55e2018-09-05 08:30:59 -07001110 void validate()
1111 {
Tanousf00032d2018-11-05 01:18:10 -03001112 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001113 {
1114 if (rule)
1115 {
Tanousf00032d2018-11-05 01:18:10 -03001116 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001117 if (upgraded)
Ed Tanous3174e4d2020-10-07 11:41:22 -07001118 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001119 rule = std::move(upgraded);
Ed Tanous3174e4d2020-10-07 11:41:22 -07001120 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001121 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -03001122 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001123 }
1124 }
Tanousf00032d2018-11-05 01:18:10 -03001125 for (PerMethod& perMethod : perMethods)
1126 {
1127 perMethod.trie.validate();
1128 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001129 }
1130
Ed Tanous1abe55e2018-09-05 08:30:59 -07001131 template <typename Adaptor>
1132 void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
1133 {
Ed Tanous271584a2019-07-09 16:24:22 -07001134 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001135 {
1136 res.result(boost::beast::http::status::not_found);
1137 res.end();
Tanousf00032d2018-11-05 01:18:10 -03001138 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001139 }
Tanousf00032d2018-11-05 01:18:10 -03001140
Ed Tanous271584a2019-07-09 16:24:22 -07001141 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001142 Trie& trie = perMethod.trie;
1143 std::vector<BaseRule*>& rules = perMethod.rules;
1144
1145 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001146 unsigned ruleIndex = found.first;
1147 if (!ruleIndex)
1148 {
1149 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001150 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001151 res.end();
1152 return;
1153 }
1154
1155 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001156 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001157 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001158 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001159
1160 if (ruleIndex == ruleSpecialRedirectSlash)
1161 {
1162 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1163 << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001164 res.result(boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001165
1166 // TODO absolute url building
1167 if (req.getHeaderValue("Host").empty())
1168 {
1169 res.addHeader("Location", std::string(req.url) + "/");
1170 }
1171 else
1172 {
1173 res.addHeader(
1174 "Location",
1175 req.isSecure
1176 ? "https://"
1177 : "http://" + std::string(req.getHeaderValue("Host")) +
1178 std::string(req.url) + "/");
1179 }
1180 res.end();
1181 return;
1182 }
1183
Ed Tanous271584a2019-07-09 16:24:22 -07001184 if ((rules[ruleIndex]->getMethods() &
1185 (1U << static_cast<size_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001186 {
1187 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1188 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001189 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001190 << rules[ruleIndex]->getMethods();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001191 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001192 res.end();
1193 return;
1194 }
1195
1196 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rules[ruleIndex]->rule
Ed Tanous271584a2019-07-09 16:24:22 -07001197 << "' " << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001198 << rules[ruleIndex]->getMethods();
1199
1200 // any uncaught exceptions become 500s
1201 try
1202 {
1203 rules[ruleIndex]->handleUpgrade(req, res, std::move(adaptor));
1204 }
Patrick Williamsc5967042021-10-06 12:39:54 -05001205 catch (const std::exception& e)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001206 {
1207 BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001208 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001209 res.end();
1210 return;
1211 }
1212 catch (...)
1213 {
1214 BMCWEB_LOG_ERROR
1215 << "An uncaught exception occurred. The type was unknown "
1216 "so no information was available.";
Ed Tanousde5c9f32019-03-26 09:17:55 -07001217 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001218 res.end();
1219 return;
1220 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001221 }
1222
zhanghch058d1b46d2021-04-01 11:18:24 +08001223 void handle(Request& req,
1224 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001225 {
Ed Tanous271584a2019-07-09 16:24:22 -07001226 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001227 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001228 asyncResp->res.result(boost::beast::http::status::not_found);
Tanousf00032d2018-11-05 01:18:10 -03001229 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001230 }
Ed Tanous271584a2019-07-09 16:24:22 -07001231 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001232 Trie& trie = perMethod.trie;
1233 std::vector<BaseRule*>& rules = perMethod.rules;
1234
1235 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001236
Ed Tanous1abe55e2018-09-05 08:30:59 -07001237 unsigned ruleIndex = found.first;
1238
1239 if (!ruleIndex)
1240 {
Ed Tanous2634dcd2019-03-26 09:28:06 -07001241 // Check to see if this url exists at any verb
1242 for (const PerMethod& p : perMethods)
1243 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001244 const std::pair<unsigned, RoutingParams>& found2 =
Ed Tanous2634dcd2019-03-26 09:28:06 -07001245 p.trie.find(req.url);
Ed Tanous23a21a12020-07-25 04:45:05 +00001246 if (found2.first > 0)
Ed Tanous2634dcd2019-03-26 09:28:06 -07001247 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001248 asyncResp->res.result(
1249 boost::beast::http::status::method_not_allowed);
Ed Tanous2634dcd2019-03-26 09:28:06 -07001250 return;
1251 }
1252 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001253 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
zhanghch058d1b46d2021-04-01 11:18:24 +08001254 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001255 return;
1256 }
1257
1258 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001259 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001260 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001261 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001262
1263 if (ruleIndex == ruleSpecialRedirectSlash)
1264 {
1265 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1266 << req.url;
zhanghch058d1b46d2021-04-01 11:18:24 +08001267 asyncResp->res.result(
1268 boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001269
1270 // TODO absolute url building
1271 if (req.getHeaderValue("Host").empty())
1272 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001273 asyncResp->res.addHeader("Location",
1274 std::string(req.url) + "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001275 }
1276 else
1277 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001278 asyncResp->res.addHeader(
1279 "Location", (req.isSecure ? "https://" : "http://") +
1280 std::string(req.getHeaderValue("Host")) +
1281 std::string(req.url) + "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001282 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001283 return;
1284 }
1285
Ed Tanous271584a2019-07-09 16:24:22 -07001286 if ((rules[ruleIndex]->getMethods() &
1287 (1U << static_cast<uint32_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001288 {
1289 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1290 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001291 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001292 << rules[ruleIndex]->getMethods();
zhanghch058d1b46d2021-04-01 11:18:24 +08001293 asyncResp->res.result(
1294 boost::beast::http::status::method_not_allowed);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001295 return;
1296 }
1297
1298 BMCWEB_LOG_DEBUG << "Matched rule '" << rules[ruleIndex]->rule << "' "
Ed Tanous271584a2019-07-09 16:24:22 -07001299 << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001300 << rules[ruleIndex]->getMethods();
1301
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001302 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001303 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001304 rules[ruleIndex]->handle(req, asyncResp, found.second);
James Feist7166bf02019-12-10 16:52:14 +00001305 return;
1306 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001307
1308 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001309 [&req, asyncResp, &rules, ruleIndex, found](
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001310 const boost::system::error_code ec,
1311 std::map<std::string, std::variant<bool, std::string,
1312 std::vector<std::string>>>
1313 userInfo) {
1314 if (ec)
1315 {
1316 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
zhanghch058d1b46d2021-04-01 11:18:24 +08001317 asyncResp->res.result(
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001318 boost::beast::http::status::internal_server_error);
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001319 return;
1320 }
1321
1322 const std::string* userRolePtr = nullptr;
1323 auto userInfoIter = userInfo.find("UserPrivilege");
1324 if (userInfoIter != userInfo.end())
1325 {
1326 userRolePtr =
1327 std::get_if<std::string>(&userInfoIter->second);
1328 }
1329
1330 std::string userRole{};
1331 if (userRolePtr != nullptr)
1332 {
1333 userRole = *userRolePtr;
1334 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1335 << " userRole = " << *userRolePtr;
1336 }
1337
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001338 bool* remoteUserPtr = nullptr;
1339 auto remoteUserIter = userInfo.find("RemoteUser");
1340 if (remoteUserIter != userInfo.end())
1341 {
1342 remoteUserPtr = std::get_if<bool>(&remoteUserIter->second);
1343 }
1344 if (remoteUserPtr == nullptr)
1345 {
1346 BMCWEB_LOG_ERROR
1347 << "RemoteUser property missing or wrong type";
zhanghch058d1b46d2021-04-01 11:18:24 +08001348 asyncResp->res.result(
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001349 boost::beast::http::status::internal_server_error);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001350 return;
1351 }
1352 bool remoteUser = *remoteUserPtr;
1353
1354 bool passwordExpired = false; // default for remote user
1355 if (!remoteUser)
1356 {
1357 bool* passwordExpiredPtr = nullptr;
1358 auto passwordExpiredIter =
1359 userInfo.find("UserPasswordExpired");
1360 if (passwordExpiredIter != userInfo.end())
1361 {
1362 passwordExpiredPtr =
1363 std::get_if<bool>(&passwordExpiredIter->second);
1364 }
1365 if (passwordExpiredPtr != nullptr)
1366 {
1367 passwordExpired = *passwordExpiredPtr;
1368 }
1369 else
1370 {
1371 BMCWEB_LOG_ERROR
1372 << "UserPasswordExpired property is expected for"
1373 " local user but is missing or wrong type";
zhanghch058d1b46d2021-04-01 11:18:24 +08001374 asyncResp->res.result(
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001375 boost::beast::http::status::internal_server_error);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001376 return;
1377 }
1378 }
1379
Ed Tanous23a21a12020-07-25 04:45:05 +00001380 // Get the userprivileges from the role
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001381 redfish::Privileges userPrivileges =
1382 redfish::getUserPrivileges(userRole);
1383
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001384 // Set isConfigureSelfOnly based on D-Bus results. This
1385 // ignores the results from both pamAuthenticateUser and the
1386 // value from any previous use of this session.
1387 req.session->isConfigureSelfOnly = passwordExpired;
1388
Ed Tanous23a21a12020-07-25 04:45:05 +00001389 // Modifyprivileges if isConfigureSelfOnly.
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001390 if (req.session->isConfigureSelfOnly)
1391 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001392 // Remove allprivileges except ConfigureSelf
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001393 userPrivileges = userPrivileges.intersection(
1394 redfish::Privileges{"ConfigureSelf"});
1395 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1396 }
1397
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001398 if (!rules[ruleIndex]->checkPrivileges(userPrivileges))
1399 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001400 asyncResp->res.result(
1401 boost::beast::http::status::forbidden);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001402 if (req.session->isConfigureSelfOnly)
1403 {
1404 redfish::messages::passwordChangeRequired(
zhanghch058d1b46d2021-04-01 11:18:24 +08001405 asyncResp->res,
1406 "/redfish/v1/AccountService/Accounts/" +
1407 req.session->username);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001408 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001409 return;
1410 }
1411
1412 req.userRole = userRole;
zhanghch058d1b46d2021-04-01 11:18:24 +08001413 rules[ruleIndex]->handle(req, asyncResp, found.second);
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001414 },
1415 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1416 "xyz.openbmc_project.User.Manager", "GetUserInfo",
1417 req.session->username);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001418 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001419
Ed Tanous1abe55e2018-09-05 08:30:59 -07001420 void debugPrint()
1421 {
Ed Tanous271584a2019-07-09 16:24:22 -07001422 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001423 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001424 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1425 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001426 perMethods[i].trie.debugPrint();
1427 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001428 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001429
Ed Tanous1abe55e2018-09-05 08:30:59 -07001430 std::vector<const std::string*> getRoutes(const std::string& parent)
1431 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001432 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001433
1434 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001435 {
Tanousf00032d2018-11-05 01:18:10 -03001436 std::vector<unsigned> x;
1437 pm.trie.findRouteIndexes(parent, x);
1438 for (unsigned index : x)
1439 {
1440 ret.push_back(&pm.rules[index]->rule);
1441 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001442 }
1443 return ret;
1444 }
1445
1446 private:
Tanousf00032d2018-11-05 01:18:10 -03001447 struct PerMethod
1448 {
1449 std::vector<BaseRule*> rules;
1450 Trie trie;
1451 // rule index 0, 1 has special meaning; preallocate it to avoid
1452 // duplication.
1453 PerMethod() : rules(2)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001454 {}
Tanousf00032d2018-11-05 01:18:10 -03001455 };
Ed Tanous888880a2020-08-24 13:48:50 -07001456
1457 const static size_t maxHttpVerbCount =
Ed Tanouscc090442020-10-07 08:20:50 -07001458 static_cast<size_t>(boost::beast::http::verb::unlink);
Ed Tanous888880a2020-08-24 13:48:50 -07001459
Tanousf00032d2018-11-05 01:18:10 -03001460 std::array<PerMethod, maxHttpVerbCount> perMethods;
1461 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001462};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001463} // namespace crow