blob: 825409185a948cf50d403b0375710d13f1eef1cd [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 Tanous55c7b7a2018-05-22 15:27:24 -070081constexpr bool isEquN(ConstStr a, unsigned ai, ConstStr b, unsigned bi,
Ed Tanous1abe55e2018-09-05 08:30:59 -070082 unsigned n)
83{
84 return ai + n > a.size() || bi + n > b.size()
85 ? false
86 : n == 0 ? true
87 : a[ai] != b[bi] ? false
88 : isEquN(a, ai + 1, b, bi + 1, n - 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070089}
90
Ed Tanous1abe55e2018-09-05 08:30:59 -070091constexpr bool isInt(ConstStr s, unsigned i)
92{
93 return isEquN(s, i, "<int>", 0, 5);
Ed Tanous7045c8d2017-04-03 10:04:37 -070094}
95
Ed Tanous1abe55e2018-09-05 08:30:59 -070096constexpr bool isUint(ConstStr s, unsigned i)
97{
98 return isEquN(s, i, "<uint>", 0, 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -070099}
100
Ed Tanous1abe55e2018-09-05 08:30:59 -0700101constexpr bool isFloat(ConstStr s, unsigned i)
102{
103 return isEquN(s, i, "<float>", 0, 7) || isEquN(s, i, "<double>", 0, 8);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700104}
105
Ed Tanous1abe55e2018-09-05 08:30:59 -0700106constexpr bool isStr(ConstStr s, unsigned i)
107{
108 return isEquN(s, i, "<str>", 0, 5) || isEquN(s, i, "<string>", 0, 8);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700109}
110
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111constexpr bool isPath(ConstStr s, unsigned i)
112{
113 return isEquN(s, i, "<path>", 0, 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700114}
Ed Tanous3dac7492017-08-02 13:46:20 -0700115
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500116template <typename T>
117constexpr int getParameterTag()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700118{
Ed Tanous69509012019-10-24 16:53:05 -0700119 if constexpr (std::is_same_v<int, T>)
120 {
121 return 1;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700122 }
Ed Tanous69509012019-10-24 16:53:05 -0700123 if constexpr (std::is_same_v<char, T>)
124 {
125 return 1;
126 }
127 if constexpr (std::is_same_v<short, T>)
128 {
129 return 1;
130 }
131 if constexpr (std::is_same_v<long, T>)
132 {
133 return 1;
134 }
135 if constexpr (std::is_same_v<long long, T>)
136 {
137 return 1;
138 }
139 if constexpr (std::is_same_v<unsigned int, T>)
140 {
141 return 2;
142 }
143 if constexpr (std::is_same_v<unsigned char, T>)
144 {
145 return 2;
146 }
147 if constexpr (std::is_same_v<unsigned short, T>)
148 {
149 return 2;
150 }
151 if constexpr (std::is_same_v<unsigned long, T>)
152 {
153 return 2;
154 }
155 if constexpr (std::is_same_v<unsigned long long, T>)
156 {
157 return 2;
158 }
159 if constexpr (std::is_same_v<double, T>)
160 {
161 return 3;
162 }
163 if constexpr (std::is_same_v<std::string, T>)
164 {
165 return 4;
166 }
167 return 0;
168}
169
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500170template <typename... Args>
171struct compute_parameter_tag_from_args_list;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700172
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500173template <>
174struct compute_parameter_tag_from_args_list<>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700175{
Ed Tanous69509012019-10-24 16:53:05 -0700176 static constexpr int value = 0;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700177};
178
179template <typename Arg, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700180struct compute_parameter_tag_from_args_list<Arg, Args...>
181{
Ed Tanous69509012019-10-24 16:53:05 -0700182 static constexpr int subValue =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700183 compute_parameter_tag_from_args_list<Args...>::value;
Ed Tanous69509012019-10-24 16:53:05 -0700184 static constexpr int value =
185 getParameterTag<typename std::decay<Arg>::type>()
186 ? subValue * 6 + getParameterTag<typename std::decay<Arg>::type>()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700187 : subValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700188};
189
Ed Tanous1abe55e2018-09-05 08:30:59 -0700190static inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
191{
192 if (a == 0)
193 {
194 return b == 0;
195 }
196 if (b == 0)
197 {
198 return a == 0;
199 }
Ed Tanous271584a2019-07-09 16:24:22 -0700200 uint64_t sa = a % 6;
201 uint64_t sb = a % 6;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700202 if (sa == 5)
203 {
204 sa = 4;
205 }
206 if (sb == 5)
207 {
208 sb = 4;
209 }
210 if (sa != sb)
211 {
212 return false;
213 }
214 return isParameterTagCompatible(a / 6, b / 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700215}
216
Ed Tanous1abe55e2018-09-05 08:30:59 -0700217static inline unsigned findClosingTagRuntime(const char* s, unsigned p)
218{
219 return s[p] == 0 ? throw std::runtime_error("unmatched tag <")
220 : s[p] == '>' ? p : findClosingTagRuntime(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700221}
222
Ed Tanous1abe55e2018-09-05 08:30:59 -0700223static inline uint64_t getParameterTagRuntime(const char* s, unsigned p = 0)
224{
225 return s[p] == 0
226 ? 0
227 : s[p] == '<'
228 ? (std::strncmp(s + p, "<int>", 5) == 0
229 ? getParameterTagRuntime(
230 s, findClosingTagRuntime(s, p)) *
231 6 +
232 1
233 : std::strncmp(s + p, "<uint>", 6) == 0
234 ? getParameterTagRuntime(
235 s, findClosingTagRuntime(s, p)) *
236 6 +
237 2
238 : (std::strncmp(s + p, "<float>", 7) == 0 ||
239 std::strncmp(s + p, "<double>", 8) == 0)
240 ? getParameterTagRuntime(
241 s, findClosingTagRuntime(s, p)) *
242 6 +
243 3
244 : (std::strncmp(s + p, "<str>", 5) ==
245 0 ||
246 std::strncmp(s + p, "<string>", 8) ==
247 0)
248 ? getParameterTagRuntime(
249 s, findClosingTagRuntime(
250 s, p)) *
251 6 +
252 4
253 : std::strncmp(s + p, "<path>",
254 6) == 0
255 ? getParameterTagRuntime(
256 s,
257 findClosingTagRuntime(
258 s, p)) *
259 6 +
260 5
261 : throw std::runtime_error(
262 "invalid parameter "
263 "type"))
264 : getParameterTagRuntime(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700265}
Ed Tanous3dac7492017-08-02 13:46:20 -0700266
Ed Tanous1abe55e2018-09-05 08:30:59 -0700267constexpr uint64_t get_parameter_tag(ConstStr s, unsigned p = 0)
268{
269 return p == s.size()
270 ? 0
271 : s[p] == '<'
272 ? (isInt(s, p)
273 ? get_parameter_tag(s, findClosingTag(s, p)) * 6 + 1
274 : isUint(s, p)
275 ? get_parameter_tag(s, findClosingTag(s, p)) *
276 6 +
277 2
278 : isFloat(s, p)
279 ? get_parameter_tag(
280 s, findClosingTag(s, p)) *
281 6 +
282 3
283 : isStr(s, p)
284 ? get_parameter_tag(
285 s, findClosingTag(s, p)) *
286 6 +
287 4
288 : isPath(s, p)
289 ? get_parameter_tag(
290 s, findClosingTag(
291 s, p)) *
292 6 +
293 5
294 : throw std::runtime_error(
295 "invalid parameter "
296 "type"))
297 : get_parameter_tag(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700298}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700299
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500300template <typename... T>
301struct S
Ed Tanous1abe55e2018-09-05 08:30:59 -0700302{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500303 template <typename U>
304 using push = S<U, T...>;
305 template <typename U>
306 using push_back = S<T..., U>;
307 template <template <typename... Args> class U>
308 using rebind = U<T...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700309};
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500310template <typename F, typename Set>
311struct CallHelper;
312template <typename F, typename... Args>
313struct CallHelper<F, S<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700314{
315 template <typename F1, typename... Args1,
316 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
317 static char __test(int);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700318
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500319 template <typename...>
320 static int __test(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700321
Ed Tanous1abe55e2018-09-05 08:30:59 -0700322 static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700323};
324
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500325template <uint64_t N>
326struct SingleTagToType
327{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700328
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500329template <>
330struct SingleTagToType<1>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700331{
332 using type = int64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700333};
334
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500335template <>
336struct SingleTagToType<2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700337{
338 using type = uint64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700339};
340
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500341template <>
342struct SingleTagToType<3>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700343{
344 using type = double;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700345};
346
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500347template <>
348struct SingleTagToType<4>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700349{
350 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700351};
352
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500353template <>
354struct SingleTagToType<5>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700355{
356 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700357};
358
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500359template <uint64_t Tag>
360struct Arguments
Ed Tanous1abe55e2018-09-05 08:30:59 -0700361{
362 using subarguments = typename Arguments<Tag / 6>::type;
363 using type = typename subarguments::template push<
364 typename SingleTagToType<Tag % 6>::type>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700365};
366
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500367template <>
368struct Arguments<0>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700369{
370 using type = S<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700371};
372
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500373template <typename... T>
374struct LastElementType
Ed Tanous1abe55e2018-09-05 08:30:59 -0700375{
376 using type =
377 typename std::tuple_element<sizeof...(T) - 1, std::tuple<T...>>::type;
378};
379
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500380template <>
381struct LastElementType<>
382{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700383
384// from
385// http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500386template <class T>
387using Invoke = typename T::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700388
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500389template <unsigned...>
390struct Seq
Ed Tanous1abe55e2018-09-05 08:30:59 -0700391{
392 using type = Seq;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700393};
394
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500395template <class S1, class S2>
396struct concat;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700397
398template <unsigned... I1, unsigned... I2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700399struct concat<Seq<I1...>, Seq<I2...>> : Seq<I1..., (sizeof...(I1) + I2)...>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500400{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700401
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500402template <class S1, class S2>
403using Concat = Invoke<concat<S1, S2>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700404
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500405template <size_t N>
406struct gen_seq;
407template <size_t N>
408using GenSeq = Invoke<gen_seq<N>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700409
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500410template <size_t N>
411struct gen_seq : Concat<GenSeq<N / 2>, GenSeq<N - N / 2>>
412{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700413
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500414template <>
415struct gen_seq<0> : Seq<>
416{};
417template <>
418struct gen_seq<1> : Seq<0>
419{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700420
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500421template <typename Seq, typename Tuple>
422struct PopBackHelper;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700423
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500424template <unsigned... N, typename Tuple>
425struct PopBackHelper<Seq<N...>, Tuple>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700426{
427 template <template <typename... Args> class U>
428 using rebind = U<typename std::tuple_element<N, Tuple>::type...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700429};
430
431template <typename... T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700432struct PopBack //: public PopBackHelper<typename
433 // gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>
Ed Tanous7045c8d2017-04-03 10:04:37 -0700434{
Ed Tanous1abe55e2018-09-05 08:30:59 -0700435 template <template <typename... Args> class U>
436 using rebind =
Ed Tanous271584a2019-07-09 16:24:22 -0700437 typename PopBackHelper<typename gen_seq<sizeof...(T) - 1UL>::type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700438 std::tuple<T...>>::template rebind<U>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700439};
440
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500441template <>
442struct PopBack<>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700443{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500444 template <template <typename... Args> class U>
445 using rebind = U<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700446};
447
448// from
449// http://stackoverflow.com/questions/2118541/check-if-c0x-parameter-pack-contains-a-type
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500450template <typename Tp, typename... List>
451struct Contains : std::true_type
452{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700453
454template <typename Tp, typename Head, typename... Rest>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500455struct Contains<Tp, Head, Rest...> :
456 std::conditional<std::is_same<Tp, Head>::value, std::true_type,
457 Contains<Tp, Rest...>>::type
458{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700459
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500460template <typename Tp>
461struct Contains<Tp> : std::false_type
462{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700463
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500464template <typename T>
465struct EmptyContext
466{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700467
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500468template <typename T>
469struct promote
Ed Tanous1abe55e2018-09-05 08:30:59 -0700470{
471 using type = T;
472};
473
474#define BMCWEB_INTERNAL_PROMOTE_TYPE(t1, t2) \
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500475 template <> \
476 struct promote<t1> \
Ed Tanous1abe55e2018-09-05 08:30:59 -0700477 { \
478 using type = t2; \
479 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700480
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700481BMCWEB_INTERNAL_PROMOTE_TYPE(char, int64_t);
482BMCWEB_INTERNAL_PROMOTE_TYPE(short, int64_t);
483BMCWEB_INTERNAL_PROMOTE_TYPE(int, int64_t);
484BMCWEB_INTERNAL_PROMOTE_TYPE(long, int64_t);
485BMCWEB_INTERNAL_PROMOTE_TYPE(long long, int64_t);
486BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned char, uint64_t);
487BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned short, uint64_t);
488BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned int, uint64_t);
489BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long, uint64_t);
490BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long long, uint64_t);
491BMCWEB_INTERNAL_PROMOTE_TYPE(float, double);
492#undef BMCWEB_INTERNAL_PROMOTE_TYPE
Ed Tanous7045c8d2017-04-03 10:04:37 -0700493
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500494template <typename T>
495using promote_t = typename promote<T>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700496
Ed Tanous1abe55e2018-09-05 08:30:59 -0700497} // namespace black_magic
Ed Tanous7045c8d2017-04-03 10:04:37 -0700498
Ed Tanous1abe55e2018-09-05 08:30:59 -0700499namespace detail
500{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700501
502template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503struct GetIndexOfElementFromTupleByTypeImpl
504{
Ed Tanous271584a2019-07-09 16:24:22 -0700505 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700506};
507
508template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700509struct GetIndexOfElementFromTupleByTypeImpl<T, N, T, Args...>
510{
Ed Tanous271584a2019-07-09 16:24:22 -0700511 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700512};
513
514template <class T, std::size_t N, class U, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700515struct GetIndexOfElementFromTupleByTypeImpl<T, N, U, Args...>
516{
Ed Tanous271584a2019-07-09 16:24:22 -0700517 static constexpr std::size_t value =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700518 GetIndexOfElementFromTupleByTypeImpl<T, N + 1, Args...>::value;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700519};
520
Ed Tanous1abe55e2018-09-05 08:30:59 -0700521} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700522
Ed Tanous1abe55e2018-09-05 08:30:59 -0700523namespace utility
524{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500525template <class T, class... Args>
526T& getElementByType(std::tuple<Args...>& t)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700527{
528 return std::get<
529 detail::GetIndexOfElementFromTupleByTypeImpl<T, 0, Args...>::value>(t);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700530}
531
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500532template <typename T>
533struct function_traits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700534
Ed Tanous7045c8d2017-04-03 10:04:37 -0700535template <typename T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536struct function_traits : public function_traits<decltype(&T::operator())>
537{
538 using parent_t = function_traits<decltype(&T::operator())>;
539 static const size_t arity = parent_t::arity;
540 using result_type = typename parent_t::result_type;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500541 template <size_t i>
542 using arg = typename parent_t::template arg<i>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700543};
Ed Tanous3dac7492017-08-02 13:46:20 -0700544
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700545template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700546struct function_traits<r (ClassType::*)(Args...) const>
547{
548 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700549
Ed Tanous1abe55e2018-09-05 08:30:59 -0700550 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700551
Ed Tanous1abe55e2018-09-05 08:30:59 -0700552 template <size_t i>
553 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700554};
555
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700556template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700557struct function_traits<r (ClassType::*)(Args...)>
558{
559 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700560
Ed Tanous1abe55e2018-09-05 08:30:59 -0700561 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700562
Ed Tanous1abe55e2018-09-05 08:30:59 -0700563 template <size_t i>
564 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700565};
566
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700567template <typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700568struct function_traits<std::function<r(Args...)>>
569{
570 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700571
Ed Tanous1abe55e2018-09-05 08:30:59 -0700572 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700573
Ed Tanous1abe55e2018-09-05 08:30:59 -0700574 template <size_t i>
575 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700576};
577
578inline static std::string base64encode(
Ed Tanousb01bf292019-03-25 19:25:26 +0000579 const char* data, size_t size,
Ed Tanous7045c8d2017-04-03 10:04:37 -0700580 const char* key =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700581 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
582{
583 std::string ret;
584 ret.resize((size + 2) / 3 * 4);
585 auto it = ret.begin();
586 while (size >= 3)
587 {
Ed Tanous271584a2019-07-09 16:24:22 -0700588 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
589 unsigned char h = static_cast<unsigned char>(
590 (static_cast<unsigned char>(*data++) & 0x03u) << 4u);
591 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
592 h = static_cast<unsigned char>(
593 (static_cast<unsigned char>(*data++) & 0x0F) << 2u);
594 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xC0) >> 6)];
595 *it++ = key[static_cast<unsigned char>(*data++) & 0x3F];
Ed Tanous7045c8d2017-04-03 10:04:37 -0700596
Ed Tanous1abe55e2018-09-05 08:30:59 -0700597 size -= 3;
598 }
599 if (size == 1)
600 {
Ed Tanous271584a2019-07-09 16:24:22 -0700601 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
602 unsigned char h = static_cast<unsigned char>(
603 (static_cast<unsigned char>(*data++) & 0x03) << 4u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700604 *it++ = key[h];
605 *it++ = '=';
606 *it++ = '=';
607 }
608 else if (size == 2)
609 {
Ed Tanous271584a2019-07-09 16:24:22 -0700610 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
611 unsigned char h = static_cast<unsigned char>(
612 (static_cast<unsigned char>(*data++) & 0x03) << 4u);
613 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
614 h = static_cast<unsigned char>(
615 (static_cast<unsigned char>(*data++) & 0x0F) << 2u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700616 *it++ = key[h];
617 *it++ = '=';
618 }
619 return ret;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700620}
621
Ed Tanousb01bf292019-03-25 19:25:26 +0000622inline static std::string base64encodeUrlsafe(const char* data, size_t size)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700623{
624 return base64encode(
625 data, size,
626 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700627}
628
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100629// TODO this is temporary and should be deleted once base64 is refactored out of
630// crow
Ed Tanous39e77502019-03-04 17:35:53 -0800631inline bool base64Decode(const std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700632{
Ed Tanous271584a2019-07-09 16:24:22 -0700633 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700634 // See note on encoding_data[] in above function
James Feist5a806642020-07-31 16:40:33 +0000635 static const char decodingData[] = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
637 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, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
640 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
641 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
642 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
643 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
644 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
645 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 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};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100655
Ed Tanous1abe55e2018-09-05 08:30:59 -0700656 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100657
Ed Tanous1abe55e2018-09-05 08:30:59 -0700658 // allocate space for output string
659 output.clear();
660 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100661
Ed Tanous1abe55e2018-09-05 08:30:59 -0700662 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500663 // dropping first two bits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700664 // and regenerate into 3 8-bits sequences
James Feist5a806642020-07-31 16:40:33 +0000665
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 for (size_t i = 0; i < inputLength; i++)
667 {
668 char base64code0;
669 char base64code1;
670 char base64code2 = 0; // initialized to 0 to suppress warnings
671 char base64code3;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100672
James Feist5a806642020-07-31 16:40:33 +0000673 base64code0 = decodingData[static_cast<int>(input[i])]; // NOLINT
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 if (base64code0 == nop)
675 { // non base64 character
676 return false;
677 }
678 if (!(++i < inputLength))
679 { // we need at least two input bytes for first
680 // byte output
681 return false;
682 }
James Feist5a806642020-07-31 16:40:33 +0000683 base64code1 = decodingData[static_cast<int>(input[i])]; // NOLINT
Ed Tanous1abe55e2018-09-05 08:30:59 -0700684 if (base64code1 == nop)
685 { // non base64 character
686 return false;
687 }
688 output +=
689 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100690
Ed Tanous1abe55e2018-09-05 08:30:59 -0700691 if (++i < inputLength)
692 {
693 char c = input[i];
694 if (c == '=')
695 { // padding , end of input
696 return (base64code1 & 0x0f) == 0;
697 }
James Feist5a806642020-07-31 16:40:33 +0000698 base64code2 = decodingData[static_cast<int>(input[i])]; // NOLINT
Ed Tanous1abe55e2018-09-05 08:30:59 -0700699 if (base64code2 == nop)
700 { // non base64 character
701 return false;
702 }
703 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
704 ((base64code2 >> 2) & 0x0f));
705 }
706
707 if (++i < inputLength)
708 {
709 char c = input[i];
710 if (c == '=')
711 { // padding , end of input
712 return (base64code2 & 0x03) == 0;
713 }
James Feist5a806642020-07-31 16:40:33 +0000714 base64code3 = decodingData[static_cast<int>(input[i])]; // NOLINT
Ed Tanous1abe55e2018-09-05 08:30:59 -0700715 if (base64code3 == nop)
716 { // non base64 character
717 return false;
718 }
719 output +=
720 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
721 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100722 }
723
Ed Tanous1abe55e2018-09-05 08:30:59 -0700724 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100725}
726
Ed Tanousa29c9972018-11-29 15:54:32 -0800727inline void escapeHtml(std::string& data)
728{
729 std::string buffer;
Ed Tanousb01bf292019-03-25 19:25:26 +0000730 // less than 5% of characters should be larger, so reserve a buffer of the
Ed Tanousa29c9972018-11-29 15:54:32 -0800731 // right size
Ed Tanous271584a2019-07-09 16:24:22 -0700732 buffer.reserve(data.size() * 11 / 10);
Ed Tanousa29c9972018-11-29 15:54:32 -0800733 for (size_t pos = 0; pos != data.size(); ++pos)
734 {
735 switch (data[pos])
736 {
737 case '&':
738 buffer.append("&amp;");
739 break;
740 case '\"':
741 buffer.append("&quot;");
742 break;
743 case '\'':
744 buffer.append("&apos;");
745 break;
746 case '<':
747 buffer.append("&lt;");
748 break;
749 case '>':
750 buffer.append("&gt;");
751 break;
752 default:
753 buffer.append(&data[pos], 1);
754 break;
755 }
756 }
757 data.swap(buffer);
758}
759
760inline void convertToLinks(std::string& s)
761{
Jason M. Billsa6e2f1c2019-12-11 14:32:14 -0800762 // Convert anything with a redfish path into a link
763 const static std::regex redfishPath{
764 "(&quot;((.*))&quot;[ \\n]*:[ "
765 "\\n]*)(&quot;((?!&quot;)/redfish/.*)&quot;)"};
766 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