blob: fad212fddd5e1a18f92bf38c2b16524117a35965 [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 {
Ed Tanous23a21a12020-07-25 04:45:05 +000042 requiresInRange(i, sizeUint);
43 return beginPtr[i];
Ed Tanous1abe55e2018-09-05 08:30:59 -070044 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070045
Ed Tanous1abe55e2018-09-05 08:30:59 -070046 constexpr operator const char*() const
47 {
48 return beginPtr;
49 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070050
Ed Tanous1abe55e2018-09-05 08:30:59 -070051 constexpr const char* begin() const
52 {
53 return beginPtr;
54 }
55 constexpr const char* end() const
56 {
57 return beginPtr + sizeUint;
58 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070059
Ed Tanous1abe55e2018-09-05 08:30:59 -070060 constexpr unsigned size() const
61 {
62 return sizeUint;
63 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070064};
65
Ed Tanous1abe55e2018-09-05 08:30:59 -070066constexpr unsigned findClosingTag(ConstStr s, unsigned p)
67{
68 return s[p] == '>' ? p : findClosingTag(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070069}
70
Ed Tanous1abe55e2018-09-05 08:30:59 -070071constexpr bool isValid(ConstStr s, unsigned i = 0, int f = 0)
72{
73 return i == s.size()
74 ? f == 0
75 : f < 0 || f >= 2
76 ? false
77 : s[i] == '<' ? isValid(s, i + 1, f + 1)
78 : s[i] == '>' ? isValid(s, i + 1, f - 1)
79 : isValid(s, i + 1, f);
Ed Tanous7045c8d2017-04-03 10:04:37 -070080}
81
Ed Tanous55c7b7a2018-05-22 15:27:24 -070082constexpr bool isEquN(ConstStr a, unsigned ai, ConstStr b, unsigned bi,
Ed Tanous1abe55e2018-09-05 08:30:59 -070083 unsigned n)
84{
85 return ai + n > a.size() || bi + n > b.size()
86 ? false
87 : n == 0 ? true
88 : a[ai] != b[bi] ? false
89 : isEquN(a, ai + 1, b, bi + 1, n - 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070090}
91
Ed Tanous1abe55e2018-09-05 08:30:59 -070092constexpr bool isInt(ConstStr s, unsigned i)
93{
94 return isEquN(s, i, "<int>", 0, 5);
Ed Tanous7045c8d2017-04-03 10:04:37 -070095}
96
Ed Tanous1abe55e2018-09-05 08:30:59 -070097constexpr bool isUint(ConstStr s, unsigned i)
98{
99 return isEquN(s, i, "<uint>", 0, 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700100}
101
Ed Tanous1abe55e2018-09-05 08:30:59 -0700102constexpr bool isFloat(ConstStr s, unsigned i)
103{
104 return isEquN(s, i, "<float>", 0, 7) || isEquN(s, i, "<double>", 0, 8);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700105}
106
Ed Tanous1abe55e2018-09-05 08:30:59 -0700107constexpr bool isStr(ConstStr s, unsigned i)
108{
109 return isEquN(s, i, "<str>", 0, 5) || isEquN(s, i, "<string>", 0, 8);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700110}
111
Ed Tanous1abe55e2018-09-05 08:30:59 -0700112constexpr bool isPath(ConstStr s, unsigned i)
113{
114 return isEquN(s, i, "<path>", 0, 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700115}
Ed Tanous3dac7492017-08-02 13:46:20 -0700116
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500117template <typename T>
118constexpr int getParameterTag()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700119{
Ed Tanous69509012019-10-24 16:53:05 -0700120 if constexpr (std::is_same_v<int, T>)
121 {
122 return 1;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 }
Ed Tanous69509012019-10-24 16:53:05 -0700124 if constexpr (std::is_same_v<char, T>)
125 {
126 return 1;
127 }
128 if constexpr (std::is_same_v<short, T>)
129 {
130 return 1;
131 }
132 if constexpr (std::is_same_v<long, T>)
133 {
134 return 1;
135 }
136 if constexpr (std::is_same_v<long long, T>)
137 {
138 return 1;
139 }
140 if constexpr (std::is_same_v<unsigned int, T>)
141 {
142 return 2;
143 }
144 if constexpr (std::is_same_v<unsigned char, T>)
145 {
146 return 2;
147 }
148 if constexpr (std::is_same_v<unsigned short, T>)
149 {
150 return 2;
151 }
152 if constexpr (std::is_same_v<unsigned long, T>)
153 {
154 return 2;
155 }
156 if constexpr (std::is_same_v<unsigned long long, T>)
157 {
158 return 2;
159 }
160 if constexpr (std::is_same_v<double, T>)
161 {
162 return 3;
163 }
164 if constexpr (std::is_same_v<std::string, T>)
165 {
166 return 4;
167 }
168 return 0;
169}
170
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500171template <typename... Args>
172struct compute_parameter_tag_from_args_list;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700173
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500174template <>
175struct compute_parameter_tag_from_args_list<>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700176{
Ed Tanous69509012019-10-24 16:53:05 -0700177 static constexpr int value = 0;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700178};
179
180template <typename Arg, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700181struct compute_parameter_tag_from_args_list<Arg, Args...>
182{
Ed Tanous69509012019-10-24 16:53:05 -0700183 static constexpr int subValue =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700184 compute_parameter_tag_from_args_list<Args...>::value;
Ed Tanous69509012019-10-24 16:53:05 -0700185 static constexpr int value =
186 getParameterTag<typename std::decay<Arg>::type>()
187 ? subValue * 6 + getParameterTag<typename std::decay<Arg>::type>()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700188 : subValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700189};
190
Ed Tanous1abe55e2018-09-05 08:30:59 -0700191static inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
192{
193 if (a == 0)
194 {
195 return b == 0;
196 }
197 if (b == 0)
198 {
199 return a == 0;
200 }
Ed Tanous271584a2019-07-09 16:24:22 -0700201 uint64_t sa = a % 6;
202 uint64_t sb = a % 6;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700203 if (sa == 5)
204 {
205 sa = 4;
206 }
207 if (sb == 5)
208 {
209 sb = 4;
210 }
211 if (sa != sb)
212 {
213 return false;
214 }
215 return isParameterTagCompatible(a / 6, b / 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700216}
217
Ed Tanous1abe55e2018-09-05 08:30:59 -0700218static inline unsigned findClosingTagRuntime(const char* s, unsigned p)
219{
220 return s[p] == 0 ? throw std::runtime_error("unmatched tag <")
221 : s[p] == '>' ? p : findClosingTagRuntime(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700222}
223
Ed Tanous1abe55e2018-09-05 08:30:59 -0700224static inline uint64_t getParameterTagRuntime(const char* s, unsigned p = 0)
225{
226 return s[p] == 0
227 ? 0
228 : s[p] == '<'
229 ? (std::strncmp(s + p, "<int>", 5) == 0
230 ? getParameterTagRuntime(
231 s, findClosingTagRuntime(s, p)) *
232 6 +
233 1
234 : std::strncmp(s + p, "<uint>", 6) == 0
235 ? getParameterTagRuntime(
236 s, findClosingTagRuntime(s, p)) *
237 6 +
238 2
239 : (std::strncmp(s + p, "<float>", 7) == 0 ||
240 std::strncmp(s + p, "<double>", 8) == 0)
241 ? getParameterTagRuntime(
242 s, findClosingTagRuntime(s, p)) *
243 6 +
244 3
245 : (std::strncmp(s + p, "<str>", 5) ==
246 0 ||
247 std::strncmp(s + p, "<string>", 8) ==
248 0)
249 ? getParameterTagRuntime(
250 s, findClosingTagRuntime(
251 s, p)) *
252 6 +
253 4
254 : std::strncmp(s + p, "<path>",
255 6) == 0
256 ? getParameterTagRuntime(
257 s,
258 findClosingTagRuntime(
259 s, p)) *
260 6 +
261 5
262 : throw std::runtime_error(
263 "invalid parameter "
264 "type"))
265 : getParameterTagRuntime(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700266}
Ed Tanous3dac7492017-08-02 13:46:20 -0700267
Ed Tanous1abe55e2018-09-05 08:30:59 -0700268constexpr uint64_t get_parameter_tag(ConstStr s, unsigned p = 0)
269{
270 return p == s.size()
271 ? 0
272 : s[p] == '<'
273 ? (isInt(s, p)
274 ? get_parameter_tag(s, findClosingTag(s, p)) * 6 + 1
275 : isUint(s, p)
276 ? get_parameter_tag(s, findClosingTag(s, p)) *
277 6 +
278 2
279 : isFloat(s, p)
280 ? get_parameter_tag(
281 s, findClosingTag(s, p)) *
282 6 +
283 3
284 : isStr(s, p)
285 ? get_parameter_tag(
286 s, findClosingTag(s, p)) *
287 6 +
288 4
289 : isPath(s, p)
290 ? get_parameter_tag(
291 s, findClosingTag(
292 s, p)) *
293 6 +
294 5
295 : throw std::runtime_error(
296 "invalid parameter "
297 "type"))
298 : get_parameter_tag(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700299}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700300
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500301template <typename... T>
302struct S
Ed Tanous1abe55e2018-09-05 08:30:59 -0700303{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500304 template <typename U>
305 using push = S<U, T...>;
306 template <typename U>
307 using push_back = S<T..., U>;
308 template <template <typename... Args> class U>
309 using rebind = U<T...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700310};
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500311template <typename F, typename Set>
312struct CallHelper;
313template <typename F, typename... Args>
314struct CallHelper<F, S<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700315{
316 template <typename F1, typename... Args1,
317 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
318 static char __test(int);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700319
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500320 template <typename...>
321 static int __test(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700322
Ed Tanous1abe55e2018-09-05 08:30:59 -0700323 static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700324};
325
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500326template <uint64_t N>
327struct SingleTagToType
328{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700329
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500330template <>
331struct SingleTagToType<1>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700332{
333 using type = int64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700334};
335
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500336template <>
337struct SingleTagToType<2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700338{
339 using type = uint64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700340};
341
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500342template <>
343struct SingleTagToType<3>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700344{
345 using type = double;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700346};
347
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500348template <>
349struct SingleTagToType<4>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700350{
351 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700352};
353
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500354template <>
355struct SingleTagToType<5>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700356{
357 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700358};
359
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500360template <uint64_t Tag>
361struct Arguments
Ed Tanous1abe55e2018-09-05 08:30:59 -0700362{
363 using subarguments = typename Arguments<Tag / 6>::type;
364 using type = typename subarguments::template push<
365 typename SingleTagToType<Tag % 6>::type>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700366};
367
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500368template <>
369struct Arguments<0>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700370{
371 using type = S<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700372};
373
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500374template <typename... T>
375struct LastElementType
Ed Tanous1abe55e2018-09-05 08:30:59 -0700376{
377 using type =
378 typename std::tuple_element<sizeof...(T) - 1, std::tuple<T...>>::type;
379};
380
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500381template <>
382struct LastElementType<>
383{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700384
385// from
386// http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500387template <class T>
388using Invoke = typename T::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700389
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500390template <unsigned...>
391struct Seq
Ed Tanous1abe55e2018-09-05 08:30:59 -0700392{
393 using type = Seq;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700394};
395
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500396template <class S1, class S2>
397struct concat;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700398
399template <unsigned... I1, unsigned... I2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700400struct concat<Seq<I1...>, Seq<I2...>> : Seq<I1..., (sizeof...(I1) + I2)...>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500401{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700402
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500403template <class S1, class S2>
404using Concat = Invoke<concat<S1, S2>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700405
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500406template <size_t N>
407struct gen_seq;
408template <size_t N>
409using GenSeq = Invoke<gen_seq<N>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700410
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500411template <size_t N>
412struct gen_seq : Concat<GenSeq<N / 2>, GenSeq<N - N / 2>>
413{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700414
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500415template <>
416struct gen_seq<0> : Seq<>
417{};
418template <>
419struct gen_seq<1> : Seq<0>
420{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700421
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500422template <typename Seq, typename Tuple>
423struct PopBackHelper;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700424
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500425template <unsigned... N, typename Tuple>
426struct PopBackHelper<Seq<N...>, Tuple>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700427{
428 template <template <typename... Args> class U>
429 using rebind = U<typename std::tuple_element<N, Tuple>::type...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700430};
431
432template <typename... T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700433struct PopBack //: public PopBackHelper<typename
434 // gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>
Ed Tanous7045c8d2017-04-03 10:04:37 -0700435{
Ed Tanous1abe55e2018-09-05 08:30:59 -0700436 template <template <typename... Args> class U>
437 using rebind =
Ed Tanous271584a2019-07-09 16:24:22 -0700438 typename PopBackHelper<typename gen_seq<sizeof...(T) - 1UL>::type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700439 std::tuple<T...>>::template rebind<U>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700440};
441
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500442template <>
443struct PopBack<>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700444{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500445 template <template <typename... Args> class U>
446 using rebind = U<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700447};
448
449// from
450// http://stackoverflow.com/questions/2118541/check-if-c0x-parameter-pack-contains-a-type
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500451template <typename Tp, typename... List>
452struct Contains : std::true_type
453{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700454
455template <typename Tp, typename Head, typename... Rest>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500456struct Contains<Tp, Head, Rest...> :
457 std::conditional<std::is_same<Tp, Head>::value, std::true_type,
458 Contains<Tp, Rest...>>::type
459{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700460
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500461template <typename Tp>
462struct Contains<Tp> : std::false_type
463{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700464
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500465template <typename T>
466struct EmptyContext
467{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700468
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500469template <typename T>
470struct promote
Ed Tanous1abe55e2018-09-05 08:30:59 -0700471{
472 using type = T;
473};
474
475#define BMCWEB_INTERNAL_PROMOTE_TYPE(t1, t2) \
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500476 template <> \
477 struct promote<t1> \
Ed Tanous1abe55e2018-09-05 08:30:59 -0700478 { \
479 using type = t2; \
480 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700481
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700482BMCWEB_INTERNAL_PROMOTE_TYPE(char, int64_t);
483BMCWEB_INTERNAL_PROMOTE_TYPE(short, int64_t);
484BMCWEB_INTERNAL_PROMOTE_TYPE(int, int64_t);
485BMCWEB_INTERNAL_PROMOTE_TYPE(long, int64_t);
486BMCWEB_INTERNAL_PROMOTE_TYPE(long long, int64_t);
487BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned char, uint64_t);
488BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned short, uint64_t);
489BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned int, uint64_t);
490BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long, uint64_t);
491BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long long, uint64_t);
492BMCWEB_INTERNAL_PROMOTE_TYPE(float, double);
493#undef BMCWEB_INTERNAL_PROMOTE_TYPE
Ed Tanous7045c8d2017-04-03 10:04:37 -0700494
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500495template <typename T>
496using promote_t = typename promote<T>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700497
Ed Tanous1abe55e2018-09-05 08:30:59 -0700498} // namespace black_magic
Ed Tanous7045c8d2017-04-03 10:04:37 -0700499
Ed Tanous1abe55e2018-09-05 08:30:59 -0700500namespace detail
501{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700502
503template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700504struct GetIndexOfElementFromTupleByTypeImpl
505{
Ed Tanous271584a2019-07-09 16:24:22 -0700506 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700507};
508
509template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700510struct GetIndexOfElementFromTupleByTypeImpl<T, N, T, Args...>
511{
Ed Tanous271584a2019-07-09 16:24:22 -0700512 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700513};
514
515template <class T, std::size_t N, class U, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700516struct GetIndexOfElementFromTupleByTypeImpl<T, N, U, Args...>
517{
Ed Tanous271584a2019-07-09 16:24:22 -0700518 static constexpr std::size_t value =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519 GetIndexOfElementFromTupleByTypeImpl<T, N + 1, Args...>::value;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700520};
521
Ed Tanous1abe55e2018-09-05 08:30:59 -0700522} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700523
Ed Tanous1abe55e2018-09-05 08:30:59 -0700524namespace utility
525{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500526template <class T, class... Args>
527T& getElementByType(std::tuple<Args...>& t)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700528{
529 return std::get<
530 detail::GetIndexOfElementFromTupleByTypeImpl<T, 0, Args...>::value>(t);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700531}
532
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500533template <typename T>
534struct function_traits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700535
Ed Tanous7045c8d2017-04-03 10:04:37 -0700536template <typename T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700537struct function_traits : public function_traits<decltype(&T::operator())>
538{
539 using parent_t = function_traits<decltype(&T::operator())>;
540 static const size_t arity = parent_t::arity;
541 using result_type = typename parent_t::result_type;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500542 template <size_t i>
543 using arg = typename parent_t::template arg<i>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700544};
Ed Tanous3dac7492017-08-02 13:46:20 -0700545
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700546template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700547struct function_traits<r (ClassType::*)(Args...) const>
548{
549 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700550
Ed Tanous1abe55e2018-09-05 08:30:59 -0700551 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700552
Ed Tanous1abe55e2018-09-05 08:30:59 -0700553 template <size_t i>
554 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700555};
556
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700557template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700558struct function_traits<r (ClassType::*)(Args...)>
559{
560 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700561
Ed Tanous1abe55e2018-09-05 08:30:59 -0700562 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700563
Ed Tanous1abe55e2018-09-05 08:30:59 -0700564 template <size_t i>
565 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700566};
567
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700568template <typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700569struct function_traits<std::function<r(Args...)>>
570{
571 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700572
Ed Tanous1abe55e2018-09-05 08:30:59 -0700573 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700574
Ed Tanous1abe55e2018-09-05 08:30:59 -0700575 template <size_t i>
576 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700577};
578
579inline static std::string base64encode(
Ed Tanousb01bf292019-03-25 19:25:26 +0000580 const char* data, size_t size,
Ed Tanous7045c8d2017-04-03 10:04:37 -0700581 const char* key =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700582 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
583{
584 std::string ret;
585 ret.resize((size + 2) / 3 * 4);
586 auto it = ret.begin();
587 while (size >= 3)
588 {
Ed Tanous271584a2019-07-09 16:24:22 -0700589 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
590 unsigned char h = static_cast<unsigned char>(
591 (static_cast<unsigned char>(*data++) & 0x03u) << 4u);
592 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
593 h = static_cast<unsigned char>(
594 (static_cast<unsigned char>(*data++) & 0x0F) << 2u);
595 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xC0) >> 6)];
596 *it++ = key[static_cast<unsigned char>(*data++) & 0x3F];
Ed Tanous7045c8d2017-04-03 10:04:37 -0700597
Ed Tanous1abe55e2018-09-05 08:30:59 -0700598 size -= 3;
599 }
600 if (size == 1)
601 {
Ed Tanous271584a2019-07-09 16:24:22 -0700602 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
603 unsigned char h = static_cast<unsigned char>(
604 (static_cast<unsigned char>(*data++) & 0x03) << 4u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700605 *it++ = key[h];
606 *it++ = '=';
607 *it++ = '=';
608 }
609 else if (size == 2)
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);
614 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
615 h = static_cast<unsigned char>(
616 (static_cast<unsigned char>(*data++) & 0x0F) << 2u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700617 *it++ = key[h];
618 *it++ = '=';
619 }
620 return ret;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700621}
622
Ed Tanousb01bf292019-03-25 19:25:26 +0000623inline static std::string base64encodeUrlsafe(const char* data, size_t size)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700624{
625 return base64encode(
626 data, size,
627 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700628}
629
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100630// TODO this is temporary and should be deleted once base64 is refactored out of
631// crow
Ed Tanous39e77502019-03-04 17:35:53 -0800632inline bool base64Decode(const std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700633{
Ed Tanous271584a2019-07-09 16:24:22 -0700634 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700635 // See note on encoding_data[] in above function
James Feist5a806642020-07-31 16:40:33 +0000636 static const char decodingData[] = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700637 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
638 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
639 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
640 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
641 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
642 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
643 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
644 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
645 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
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, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
650 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
651 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
652 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
653 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
654 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
655 nop, nop, nop, nop};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100656
Ed Tanous1abe55e2018-09-05 08:30:59 -0700657 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100658
Ed Tanous1abe55e2018-09-05 08:30:59 -0700659 // allocate space for output string
660 output.clear();
661 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100662
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500664 // dropping first two bits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 // and regenerate into 3 8-bits sequences
James Feist5a806642020-07-31 16:40:33 +0000666
Ed Tanous1abe55e2018-09-05 08:30:59 -0700667 for (size_t i = 0; i < inputLength; i++)
668 {
669 char base64code0;
670 char base64code1;
671 char base64code2 = 0; // initialized to 0 to suppress warnings
672 char base64code3;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100673
James Feist5a806642020-07-31 16:40:33 +0000674 base64code0 = decodingData[static_cast<int>(input[i])]; // NOLINT
Ed Tanous1abe55e2018-09-05 08:30:59 -0700675 if (base64code0 == nop)
676 { // non base64 character
677 return false;
678 }
679 if (!(++i < inputLength))
680 { // we need at least two input bytes for first
681 // byte output
682 return false;
683 }
James Feist5a806642020-07-31 16:40:33 +0000684 base64code1 = decodingData[static_cast<int>(input[i])]; // NOLINT
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685 if (base64code1 == nop)
686 { // non base64 character
687 return false;
688 }
689 output +=
690 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100691
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 if (++i < inputLength)
693 {
694 char c = input[i];
695 if (c == '=')
696 { // padding , end of input
697 return (base64code1 & 0x0f) == 0;
698 }
James Feist5a806642020-07-31 16:40:33 +0000699 base64code2 = decodingData[static_cast<int>(input[i])]; // NOLINT
Ed Tanous1abe55e2018-09-05 08:30:59 -0700700 if (base64code2 == nop)
701 { // non base64 character
702 return false;
703 }
704 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
705 ((base64code2 >> 2) & 0x0f));
706 }
707
708 if (++i < inputLength)
709 {
710 char c = input[i];
711 if (c == '=')
712 { // padding , end of input
713 return (base64code2 & 0x03) == 0;
714 }
James Feist5a806642020-07-31 16:40:33 +0000715 base64code3 = decodingData[static_cast<int>(input[i])]; // NOLINT
Ed Tanous1abe55e2018-09-05 08:30:59 -0700716 if (base64code3 == nop)
717 { // non base64 character
718 return false;
719 }
720 output +=
721 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
722 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100723 }
724
Ed Tanous1abe55e2018-09-05 08:30:59 -0700725 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100726}
727
Ed Tanousa29c9972018-11-29 15:54:32 -0800728inline void escapeHtml(std::string& data)
729{
730 std::string buffer;
Ed Tanousb01bf292019-03-25 19:25:26 +0000731 // less than 5% of characters should be larger, so reserve a buffer of the
Ed Tanousa29c9972018-11-29 15:54:32 -0800732 // right size
Ed Tanous271584a2019-07-09 16:24:22 -0700733 buffer.reserve(data.size() * 11 / 10);
Ed Tanousa29c9972018-11-29 15:54:32 -0800734 for (size_t pos = 0; pos != data.size(); ++pos)
735 {
736 switch (data[pos])
737 {
738 case '&':
739 buffer.append("&amp;");
740 break;
741 case '\"':
742 buffer.append("&quot;");
743 break;
744 case '\'':
745 buffer.append("&apos;");
746 break;
747 case '<':
748 buffer.append("&lt;");
749 break;
750 case '>':
751 buffer.append("&gt;");
752 break;
753 default:
754 buffer.append(&data[pos], 1);
755 break;
756 }
757 }
758 data.swap(buffer);
759}
760
761inline void convertToLinks(std::string& s)
762{
Jason M. Billsa6e2f1c2019-12-11 14:32:14 -0800763 // Convert anything with a redfish path into a link
Ed Tanous23a21a12020-07-25 04:45:05 +0000764 const std::regex redfishPath{"(&quot;((.*))&quot;[ \\n]*:[ "
765 "\\n]*)(&quot;((?!&quot;)/redfish/.*)&quot;)"};
Jason M. Billsa6e2f1c2019-12-11 14:32:14 -0800766 s = std::regex_replace(s, redfishPath, "$1<a href=\"$5\">$4</a>");
Ed Tanousa29c9972018-11-29 15:54:32 -0800767}
768
Andrew Geisslercb92c032018-08-17 07:56:14 -0700769/**
770 * Method returns Date Time information according to requested format
771 *
772 * @param[in] time time in second since the Epoch
773 *
774 * @return Date Time according to requested format
775 */
776inline std::string getDateTime(const std::time_t& time)
777{
778 std::array<char, 128> dateTime;
779 std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
780
781 if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
782 std::localtime(&time)))
783 {
784 // insert the colon required by the ISO 8601 standard
785 redfishDateTime = std::string(dateTime.data());
786 redfishDateTime.insert(redfishDateTime.end() - 2, ':');
787 }
788
789 return redfishDateTime;
790}
791
792inline std::string dateTimeNow()
793{
794 std::time_t time = std::time(nullptr);
795 return getDateTime(time);
796}
797
Ed Tanous51dae672018-09-05 16:07:32 -0700798inline bool constantTimeStringCompare(const std::string_view a,
799 const std::string_view b)
800{
801 // Important note, this function is ONLY constant time if the two input
802 // sizes are the same
803 if (a.size() != b.size())
804 {
805 return false;
806 }
807 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
808}
809
810struct ConstantTimeCompare
811{
812 bool operator()(const std::string_view a, const std::string_view b) const
813 {
814 return constantTimeStringCompare(a, b);
815 }
816};
817
Ed Tanous1abe55e2018-09-05 08:30:59 -0700818} // namespace utility
819} // namespace crow