blob: 65c7b7008bc2d6392859bf8d4faf1ae88708fae3 [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
2
Ed Tanous04e438c2020-10-03 08:06:26 -07003#include "common.hpp"
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06004#include "error_messages.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -07005#include "http_request.hpp"
6#include "http_response.hpp"
7#include "logging.hpp"
Tanousf00032d2018-11-05 01:18:10 -03008#include "privileges.hpp"
Ratan Gupta6f359562019-04-03 10:39:08 +05309#include "sessions.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -070010#include "utility.hpp"
11#include "websocket.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070012
Iwona Klimaszewskac0a1c8a2019-07-12 18:26:38 +020013#include <async_resp.hpp>
Tanousf00032d2018-11-05 01:18:10 -030014#include <boost/container/flat_map.hpp>
15#include <boost/container/small_vector.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070016#include <boost/lexical_cast.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050017
Ed Tanouse0d918b2018-03-27 17:41:04 -070018#include <cerrno>
Ed Tanous7045c8d2017-04-03 10:04:37 -070019#include <cstdint>
Ed Tanouse0d918b2018-03-27 17:41:04 -070020#include <cstdlib>
Ed Tanous3dac7492017-08-02 13:46:20 -070021#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070022#include <memory>
23#include <tuple>
Ed Tanous7045c8d2017-04-03 10:04:37 -070024#include <utility>
25#include <vector>
Ed Tanous9140a672017-04-24 17:01:32 -070026
Ed Tanous1abe55e2018-09-05 08:30:59 -070027namespace crow
28{
Tanousf00032d2018-11-05 01:18:10 -030029
Ed Tanous1abe55e2018-09-05 08:30:59 -070030class BaseRule
31{
32 public:
Ed Tanousf23b7292020-10-15 09:41:17 -070033 BaseRule(const std::string& thisRule) : rule(thisRule)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050034 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070035
Ed Tanous0c0084a2019-10-24 15:57:51 -070036 virtual ~BaseRule() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -070037
Ed Tanous1abe55e2018-09-05 08:30:59 -070038 virtual void validate() = 0;
39 std::unique_ptr<BaseRule> upgrade()
40 {
41 if (ruleToUpgrade)
Ed Tanous3174e4d2020-10-07 11:41:22 -070042 {
Ed Tanous1abe55e2018-09-05 08:30:59 -070043 return std::move(ruleToUpgrade);
Ed Tanous3174e4d2020-10-07 11:41:22 -070044 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070045 return {};
46 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070047
Ed Tanous1abe55e2018-09-05 08:30:59 -070048 virtual void handle(const Request&, Response&, 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;
121 Response& res;
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(
193 cparams.req, cparams.res,
194 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 {
Tanousf00032d2018-11-05 01:18:10 -0300210 handler = [f = std::move(f)](const Request&, Response& res,
211 Args... args) {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700212 res.result(f(args...));
Tanousf00032d2018-11-05 01:18:10 -0300213 res.end();
214 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700215 }
216
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500217 template <typename Req, typename... Args>
218 struct ReqHandlerWrapper
Ed Tanous1abe55e2018-09-05 08:30:59 -0700219 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000220 ReqHandlerWrapper(Func fIn) : f(std::move(fIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500221 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700222
Ed Tanous1abe55e2018-09-05 08:30:59 -0700223 void operator()(const Request& req, Response& res, Args... args)
224 {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700225 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700226 res.end();
227 }
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,
241 Response&>::value,
242 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,
262 Response&>::value,
263 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 {
271 using type =
272 std::function<void(const crow::Request&, crow::Response&, Args...)>;
273 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700274 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700275 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700276
Ed Tanous1abe55e2018-09-05 08:30:59 -0700277 template <typename... Args>
278 struct HandlerTypeHelper<const Request&, Args...>
279 {
280 using type =
281 std::function<void(const crow::Request&, crow::Response&, Args...)>;
282 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700283 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700284 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700285
Ed Tanous1abe55e2018-09-05 08:30:59 -0700286 template <typename... Args>
287 struct HandlerTypeHelper<const Request&, Response&, Args...>
288 {
289 using type =
290 std::function<void(const crow::Request&, crow::Response&, Args...)>;
291 using args_type =
Ed Tanous988403c2020-08-24 11:29:49 -0700292 black_magic::S<typename black_magic::PromoteT<Args>...>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700293 };
294
295 typename HandlerTypeHelper<ArgsWrapped...>::type handler;
296
297 void operator()(const Request& req, Response& res,
298 const RoutingParams& params)
299 {
300 detail::routing_handler_call_helper::Call<
301 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
302 0, 0, 0, 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
303 black_magic::S<>>()(
304 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
305 handler, params, req, res});
306 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700307};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700308} // namespace routing_handler_call_helper
309} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700310
Ed Tanous1abe55e2018-09-05 08:30:59 -0700311class WebSocketRule : public BaseRule
312{
313 using self_t = WebSocketRule;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700314
Ed Tanous1abe55e2018-09-05 08:30:59 -0700315 public:
Ed Tanousf23b7292020-10-15 09:41:17 -0700316 WebSocketRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500317 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700318
Ed Tanous1abe55e2018-09-05 08:30:59 -0700319 void validate() override
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500320 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700321
Ed Tanous1abe55e2018-09-05 08:30:59 -0700322 void handle(const Request&, Response& res, const RoutingParams&) override
323 {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700324 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700325 res.end();
326 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700327
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000328 void handleUpgrade(const Request& req, Response&,
Ed Tanousceac6f72018-12-02 11:58:47 -0800329 boost::asio::ip::tcp::socket&& adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700330 {
Ratan Gupta02453b12019-10-22 14:43:36 +0530331 std::shared_ptr<
332 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>
333 myConnection = std::make_shared<
334 crow::websocket::ConnectionImpl<boost::asio::ip::tcp::socket>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000335 req, std::move(adaptor), openHandler, messageHandler,
Ratan Gupta02453b12019-10-22 14:43:36 +0530336 closeHandler, errorHandler);
337 myConnection->start();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700338 }
339#ifdef BMCWEB_ENABLE_SSL
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000340 void handleUpgrade(const Request& req, Response&,
Ed Tanousceac6f72018-12-02 11:58:47 -0800341 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
342 adaptor) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700343 {
Ed Tanousceac6f72018-12-02 11:58:47 -0800344 std::shared_ptr<crow::websocket::ConnectionImpl<
345 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
346 myConnection = std::make_shared<crow::websocket::ConnectionImpl<
347 boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000348 req, std::move(adaptor), openHandler, messageHandler,
Ed Tanousceac6f72018-12-02 11:58:47 -0800349 closeHandler, errorHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700350 myConnection->start();
351 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700352#endif
353
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500354 template <typename Func>
355 self_t& onopen(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700356 {
357 openHandler = f;
358 return *this;
359 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700360
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500361 template <typename Func>
362 self_t& onmessage(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700363 {
364 messageHandler = f;
365 return *this;
366 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700367
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500368 template <typename Func>
369 self_t& onclose(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700370 {
371 closeHandler = f;
372 return *this;
373 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700374
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500375 template <typename Func>
376 self_t& onerror(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700377 {
378 errorHandler = f;
379 return *this;
380 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700381
Ed Tanous1abe55e2018-09-05 08:30:59 -0700382 protected:
Iwona Klimaszewskac0a1c8a2019-07-12 18:26:38 +0200383 std::function<void(crow::websocket::Connection&,
384 std::shared_ptr<bmcweb::AsyncResp>)>
385 openHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700386 std::function<void(crow::websocket::Connection&, const std::string&, bool)>
387 messageHandler;
388 std::function<void(crow::websocket::Connection&, const std::string&)>
389 closeHandler;
390 std::function<void(crow::websocket::Connection&)> errorHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700391};
392
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500393template <typename T>
394struct RuleParameterTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700395{
396 using self_t = T;
397 WebSocketRule& websocket()
398 {
Ed Tanous271584a2019-07-09 16:24:22 -0700399 self_t* self = static_cast<self_t*>(this);
400 WebSocketRule* p = new WebSocketRule(self->rule);
401 self->ruleToUpgrade.reset(p);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700402 return *p;
403 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700404
Ed Tanousf23b7292020-10-15 09:41:17 -0700405 self_t& name(const std::string_view name) noexcept
Ed Tanous1abe55e2018-09-05 08:30:59 -0700406 {
Ed Tanous271584a2019-07-09 16:24:22 -0700407 self_t* self = static_cast<self_t*>(this);
Ed Tanousf23b7292020-10-15 09:41:17 -0700408 self->nameStr = name;
Ed Tanous271584a2019-07-09 16:24:22 -0700409 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700410 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700411
Ed Tanous1abe55e2018-09-05 08:30:59 -0700412 self_t& methods(boost::beast::http::verb method)
413 {
Ed Tanous271584a2019-07-09 16:24:22 -0700414 self_t* self = static_cast<self_t*>(this);
415 self->methodsBitfield = 1U << static_cast<size_t>(method);
416 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700417 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700418
Ed Tanous1abe55e2018-09-05 08:30:59 -0700419 template <typename... MethodArgs>
Ed Tanous81ce6092020-12-17 16:54:55 +0000420 self_t& methods(boost::beast::http::verb method, MethodArgs... argsMethod)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700421 {
Ed Tanous271584a2019-07-09 16:24:22 -0700422 self_t* self = static_cast<self_t*>(this);
Ed Tanous81ce6092020-12-17 16:54:55 +0000423 methods(argsMethod...);
Ed Tanous271584a2019-07-09 16:24:22 -0700424 self->methodsBitfield |= 1U << static_cast<size_t>(method);
425 return *self;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700426 }
Tanousf00032d2018-11-05 01:18:10 -0300427
428 template <typename... MethodArgs>
Ed Tanous23a21a12020-07-25 04:45:05 +0000429 self_t& privileges(std::initializer_list<const char*> l)
Tanousf00032d2018-11-05 01:18:10 -0300430 {
Ed Tanous271584a2019-07-09 16:24:22 -0700431 self_t* self = static_cast<self_t*>(this);
432 self->privilegesSet.emplace_back(l);
433 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300434 }
435
436 template <typename... MethodArgs>
Ed Tanous23a21a12020-07-25 04:45:05 +0000437 self_t& privileges(const std::vector<redfish::Privileges>& p)
Tanousf00032d2018-11-05 01:18:10 -0300438 {
Ed Tanous271584a2019-07-09 16:24:22 -0700439 self_t* self = static_cast<self_t*>(this);
Tanousf00032d2018-11-05 01:18:10 -0300440 for (const redfish::Privileges& privilege : p)
441 {
Ed Tanous271584a2019-07-09 16:24:22 -0700442 self->privilegesSet.emplace_back(privilege);
Tanousf00032d2018-11-05 01:18:10 -0300443 }
Ed Tanous271584a2019-07-09 16:24:22 -0700444 return *self;
Tanousf00032d2018-11-05 01:18:10 -0300445 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700446};
447
Ed Tanous1abe55e2018-09-05 08:30:59 -0700448class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
449{
450 public:
Ed Tanousf23b7292020-10-15 09:41:17 -0700451 DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500452 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700453
Ed Tanous1abe55e2018-09-05 08:30:59 -0700454 void validate() override
455 {
456 if (!erasedHandler)
457 {
458 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
459 "no handler for url " + rule);
460 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700461 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700462
Ed Tanous1abe55e2018-09-05 08:30:59 -0700463 void handle(const Request& req, Response& res,
464 const RoutingParams& params) override
465 {
466 erasedHandler(req, res, params);
467 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700468
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500469 template <typename Func>
470 void operator()(Func f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700471 {
472 using function_t = utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700473 erasedHandler =
Ed Tanous988403c2020-08-24 11:29:49 -0700474 wrap(std::move(f),
475 std::make_integer_sequence<unsigned, function_t::arity>{});
Ed Tanous1abe55e2018-09-05 08:30:59 -0700476 }
477
478 // enable_if Arg1 == request && Arg2 == Response
Gunnar Mills6be0e402020-07-08 13:21:51 -0500479 // enable_if Arg1 == request && Arg2 != response
Ed Tanous1abe55e2018-09-05 08:30:59 -0700480 // enable_if Arg1 != request
481
482 template <typename Func, unsigned... Indices>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700483 std::function<void(const Request&, Response&, const RoutingParams&)>
Ed Tanous988403c2020-08-24 11:29:49 -0700484 wrap(Func f, std::integer_sequence<unsigned, Indices...>)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700485 {
Ed Tanous988403c2020-08-24 11:29:49 -0700486 using function_t = crow::utility::function_traits<Func>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700487
488 if (!black_magic::isParameterTagCompatible(
Ed Tanous988403c2020-08-24 11:29:49 -0700489 black_magic::getParameterTag(rule.c_str()),
490 black_magic::computeParameterTagFromArgsList<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700491 typename function_t::template arg<Indices>...>::value))
492 {
493 throw std::runtime_error("routeDynamic: Handler type is mismatched "
494 "with URL parameters: " +
495 rule);
496 }
497 auto ret = detail::routing_handler_call_helper::Wrapped<
498 Func, typename function_t::template arg<Indices>...>();
499 ret.template set<typename function_t::template arg<Indices>...>(
500 std::move(f));
501 return ret;
502 }
503
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500504 template <typename Func>
505 void operator()(std::string name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700506 {
507 nameStr = std::move(name);
508 (*this).template operator()<Func>(std::forward(f));
509 }
510
511 private:
512 std::function<void(const Request&, Response&, const RoutingParams&)>
513 erasedHandler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700514};
515
516template <typename... Args>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500517class TaggedRule :
518 public BaseRule,
519 public RuleParameterTraits<TaggedRule<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520{
521 public:
522 using self_t = TaggedRule<Args...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700523
Ed Tanousf23b7292020-10-15 09:41:17 -0700524 TaggedRule(const std::string& ruleIn) : BaseRule(ruleIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500525 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700526
Ed Tanous1abe55e2018-09-05 08:30:59 -0700527 void validate() override
528 {
529 if (!handler)
530 {
531 throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
532 "no handler for url " + rule);
533 }
534 }
535
536 template <typename Func>
537 typename std::enable_if<
538 black_magic::CallHelper<Func, black_magic::S<Args...>>::value,
539 void>::type
540 operator()(Func&& f)
541 {
542 static_assert(
543 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
544 black_magic::CallHelper<
545 Func, black_magic::S<crow::Request, Args...>>::value,
546 "Handler type is mismatched with URL parameters");
547 static_assert(
548 !std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
549 "Handler function cannot have void return type; valid return "
550 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500551 "string, int, crow::response, nlohmann::json");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700552
553 handler = [f = std::move(f)](const Request&, Response& res,
554 Args... args) {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700555 res.result(f(args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700556 res.end();
557 };
558 }
559
560 template <typename Func>
561 typename std::enable_if<
562 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
Ed Tanous7045c8d2017-04-03 10:04:37 -0700563 black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700564 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700565 void>::type
566 operator()(Func&& f)
567 {
568 static_assert(
569 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
570 black_magic::CallHelper<
571 Func, black_magic::S<crow::Request, Args...>>::value,
572 "Handler type is mismatched with URL parameters");
573 static_assert(
574 !std::is_same<void, decltype(f(std::declval<crow::Request>(),
575 std::declval<Args>()...))>::value,
576 "Handler function cannot have void return type; valid return "
577 "types: "
Gunnar Mills6be0e402020-07-08 13:21:51 -0500578 "string, int, crow::response,nlohmann::json");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700579
Ed Tanous1abe55e2018-09-05 08:30:59 -0700580 handler = [f = std::move(f)](const crow::Request& req,
581 crow::Response& res, Args... args) {
Ed Tanousde5c9f32019-03-26 09:17:55 -0700582 res.result(f(req, args...));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700583 res.end();
584 };
585 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700586
Ed Tanous1abe55e2018-09-05 08:30:59 -0700587 template <typename Func>
588 typename std::enable_if<
589 !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
590 !black_magic::CallHelper<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700591 Func, black_magic::S<crow::Request, Args...>>::value,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700592 void>::type
593 operator()(Func&& f)
594 {
595 static_assert(
596 black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
597 black_magic::CallHelper<
598 Func, black_magic::S<crow::Request, Args...>>::value ||
599 black_magic::CallHelper<
600 Func, black_magic::S<crow::Request, crow::Response&,
601 Args...>>::value,
602 "Handler type is mismatched with URL parameters");
603 static_assert(
604 std::is_same<void, decltype(f(std::declval<crow::Request>(),
605 std::declval<crow::Response&>(),
606 std::declval<Args>()...))>::value,
Tanousf00032d2018-11-05 01:18:10 -0300607 "Handler function with response argument should have void "
608 "return "
Ed Tanous1abe55e2018-09-05 08:30:59 -0700609 "type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700610
Ed Tanous1abe55e2018-09-05 08:30:59 -0700611 handler = std::move(f);
612 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700613
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500614 template <typename Func>
Ed Tanousf23b7292020-10-15 09:41:17 -0700615 void operator()(const std::string_view name, Func&& f)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700616 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700617 nameStr = name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700618 (*this).template operator()<Func>(std::forward(f));
619 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700620
Ed Tanous1abe55e2018-09-05 08:30:59 -0700621 void handle(const Request& req, Response& res,
622 const RoutingParams& params) override
623 {
624 detail::routing_handler_call_helper::Call<
625 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
626 0, 0, 0, 0, black_magic::S<Args...>, black_magic::S<>>()(
627 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
628 handler, params, req, res});
629 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700630
Ed Tanous1abe55e2018-09-05 08:30:59 -0700631 private:
632 std::function<void(const crow::Request&, crow::Response&, Args...)> handler;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700633};
634
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700635const int ruleSpecialRedirectSlash = 1;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700636
Ed Tanous1abe55e2018-09-05 08:30:59 -0700637class Trie
638{
639 public:
640 struct Node
641 {
642 unsigned ruleIndex{};
Ed Tanous271584a2019-07-09 16:24:22 -0700643 std::array<size_t, static_cast<size_t>(ParamType::MAX)>
644 paramChildrens{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700645 boost::container::flat_map<std::string, unsigned> children;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700646
Ed Tanous1abe55e2018-09-05 08:30:59 -0700647 bool isSimpleNode() const
648 {
649 return !ruleIndex && std::all_of(std::begin(paramChildrens),
650 std::end(paramChildrens),
Ed Tanous271584a2019-07-09 16:24:22 -0700651 [](size_t x) { return !x; });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700652 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700653 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700654
Ed Tanous1abe55e2018-09-05 08:30:59 -0700655 Trie() : nodes(1)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500656 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700657
658 private:
659 void optimizeNode(Node* node)
660 {
Ed Tanous271584a2019-07-09 16:24:22 -0700661 for (size_t x : node->paramChildrens)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700662 {
663 if (!x)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700664 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 continue;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700666 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700667 Node* child = &nodes[x];
668 optimizeNode(child);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700669 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700670 if (node->children.empty())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700671 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700672 return;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700673 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 bool mergeWithChild = true;
Tanousf00032d2018-11-05 01:18:10 -0300675 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700676 {
677 Node* child = &nodes[kv.second];
678 if (!child->isSimpleNode())
679 {
680 mergeWithChild = false;
681 break;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700682 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 }
684 if (mergeWithChild)
685 {
686 decltype(node->children) merged;
Tanousf00032d2018-11-05 01:18:10 -0300687 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688 {
689 Node* child = &nodes[kv.second];
Tanousf00032d2018-11-05 01:18:10 -0300690 for (const std::pair<std::string, unsigned>& childKv :
691 child->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 {
693 merged[kv.first + childKv.first] = childKv.second;
694 }
695 }
696 node->children = std::move(merged);
697 optimizeNode(node);
698 }
699 else
700 {
Tanousf00032d2018-11-05 01:18:10 -0300701 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700702 {
703 Node* child = &nodes[kv.second];
704 optimizeNode(child);
705 }
706 }
707 }
708
709 void optimize()
710 {
711 optimizeNode(head());
712 }
713
714 public:
715 void validate()
716 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700717 optimize();
718 }
719
Ed Tanous81ce6092020-12-17 16:54:55 +0000720 void findRouteIndexes(const std::string& reqUrl,
721 std::vector<unsigned>& routeIndexes,
Tanousf00032d2018-11-05 01:18:10 -0300722 const Node* node = nullptr, unsigned pos = 0) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700723 {
724 if (node == nullptr)
725 {
726 node = head();
727 }
Tanousf00032d2018-11-05 01:18:10 -0300728 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 {
730 const std::string& fragment = kv.first;
731 const Node* child = &nodes[kv.second];
Ed Tanous81ce6092020-12-17 16:54:55 +0000732 if (pos >= reqUrl.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700733 {
734 if (child->ruleIndex != 0 && fragment != "/")
735 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000736 routeIndexes.push_back(child->ruleIndex);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700737 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000738 findRouteIndexes(reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700739 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700740 }
741 else
742 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000743 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700744 {
Ed Tanous271584a2019-07-09 16:24:22 -0700745 findRouteIndexes(
Ed Tanous81ce6092020-12-17 16:54:55 +0000746 reqUrl, routeIndexes, child,
Ed Tanous271584a2019-07-09 16:24:22 -0700747 static_cast<unsigned>(pos + fragment.size()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700748 }
749 }
750 }
751 }
752
753 std::pair<unsigned, RoutingParams>
Ed Tanous81ce6092020-12-17 16:54:55 +0000754 find(const std::string_view reqUrl, const Node* node = nullptr,
Ed Tanous271584a2019-07-09 16:24:22 -0700755 size_t pos = 0, RoutingParams* params = nullptr) const
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 {
757 RoutingParams empty;
758 if (params == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700759 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700760 params = &empty;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700761 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700762
763 unsigned found{};
764 RoutingParams matchParams;
765
766 if (node == nullptr)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700767 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700768 node = head();
Ed Tanous3174e4d2020-10-07 11:41:22 -0700769 }
Ed Tanous81ce6092020-12-17 16:54:55 +0000770 if (pos == reqUrl.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -0700771 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700772 return {node->ruleIndex, *params};
Ed Tanous3174e4d2020-10-07 11:41:22 -0700773 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700774
775 auto updateFound =
776 [&found, &matchParams](std::pair<unsigned, RoutingParams>& ret) {
777 if (ret.first && (!found || found > ret.first))
778 {
779 found = ret.first;
780 matchParams = std::move(ret.second);
781 }
782 };
783
Ed Tanous271584a2019-07-09 16:24:22 -0700784 if (node->paramChildrens[static_cast<size_t>(ParamType::INT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700785 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000786 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 if ((c >= '0' && c <= '9') || c == '+' || c == '-')
788 {
789 char* eptr;
790 errno = 0;
791 long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000792 std::strtoll(reqUrl.data() + pos, &eptr, 10);
793 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700794 {
795 params->intParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000796 std::pair<unsigned, RoutingParams> ret =
797 find(reqUrl,
798 &nodes[node->paramChildrens[static_cast<size_t>(
799 ParamType::INT)]],
800 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 updateFound(ret);
802 params->intParams.pop_back();
803 }
804 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700805 }
806
Ed Tanous271584a2019-07-09 16:24:22 -0700807 if (node->paramChildrens[static_cast<size_t>(ParamType::UINT)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700808 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000809 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700810 if ((c >= '0' && c <= '9') || c == '+')
811 {
812 char* eptr;
813 errno = 0;
814 unsigned long long int value =
Ed Tanous81ce6092020-12-17 16:54:55 +0000815 std::strtoull(reqUrl.data() + pos, &eptr, 10);
816 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700817 {
818 params->uintParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000819 std::pair<unsigned, RoutingParams> ret =
820 find(reqUrl,
821 &nodes[node->paramChildrens[static_cast<size_t>(
822 ParamType::UINT)]],
823 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700824 updateFound(ret);
825 params->uintParams.pop_back();
826 }
827 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700828 }
829
Ed Tanous271584a2019-07-09 16:24:22 -0700830 if (node->paramChildrens[static_cast<size_t>(ParamType::DOUBLE)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700831 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000832 char c = reqUrl[pos];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
834 {
835 char* eptr;
836 errno = 0;
Ed Tanous81ce6092020-12-17 16:54:55 +0000837 double value = std::strtod(reqUrl.data() + pos, &eptr);
838 if (errno != ERANGE && eptr != reqUrl.data() + pos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700839 {
840 params->doubleParams.push_back(value);
Ed Tanous81ce6092020-12-17 16:54:55 +0000841 std::pair<unsigned, RoutingParams> ret =
842 find(reqUrl,
843 &nodes[node->paramChildrens[static_cast<size_t>(
844 ParamType::DOUBLE)]],
845 static_cast<size_t>(eptr - reqUrl.data()), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700846 updateFound(ret);
847 params->doubleParams.pop_back();
848 }
849 }
850 }
851
Ed Tanous271584a2019-07-09 16:24:22 -0700852 if (node->paramChildrens[static_cast<size_t>(ParamType::STRING)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700853 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000854 size_t epos = pos;
Ed Tanous81ce6092020-12-17 16:54:55 +0000855 for (; epos < reqUrl.size(); epos++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700856 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000857 if (reqUrl[epos] == '/')
Ed Tanous3174e4d2020-10-07 11:41:22 -0700858 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700859 break;
Ed Tanous3174e4d2020-10-07 11:41:22 -0700860 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700861 }
862
863 if (epos != pos)
864 {
865 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000866 reqUrl.substr(pos, epos - pos));
Tanousf00032d2018-11-05 01:18:10 -0300867 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000868 find(reqUrl,
Ed Tanous271584a2019-07-09 16:24:22 -0700869 &nodes[node->paramChildrens[static_cast<size_t>(
870 ParamType::STRING)]],
Ed Tanousb01bf292019-03-25 19:25:26 +0000871 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700872 updateFound(ret);
873 params->stringParams.pop_back();
874 }
875 }
876
Ed Tanous271584a2019-07-09 16:24:22 -0700877 if (node->paramChildrens[static_cast<size_t>(ParamType::PATH)])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700878 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000879 size_t epos = reqUrl.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700880
881 if (epos != pos)
882 {
883 params->stringParams.emplace_back(
Ed Tanous81ce6092020-12-17 16:54:55 +0000884 reqUrl.substr(pos, epos - pos));
Ed Tanous271584a2019-07-09 16:24:22 -0700885 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::PATH)]],
889 epos, params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700890 updateFound(ret);
891 params->stringParams.pop_back();
892 }
893 }
894
Tanousf00032d2018-11-05 01:18:10 -0300895 for (const std::pair<std::string, unsigned>& kv : node->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700896 {
897 const std::string& fragment = kv.first;
898 const Node* child = &nodes[kv.second];
899
Ed Tanous81ce6092020-12-17 16:54:55 +0000900 if (reqUrl.compare(pos, fragment.size(), fragment) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700901 {
Tanousf00032d2018-11-05 01:18:10 -0300902 std::pair<unsigned, RoutingParams> ret =
Ed Tanous81ce6092020-12-17 16:54:55 +0000903 find(reqUrl, child, pos + fragment.size(), params);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700904 updateFound(ret);
905 }
906 }
907
908 return {found, matchParams};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700909 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700910
911 void add(const std::string& url, unsigned ruleIndex)
912 {
Ed Tanous271584a2019-07-09 16:24:22 -0700913 size_t idx = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700914
915 for (unsigned i = 0; i < url.size(); i++)
916 {
917 char c = url[i];
918 if (c == '<')
919 {
Tanousf00032d2018-11-05 01:18:10 -0300920 const static std::array<std::pair<ParamType, std::string>, 7>
921 paramTraits = {{
922 {ParamType::INT, "<int>"},
923 {ParamType::UINT, "<uint>"},
924 {ParamType::DOUBLE, "<float>"},
925 {ParamType::DOUBLE, "<double>"},
926 {ParamType::STRING, "<str>"},
927 {ParamType::STRING, "<string>"},
928 {ParamType::PATH, "<path>"},
929 }};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700930
Tanousf00032d2018-11-05 01:18:10 -0300931 for (const std::pair<ParamType, std::string>& x : paramTraits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700932 {
Tanousf00032d2018-11-05 01:18:10 -0300933 if (url.compare(i, x.second.size(), x.second) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700934 {
Ed Tanous271584a2019-07-09 16:24:22 -0700935 size_t index = static_cast<size_t>(x.first);
936 if (!nodes[idx].paramChildrens[index])
Ed Tanous1abe55e2018-09-05 08:30:59 -0700937 {
Tanousf00032d2018-11-05 01:18:10 -0300938 unsigned newNodeIdx = newNode();
Ed Tanous271584a2019-07-09 16:24:22 -0700939 nodes[idx].paramChildrens[index] = newNodeIdx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700940 }
Ed Tanous271584a2019-07-09 16:24:22 -0700941 idx = nodes[idx].paramChildrens[index];
942 i += static_cast<unsigned>(x.second.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700943 break;
944 }
945 }
946
947 i--;
948 }
949 else
950 {
951 std::string piece(&c, 1);
952 if (!nodes[idx].children.count(piece))
953 {
Tanousf00032d2018-11-05 01:18:10 -0300954 unsigned newNodeIdx = newNode();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700955 nodes[idx].children.emplace(piece, newNodeIdx);
956 }
957 idx = nodes[idx].children[piece];
958 }
959 }
960 if (nodes[idx].ruleIndex)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700961 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700962 throw std::runtime_error("handler already exists for " + url);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700963 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700964 nodes[idx].ruleIndex = ruleIndex;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700965 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700966
Ed Tanous1abe55e2018-09-05 08:30:59 -0700967 private:
Ed Tanous271584a2019-07-09 16:24:22 -0700968 void debugNodePrint(Node* n, size_t level)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700969 {
Ed Tanous271584a2019-07-09 16:24:22 -0700970 for (size_t i = 0; i < static_cast<size_t>(ParamType::MAX); i++)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700971 {
972 if (n->paramChildrens[i])
973 {
974 BMCWEB_LOG_DEBUG << std::string(
Ed Tanous271584a2019-07-09 16:24:22 -0700975 2U * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
976 switch (static_cast<ParamType>(i))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700977 {
978 case ParamType::INT:
979 BMCWEB_LOG_DEBUG << "<int>";
980 break;
981 case ParamType::UINT:
982 BMCWEB_LOG_DEBUG << "<uint>";
983 break;
984 case ParamType::DOUBLE:
985 BMCWEB_LOG_DEBUG << "<float>";
986 break;
987 case ParamType::STRING:
988 BMCWEB_LOG_DEBUG << "<str>";
989 break;
990 case ParamType::PATH:
991 BMCWEB_LOG_DEBUG << "<path>";
992 break;
Ed Tanous23a21a12020-07-25 04:45:05 +0000993 case ParamType::MAX:
Ed Tanous1abe55e2018-09-05 08:30:59 -0700994 BMCWEB_LOG_DEBUG << "<ERROR>";
995 break;
996 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700997
Ed Tanous1abe55e2018-09-05 08:30:59 -0700998 debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
999 }
1000 }
Tanousf00032d2018-11-05 01:18:10 -03001001 for (const std::pair<std::string, unsigned>& kv : n->children)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001002 {
1003 BMCWEB_LOG_DEBUG
Ed Tanous271584a2019-07-09 16:24:22 -07001004 << std::string(2U * level, ' ') /*<< "(" << kv.second << ") "*/
Ed Tanous1abe55e2018-09-05 08:30:59 -07001005 << kv.first;
1006 debugNodePrint(&nodes[kv.second], level + 1);
1007 }
1008 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001009
Ed Tanous1abe55e2018-09-05 08:30:59 -07001010 public:
1011 void debugPrint()
1012 {
Ed Tanous271584a2019-07-09 16:24:22 -07001013 debugNodePrint(head(), 0U);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001014 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001015
Ed Tanous1abe55e2018-09-05 08:30:59 -07001016 private:
1017 const Node* head() const
1018 {
1019 return &nodes.front();
1020 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001021
Ed Tanous1abe55e2018-09-05 08:30:59 -07001022 Node* head()
1023 {
1024 return &nodes.front();
1025 }
1026
1027 unsigned newNode()
1028 {
1029 nodes.resize(nodes.size() + 1);
Ed Tanous271584a2019-07-09 16:24:22 -07001030 return static_cast<unsigned>(nodes.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001031 }
1032
1033 std::vector<Node> nodes;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001034};
1035
Ed Tanous1abe55e2018-09-05 08:30:59 -07001036class Router
1037{
1038 public:
Ed Tanous0c0084a2019-10-24 15:57:51 -07001039 Router() = default;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001040
Ed Tanous1abe55e2018-09-05 08:30:59 -07001041 DynamicRule& newRuleDynamic(const std::string& rule)
1042 {
1043 std::unique_ptr<DynamicRule> ruleObject =
1044 std::make_unique<DynamicRule>(rule);
1045 DynamicRule* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001046 allRules.emplace_back(std::move(ruleObject));
Ed Tanous7045c8d2017-04-03 10:04:37 -07001047
Ed Tanous1abe55e2018-09-05 08:30:59 -07001048 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001049 }
1050
Ed Tanous1abe55e2018-09-05 08:30:59 -07001051 template <uint64_t N>
1052 typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
1053 newRuleTagged(const std::string& rule)
1054 {
1055 using RuleT = typename black_magic::Arguments<N>::type::template rebind<
1056 TaggedRule>;
1057 std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
1058 RuleT* ptr = ruleObject.get();
Tanousf00032d2018-11-05 01:18:10 -03001059 allRules.emplace_back(std::move(ruleObject));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001060
1061 return *ptr;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001062 }
1063
Tanousf00032d2018-11-05 01:18:10 -03001064 void internalAddRuleObject(const std::string& rule, BaseRule* ruleObject)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001065 {
Tanousf00032d2018-11-05 01:18:10 -03001066 if (ruleObject == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001067 {
Tanousf00032d2018-11-05 01:18:10 -03001068 return;
1069 }
Ed Tanous888880a2020-08-24 13:48:50 -07001070 for (size_t method = 0, methodBit = 1; method < maxHttpVerbCount;
Ed Tanous2c70f802020-09-28 14:29:23 -07001071 method++, methodBit <<= 1)
Tanousf00032d2018-11-05 01:18:10 -03001072 {
Ed Tanous2c70f802020-09-28 14:29:23 -07001073 if (ruleObject->methodsBitfield & methodBit)
Tanousf00032d2018-11-05 01:18:10 -03001074 {
1075 perMethods[method].rules.emplace_back(ruleObject);
1076 perMethods[method].trie.add(
Ed Tanous271584a2019-07-09 16:24:22 -07001077 rule, static_cast<unsigned>(
1078 perMethods[method].rules.size() - 1U));
Tanousf00032d2018-11-05 01:18:10 -03001079 // directory case:
1080 // request to `/about' url matches `/about/' rule
1081 if (rule.size() > 2 && rule.back() == '/')
1082 {
1083 perMethods[method].trie.add(
1084 rule.substr(0, rule.size() - 1),
Ed Tanous271584a2019-07-09 16:24:22 -07001085 static_cast<unsigned>(perMethods[method].rules.size() -
1086 1));
Tanousf00032d2018-11-05 01:18:10 -03001087 }
1088 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001089 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001090 }
1091
Ed Tanous1abe55e2018-09-05 08:30:59 -07001092 void validate()
1093 {
Tanousf00032d2018-11-05 01:18:10 -03001094 for (std::unique_ptr<BaseRule>& rule : allRules)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001095 {
1096 if (rule)
1097 {
Tanousf00032d2018-11-05 01:18:10 -03001098 std::unique_ptr<BaseRule> upgraded = rule->upgrade();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001099 if (upgraded)
Ed Tanous3174e4d2020-10-07 11:41:22 -07001100 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001101 rule = std::move(upgraded);
Ed Tanous3174e4d2020-10-07 11:41:22 -07001102 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001103 rule->validate();
Tanousf00032d2018-11-05 01:18:10 -03001104 internalAddRuleObject(rule->rule, rule.get());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001105 }
1106 }
Tanousf00032d2018-11-05 01:18:10 -03001107 for (PerMethod& perMethod : perMethods)
1108 {
1109 perMethod.trie.validate();
1110 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001111 }
1112
Ed Tanous1abe55e2018-09-05 08:30:59 -07001113 template <typename Adaptor>
1114 void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
1115 {
Ed Tanous271584a2019-07-09 16:24:22 -07001116 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001117 {
1118 res.result(boost::beast::http::status::not_found);
1119 res.end();
Tanousf00032d2018-11-05 01:18:10 -03001120 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001121 }
Tanousf00032d2018-11-05 01:18:10 -03001122
Ed Tanous271584a2019-07-09 16:24:22 -07001123 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001124 Trie& trie = perMethod.trie;
1125 std::vector<BaseRule*>& rules = perMethod.rules;
1126
1127 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001128 unsigned ruleIndex = found.first;
1129 if (!ruleIndex)
1130 {
1131 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001132 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001133 res.end();
1134 return;
1135 }
1136
1137 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001138 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001139 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001140 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001141
1142 if (ruleIndex == ruleSpecialRedirectSlash)
1143 {
1144 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1145 << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001146 res.result(boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001147
1148 // TODO absolute url building
1149 if (req.getHeaderValue("Host").empty())
1150 {
1151 res.addHeader("Location", std::string(req.url) + "/");
1152 }
1153 else
1154 {
1155 res.addHeader(
1156 "Location",
1157 req.isSecure
1158 ? "https://"
1159 : "http://" + std::string(req.getHeaderValue("Host")) +
1160 std::string(req.url) + "/");
1161 }
1162 res.end();
1163 return;
1164 }
1165
Ed Tanous271584a2019-07-09 16:24:22 -07001166 if ((rules[ruleIndex]->getMethods() &
1167 (1U << static_cast<size_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001168 {
1169 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1170 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001171 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001172 << rules[ruleIndex]->getMethods();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001173 res.result(boost::beast::http::status::not_found);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001174 res.end();
1175 return;
1176 }
1177
1178 BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rules[ruleIndex]->rule
Ed Tanous271584a2019-07-09 16:24:22 -07001179 << "' " << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001180 << rules[ruleIndex]->getMethods();
1181
1182 // any uncaught exceptions become 500s
1183 try
1184 {
1185 rules[ruleIndex]->handleUpgrade(req, res, std::move(adaptor));
1186 }
1187 catch (std::exception& e)
1188 {
1189 BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001190 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001191 res.end();
1192 return;
1193 }
1194 catch (...)
1195 {
1196 BMCWEB_LOG_ERROR
1197 << "An uncaught exception occurred. The type was unknown "
1198 "so no information was available.";
Ed Tanousde5c9f32019-03-26 09:17:55 -07001199 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001200 res.end();
1201 return;
1202 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001203 }
1204
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001205 void handle(Request& req, Response& res)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001206 {
Ed Tanous271584a2019-07-09 16:24:22 -07001207 if (static_cast<size_t>(req.method()) >= perMethods.size())
Ed Tanous888880a2020-08-24 13:48:50 -07001208 {
1209 res.result(boost::beast::http::status::not_found);
1210 res.end();
Tanousf00032d2018-11-05 01:18:10 -03001211 return;
Ed Tanous888880a2020-08-24 13:48:50 -07001212 }
Ed Tanous271584a2019-07-09 16:24:22 -07001213 PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Tanousf00032d2018-11-05 01:18:10 -03001214 Trie& trie = perMethod.trie;
1215 std::vector<BaseRule*>& rules = perMethod.rules;
1216
1217 const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001218
Ed Tanous1abe55e2018-09-05 08:30:59 -07001219 unsigned ruleIndex = found.first;
1220
1221 if (!ruleIndex)
1222 {
Ed Tanous2634dcd2019-03-26 09:28:06 -07001223 // Check to see if this url exists at any verb
1224 for (const PerMethod& p : perMethods)
1225 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001226 const std::pair<unsigned, RoutingParams>& found2 =
Ed Tanous2634dcd2019-03-26 09:28:06 -07001227 p.trie.find(req.url);
Ed Tanous23a21a12020-07-25 04:45:05 +00001228 if (found2.first > 0)
Ed Tanous2634dcd2019-03-26 09:28:06 -07001229 {
1230 res.result(boost::beast::http::status::method_not_allowed);
1231 res.end();
1232 return;
1233 }
1234 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001235 BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
1236 res.result(boost::beast::http::status::not_found);
1237 res.end();
1238 return;
1239 }
1240
1241 if (ruleIndex >= rules.size())
Ed Tanous3174e4d2020-10-07 11:41:22 -07001242 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001243 throw std::runtime_error("Trie internal structure corrupted!");
Ed Tanous3174e4d2020-10-07 11:41:22 -07001244 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001245
1246 if (ruleIndex == ruleSpecialRedirectSlash)
1247 {
1248 BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
1249 << req.url;
Ed Tanousde5c9f32019-03-26 09:17:55 -07001250 res.result(boost::beast::http::status::moved_permanently);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001251
1252 // TODO absolute url building
1253 if (req.getHeaderValue("Host").empty())
1254 {
1255 res.addHeader("Location", std::string(req.url) + "/");
1256 }
1257 else
1258 {
1259 res.addHeader("Location",
1260 (req.isSecure ? "https://" : "http://") +
1261 std::string(req.getHeaderValue("Host")) +
1262 std::string(req.url) + "/");
1263 }
1264 res.end();
1265 return;
1266 }
1267
Ed Tanous271584a2019-07-09 16:24:22 -07001268 if ((rules[ruleIndex]->getMethods() &
1269 (1U << static_cast<uint32_t>(req.method()))) == 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001270 {
1271 BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
1272 << " with " << req.methodString() << "("
Ed Tanous271584a2019-07-09 16:24:22 -07001273 << static_cast<uint32_t>(req.method()) << ") / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001274 << rules[ruleIndex]->getMethods();
Ed Tanousde5c9f32019-03-26 09:17:55 -07001275 res.result(boost::beast::http::status::method_not_allowed);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001276 res.end();
1277 return;
1278 }
1279
1280 BMCWEB_LOG_DEBUG << "Matched rule '" << rules[ruleIndex]->rule << "' "
Ed Tanous271584a2019-07-09 16:24:22 -07001281 << static_cast<uint32_t>(req.method()) << " / "
Ed Tanous1abe55e2018-09-05 08:30:59 -07001282 << rules[ruleIndex]->getMethods();
1283
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001284 if (req.session == nullptr)
James Feist7166bf02019-12-10 16:52:14 +00001285 {
1286 rules[ruleIndex]->handle(req, res, found.second);
James Feist7166bf02019-12-10 16:52:14 +00001287 return;
1288 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001289
1290 crow::connections::systemBus->async_method_call(
1291 [&req, &res, &rules, ruleIndex, found](
1292 const boost::system::error_code ec,
1293 std::map<std::string, std::variant<bool, std::string,
1294 std::vector<std::string>>>
1295 userInfo) {
1296 if (ec)
1297 {
1298 BMCWEB_LOG_ERROR << "GetUserInfo failed...";
1299 res.result(
1300 boost::beast::http::status::internal_server_error);
1301 res.end();
1302 return;
1303 }
1304
1305 const std::string* userRolePtr = nullptr;
1306 auto userInfoIter = userInfo.find("UserPrivilege");
1307 if (userInfoIter != userInfo.end())
1308 {
1309 userRolePtr =
1310 std::get_if<std::string>(&userInfoIter->second);
1311 }
1312
1313 std::string userRole{};
1314 if (userRolePtr != nullptr)
1315 {
1316 userRole = *userRolePtr;
1317 BMCWEB_LOG_DEBUG << "userName = " << req.session->username
1318 << " userRole = " << *userRolePtr;
1319 }
1320
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001321 bool* remoteUserPtr = nullptr;
1322 auto remoteUserIter = userInfo.find("RemoteUser");
1323 if (remoteUserIter != userInfo.end())
1324 {
1325 remoteUserPtr = std::get_if<bool>(&remoteUserIter->second);
1326 }
1327 if (remoteUserPtr == nullptr)
1328 {
1329 BMCWEB_LOG_ERROR
1330 << "RemoteUser property missing or wrong type";
1331 res.result(
1332 boost::beast::http::status::internal_server_error);
1333 res.end();
1334 return;
1335 }
1336 bool remoteUser = *remoteUserPtr;
1337
1338 bool passwordExpired = false; // default for remote user
1339 if (!remoteUser)
1340 {
1341 bool* passwordExpiredPtr = nullptr;
1342 auto passwordExpiredIter =
1343 userInfo.find("UserPasswordExpired");
1344 if (passwordExpiredIter != userInfo.end())
1345 {
1346 passwordExpiredPtr =
1347 std::get_if<bool>(&passwordExpiredIter->second);
1348 }
1349 if (passwordExpiredPtr != nullptr)
1350 {
1351 passwordExpired = *passwordExpiredPtr;
1352 }
1353 else
1354 {
1355 BMCWEB_LOG_ERROR
1356 << "UserPasswordExpired property is expected for"
1357 " local user but is missing or wrong type";
1358 res.result(
1359 boost::beast::http::status::internal_server_error);
1360 res.end();
1361 return;
1362 }
1363 }
1364
Ed Tanous23a21a12020-07-25 04:45:05 +00001365 // Get the userprivileges from the role
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001366 redfish::Privileges userPrivileges =
1367 redfish::getUserPrivileges(userRole);
1368
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001369 // Set isConfigureSelfOnly based on D-Bus results. This
1370 // ignores the results from both pamAuthenticateUser and the
1371 // value from any previous use of this session.
1372 req.session->isConfigureSelfOnly = passwordExpired;
1373
Ed Tanous23a21a12020-07-25 04:45:05 +00001374 // Modifyprivileges if isConfigureSelfOnly.
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001375 if (req.session->isConfigureSelfOnly)
1376 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001377 // Remove allprivileges except ConfigureSelf
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001378 userPrivileges = userPrivileges.intersection(
1379 redfish::Privileges{"ConfigureSelf"});
1380 BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
1381 }
1382
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001383 if (!rules[ruleIndex]->checkPrivileges(userPrivileges))
1384 {
1385 res.result(boost::beast::http::status::forbidden);
Joseph Reynolds3bf4e632020-02-06 14:44:32 -06001386 if (req.session->isConfigureSelfOnly)
1387 {
1388 redfish::messages::passwordChangeRequired(
1389 res, "/redfish/v1/AccountService/Accounts/" +
1390 req.session->username);
1391 }
RAJESWARAN THILLAIGOVINDAN61dbeef2019-12-13 04:26:54 -06001392 res.end();
1393 return;
1394 }
1395
1396 req.userRole = userRole;
1397
1398 rules[ruleIndex]->handle(req, res, found.second);
1399 },
1400 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1401 "xyz.openbmc_project.User.Manager", "GetUserInfo",
1402 req.session->username);
Ed Tanous7045c8d2017-04-03 10:04:37 -07001403 }
Ed Tanous7045c8d2017-04-03 10:04:37 -07001404
Ed Tanous1abe55e2018-09-05 08:30:59 -07001405 void debugPrint()
1406 {
Ed Tanous271584a2019-07-09 16:24:22 -07001407 for (size_t i = 0; i < perMethods.size(); i++)
Tanousf00032d2018-11-05 01:18:10 -03001408 {
Ed Tanous23a21a12020-07-25 04:45:05 +00001409 BMCWEB_LOG_DEBUG << boost::beast::http::to_string(
1410 static_cast<boost::beast::http::verb>(i));
Tanousf00032d2018-11-05 01:18:10 -03001411 perMethods[i].trie.debugPrint();
1412 }
Ed Tanous3dac7492017-08-02 13:46:20 -07001413 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001414
Ed Tanous1abe55e2018-09-05 08:30:59 -07001415 std::vector<const std::string*> getRoutes(const std::string& parent)
1416 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001417 std::vector<const std::string*> ret;
Tanousf00032d2018-11-05 01:18:10 -03001418
1419 for (const PerMethod& pm : perMethods)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001420 {
Tanousf00032d2018-11-05 01:18:10 -03001421 std::vector<unsigned> x;
1422 pm.trie.findRouteIndexes(parent, x);
1423 for (unsigned index : x)
1424 {
1425 ret.push_back(&pm.rules[index]->rule);
1426 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001427 }
1428 return ret;
1429 }
1430
1431 private:
Tanousf00032d2018-11-05 01:18:10 -03001432 struct PerMethod
1433 {
1434 std::vector<BaseRule*> rules;
1435 Trie trie;
1436 // rule index 0, 1 has special meaning; preallocate it to avoid
1437 // duplication.
1438 PerMethod() : rules(2)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001439 {}
Tanousf00032d2018-11-05 01:18:10 -03001440 };
Ed Tanous888880a2020-08-24 13:48:50 -07001441
1442 const static size_t maxHttpVerbCount =
Ed Tanouscc090442020-10-07 08:20:50 -07001443 static_cast<size_t>(boost::beast::http::verb::unlink);
Ed Tanous888880a2020-08-24 13:48:50 -07001444
Tanousf00032d2018-11-05 01:18:10 -03001445 std::array<PerMethod, maxHttpVerbCount> perMethods;
1446 std::vector<std::unique_ptr<BaseRule>> allRules;
Ed Tanous7045c8d2017-04-03 10:04:37 -07001447};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001448} // namespace crow