blob: 59abc8ddd1cb7a0e51279310098022cb029fd2f3 [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
2
Ed Tanous1abe55e2018-09-05 08:30:59 -07003#include "nlohmann/json.hpp"
4
Ed Tanous51dae672018-09-05 16:07:32 -07005#include <openssl/crypto.h>
6
Ed Tanous7045c8d2017-04-03 10:04:37 -07007#include <cstdint>
8#include <cstring>
9#include <functional>
Ed Tanousa29c9972018-11-29 15:54:32 -080010#include <regex>
Ed Tanous7045c8d2017-04-03 10:04:37 -070011#include <stdexcept>
12#include <string>
13#include <tuple>
Ed Tanous7045c8d2017-04-03 10:04:37 -070014
Ed Tanous1abe55e2018-09-05 08:30:59 -070015namespace crow
16{
17namespace black_magic
18{
19struct OutOfRange
20{
21 OutOfRange(unsigned /*pos*/, unsigned /*length*/)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050022 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070023};
Ed Tanous1abe55e2018-09-05 08:30:59 -070024constexpr unsigned requiresInRange(unsigned i, unsigned len)
25{
26 return i >= len ? throw OutOfRange(i, len) : i;
Ed Tanous7045c8d2017-04-03 10:04:37 -070027}
28
Ed Tanous1abe55e2018-09-05 08:30:59 -070029class ConstStr
30{
31 const char* const beginPtr;
32 unsigned sizeUint;
Ed Tanous7045c8d2017-04-03 10:04:37 -070033
Ed Tanous1abe55e2018-09-05 08:30:59 -070034 public:
35 template <unsigned N>
36 constexpr ConstStr(const char (&arr)[N]) : beginPtr(arr), sizeUint(N - 1)
37 {
38 static_assert(N >= 1, "not a string literal");
39 }
40 constexpr char operator[](unsigned i) const
41 {
42 return requiresInRange(i, sizeUint), beginPtr[i];
43 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070044
Ed Tanous1abe55e2018-09-05 08:30:59 -070045 constexpr operator const char*() const
46 {
47 return beginPtr;
48 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070049
Ed Tanous1abe55e2018-09-05 08:30:59 -070050 constexpr const char* begin() const
51 {
52 return beginPtr;
53 }
54 constexpr const char* end() const
55 {
56 return beginPtr + sizeUint;
57 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070058
Ed Tanous1abe55e2018-09-05 08:30:59 -070059 constexpr unsigned size() const
60 {
61 return sizeUint;
62 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070063};
64
Ed Tanous1abe55e2018-09-05 08:30:59 -070065constexpr unsigned findClosingTag(ConstStr s, unsigned p)
66{
67 return s[p] == '>' ? p : findClosingTag(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070068}
69
Ed Tanous1abe55e2018-09-05 08:30:59 -070070constexpr bool isValid(ConstStr s, unsigned i = 0, int f = 0)
71{
72 return i == s.size()
73 ? f == 0
74 : f < 0 || f >= 2
75 ? false
76 : s[i] == '<' ? isValid(s, i + 1, f + 1)
77 : s[i] == '>' ? isValid(s, i + 1, f - 1)
78 : isValid(s, i + 1, f);
Ed Tanous7045c8d2017-04-03 10:04:37 -070079}
80
Ed Tanous1abe55e2018-09-05 08:30:59 -070081constexpr bool isEquP(const char* a, const char* b, unsigned n)
82{
83 return *a == 0 && *b == 0 && n == 0
84 ? true
85 : (*a == 0 || *b == 0)
86 ? false
87 : n == 0 ? true
88 : *a != *b ? false : isEquP(a + 1, b + 1, n - 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070089}
90
Ed Tanous55c7b7a2018-05-22 15:27:24 -070091constexpr bool isEquN(ConstStr a, unsigned ai, ConstStr b, unsigned bi,
Ed Tanous1abe55e2018-09-05 08:30:59 -070092 unsigned n)
93{
94 return ai + n > a.size() || bi + n > b.size()
95 ? false
96 : n == 0 ? true
97 : a[ai] != b[bi] ? false
98 : isEquN(a, ai + 1, b, bi + 1, n - 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070099}
100
Ed Tanous1abe55e2018-09-05 08:30:59 -0700101constexpr bool isInt(ConstStr s, unsigned i)
102{
103 return isEquN(s, i, "<int>", 0, 5);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700104}
105
Ed Tanous1abe55e2018-09-05 08:30:59 -0700106constexpr bool isUint(ConstStr s, unsigned i)
107{
108 return isEquN(s, i, "<uint>", 0, 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700109}
110
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111constexpr bool isFloat(ConstStr s, unsigned i)
112{
113 return isEquN(s, i, "<float>", 0, 7) || isEquN(s, i, "<double>", 0, 8);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700114}
115
Ed Tanous1abe55e2018-09-05 08:30:59 -0700116constexpr bool isStr(ConstStr s, unsigned i)
117{
118 return isEquN(s, i, "<str>", 0, 5) || isEquN(s, i, "<string>", 0, 8);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700119}
120
Ed Tanous1abe55e2018-09-05 08:30:59 -0700121constexpr bool isPath(ConstStr s, unsigned i)
122{
123 return isEquN(s, i, "<path>", 0, 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700124}
Ed Tanous3dac7492017-08-02 13:46:20 -0700125
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500126template <typename T>
127constexpr int getParameterTag()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128{
Ed Tanous69509012019-10-24 16:53:05 -0700129 if constexpr (std::is_same_v<int, T>)
130 {
131 return 1;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700132 }
Ed Tanous69509012019-10-24 16:53:05 -0700133 if constexpr (std::is_same_v<char, T>)
134 {
135 return 1;
136 }
137 if constexpr (std::is_same_v<short, T>)
138 {
139 return 1;
140 }
141 if constexpr (std::is_same_v<long, T>)
142 {
143 return 1;
144 }
145 if constexpr (std::is_same_v<long long, T>)
146 {
147 return 1;
148 }
149 if constexpr (std::is_same_v<unsigned int, T>)
150 {
151 return 2;
152 }
153 if constexpr (std::is_same_v<unsigned char, T>)
154 {
155 return 2;
156 }
157 if constexpr (std::is_same_v<unsigned short, T>)
158 {
159 return 2;
160 }
161 if constexpr (std::is_same_v<unsigned long, T>)
162 {
163 return 2;
164 }
165 if constexpr (std::is_same_v<unsigned long long, T>)
166 {
167 return 2;
168 }
169 if constexpr (std::is_same_v<double, T>)
170 {
171 return 3;
172 }
173 if constexpr (std::is_same_v<std::string, T>)
174 {
175 return 4;
176 }
177 return 0;
178}
179
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500180template <typename... Args>
181struct compute_parameter_tag_from_args_list;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700182
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500183template <>
184struct compute_parameter_tag_from_args_list<>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700185{
Ed Tanous69509012019-10-24 16:53:05 -0700186 static constexpr int value = 0;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700187};
188
189template <typename Arg, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700190struct compute_parameter_tag_from_args_list<Arg, Args...>
191{
Ed Tanous69509012019-10-24 16:53:05 -0700192 static constexpr int subValue =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700193 compute_parameter_tag_from_args_list<Args...>::value;
Ed Tanous69509012019-10-24 16:53:05 -0700194 static constexpr int value =
195 getParameterTag<typename std::decay<Arg>::type>()
196 ? subValue * 6 + getParameterTag<typename std::decay<Arg>::type>()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700197 : subValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700198};
199
Ed Tanous1abe55e2018-09-05 08:30:59 -0700200static inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
201{
202 if (a == 0)
203 {
204 return b == 0;
205 }
206 if (b == 0)
207 {
208 return a == 0;
209 }
Ed Tanous271584a2019-07-09 16:24:22 -0700210 uint64_t sa = a % 6;
211 uint64_t sb = a % 6;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700212 if (sa == 5)
213 {
214 sa = 4;
215 }
216 if (sb == 5)
217 {
218 sb = 4;
219 }
220 if (sa != sb)
221 {
222 return false;
223 }
224 return isParameterTagCompatible(a / 6, b / 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700225}
226
Ed Tanous1abe55e2018-09-05 08:30:59 -0700227static inline unsigned findClosingTagRuntime(const char* s, unsigned p)
228{
229 return s[p] == 0 ? throw std::runtime_error("unmatched tag <")
230 : s[p] == '>' ? p : findClosingTagRuntime(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700231}
232
Ed Tanous1abe55e2018-09-05 08:30:59 -0700233static inline uint64_t getParameterTagRuntime(const char* s, unsigned p = 0)
234{
235 return s[p] == 0
236 ? 0
237 : s[p] == '<'
238 ? (std::strncmp(s + p, "<int>", 5) == 0
239 ? getParameterTagRuntime(
240 s, findClosingTagRuntime(s, p)) *
241 6 +
242 1
243 : std::strncmp(s + p, "<uint>", 6) == 0
244 ? getParameterTagRuntime(
245 s, findClosingTagRuntime(s, p)) *
246 6 +
247 2
248 : (std::strncmp(s + p, "<float>", 7) == 0 ||
249 std::strncmp(s + p, "<double>", 8) == 0)
250 ? getParameterTagRuntime(
251 s, findClosingTagRuntime(s, p)) *
252 6 +
253 3
254 : (std::strncmp(s + p, "<str>", 5) ==
255 0 ||
256 std::strncmp(s + p, "<string>", 8) ==
257 0)
258 ? getParameterTagRuntime(
259 s, findClosingTagRuntime(
260 s, p)) *
261 6 +
262 4
263 : std::strncmp(s + p, "<path>",
264 6) == 0
265 ? getParameterTagRuntime(
266 s,
267 findClosingTagRuntime(
268 s, p)) *
269 6 +
270 5
271 : throw std::runtime_error(
272 "invalid parameter "
273 "type"))
274 : getParameterTagRuntime(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700275}
Ed Tanous3dac7492017-08-02 13:46:20 -0700276
Ed Tanous1abe55e2018-09-05 08:30:59 -0700277constexpr uint64_t get_parameter_tag(ConstStr s, unsigned p = 0)
278{
279 return p == s.size()
280 ? 0
281 : s[p] == '<'
282 ? (isInt(s, p)
283 ? get_parameter_tag(s, findClosingTag(s, p)) * 6 + 1
284 : isUint(s, p)
285 ? get_parameter_tag(s, findClosingTag(s, p)) *
286 6 +
287 2
288 : isFloat(s, p)
289 ? get_parameter_tag(
290 s, findClosingTag(s, p)) *
291 6 +
292 3
293 : isStr(s, p)
294 ? get_parameter_tag(
295 s, findClosingTag(s, p)) *
296 6 +
297 4
298 : isPath(s, p)
299 ? get_parameter_tag(
300 s, findClosingTag(
301 s, p)) *
302 6 +
303 5
304 : throw std::runtime_error(
305 "invalid parameter "
306 "type"))
307 : get_parameter_tag(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700308}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700309
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500310template <typename... T>
311struct S
Ed Tanous1abe55e2018-09-05 08:30:59 -0700312{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500313 template <typename U>
314 using push = S<U, T...>;
315 template <typename U>
316 using push_back = S<T..., U>;
317 template <template <typename... Args> class U>
318 using rebind = U<T...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700319};
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500320template <typename F, typename Set>
321struct CallHelper;
322template <typename F, typename... Args>
323struct CallHelper<F, S<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700324{
325 template <typename F1, typename... Args1,
326 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
327 static char __test(int);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700328
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500329 template <typename...>
330 static int __test(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700331
Ed Tanous1abe55e2018-09-05 08:30:59 -0700332 static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700333};
334
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500335template <uint64_t N>
336struct SingleTagToType
337{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700338
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500339template <>
340struct SingleTagToType<1>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700341{
342 using type = int64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700343};
344
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500345template <>
346struct SingleTagToType<2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700347{
348 using type = uint64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700349};
350
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500351template <>
352struct SingleTagToType<3>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700353{
354 using type = double;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700355};
356
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500357template <>
358struct SingleTagToType<4>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700359{
360 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700361};
362
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500363template <>
364struct SingleTagToType<5>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700365{
366 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700367};
368
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500369template <uint64_t Tag>
370struct Arguments
Ed Tanous1abe55e2018-09-05 08:30:59 -0700371{
372 using subarguments = typename Arguments<Tag / 6>::type;
373 using type = typename subarguments::template push<
374 typename SingleTagToType<Tag % 6>::type>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700375};
376
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500377template <>
378struct Arguments<0>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700379{
380 using type = S<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700381};
382
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500383template <typename... T>
384struct LastElementType
Ed Tanous1abe55e2018-09-05 08:30:59 -0700385{
386 using type =
387 typename std::tuple_element<sizeof...(T) - 1, std::tuple<T...>>::type;
388};
389
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500390template <>
391struct LastElementType<>
392{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700393
394// from
395// http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500396template <class T>
397using Invoke = typename T::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700398
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500399template <unsigned...>
400struct Seq
Ed Tanous1abe55e2018-09-05 08:30:59 -0700401{
402 using type = Seq;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700403};
404
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500405template <class S1, class S2>
406struct concat;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700407
408template <unsigned... I1, unsigned... I2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700409struct concat<Seq<I1...>, Seq<I2...>> : Seq<I1..., (sizeof...(I1) + I2)...>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500410{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700411
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500412template <class S1, class S2>
413using Concat = Invoke<concat<S1, S2>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700414
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500415template <size_t N>
416struct gen_seq;
417template <size_t N>
418using GenSeq = Invoke<gen_seq<N>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700419
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500420template <size_t N>
421struct gen_seq : Concat<GenSeq<N / 2>, GenSeq<N - N / 2>>
422{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700423
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500424template <>
425struct gen_seq<0> : Seq<>
426{};
427template <>
428struct gen_seq<1> : Seq<0>
429{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700430
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500431template <typename Seq, typename Tuple>
432struct PopBackHelper;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700433
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500434template <unsigned... N, typename Tuple>
435struct PopBackHelper<Seq<N...>, Tuple>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700436{
437 template <template <typename... Args> class U>
438 using rebind = U<typename std::tuple_element<N, Tuple>::type...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700439};
440
441template <typename... T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700442struct PopBack //: public PopBackHelper<typename
443 // gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>
Ed Tanous7045c8d2017-04-03 10:04:37 -0700444{
Ed Tanous1abe55e2018-09-05 08:30:59 -0700445 template <template <typename... Args> class U>
446 using rebind =
Ed Tanous271584a2019-07-09 16:24:22 -0700447 typename PopBackHelper<typename gen_seq<sizeof...(T) - 1UL>::type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700448 std::tuple<T...>>::template rebind<U>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700449};
450
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500451template <>
452struct PopBack<>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700453{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500454 template <template <typename... Args> class U>
455 using rebind = U<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700456};
457
458// from
459// http://stackoverflow.com/questions/2118541/check-if-c0x-parameter-pack-contains-a-type
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500460template <typename Tp, typename... List>
461struct Contains : std::true_type
462{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700463
464template <typename Tp, typename Head, typename... Rest>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500465struct Contains<Tp, Head, Rest...> :
466 std::conditional<std::is_same<Tp, Head>::value, std::true_type,
467 Contains<Tp, Rest...>>::type
468{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700469
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500470template <typename Tp>
471struct Contains<Tp> : std::false_type
472{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700473
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500474template <typename T>
475struct EmptyContext
476{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700477
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500478template <typename T>
479struct promote
Ed Tanous1abe55e2018-09-05 08:30:59 -0700480{
481 using type = T;
482};
483
484#define BMCWEB_INTERNAL_PROMOTE_TYPE(t1, t2) \
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500485 template <> \
486 struct promote<t1> \
Ed Tanous1abe55e2018-09-05 08:30:59 -0700487 { \
488 using type = t2; \
489 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700490
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700491BMCWEB_INTERNAL_PROMOTE_TYPE(char, int64_t);
492BMCWEB_INTERNAL_PROMOTE_TYPE(short, int64_t);
493BMCWEB_INTERNAL_PROMOTE_TYPE(int, int64_t);
494BMCWEB_INTERNAL_PROMOTE_TYPE(long, int64_t);
495BMCWEB_INTERNAL_PROMOTE_TYPE(long long, int64_t);
496BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned char, uint64_t);
497BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned short, uint64_t);
498BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned int, uint64_t);
499BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long, uint64_t);
500BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long long, uint64_t);
501BMCWEB_INTERNAL_PROMOTE_TYPE(float, double);
502#undef BMCWEB_INTERNAL_PROMOTE_TYPE
Ed Tanous7045c8d2017-04-03 10:04:37 -0700503
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500504template <typename T>
505using promote_t = typename promote<T>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700506
Ed Tanous1abe55e2018-09-05 08:30:59 -0700507} // namespace black_magic
Ed Tanous7045c8d2017-04-03 10:04:37 -0700508
Ed Tanous1abe55e2018-09-05 08:30:59 -0700509namespace detail
510{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700511
512template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700513struct GetIndexOfElementFromTupleByTypeImpl
514{
Ed Tanous271584a2019-07-09 16:24:22 -0700515 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700516};
517
518template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519struct GetIndexOfElementFromTupleByTypeImpl<T, N, T, Args...>
520{
Ed Tanous271584a2019-07-09 16:24:22 -0700521 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700522};
523
524template <class T, std::size_t N, class U, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700525struct GetIndexOfElementFromTupleByTypeImpl<T, N, U, Args...>
526{
Ed Tanous271584a2019-07-09 16:24:22 -0700527 static constexpr std::size_t value =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700528 GetIndexOfElementFromTupleByTypeImpl<T, N + 1, Args...>::value;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700529};
530
Ed Tanous1abe55e2018-09-05 08:30:59 -0700531} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700532
Ed Tanous1abe55e2018-09-05 08:30:59 -0700533namespace utility
534{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500535template <class T, class... Args>
536T& getElementByType(std::tuple<Args...>& t)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700537{
538 return std::get<
539 detail::GetIndexOfElementFromTupleByTypeImpl<T, 0, Args...>::value>(t);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700540}
541
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500542template <typename T>
543struct function_traits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700544
Ed Tanous7045c8d2017-04-03 10:04:37 -0700545template <typename T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700546struct function_traits : public function_traits<decltype(&T::operator())>
547{
548 using parent_t = function_traits<decltype(&T::operator())>;
549 static const size_t arity = parent_t::arity;
550 using result_type = typename parent_t::result_type;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500551 template <size_t i>
552 using arg = typename parent_t::template arg<i>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700553};
Ed Tanous3dac7492017-08-02 13:46:20 -0700554
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700555template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700556struct function_traits<r (ClassType::*)(Args...) const>
557{
558 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700559
Ed Tanous1abe55e2018-09-05 08:30:59 -0700560 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700561
Ed Tanous1abe55e2018-09-05 08:30:59 -0700562 template <size_t i>
563 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700564};
565
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700566template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700567struct function_traits<r (ClassType::*)(Args...)>
568{
569 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700570
Ed Tanous1abe55e2018-09-05 08:30:59 -0700571 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700572
Ed Tanous1abe55e2018-09-05 08:30:59 -0700573 template <size_t i>
574 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700575};
576
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700577template <typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700578struct function_traits<std::function<r(Args...)>>
579{
580 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700581
Ed Tanous1abe55e2018-09-05 08:30:59 -0700582 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700583
Ed Tanous1abe55e2018-09-05 08:30:59 -0700584 template <size_t i>
585 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700586};
587
588inline static std::string base64encode(
Ed Tanousb01bf292019-03-25 19:25:26 +0000589 const char* data, size_t size,
Ed Tanous7045c8d2017-04-03 10:04:37 -0700590 const char* key =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700591 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
592{
593 std::string ret;
594 ret.resize((size + 2) / 3 * 4);
595 auto it = ret.begin();
596 while (size >= 3)
597 {
Ed Tanous271584a2019-07-09 16:24:22 -0700598 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
599 unsigned char h = static_cast<unsigned char>(
600 (static_cast<unsigned char>(*data++) & 0x03u) << 4u);
601 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
602 h = static_cast<unsigned char>(
603 (static_cast<unsigned char>(*data++) & 0x0F) << 2u);
604 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xC0) >> 6)];
605 *it++ = key[static_cast<unsigned char>(*data++) & 0x3F];
Ed Tanous7045c8d2017-04-03 10:04:37 -0700606
Ed Tanous1abe55e2018-09-05 08:30:59 -0700607 size -= 3;
608 }
609 if (size == 1)
610 {
Ed Tanous271584a2019-07-09 16:24:22 -0700611 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
612 unsigned char h = static_cast<unsigned char>(
613 (static_cast<unsigned char>(*data++) & 0x03) << 4u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700614 *it++ = key[h];
615 *it++ = '=';
616 *it++ = '=';
617 }
618 else if (size == 2)
619 {
Ed Tanous271584a2019-07-09 16:24:22 -0700620 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
621 unsigned char h = static_cast<unsigned char>(
622 (static_cast<unsigned char>(*data++) & 0x03) << 4u);
623 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
624 h = static_cast<unsigned char>(
625 (static_cast<unsigned char>(*data++) & 0x0F) << 2u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700626 *it++ = key[h];
627 *it++ = '=';
628 }
629 return ret;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700630}
631
Ed Tanousb01bf292019-03-25 19:25:26 +0000632inline static std::string base64encodeUrlsafe(const char* data, size_t size)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700633{
634 return base64encode(
635 data, size,
636 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700637}
638
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100639// TODO this is temporary and should be deleted once base64 is refactored out of
640// crow
Ed Tanous39e77502019-03-04 17:35:53 -0800641inline bool base64Decode(const std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700642{
Ed Tanous271584a2019-07-09 16:24:22 -0700643 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700644 // See note on encoding_data[] in above function
645 static const char decodingData[] = {
646 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
647 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
648 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
649 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
650 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
651 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
652 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
653 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
654 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
655 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
656 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
657 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
658 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
659 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
660 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
661 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
662 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
663 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
664 nop, nop, nop, nop};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100665
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100667
Ed Tanous1abe55e2018-09-05 08:30:59 -0700668 // allocate space for output string
669 output.clear();
670 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100671
Ed Tanous1abe55e2018-09-05 08:30:59 -0700672 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
673 // droping first two bits
674 // and regenerate into 3 8-bits sequences
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100675
Ed Tanous1abe55e2018-09-05 08:30:59 -0700676 for (size_t i = 0; i < inputLength; i++)
677 {
678 char base64code0;
679 char base64code1;
680 char base64code2 = 0; // initialized to 0 to suppress warnings
681 char base64code3;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100682
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 base64code0 = decodingData[static_cast<int>(input[i])]; // NOLINT
684 if (base64code0 == nop)
685 { // non base64 character
686 return false;
687 }
688 if (!(++i < inputLength))
689 { // we need at least two input bytes for first
690 // byte output
691 return false;
692 }
693 base64code1 = decodingData[static_cast<int>(input[i])]; // NOLINT
694 if (base64code1 == nop)
695 { // non base64 character
696 return false;
697 }
698 output +=
699 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100700
Ed Tanous1abe55e2018-09-05 08:30:59 -0700701 if (++i < inputLength)
702 {
703 char c = input[i];
704 if (c == '=')
705 { // padding , end of input
706 return (base64code1 & 0x0f) == 0;
707 }
708 base64code2 = decodingData[static_cast<int>(input[i])]; // NOLINT
709 if (base64code2 == nop)
710 { // non base64 character
711 return false;
712 }
713 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
714 ((base64code2 >> 2) & 0x0f));
715 }
716
717 if (++i < inputLength)
718 {
719 char c = input[i];
720 if (c == '=')
721 { // padding , end of input
722 return (base64code2 & 0x03) == 0;
723 }
724 base64code3 = decodingData[static_cast<int>(input[i])]; // NOLINT
725 if (base64code3 == nop)
726 { // non base64 character
727 return false;
728 }
729 output +=
730 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
731 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100732 }
733
Ed Tanous1abe55e2018-09-05 08:30:59 -0700734 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100735}
736
Ed Tanousa29c9972018-11-29 15:54:32 -0800737inline void escapeHtml(std::string& data)
738{
739 std::string buffer;
Ed Tanousb01bf292019-03-25 19:25:26 +0000740 // less than 5% of characters should be larger, so reserve a buffer of the
Ed Tanousa29c9972018-11-29 15:54:32 -0800741 // right size
Ed Tanous271584a2019-07-09 16:24:22 -0700742 buffer.reserve(data.size() * 11 / 10);
Ed Tanousa29c9972018-11-29 15:54:32 -0800743 for (size_t pos = 0; pos != data.size(); ++pos)
744 {
745 switch (data[pos])
746 {
747 case '&':
748 buffer.append("&amp;");
749 break;
750 case '\"':
751 buffer.append("&quot;");
752 break;
753 case '\'':
754 buffer.append("&apos;");
755 break;
756 case '<':
757 buffer.append("&lt;");
758 break;
759 case '>':
760 buffer.append("&gt;");
761 break;
762 default:
763 buffer.append(&data[pos], 1);
764 break;
765 }
766 }
767 data.swap(buffer);
768}
769
770inline void convertToLinks(std::string& s)
771{
Jason M. Billsa6e2f1c2019-12-11 14:32:14 -0800772 // Convert anything with a redfish path into a link
773 const static std::regex redfishPath{
774 "(&quot;((.*))&quot;[ \\n]*:[ "
775 "\\n]*)(&quot;((?!&quot;)/redfish/.*)&quot;)"};
776 s = std::regex_replace(s, redfishPath, "$1<a href=\"$5\">$4</a>");
Ed Tanousa29c9972018-11-29 15:54:32 -0800777}
778
Andrew Geisslercb92c032018-08-17 07:56:14 -0700779/**
780 * Method returns Date Time information according to requested format
781 *
782 * @param[in] time time in second since the Epoch
783 *
784 * @return Date Time according to requested format
785 */
786inline std::string getDateTime(const std::time_t& time)
787{
788 std::array<char, 128> dateTime;
789 std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
790
791 if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
792 std::localtime(&time)))
793 {
794 // insert the colon required by the ISO 8601 standard
795 redfishDateTime = std::string(dateTime.data());
796 redfishDateTime.insert(redfishDateTime.end() - 2, ':');
797 }
798
799 return redfishDateTime;
800}
801
802inline std::string dateTimeNow()
803{
804 std::time_t time = std::time(nullptr);
805 return getDateTime(time);
806}
807
Ed Tanous51dae672018-09-05 16:07:32 -0700808inline bool constantTimeStringCompare(const std::string_view a,
809 const std::string_view b)
810{
811 // Important note, this function is ONLY constant time if the two input
812 // sizes are the same
813 if (a.size() != b.size())
814 {
815 return false;
816 }
817 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
818}
819
820struct ConstantTimeCompare
821{
822 bool operator()(const std::string_view a, const std::string_view b) const
823 {
824 return constantTimeStringCompare(a, b);
825 }
826};
827
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828} // namespace utility
829} // namespace crow