blob: d08d548f5ba2ea5e52565891484820e1dd569443 [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 Tanous7045c8d2017-04-03 10:04:37 -07005#include <cstdint>
6#include <cstring>
7#include <functional>
Ed Tanousa29c9972018-11-29 15:54:32 -08008#include <regex>
Ed Tanous7045c8d2017-04-03 10:04:37 -07009#include <stdexcept>
10#include <string>
11#include <tuple>
Ed Tanous7045c8d2017-04-03 10:04:37 -070012
Ed Tanous1abe55e2018-09-05 08:30:59 -070013namespace crow
14{
15namespace black_magic
16{
17struct OutOfRange
18{
19 OutOfRange(unsigned /*pos*/, unsigned /*length*/)
20 {
21 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070022};
Ed Tanous1abe55e2018-09-05 08:30:59 -070023constexpr unsigned requiresInRange(unsigned i, unsigned len)
24{
25 return i >= len ? throw OutOfRange(i, len) : i;
Ed Tanous7045c8d2017-04-03 10:04:37 -070026}
27
Ed Tanous1abe55e2018-09-05 08:30:59 -070028class ConstStr
29{
30 const char* const beginPtr;
31 unsigned sizeUint;
Ed Tanous7045c8d2017-04-03 10:04:37 -070032
Ed Tanous1abe55e2018-09-05 08:30:59 -070033 public:
34 template <unsigned N>
35 constexpr ConstStr(const char (&arr)[N]) : beginPtr(arr), sizeUint(N - 1)
36 {
37 static_assert(N >= 1, "not a string literal");
38 }
39 constexpr char operator[](unsigned i) const
40 {
41 return requiresInRange(i, sizeUint), beginPtr[i];
42 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070043
Ed Tanous1abe55e2018-09-05 08:30:59 -070044 constexpr operator const char*() const
45 {
46 return beginPtr;
47 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070048
Ed Tanous1abe55e2018-09-05 08:30:59 -070049 constexpr const char* begin() const
50 {
51 return beginPtr;
52 }
53 constexpr const char* end() const
54 {
55 return beginPtr + sizeUint;
56 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070057
Ed Tanous1abe55e2018-09-05 08:30:59 -070058 constexpr unsigned size() const
59 {
60 return sizeUint;
61 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070062};
63
Ed Tanous1abe55e2018-09-05 08:30:59 -070064constexpr unsigned findClosingTag(ConstStr s, unsigned p)
65{
66 return s[p] == '>' ? p : findClosingTag(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070067}
68
Ed Tanous1abe55e2018-09-05 08:30:59 -070069constexpr bool isValid(ConstStr s, unsigned i = 0, int f = 0)
70{
71 return i == s.size()
72 ? f == 0
73 : f < 0 || f >= 2
74 ? false
75 : s[i] == '<' ? isValid(s, i + 1, f + 1)
76 : s[i] == '>' ? isValid(s, i + 1, f - 1)
77 : isValid(s, i + 1, f);
Ed Tanous7045c8d2017-04-03 10:04:37 -070078}
79
Ed Tanous1abe55e2018-09-05 08:30:59 -070080constexpr bool isEquP(const char* a, const char* b, unsigned n)
81{
82 return *a == 0 && *b == 0 && n == 0
83 ? true
84 : (*a == 0 || *b == 0)
85 ? false
86 : n == 0 ? true
87 : *a != *b ? false : isEquP(a + 1, b + 1, n - 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070088}
89
Ed Tanous55c7b7a2018-05-22 15:27:24 -070090constexpr bool isEquN(ConstStr a, unsigned ai, ConstStr b, unsigned bi,
Ed Tanous1abe55e2018-09-05 08:30:59 -070091 unsigned n)
92{
93 return ai + n > a.size() || bi + n > b.size()
94 ? false
95 : n == 0 ? true
96 : a[ai] != b[bi] ? false
97 : isEquN(a, ai + 1, b, bi + 1, n - 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070098}
99
Ed Tanous1abe55e2018-09-05 08:30:59 -0700100constexpr bool isInt(ConstStr s, unsigned i)
101{
102 return isEquN(s, i, "<int>", 0, 5);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700103}
104
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105constexpr bool isUint(ConstStr s, unsigned i)
106{
107 return isEquN(s, i, "<uint>", 0, 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700108}
109
Ed Tanous1abe55e2018-09-05 08:30:59 -0700110constexpr bool isFloat(ConstStr s, unsigned i)
111{
112 return isEquN(s, i, "<float>", 0, 7) || isEquN(s, i, "<double>", 0, 8);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700113}
114
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115constexpr bool isStr(ConstStr s, unsigned i)
116{
117 return isEquN(s, i, "<str>", 0, 5) || isEquN(s, i, "<string>", 0, 8);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700118}
119
Ed Tanous1abe55e2018-09-05 08:30:59 -0700120constexpr bool isPath(ConstStr s, unsigned i)
121{
122 return isEquN(s, i, "<path>", 0, 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700123}
Ed Tanous3dac7492017-08-02 13:46:20 -0700124
Ed Tanous1abe55e2018-09-05 08:30:59 -0700125template <typename T> struct parameter_tag
126{
127 static const int value = 0;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700128};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700129#define BMCWEB_INTERNAL_PARAMETER_TAG(t, i) \
130 template <> struct parameter_tag<t> \
131 { \
132 static const int value = i; \
133 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700134BMCWEB_INTERNAL_PARAMETER_TAG(int, 1);
135BMCWEB_INTERNAL_PARAMETER_TAG(char, 1);
136BMCWEB_INTERNAL_PARAMETER_TAG(short, 1);
137BMCWEB_INTERNAL_PARAMETER_TAG(long, 1);
138BMCWEB_INTERNAL_PARAMETER_TAG(long long, 1);
139BMCWEB_INTERNAL_PARAMETER_TAG(unsigned int, 2);
140BMCWEB_INTERNAL_PARAMETER_TAG(unsigned char, 2);
141BMCWEB_INTERNAL_PARAMETER_TAG(unsigned short, 2);
142BMCWEB_INTERNAL_PARAMETER_TAG(unsigned long, 2);
143BMCWEB_INTERNAL_PARAMETER_TAG(unsigned long long, 2);
144BMCWEB_INTERNAL_PARAMETER_TAG(double, 3);
145BMCWEB_INTERNAL_PARAMETER_TAG(std::string, 4);
146#undef BMCWEB_INTERNAL_PARAMETER_TAG
Ed Tanous1abe55e2018-09-05 08:30:59 -0700147template <typename... Args> struct compute_parameter_tag_from_args_list;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700148
Ed Tanous1abe55e2018-09-05 08:30:59 -0700149template <> struct compute_parameter_tag_from_args_list<>
150{
151 static const int value = 0;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700152};
153
154template <typename Arg, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700155struct compute_parameter_tag_from_args_list<Arg, Args...>
156{
157 static const int subValue =
158 compute_parameter_tag_from_args_list<Args...>::value;
159 static const int value =
160 parameter_tag<typename std::decay<Arg>::type>::value
161 ? subValue * 6 +
162 parameter_tag<typename std::decay<Arg>::type>::value
163 : subValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700164};
165
Ed Tanous1abe55e2018-09-05 08:30:59 -0700166static inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
167{
168 if (a == 0)
169 {
170 return b == 0;
171 }
172 if (b == 0)
173 {
174 return a == 0;
175 }
Ed Tanous271584a2019-07-09 16:24:22 -0700176 uint64_t sa = a % 6;
177 uint64_t sb = a % 6;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700178 if (sa == 5)
179 {
180 sa = 4;
181 }
182 if (sb == 5)
183 {
184 sb = 4;
185 }
186 if (sa != sb)
187 {
188 return false;
189 }
190 return isParameterTagCompatible(a / 6, b / 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700191}
192
Ed Tanous1abe55e2018-09-05 08:30:59 -0700193static inline unsigned findClosingTagRuntime(const char* s, unsigned p)
194{
195 return s[p] == 0 ? throw std::runtime_error("unmatched tag <")
196 : s[p] == '>' ? p : findClosingTagRuntime(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700197}
198
Ed Tanous1abe55e2018-09-05 08:30:59 -0700199static inline uint64_t getParameterTagRuntime(const char* s, unsigned p = 0)
200{
201 return s[p] == 0
202 ? 0
203 : s[p] == '<'
204 ? (std::strncmp(s + p, "<int>", 5) == 0
205 ? getParameterTagRuntime(
206 s, findClosingTagRuntime(s, p)) *
207 6 +
208 1
209 : std::strncmp(s + p, "<uint>", 6) == 0
210 ? getParameterTagRuntime(
211 s, findClosingTagRuntime(s, p)) *
212 6 +
213 2
214 : (std::strncmp(s + p, "<float>", 7) == 0 ||
215 std::strncmp(s + p, "<double>", 8) == 0)
216 ? getParameterTagRuntime(
217 s, findClosingTagRuntime(s, p)) *
218 6 +
219 3
220 : (std::strncmp(s + p, "<str>", 5) ==
221 0 ||
222 std::strncmp(s + p, "<string>", 8) ==
223 0)
224 ? getParameterTagRuntime(
225 s, findClosingTagRuntime(
226 s, p)) *
227 6 +
228 4
229 : std::strncmp(s + p, "<path>",
230 6) == 0
231 ? getParameterTagRuntime(
232 s,
233 findClosingTagRuntime(
234 s, p)) *
235 6 +
236 5
237 : throw std::runtime_error(
238 "invalid parameter "
239 "type"))
240 : getParameterTagRuntime(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700241}
Ed Tanous3dac7492017-08-02 13:46:20 -0700242
Ed Tanous1abe55e2018-09-05 08:30:59 -0700243constexpr uint64_t get_parameter_tag(ConstStr s, unsigned p = 0)
244{
245 return p == s.size()
246 ? 0
247 : s[p] == '<'
248 ? (isInt(s, p)
249 ? get_parameter_tag(s, findClosingTag(s, p)) * 6 + 1
250 : isUint(s, p)
251 ? get_parameter_tag(s, findClosingTag(s, p)) *
252 6 +
253 2
254 : isFloat(s, p)
255 ? get_parameter_tag(
256 s, findClosingTag(s, p)) *
257 6 +
258 3
259 : isStr(s, p)
260 ? get_parameter_tag(
261 s, findClosingTag(s, p)) *
262 6 +
263 4
264 : isPath(s, p)
265 ? get_parameter_tag(
266 s, findClosingTag(
267 s, p)) *
268 6 +
269 5
270 : throw std::runtime_error(
271 "invalid parameter "
272 "type"))
273 : get_parameter_tag(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700274}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700275
Ed Tanous1abe55e2018-09-05 08:30:59 -0700276template <typename... T> struct S
277{
278 template <typename U> using push = S<U, T...>;
279 template <typename U> using push_back = S<T..., U>;
280 template <template <typename... Args> class U> using rebind = U<T...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700281};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700282template <typename F, typename Set> struct CallHelper;
283template <typename F, typename... Args> struct CallHelper<F, S<Args...>>
284{
285 template <typename F1, typename... Args1,
286 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
287 static char __test(int);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700288
Ed Tanous1abe55e2018-09-05 08:30:59 -0700289 template <typename...> static int __test(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700290
Ed Tanous1abe55e2018-09-05 08:30:59 -0700291 static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700292};
293
Ed Tanous271584a2019-07-09 16:24:22 -0700294template <uint64_t N> struct SingleTagToType
Ed Tanous1abe55e2018-09-05 08:30:59 -0700295{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700296};
297
Ed Tanous1abe55e2018-09-05 08:30:59 -0700298template <> struct SingleTagToType<1>
299{
300 using type = int64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700301};
302
Ed Tanous1abe55e2018-09-05 08:30:59 -0700303template <> struct SingleTagToType<2>
304{
305 using type = uint64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700306};
307
Ed Tanous1abe55e2018-09-05 08:30:59 -0700308template <> struct SingleTagToType<3>
309{
310 using type = double;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700311};
312
Ed Tanous1abe55e2018-09-05 08:30:59 -0700313template <> struct SingleTagToType<4>
314{
315 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700316};
317
Ed Tanous1abe55e2018-09-05 08:30:59 -0700318template <> struct SingleTagToType<5>
319{
320 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700321};
322
Ed Tanous1abe55e2018-09-05 08:30:59 -0700323template <uint64_t Tag> struct Arguments
324{
325 using subarguments = typename Arguments<Tag / 6>::type;
326 using type = typename subarguments::template push<
327 typename SingleTagToType<Tag % 6>::type>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700328};
329
Ed Tanous1abe55e2018-09-05 08:30:59 -0700330template <> struct Arguments<0>
331{
332 using type = S<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700333};
334
Ed Tanous1abe55e2018-09-05 08:30:59 -0700335template <typename... T> struct LastElementType
336{
337 using type =
338 typename std::tuple_element<sizeof...(T) - 1, std::tuple<T...>>::type;
339};
340
341template <> struct LastElementType<>
342{
343};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700344
345// from
346// http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth
Ed Tanous1abe55e2018-09-05 08:30:59 -0700347template <class T> using Invoke = typename T::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700348
Ed Tanous1abe55e2018-09-05 08:30:59 -0700349template <unsigned...> struct Seq
350{
351 using type = Seq;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700352};
353
Ed Tanous1abe55e2018-09-05 08:30:59 -0700354template <class S1, class S2> struct concat;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700355
356template <unsigned... I1, unsigned... I2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700357struct concat<Seq<I1...>, Seq<I2...>> : Seq<I1..., (sizeof...(I1) + I2)...>
358{
359};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700360
Ed Tanous1abe55e2018-09-05 08:30:59 -0700361template <class S1, class S2> using Concat = Invoke<concat<S1, S2>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700362
Ed Tanous271584a2019-07-09 16:24:22 -0700363template <size_t N> struct gen_seq;
364template <size_t N> using GenSeq = Invoke<gen_seq<N>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700365
Ed Tanous271584a2019-07-09 16:24:22 -0700366template <size_t N> struct gen_seq : Concat<GenSeq<N / 2>, GenSeq<N - N / 2>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700367{
368};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700369
Ed Tanous1abe55e2018-09-05 08:30:59 -0700370template <> struct gen_seq<0> : Seq<>
371{
372};
373template <> struct gen_seq<1> : Seq<0>
374{
375};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700376
Ed Tanous1abe55e2018-09-05 08:30:59 -0700377template <typename Seq, typename Tuple> struct PopBackHelper;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700378
Ed Tanous1abe55e2018-09-05 08:30:59 -0700379template <unsigned... N, typename Tuple> struct PopBackHelper<Seq<N...>, Tuple>
380{
381 template <template <typename... Args> class U>
382 using rebind = U<typename std::tuple_element<N, Tuple>::type...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700383};
384
385template <typename... T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700386struct PopBack //: public PopBackHelper<typename
387 // gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>
Ed Tanous7045c8d2017-04-03 10:04:37 -0700388{
Ed Tanous1abe55e2018-09-05 08:30:59 -0700389 template <template <typename... Args> class U>
390 using rebind =
Ed Tanous271584a2019-07-09 16:24:22 -0700391 typename PopBackHelper<typename gen_seq<sizeof...(T) - 1UL>::type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700392 std::tuple<T...>>::template rebind<U>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700393};
394
Ed Tanous1abe55e2018-09-05 08:30:59 -0700395template <> struct PopBack<>
396{
397 template <template <typename... Args> class U> using rebind = U<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700398};
399
400// from
401// http://stackoverflow.com/questions/2118541/check-if-c0x-parameter-pack-contains-a-type
Ed Tanous1abe55e2018-09-05 08:30:59 -0700402template <typename Tp, typename... List> struct Contains : std::true_type
403{
404};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700405
406template <typename Tp, typename Head, typename... Rest>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700407struct Contains<Tp, Head, Rest...>
Ed Tanous7045c8d2017-04-03 10:04:37 -0700408 : std::conditional<std::is_same<Tp, Head>::value, std::true_type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700409 Contains<Tp, Rest...>>::type
410{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700411};
412
Ed Tanous1abe55e2018-09-05 08:30:59 -0700413template <typename Tp> struct Contains<Tp> : std::false_type
414{
415};
416
417template <typename T> struct EmptyContext
418{
419};
420
421template <typename T> struct promote
422{
423 using type = T;
424};
425
426#define BMCWEB_INTERNAL_PROMOTE_TYPE(t1, t2) \
427 template <> struct promote<t1> \
428 { \
429 using type = t2; \
430 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700431
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700432BMCWEB_INTERNAL_PROMOTE_TYPE(char, int64_t);
433BMCWEB_INTERNAL_PROMOTE_TYPE(short, int64_t);
434BMCWEB_INTERNAL_PROMOTE_TYPE(int, int64_t);
435BMCWEB_INTERNAL_PROMOTE_TYPE(long, int64_t);
436BMCWEB_INTERNAL_PROMOTE_TYPE(long long, int64_t);
437BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned char, uint64_t);
438BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned short, uint64_t);
439BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned int, uint64_t);
440BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long, uint64_t);
441BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long long, uint64_t);
442BMCWEB_INTERNAL_PROMOTE_TYPE(float, double);
443#undef BMCWEB_INTERNAL_PROMOTE_TYPE
Ed Tanous7045c8d2017-04-03 10:04:37 -0700444
Ed Tanous1abe55e2018-09-05 08:30:59 -0700445template <typename T> using promote_t = typename promote<T>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700446
Ed Tanous1abe55e2018-09-05 08:30:59 -0700447} // namespace black_magic
Ed Tanous7045c8d2017-04-03 10:04:37 -0700448
Ed Tanous1abe55e2018-09-05 08:30:59 -0700449namespace detail
450{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700451
452template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700453struct GetIndexOfElementFromTupleByTypeImpl
454{
Ed Tanous271584a2019-07-09 16:24:22 -0700455 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700456};
457
458template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700459struct GetIndexOfElementFromTupleByTypeImpl<T, N, T, Args...>
460{
Ed Tanous271584a2019-07-09 16:24:22 -0700461 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700462};
463
464template <class T, std::size_t N, class U, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700465struct GetIndexOfElementFromTupleByTypeImpl<T, N, U, Args...>
466{
Ed Tanous271584a2019-07-09 16:24:22 -0700467 static constexpr std::size_t value =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700468 GetIndexOfElementFromTupleByTypeImpl<T, N + 1, Args...>::value;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700469};
470
Ed Tanous1abe55e2018-09-05 08:30:59 -0700471} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700472
Ed Tanous1abe55e2018-09-05 08:30:59 -0700473namespace utility
474{
475template <class T, class... Args> T& getElementByType(std::tuple<Args...>& t)
476{
477 return std::get<
478 detail::GetIndexOfElementFromTupleByTypeImpl<T, 0, Args...>::value>(t);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700479}
480
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481template <typename T> struct function_traits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700482
Ed Tanous7045c8d2017-04-03 10:04:37 -0700483template <typename T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700484struct function_traits : public function_traits<decltype(&T::operator())>
485{
486 using parent_t = function_traits<decltype(&T::operator())>;
487 static const size_t arity = parent_t::arity;
488 using result_type = typename parent_t::result_type;
489 template <size_t i> using arg = typename parent_t::template arg<i>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700490};
Ed Tanous3dac7492017-08-02 13:46:20 -0700491
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700492template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700493struct function_traits<r (ClassType::*)(Args...) const>
494{
495 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700496
Ed Tanous1abe55e2018-09-05 08:30:59 -0700497 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700498
Ed Tanous1abe55e2018-09-05 08:30:59 -0700499 template <size_t i>
500 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700501};
502
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700503template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700504struct function_traits<r (ClassType::*)(Args...)>
505{
506 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700507
Ed Tanous1abe55e2018-09-05 08:30:59 -0700508 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700509
Ed Tanous1abe55e2018-09-05 08:30:59 -0700510 template <size_t i>
511 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700512};
513
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700514template <typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700515struct function_traits<std::function<r(Args...)>>
516{
517 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700518
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700520
Ed Tanous1abe55e2018-09-05 08:30:59 -0700521 template <size_t i>
522 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700523};
524
525inline static std::string base64encode(
Ed Tanousb01bf292019-03-25 19:25:26 +0000526 const char* data, size_t size,
Ed Tanous7045c8d2017-04-03 10:04:37 -0700527 const char* key =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700528 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
529{
530 std::string ret;
531 ret.resize((size + 2) / 3 * 4);
532 auto it = ret.begin();
533 while (size >= 3)
534 {
Ed Tanous271584a2019-07-09 16:24:22 -0700535 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
536 unsigned char h = static_cast<unsigned char>(
537 (static_cast<unsigned char>(*data++) & 0x03u) << 4u);
538 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
539 h = static_cast<unsigned char>(
540 (static_cast<unsigned char>(*data++) & 0x0F) << 2u);
541 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xC0) >> 6)];
542 *it++ = key[static_cast<unsigned char>(*data++) & 0x3F];
Ed Tanous7045c8d2017-04-03 10:04:37 -0700543
Ed Tanous1abe55e2018-09-05 08:30:59 -0700544 size -= 3;
545 }
546 if (size == 1)
547 {
Ed Tanous271584a2019-07-09 16:24:22 -0700548 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
549 unsigned char h = static_cast<unsigned char>(
550 (static_cast<unsigned char>(*data++) & 0x03) << 4u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700551 *it++ = key[h];
552 *it++ = '=';
553 *it++ = '=';
554 }
555 else if (size == 2)
556 {
Ed Tanous271584a2019-07-09 16:24:22 -0700557 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
558 unsigned char h = static_cast<unsigned char>(
559 (static_cast<unsigned char>(*data++) & 0x03) << 4u);
560 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
561 h = static_cast<unsigned char>(
562 (static_cast<unsigned char>(*data++) & 0x0F) << 2u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700563 *it++ = key[h];
564 *it++ = '=';
565 }
566 return ret;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700567}
568
Ed Tanousb01bf292019-03-25 19:25:26 +0000569inline static std::string base64encodeUrlsafe(const char* data, size_t size)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700570{
571 return base64encode(
572 data, size,
573 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700574}
575
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100576// TODO this is temporary and should be deleted once base64 is refactored out of
577// crow
Ed Tanous39e77502019-03-04 17:35:53 -0800578inline bool base64Decode(const std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700579{
Ed Tanous271584a2019-07-09 16:24:22 -0700580 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700581 // See note on encoding_data[] in above function
582 static const char decodingData[] = {
583 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
584 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
585 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
586 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
587 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
588 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
589 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
590 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
591 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
592 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
593 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
594 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
595 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
596 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
597 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
598 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
599 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
600 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
601 nop, nop, nop, nop};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100602
Ed Tanous1abe55e2018-09-05 08:30:59 -0700603 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100604
Ed Tanous1abe55e2018-09-05 08:30:59 -0700605 // allocate space for output string
606 output.clear();
607 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100608
Ed Tanous1abe55e2018-09-05 08:30:59 -0700609 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
610 // droping first two bits
611 // and regenerate into 3 8-bits sequences
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100612
Ed Tanous1abe55e2018-09-05 08:30:59 -0700613 for (size_t i = 0; i < inputLength; i++)
614 {
615 char base64code0;
616 char base64code1;
617 char base64code2 = 0; // initialized to 0 to suppress warnings
618 char base64code3;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100619
Ed Tanous1abe55e2018-09-05 08:30:59 -0700620 base64code0 = decodingData[static_cast<int>(input[i])]; // NOLINT
621 if (base64code0 == nop)
622 { // non base64 character
623 return false;
624 }
625 if (!(++i < inputLength))
626 { // we need at least two input bytes for first
627 // byte output
628 return false;
629 }
630 base64code1 = decodingData[static_cast<int>(input[i])]; // NOLINT
631 if (base64code1 == nop)
632 { // non base64 character
633 return false;
634 }
635 output +=
636 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100637
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638 if (++i < inputLength)
639 {
640 char c = input[i];
641 if (c == '=')
642 { // padding , end of input
643 return (base64code1 & 0x0f) == 0;
644 }
645 base64code2 = decodingData[static_cast<int>(input[i])]; // NOLINT
646 if (base64code2 == nop)
647 { // non base64 character
648 return false;
649 }
650 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
651 ((base64code2 >> 2) & 0x0f));
652 }
653
654 if (++i < inputLength)
655 {
656 char c = input[i];
657 if (c == '=')
658 { // padding , end of input
659 return (base64code2 & 0x03) == 0;
660 }
661 base64code3 = decodingData[static_cast<int>(input[i])]; // NOLINT
662 if (base64code3 == nop)
663 { // non base64 character
664 return false;
665 }
666 output +=
667 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
668 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100669 }
670
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100672}
673
Ed Tanousa29c9972018-11-29 15:54:32 -0800674inline void escapeHtml(std::string& data)
675{
676 std::string buffer;
Ed Tanousb01bf292019-03-25 19:25:26 +0000677 // less than 5% of characters should be larger, so reserve a buffer of the
Ed Tanousa29c9972018-11-29 15:54:32 -0800678 // right size
Ed Tanous271584a2019-07-09 16:24:22 -0700679 buffer.reserve(data.size() * 11 / 10);
Ed Tanousa29c9972018-11-29 15:54:32 -0800680 for (size_t pos = 0; pos != data.size(); ++pos)
681 {
682 switch (data[pos])
683 {
684 case '&':
685 buffer.append("&amp;");
686 break;
687 case '\"':
688 buffer.append("&quot;");
689 break;
690 case '\'':
691 buffer.append("&apos;");
692 break;
693 case '<':
694 buffer.append("&lt;");
695 break;
696 case '>':
697 buffer.append("&gt;");
698 break;
699 default:
700 buffer.append(&data[pos], 1);
701 break;
702 }
703 }
704 data.swap(buffer);
705}
706
707inline void convertToLinks(std::string& s)
708{
709 const static std::regex r{"(&quot;@odata\\.((id)|(Context))&quot;[ \\n]*:[ "
710 "\\n]*)(&quot;((?!&quot;).*)&quot;)"};
711 s = std::regex_replace(s, r, "$1<a href=\"$6\">$5</a>");
712
713 const static std::regex nextLink{
714 "(&quot;Members@odata\\.((nextLink))&quot;[ \\n]*:[ "
715 "\\n]*)(&quot;((?!&quot;).*)&quot;)"};
716 s = std::regex_replace(s, nextLink, "$1<a href=\"$5\">$4</a>");
Jason M. Billsc6c91d42019-03-29 13:09:34 -0700717
718 const static std::regex uri{"(&quot;((Uri))&quot;[ \\n]*:[ "
719 "\\n]*)(&quot;((?!&quot;).*)&quot;)"};
720 s = std::regex_replace(s, uri, "$1<a href=\"$5\">$4</a>");
Ed Tanousa29c9972018-11-29 15:54:32 -0800721}
722
Andrew Geisslercb92c032018-08-17 07:56:14 -0700723/**
724 * Method returns Date Time information according to requested format
725 *
726 * @param[in] time time in second since the Epoch
727 *
728 * @return Date Time according to requested format
729 */
730inline std::string getDateTime(const std::time_t& time)
731{
732 std::array<char, 128> dateTime;
733 std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
734
735 if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
736 std::localtime(&time)))
737 {
738 // insert the colon required by the ISO 8601 standard
739 redfishDateTime = std::string(dateTime.data());
740 redfishDateTime.insert(redfishDateTime.end() - 2, ':');
741 }
742
743 return redfishDateTime;
744}
745
746inline std::string dateTimeNow()
747{
748 std::time_t time = std::time(nullptr);
749 return getDateTime(time);
750}
751
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752} // namespace utility
753} // namespace crow