blob: c71187d0c84aa9abdd5f69abb70696c2b8283ea3 [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*/)
22 {
23 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070024};
Ed Tanous1abe55e2018-09-05 08:30:59 -070025constexpr unsigned requiresInRange(unsigned i, unsigned len)
26{
27 return i >= len ? throw OutOfRange(i, len) : i;
Ed Tanous7045c8d2017-04-03 10:04:37 -070028}
29
Ed Tanous1abe55e2018-09-05 08:30:59 -070030class ConstStr
31{
32 const char* const beginPtr;
33 unsigned sizeUint;
Ed Tanous7045c8d2017-04-03 10:04:37 -070034
Ed Tanous1abe55e2018-09-05 08:30:59 -070035 public:
36 template <unsigned N>
37 constexpr ConstStr(const char (&arr)[N]) : beginPtr(arr), sizeUint(N - 1)
38 {
39 static_assert(N >= 1, "not a string literal");
40 }
41 constexpr char operator[](unsigned i) const
42 {
43 return requiresInRange(i, sizeUint), beginPtr[i];
44 }
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 Tanous1abe55e2018-09-05 08:30:59 -070082constexpr bool isEquP(const char* a, const char* b, unsigned n)
83{
84 return *a == 0 && *b == 0 && n == 0
85 ? true
86 : (*a == 0 || *b == 0)
87 ? false
88 : n == 0 ? true
89 : *a != *b ? false : isEquP(a + 1, b + 1, n - 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070090}
91
Ed Tanous55c7b7a2018-05-22 15:27:24 -070092constexpr bool isEquN(ConstStr a, unsigned ai, ConstStr b, unsigned bi,
Ed Tanous1abe55e2018-09-05 08:30:59 -070093 unsigned n)
94{
95 return ai + n > a.size() || bi + n > b.size()
96 ? false
97 : n == 0 ? true
98 : a[ai] != b[bi] ? false
99 : isEquN(a, ai + 1, b, bi + 1, n - 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700100}
101
Ed Tanous1abe55e2018-09-05 08:30:59 -0700102constexpr bool isInt(ConstStr s, unsigned i)
103{
104 return isEquN(s, i, "<int>", 0, 5);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700105}
106
Ed Tanous1abe55e2018-09-05 08:30:59 -0700107constexpr bool isUint(ConstStr s, unsigned i)
108{
109 return isEquN(s, i, "<uint>", 0, 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700110}
111
Ed Tanous1abe55e2018-09-05 08:30:59 -0700112constexpr bool isFloat(ConstStr s, unsigned i)
113{
114 return isEquN(s, i, "<float>", 0, 7) || isEquN(s, i, "<double>", 0, 8);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700115}
116
Ed Tanous1abe55e2018-09-05 08:30:59 -0700117constexpr bool isStr(ConstStr s, unsigned i)
118{
119 return isEquN(s, i, "<str>", 0, 5) || isEquN(s, i, "<string>", 0, 8);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700120}
121
Ed Tanous1abe55e2018-09-05 08:30:59 -0700122constexpr bool isPath(ConstStr s, unsigned i)
123{
124 return isEquN(s, i, "<path>", 0, 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700125}
Ed Tanous3dac7492017-08-02 13:46:20 -0700126
Ed Tanous69509012019-10-24 16:53:05 -0700127template <typename T> constexpr int getParameterTag()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128{
Ed Tanous69509012019-10-24 16:53:05 -0700129 if constexpr (std::is_same_v<int, T>)
130 {
131 return 1;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700132 }
Ed Tanous69509012019-10-24 16:53:05 -0700133 if constexpr (std::is_same_v<char, T>)
134 {
135 return 1;
136 }
137 if constexpr (std::is_same_v<short, T>)
138 {
139 return 1;
140 }
141 if constexpr (std::is_same_v<long, T>)
142 {
143 return 1;
144 }
145 if constexpr (std::is_same_v<long long, T>)
146 {
147 return 1;
148 }
149 if constexpr (std::is_same_v<unsigned int, T>)
150 {
151 return 2;
152 }
153 if constexpr (std::is_same_v<unsigned char, T>)
154 {
155 return 2;
156 }
157 if constexpr (std::is_same_v<unsigned short, T>)
158 {
159 return 2;
160 }
161 if constexpr (std::is_same_v<unsigned long, T>)
162 {
163 return 2;
164 }
165 if constexpr (std::is_same_v<unsigned long long, T>)
166 {
167 return 2;
168 }
169 if constexpr (std::is_same_v<double, T>)
170 {
171 return 3;
172 }
173 if constexpr (std::is_same_v<std::string, T>)
174 {
175 return 4;
176 }
177 return 0;
178}
179
Ed Tanous1abe55e2018-09-05 08:30:59 -0700180template <typename... Args> struct compute_parameter_tag_from_args_list;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700181
Ed Tanous1abe55e2018-09-05 08:30:59 -0700182template <> struct compute_parameter_tag_from_args_list<>
183{
Ed Tanous69509012019-10-24 16:53:05 -0700184 static constexpr int value = 0;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700185};
186
187template <typename Arg, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700188struct compute_parameter_tag_from_args_list<Arg, Args...>
189{
Ed Tanous69509012019-10-24 16:53:05 -0700190 static constexpr int subValue =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700191 compute_parameter_tag_from_args_list<Args...>::value;
Ed Tanous69509012019-10-24 16:53:05 -0700192 static constexpr int value =
193 getParameterTag<typename std::decay<Arg>::type>()
194 ? subValue * 6 + getParameterTag<typename std::decay<Arg>::type>()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700195 : subValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700196};
197
Ed Tanous1abe55e2018-09-05 08:30:59 -0700198static inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
199{
200 if (a == 0)
201 {
202 return b == 0;
203 }
204 if (b == 0)
205 {
206 return a == 0;
207 }
Ed Tanous271584a2019-07-09 16:24:22 -0700208 uint64_t sa = a % 6;
209 uint64_t sb = a % 6;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700210 if (sa == 5)
211 {
212 sa = 4;
213 }
214 if (sb == 5)
215 {
216 sb = 4;
217 }
218 if (sa != sb)
219 {
220 return false;
221 }
222 return isParameterTagCompatible(a / 6, b / 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700223}
224
Ed Tanous1abe55e2018-09-05 08:30:59 -0700225static inline unsigned findClosingTagRuntime(const char* s, unsigned p)
226{
227 return s[p] == 0 ? throw std::runtime_error("unmatched tag <")
228 : s[p] == '>' ? p : findClosingTagRuntime(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700229}
230
Ed Tanous1abe55e2018-09-05 08:30:59 -0700231static inline uint64_t getParameterTagRuntime(const char* s, unsigned p = 0)
232{
233 return s[p] == 0
234 ? 0
235 : s[p] == '<'
236 ? (std::strncmp(s + p, "<int>", 5) == 0
237 ? getParameterTagRuntime(
238 s, findClosingTagRuntime(s, p)) *
239 6 +
240 1
241 : std::strncmp(s + p, "<uint>", 6) == 0
242 ? getParameterTagRuntime(
243 s, findClosingTagRuntime(s, p)) *
244 6 +
245 2
246 : (std::strncmp(s + p, "<float>", 7) == 0 ||
247 std::strncmp(s + p, "<double>", 8) == 0)
248 ? getParameterTagRuntime(
249 s, findClosingTagRuntime(s, p)) *
250 6 +
251 3
252 : (std::strncmp(s + p, "<str>", 5) ==
253 0 ||
254 std::strncmp(s + p, "<string>", 8) ==
255 0)
256 ? getParameterTagRuntime(
257 s, findClosingTagRuntime(
258 s, p)) *
259 6 +
260 4
261 : std::strncmp(s + p, "<path>",
262 6) == 0
263 ? getParameterTagRuntime(
264 s,
265 findClosingTagRuntime(
266 s, p)) *
267 6 +
268 5
269 : throw std::runtime_error(
270 "invalid parameter "
271 "type"))
272 : getParameterTagRuntime(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700273}
Ed Tanous3dac7492017-08-02 13:46:20 -0700274
Ed Tanous1abe55e2018-09-05 08:30:59 -0700275constexpr uint64_t get_parameter_tag(ConstStr s, unsigned p = 0)
276{
277 return p == s.size()
278 ? 0
279 : s[p] == '<'
280 ? (isInt(s, p)
281 ? get_parameter_tag(s, findClosingTag(s, p)) * 6 + 1
282 : isUint(s, p)
283 ? get_parameter_tag(s, findClosingTag(s, p)) *
284 6 +
285 2
286 : isFloat(s, p)
287 ? get_parameter_tag(
288 s, findClosingTag(s, p)) *
289 6 +
290 3
291 : isStr(s, p)
292 ? get_parameter_tag(
293 s, findClosingTag(s, p)) *
294 6 +
295 4
296 : isPath(s, p)
297 ? get_parameter_tag(
298 s, findClosingTag(
299 s, p)) *
300 6 +
301 5
302 : throw std::runtime_error(
303 "invalid parameter "
304 "type"))
305 : get_parameter_tag(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700306}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700307
Ed Tanous1abe55e2018-09-05 08:30:59 -0700308template <typename... T> struct S
309{
310 template <typename U> using push = S<U, T...>;
311 template <typename U> using push_back = S<T..., U>;
312 template <template <typename... Args> class U> using rebind = U<T...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700313};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700314template <typename F, typename Set> struct CallHelper;
315template <typename F, typename... Args> struct CallHelper<F, S<Args...>>
316{
317 template <typename F1, typename... Args1,
318 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
319 static char __test(int);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700320
Ed Tanous1abe55e2018-09-05 08:30:59 -0700321 template <typename...> 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
Ed Tanous271584a2019-07-09 16:24:22 -0700326template <uint64_t N> struct SingleTagToType
Ed Tanous1abe55e2018-09-05 08:30:59 -0700327{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700328};
329
Ed Tanous1abe55e2018-09-05 08:30:59 -0700330template <> struct SingleTagToType<1>
331{
332 using type = int64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700333};
334
Ed Tanous1abe55e2018-09-05 08:30:59 -0700335template <> struct SingleTagToType<2>
336{
337 using type = uint64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700338};
339
Ed Tanous1abe55e2018-09-05 08:30:59 -0700340template <> struct SingleTagToType<3>
341{
342 using type = double;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700343};
344
Ed Tanous1abe55e2018-09-05 08:30:59 -0700345template <> struct SingleTagToType<4>
346{
347 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700348};
349
Ed Tanous1abe55e2018-09-05 08:30:59 -0700350template <> struct SingleTagToType<5>
351{
352 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700353};
354
Ed Tanous1abe55e2018-09-05 08:30:59 -0700355template <uint64_t Tag> struct Arguments
356{
357 using subarguments = typename Arguments<Tag / 6>::type;
358 using type = typename subarguments::template push<
359 typename SingleTagToType<Tag % 6>::type>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700360};
361
Ed Tanous1abe55e2018-09-05 08:30:59 -0700362template <> struct Arguments<0>
363{
364 using type = S<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700365};
366
Ed Tanous1abe55e2018-09-05 08:30:59 -0700367template <typename... T> struct LastElementType
368{
369 using type =
370 typename std::tuple_element<sizeof...(T) - 1, std::tuple<T...>>::type;
371};
372
373template <> struct LastElementType<>
374{
375};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700376
377// from
378// http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth
Ed Tanous1abe55e2018-09-05 08:30:59 -0700379template <class T> using Invoke = typename T::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700380
Ed Tanous1abe55e2018-09-05 08:30:59 -0700381template <unsigned...> struct Seq
382{
383 using type = Seq;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700384};
385
Ed Tanous1abe55e2018-09-05 08:30:59 -0700386template <class S1, class S2> struct concat;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700387
388template <unsigned... I1, unsigned... I2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700389struct concat<Seq<I1...>, Seq<I2...>> : Seq<I1..., (sizeof...(I1) + I2)...>
390{
391};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700392
Ed Tanous1abe55e2018-09-05 08:30:59 -0700393template <class S1, class S2> using Concat = Invoke<concat<S1, S2>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700394
Ed Tanous271584a2019-07-09 16:24:22 -0700395template <size_t N> struct gen_seq;
396template <size_t N> using GenSeq = Invoke<gen_seq<N>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700397
Ed Tanous271584a2019-07-09 16:24:22 -0700398template <size_t N> struct gen_seq : Concat<GenSeq<N / 2>, GenSeq<N - N / 2>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700399{
400};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700401
Ed Tanous1abe55e2018-09-05 08:30:59 -0700402template <> struct gen_seq<0> : Seq<>
403{
404};
405template <> struct gen_seq<1> : Seq<0>
406{
407};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700408
Ed Tanous1abe55e2018-09-05 08:30:59 -0700409template <typename Seq, typename Tuple> struct PopBackHelper;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700410
Ed Tanous1abe55e2018-09-05 08:30:59 -0700411template <unsigned... N, typename Tuple> struct PopBackHelper<Seq<N...>, Tuple>
412{
413 template <template <typename... Args> class U>
414 using rebind = U<typename std::tuple_element<N, Tuple>::type...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700415};
416
417template <typename... T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700418struct PopBack //: public PopBackHelper<typename
419 // gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>
Ed Tanous7045c8d2017-04-03 10:04:37 -0700420{
Ed Tanous1abe55e2018-09-05 08:30:59 -0700421 template <template <typename... Args> class U>
422 using rebind =
Ed Tanous271584a2019-07-09 16:24:22 -0700423 typename PopBackHelper<typename gen_seq<sizeof...(T) - 1UL>::type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700424 std::tuple<T...>>::template rebind<U>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700425};
426
Ed Tanous1abe55e2018-09-05 08:30:59 -0700427template <> struct PopBack<>
428{
429 template <template <typename... Args> class U> using rebind = U<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700430};
431
432// from
433// http://stackoverflow.com/questions/2118541/check-if-c0x-parameter-pack-contains-a-type
Ed Tanous1abe55e2018-09-05 08:30:59 -0700434template <typename Tp, typename... List> struct Contains : std::true_type
435{
436};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700437
438template <typename Tp, typename Head, typename... Rest>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700439struct Contains<Tp, Head, Rest...>
Ed Tanous7045c8d2017-04-03 10:04:37 -0700440 : std::conditional<std::is_same<Tp, Head>::value, std::true_type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700441 Contains<Tp, Rest...>>::type
442{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700443};
444
Ed Tanous1abe55e2018-09-05 08:30:59 -0700445template <typename Tp> struct Contains<Tp> : std::false_type
446{
447};
448
449template <typename T> struct EmptyContext
450{
451};
452
453template <typename T> struct promote
454{
455 using type = T;
456};
457
458#define BMCWEB_INTERNAL_PROMOTE_TYPE(t1, t2) \
459 template <> struct promote<t1> \
460 { \
461 using type = t2; \
462 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700463
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700464BMCWEB_INTERNAL_PROMOTE_TYPE(char, int64_t);
465BMCWEB_INTERNAL_PROMOTE_TYPE(short, int64_t);
466BMCWEB_INTERNAL_PROMOTE_TYPE(int, int64_t);
467BMCWEB_INTERNAL_PROMOTE_TYPE(long, int64_t);
468BMCWEB_INTERNAL_PROMOTE_TYPE(long long, int64_t);
469BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned char, uint64_t);
470BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned short, uint64_t);
471BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned int, uint64_t);
472BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long, uint64_t);
473BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long long, uint64_t);
474BMCWEB_INTERNAL_PROMOTE_TYPE(float, double);
475#undef BMCWEB_INTERNAL_PROMOTE_TYPE
Ed Tanous7045c8d2017-04-03 10:04:37 -0700476
Ed Tanous1abe55e2018-09-05 08:30:59 -0700477template <typename T> using promote_t = typename promote<T>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700478
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479} // namespace black_magic
Ed Tanous7045c8d2017-04-03 10:04:37 -0700480
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481namespace detail
482{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700483
484template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700485struct GetIndexOfElementFromTupleByTypeImpl
486{
Ed Tanous271584a2019-07-09 16:24:22 -0700487 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700488};
489
490template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700491struct GetIndexOfElementFromTupleByTypeImpl<T, N, T, Args...>
492{
Ed Tanous271584a2019-07-09 16:24:22 -0700493 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700494};
495
496template <class T, std::size_t N, class U, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700497struct GetIndexOfElementFromTupleByTypeImpl<T, N, U, Args...>
498{
Ed Tanous271584a2019-07-09 16:24:22 -0700499 static constexpr std::size_t value =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700500 GetIndexOfElementFromTupleByTypeImpl<T, N + 1, Args...>::value;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700501};
502
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700504
Ed Tanous1abe55e2018-09-05 08:30:59 -0700505namespace utility
506{
507template <class T, class... Args> T& getElementByType(std::tuple<Args...>& t)
508{
509 return std::get<
510 detail::GetIndexOfElementFromTupleByTypeImpl<T, 0, Args...>::value>(t);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700511}
512
Ed Tanous1abe55e2018-09-05 08:30:59 -0700513template <typename T> struct function_traits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700514
Ed Tanous7045c8d2017-04-03 10:04:37 -0700515template <typename T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700516struct function_traits : public function_traits<decltype(&T::operator())>
517{
518 using parent_t = function_traits<decltype(&T::operator())>;
519 static const size_t arity = parent_t::arity;
520 using result_type = typename parent_t::result_type;
521 template <size_t i> using arg = typename parent_t::template arg<i>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700522};
Ed Tanous3dac7492017-08-02 13:46:20 -0700523
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700524template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700525struct function_traits<r (ClassType::*)(Args...) const>
526{
527 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700528
Ed Tanous1abe55e2018-09-05 08:30:59 -0700529 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700530
Ed Tanous1abe55e2018-09-05 08:30:59 -0700531 template <size_t i>
532 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700533};
534
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700535template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536struct function_traits<r (ClassType::*)(Args...)>
537{
538 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700539
Ed Tanous1abe55e2018-09-05 08:30:59 -0700540 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700541
Ed Tanous1abe55e2018-09-05 08:30:59 -0700542 template <size_t i>
543 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700544};
545
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700546template <typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700547struct function_traits<std::function<r(Args...)>>
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
557inline static std::string base64encode(
Ed Tanousb01bf292019-03-25 19:25:26 +0000558 const char* data, size_t size,
Ed Tanous7045c8d2017-04-03 10:04:37 -0700559 const char* key =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700560 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
561{
562 std::string ret;
563 ret.resize((size + 2) / 3 * 4);
564 auto it = ret.begin();
565 while (size >= 3)
566 {
Ed Tanous271584a2019-07-09 16:24:22 -0700567 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
568 unsigned char h = static_cast<unsigned char>(
569 (static_cast<unsigned char>(*data++) & 0x03u) << 4u);
570 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
571 h = static_cast<unsigned char>(
572 (static_cast<unsigned char>(*data++) & 0x0F) << 2u);
573 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xC0) >> 6)];
574 *it++ = key[static_cast<unsigned char>(*data++) & 0x3F];
Ed Tanous7045c8d2017-04-03 10:04:37 -0700575
Ed Tanous1abe55e2018-09-05 08:30:59 -0700576 size -= 3;
577 }
578 if (size == 1)
579 {
Ed Tanous271584a2019-07-09 16:24:22 -0700580 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
581 unsigned char h = static_cast<unsigned char>(
582 (static_cast<unsigned char>(*data++) & 0x03) << 4u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700583 *it++ = key[h];
584 *it++ = '=';
585 *it++ = '=';
586 }
587 else if (size == 2)
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++) & 0x03) << 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);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700595 *it++ = key[h];
596 *it++ = '=';
597 }
598 return ret;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700599}
600
Ed Tanousb01bf292019-03-25 19:25:26 +0000601inline static std::string base64encodeUrlsafe(const char* data, size_t size)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700602{
603 return base64encode(
604 data, size,
605 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700606}
607
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100608// TODO this is temporary and should be deleted once base64 is refactored out of
609// crow
Ed Tanous39e77502019-03-04 17:35:53 -0800610inline bool base64Decode(const std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700611{
Ed Tanous271584a2019-07-09 16:24:22 -0700612 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700613 // See note on encoding_data[] in above function
614 static const char decodingData[] = {
615 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
616 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
617 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
618 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
619 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
620 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
621 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
622 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
623 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
624 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
625 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
626 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
627 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
628 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
629 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
630 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
631 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
632 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
633 nop, nop, nop, nop};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100634
Ed Tanous1abe55e2018-09-05 08:30:59 -0700635 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100636
Ed Tanous1abe55e2018-09-05 08:30:59 -0700637 // allocate space for output string
638 output.clear();
639 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100640
Ed Tanous1abe55e2018-09-05 08:30:59 -0700641 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
642 // droping first two bits
643 // and regenerate into 3 8-bits sequences
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100644
Ed Tanous1abe55e2018-09-05 08:30:59 -0700645 for (size_t i = 0; i < inputLength; i++)
646 {
647 char base64code0;
648 char base64code1;
649 char base64code2 = 0; // initialized to 0 to suppress warnings
650 char base64code3;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100651
Ed Tanous1abe55e2018-09-05 08:30:59 -0700652 base64code0 = decodingData[static_cast<int>(input[i])]; // NOLINT
653 if (base64code0 == nop)
654 { // non base64 character
655 return false;
656 }
657 if (!(++i < inputLength))
658 { // we need at least two input bytes for first
659 // byte output
660 return false;
661 }
662 base64code1 = decodingData[static_cast<int>(input[i])]; // NOLINT
663 if (base64code1 == nop)
664 { // non base64 character
665 return false;
666 }
667 output +=
668 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100669
Ed Tanous1abe55e2018-09-05 08:30:59 -0700670 if (++i < inputLength)
671 {
672 char c = input[i];
673 if (c == '=')
674 { // padding , end of input
675 return (base64code1 & 0x0f) == 0;
676 }
677 base64code2 = decodingData[static_cast<int>(input[i])]; // NOLINT
678 if (base64code2 == nop)
679 { // non base64 character
680 return false;
681 }
682 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
683 ((base64code2 >> 2) & 0x0f));
684 }
685
686 if (++i < inputLength)
687 {
688 char c = input[i];
689 if (c == '=')
690 { // padding , end of input
691 return (base64code2 & 0x03) == 0;
692 }
693 base64code3 = decodingData[static_cast<int>(input[i])]; // NOLINT
694 if (base64code3 == nop)
695 { // non base64 character
696 return false;
697 }
698 output +=
699 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
700 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100701 }
702
Ed Tanous1abe55e2018-09-05 08:30:59 -0700703 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100704}
705
Ed Tanousa29c9972018-11-29 15:54:32 -0800706inline void escapeHtml(std::string& data)
707{
708 std::string buffer;
Ed Tanousb01bf292019-03-25 19:25:26 +0000709 // less than 5% of characters should be larger, so reserve a buffer of the
Ed Tanousa29c9972018-11-29 15:54:32 -0800710 // right size
Ed Tanous271584a2019-07-09 16:24:22 -0700711 buffer.reserve(data.size() * 11 / 10);
Ed Tanousa29c9972018-11-29 15:54:32 -0800712 for (size_t pos = 0; pos != data.size(); ++pos)
713 {
714 switch (data[pos])
715 {
716 case '&':
717 buffer.append("&amp;");
718 break;
719 case '\"':
720 buffer.append("&quot;");
721 break;
722 case '\'':
723 buffer.append("&apos;");
724 break;
725 case '<':
726 buffer.append("&lt;");
727 break;
728 case '>':
729 buffer.append("&gt;");
730 break;
731 default:
732 buffer.append(&data[pos], 1);
733 break;
734 }
735 }
736 data.swap(buffer);
737}
738
739inline void convertToLinks(std::string& s)
740{
Jason M. Billsa6e2f1c2019-12-11 14:32:14 -0800741 // Convert anything with a redfish path into a link
742 const static std::regex redfishPath{
743 "(&quot;((.*))&quot;[ \\n]*:[ "
744 "\\n]*)(&quot;((?!&quot;)/redfish/.*)&quot;)"};
745 s = std::regex_replace(s, redfishPath, "$1<a href=\"$5\">$4</a>");
Ed Tanousa29c9972018-11-29 15:54:32 -0800746}
747
Andrew Geisslercb92c032018-08-17 07:56:14 -0700748/**
749 * Method returns Date Time information according to requested format
750 *
751 * @param[in] time time in second since the Epoch
752 *
753 * @return Date Time according to requested format
754 */
755inline std::string getDateTime(const std::time_t& time)
756{
757 std::array<char, 128> dateTime;
758 std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
759
760 if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
761 std::localtime(&time)))
762 {
763 // insert the colon required by the ISO 8601 standard
764 redfishDateTime = std::string(dateTime.data());
765 redfishDateTime.insert(redfishDateTime.end() - 2, ':');
766 }
767
768 return redfishDateTime;
769}
770
771inline std::string dateTimeNow()
772{
773 std::time_t time = std::time(nullptr);
774 return getDateTime(time);
775}
776
Ed Tanous51dae672018-09-05 16:07:32 -0700777inline bool constantTimeStringCompare(const std::string_view a,
778 const std::string_view b)
779{
780 // Important note, this function is ONLY constant time if the two input
781 // sizes are the same
782 if (a.size() != b.size())
783 {
784 return false;
785 }
786 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
787}
788
789struct ConstantTimeCompare
790{
791 bool operator()(const std::string_view a, const std::string_view b) const
792 {
793 return constantTimeStringCompare(a, b);
794 }
795};
796
Ed Tanous1abe55e2018-09-05 08:30:59 -0700797} // namespace utility
798} // namespace crow