blob: 862f1db145969a877e133802250bd448ee48653b [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>()...))>
Ed Tanous2c70f802020-09-28 14:29:23 -0700318 static char test(int);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700319
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500320 template <typename...>
Ed Tanous2c70f802020-09-28 14:29:23 -0700321 static int test(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700322
Ed Tanous2c70f802020-09-28 14:29:23 -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
Jonathan Doman5beaf842020-08-14 11:23:33 -0700636 static const std::array<char, 256> 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
Jonathan Doman5beaf842020-08-14 11:23:33 -0700663 auto getCodeValue = [](char c) {
664 auto code = static_cast<unsigned char>(c);
665 // Ensure we cannot index outside the bounds of the decoding array
666 static_assert(std::numeric_limits<decltype(code)>::max() <
667 decodingData.size());
668 return decodingData[code];
669 };
670
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500672 // dropping first two bits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673 // and regenerate into 3 8-bits sequences
James Feist5a806642020-07-31 16:40:33 +0000674
Ed Tanous1abe55e2018-09-05 08:30:59 -0700675 for (size_t i = 0; i < inputLength; i++)
676 {
677 char base64code0;
678 char base64code1;
679 char base64code2 = 0; // initialized to 0 to suppress warnings
680 char base64code3;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100681
Jonathan Doman5beaf842020-08-14 11:23:33 -0700682 base64code0 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 if (base64code0 == nop)
684 { // non base64 character
685 return false;
686 }
687 if (!(++i < inputLength))
688 { // we need at least two input bytes for first
689 // byte output
690 return false;
691 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700692 base64code1 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700693 if (base64code1 == nop)
694 { // non base64 character
695 return false;
696 }
697 output +=
698 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100699
Ed Tanous1abe55e2018-09-05 08:30:59 -0700700 if (++i < inputLength)
701 {
702 char c = input[i];
703 if (c == '=')
704 { // padding , end of input
705 return (base64code1 & 0x0f) == 0;
706 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700707 base64code2 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700708 if (base64code2 == nop)
709 { // non base64 character
710 return false;
711 }
712 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
713 ((base64code2 >> 2) & 0x0f));
714 }
715
716 if (++i < inputLength)
717 {
718 char c = input[i];
719 if (c == '=')
720 { // padding , end of input
721 return (base64code2 & 0x03) == 0;
722 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700723 base64code3 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700724 if (base64code3 == nop)
725 { // non base64 character
726 return false;
727 }
728 output +=
729 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
730 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100731 }
732
Ed Tanous1abe55e2018-09-05 08:30:59 -0700733 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100734}
735
Andrew Geisslercb92c032018-08-17 07:56:14 -0700736/**
737 * Method returns Date Time information according to requested format
738 *
739 * @param[in] time time in second since the Epoch
740 *
741 * @return Date Time according to requested format
742 */
743inline std::string getDateTime(const std::time_t& time)
744{
745 std::array<char, 128> dateTime;
746 std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
747
748 if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
749 std::localtime(&time)))
750 {
751 // insert the colon required by the ISO 8601 standard
752 redfishDateTime = std::string(dateTime.data());
753 redfishDateTime.insert(redfishDateTime.end() - 2, ':');
754 }
755
756 return redfishDateTime;
757}
758
759inline std::string dateTimeNow()
760{
761 std::time_t time = std::time(nullptr);
762 return getDateTime(time);
763}
764
Ed Tanous51dae672018-09-05 16:07:32 -0700765inline bool constantTimeStringCompare(const std::string_view a,
766 const std::string_view b)
767{
768 // Important note, this function is ONLY constant time if the two input
769 // sizes are the same
770 if (a.size() != b.size())
771 {
772 return false;
773 }
774 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
775}
776
777struct ConstantTimeCompare
778{
779 bool operator()(const std::string_view a, const std::string_view b) const
780 {
781 return constantTimeStringCompare(a, b);
782 }
783};
784
George Liud139c232020-08-18 18:48:57 +0800785inline std::time_t getTimestamp(uint64_t millisTimeStamp)
786{
787 // Retrieve Created property with format:
788 // yyyy-mm-ddThh:mm:ss
789 std::chrono::milliseconds chronoTimeStamp(millisTimeStamp);
790 return std::chrono::duration_cast<std::chrono::duration<int>>(
791 chronoTimeStamp)
792 .count();
793}
794
Ed Tanous1abe55e2018-09-05 08:30:59 -0700795} // namespace utility
796} // namespace crow