blob: 873cfe41ed9f4718bc7a8177adcf8563e290f98d [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
Ed Tanous1abe55e2018-09-05 08:30:59 -07002
Ed Tanous51dae672018-09-05 16:07:32 -07003#include <openssl/crypto.h>
4
Nan Zhou1d8782e2021-11-29 22:23:18 -08005#include <boost/date_time/posix_time/posix_time.hpp>
Ed Tanouseae855c2021-10-26 11:26:02 -07006#include <boost/url/url.hpp>
Nan Zhou1d8782e2021-11-29 22:23:18 -08007
Ed Tanous9ea15c32022-01-04 14:18:22 -08008#include <array>
Ed Tanous74849be2021-02-05 09:47:47 -08009#include <chrono>
Ed Tanous7045c8d2017-04-03 10:04:37 -070010#include <cstdint>
Ed Tanous9ea15c32022-01-04 14:18:22 -080011#include <ctime>
Ed Tanous7045c8d2017-04-03 10:04:37 -070012#include <functional>
Ed Tanous9ea15c32022-01-04 14:18:22 -080013#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070014#include <stdexcept>
15#include <string>
Ed Tanous9ea15c32022-01-04 14:18:22 -080016#include <string_view>
Ed Tanous7045c8d2017-04-03 10:04:37 -070017#include <tuple>
Ed Tanous9ea15c32022-01-04 14:18:22 -080018#include <type_traits>
19#include <utility>
Ed Tanous7045c8d2017-04-03 10:04:37 -070020
Ed Tanous1abe55e2018-09-05 08:30:59 -070021namespace crow
22{
23namespace black_magic
24{
Ed Tanous7045c8d2017-04-03 10:04:37 -070025
Ed Tanous988403c2020-08-24 11:29:49 -070026constexpr unsigned findClosingTag(std::string_view s, unsigned p)
Ed Tanous1abe55e2018-09-05 08:30:59 -070027{
28 return s[p] == '>' ? p : findClosingTag(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070029}
30
Ed Tanous988403c2020-08-24 11:29:49 -070031constexpr bool isInt(std::string_view s, unsigned i)
Ed Tanous1abe55e2018-09-05 08:30:59 -070032{
Ed Tanous988403c2020-08-24 11:29:49 -070033 return s.substr(i, 5) == "<int>";
Ed Tanous7045c8d2017-04-03 10:04:37 -070034}
35
Ed Tanous988403c2020-08-24 11:29:49 -070036constexpr bool isUint(std::string_view s, unsigned i)
Ed Tanous1abe55e2018-09-05 08:30:59 -070037{
Ed Tanous988403c2020-08-24 11:29:49 -070038 return s.substr(i, 6) == "<uint>";
Ed Tanous7045c8d2017-04-03 10:04:37 -070039}
40
Ed Tanous988403c2020-08-24 11:29:49 -070041constexpr bool isFloat(std::string_view s, unsigned i)
Ed Tanous1abe55e2018-09-05 08:30:59 -070042{
Ed Tanous988403c2020-08-24 11:29:49 -070043 return s.substr(i, 7) == "<float>" || s.substr(i, 8) == "<double>";
Ed Tanous7045c8d2017-04-03 10:04:37 -070044}
45
Ed Tanous988403c2020-08-24 11:29:49 -070046constexpr bool isStr(std::string_view s, unsigned i)
Ed Tanous1abe55e2018-09-05 08:30:59 -070047{
Ed Tanous988403c2020-08-24 11:29:49 -070048 return s.substr(i, 5) == "<str>" || s.substr(i, 8) == "<string>";
Ed Tanous7045c8d2017-04-03 10:04:37 -070049}
50
Ed Tanous988403c2020-08-24 11:29:49 -070051constexpr bool isPath(std::string_view s, unsigned i)
Ed Tanous1abe55e2018-09-05 08:30:59 -070052{
Ed Tanous988403c2020-08-24 11:29:49 -070053 return s.substr(i, 6) == "<path>";
Ed Tanous7045c8d2017-04-03 10:04:37 -070054}
Ed Tanous3dac7492017-08-02 13:46:20 -070055
Gunnar Mills1214b7e2020-06-04 10:11:30 -050056template <typename T>
57constexpr int getParameterTag()
Ed Tanous1abe55e2018-09-05 08:30:59 -070058{
Ed Tanous69509012019-10-24 16:53:05 -070059 if constexpr (std::is_same_v<int, T>)
60 {
61 return 1;
Ed Tanous1abe55e2018-09-05 08:30:59 -070062 }
Ed Tanous69509012019-10-24 16:53:05 -070063 if constexpr (std::is_same_v<char, T>)
64 {
65 return 1;
66 }
67 if constexpr (std::is_same_v<short, T>)
68 {
69 return 1;
70 }
71 if constexpr (std::is_same_v<long, T>)
72 {
73 return 1;
74 }
75 if constexpr (std::is_same_v<long long, T>)
76 {
77 return 1;
78 }
79 if constexpr (std::is_same_v<unsigned int, T>)
80 {
81 return 2;
82 }
83 if constexpr (std::is_same_v<unsigned char, T>)
84 {
85 return 2;
86 }
87 if constexpr (std::is_same_v<unsigned short, T>)
88 {
89 return 2;
90 }
91 if constexpr (std::is_same_v<unsigned long, T>)
92 {
93 return 2;
94 }
95 if constexpr (std::is_same_v<unsigned long long, T>)
96 {
97 return 2;
98 }
99 if constexpr (std::is_same_v<double, T>)
100 {
101 return 3;
102 }
103 if constexpr (std::is_same_v<std::string, T>)
104 {
105 return 4;
106 }
107 return 0;
108}
109
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500110template <typename... Args>
Ed Tanous988403c2020-08-24 11:29:49 -0700111struct computeParameterTagFromArgsList;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700112
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500113template <>
Ed Tanous988403c2020-08-24 11:29:49 -0700114struct computeParameterTagFromArgsList<>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115{
Ed Tanous69509012019-10-24 16:53:05 -0700116 static constexpr int value = 0;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700117};
118
119template <typename Arg, typename... Args>
Ed Tanous988403c2020-08-24 11:29:49 -0700120struct computeParameterTagFromArgsList<Arg, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700121{
Ed Tanous69509012019-10-24 16:53:05 -0700122 static constexpr int subValue =
Ed Tanous988403c2020-08-24 11:29:49 -0700123 computeParameterTagFromArgsList<Args...>::value;
Ed Tanous69509012019-10-24 16:53:05 -0700124 static constexpr int value =
125 getParameterTag<typename std::decay<Arg>::type>()
126 ? subValue * 6 + getParameterTag<typename std::decay<Arg>::type>()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700127 : subValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700128};
129
Ed Tanous988403c2020-08-24 11:29:49 -0700130inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700131{
Ed Tanousb00dcc22021-02-23 12:52:50 -0800132
Ed Tanous1abe55e2018-09-05 08:30:59 -0700133 if (a == 0)
134 {
135 return b == 0;
136 }
137 if (b == 0)
138 {
139 return a == 0;
140 }
Ed Tanous271584a2019-07-09 16:24:22 -0700141 uint64_t sa = a % 6;
142 uint64_t sb = a % 6;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700143 if (sa == 5)
144 {
145 sa = 4;
146 }
147 if (sb == 5)
148 {
149 sb = 4;
150 }
151 if (sa != sb)
152 {
153 return false;
154 }
155 return isParameterTagCompatible(a / 6, b / 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700156}
157
Ed Tanous988403c2020-08-24 11:29:49 -0700158constexpr uint64_t getParameterTag(std::string_view s, unsigned p = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700159{
Ed Tanousb00dcc22021-02-23 12:52:50 -0800160
Ed Tanous988403c2020-08-24 11:29:49 -0700161 if (p == s.size())
162 {
163 return 0;
164 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700165
Ed Tanous988403c2020-08-24 11:29:49 -0700166 if (s[p] != '<')
167 {
168 return getParameterTag(s, p + 1);
169 }
Ed Tanous3dac7492017-08-02 13:46:20 -0700170
Ed Tanous988403c2020-08-24 11:29:49 -0700171 if (isInt(s, p))
172 {
173 return getParameterTag(s, findClosingTag(s, p)) * 6 + 1;
174 }
175
176 if (isUint(s, p))
177 {
178 return getParameterTag(s, findClosingTag(s, p)) * 6 + 2;
179 }
180
181 if (isFloat(s, p))
182 {
183 return getParameterTag(s, findClosingTag(s, p)) * 6 + 3;
184 }
185
186 if (isStr(s, p))
187 {
188 return getParameterTag(s, findClosingTag(s, p)) * 6 + 4;
189 }
190
191 if (isPath(s, p))
192 {
193 return getParameterTag(s, findClosingTag(s, p)) * 6 + 5;
194 }
195
196 throw std::runtime_error("invalid parameter type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700197}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700198
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500199template <typename... T>
200struct S
Ed Tanous1abe55e2018-09-05 08:30:59 -0700201{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500202 template <typename U>
203 using push = S<U, T...>;
204 template <typename U>
205 using push_back = S<T..., U>;
206 template <template <typename... Args> class U>
207 using rebind = U<T...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700208};
Ed Tanous988403c2020-08-24 11:29:49 -0700209
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500210template <typename F, typename Set>
211struct CallHelper;
Ed Tanous988403c2020-08-24 11:29:49 -0700212
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500213template <typename F, typename... Args>
214struct CallHelper<F, S<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700215{
216 template <typename F1, typename... Args1,
217 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
Ed Tanous2c70f802020-09-28 14:29:23 -0700218 static char test(int);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700219
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500220 template <typename...>
Ed Tanous2c70f802020-09-28 14:29:23 -0700221 static int test(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700222
Ed Tanous2c70f802020-09-28 14:29:23 -0700223 static constexpr bool value = sizeof(test<F, Args...>(0)) == sizeof(char);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700224};
225
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500226template <uint64_t N>
227struct SingleTagToType
228{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700229
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500230template <>
231struct SingleTagToType<1>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700232{
233 using type = int64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700234};
235
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500236template <>
237struct SingleTagToType<2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700238{
239 using type = uint64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700240};
241
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500242template <>
243struct SingleTagToType<3>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700244{
245 using type = double;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700246};
247
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500248template <>
249struct SingleTagToType<4>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700250{
251 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700252};
253
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500254template <>
255struct SingleTagToType<5>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700256{
257 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700258};
259
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500260template <uint64_t Tag>
261struct Arguments
Ed Tanous1abe55e2018-09-05 08:30:59 -0700262{
263 using subarguments = typename Arguments<Tag / 6>::type;
264 using type = typename subarguments::template push<
265 typename SingleTagToType<Tag % 6>::type>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700266};
267
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500268template <>
269struct Arguments<0>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700270{
271 using type = S<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700272};
273
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500274template <typename T>
Ed Tanous988403c2020-08-24 11:29:49 -0700275struct Promote
Ed Tanous1abe55e2018-09-05 08:30:59 -0700276{
277 using type = T;
278};
279
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500280template <typename T>
Ed Tanous988403c2020-08-24 11:29:49 -0700281using PromoteT = typename Promote<T>::type;
282
283template <>
284struct Promote<char>
285{
286 using type = int64_t;
287};
288template <>
289struct Promote<short>
290{
291 using type = int64_t;
292};
293template <>
294struct Promote<int>
295{
296 using type = int64_t;
297};
298template <>
299struct Promote<long>
300{
301 using type = int64_t;
302};
303template <>
304struct Promote<long long>
305{
306 using type = int64_t;
307};
308template <>
309struct Promote<unsigned char>
310{
311 using type = uint64_t;
312};
313template <>
314struct Promote<unsigned short>
315{
316 using type = uint64_t;
317};
318template <>
319struct Promote<unsigned int>
320{
321 using type = uint64_t;
322};
323template <>
324struct Promote<unsigned long>
325{
326 using type = uint64_t;
327};
328template <>
329struct Promote<unsigned long long>
330{
331 using type = uint64_t;
332};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700333
Ed Tanous1abe55e2018-09-05 08:30:59 -0700334} // namespace black_magic
Ed Tanous7045c8d2017-04-03 10:04:37 -0700335
Ed Tanous1abe55e2018-09-05 08:30:59 -0700336namespace detail
337{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700338
339template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700340struct GetIndexOfElementFromTupleByTypeImpl
341{
Ed Tanous271584a2019-07-09 16:24:22 -0700342 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700343};
344
345template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700346struct GetIndexOfElementFromTupleByTypeImpl<T, N, T, Args...>
347{
Ed Tanous271584a2019-07-09 16:24:22 -0700348 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700349};
350
351template <class T, std::size_t N, class U, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700352struct GetIndexOfElementFromTupleByTypeImpl<T, N, U, Args...>
353{
Ed Tanous271584a2019-07-09 16:24:22 -0700354 static constexpr std::size_t value =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700355 GetIndexOfElementFromTupleByTypeImpl<T, N + 1, Args...>::value;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700356};
357
Ed Tanous1abe55e2018-09-05 08:30:59 -0700358} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700359
Ed Tanous1abe55e2018-09-05 08:30:59 -0700360namespace utility
361{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500362template <class T, class... Args>
363T& getElementByType(std::tuple<Args...>& t)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700364{
365 return std::get<
366 detail::GetIndexOfElementFromTupleByTypeImpl<T, 0, Args...>::value>(t);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700367}
368
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500369template <typename T>
370struct function_traits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700371
Ed Tanous7045c8d2017-04-03 10:04:37 -0700372template <typename T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700373struct function_traits : public function_traits<decltype(&T::operator())>
374{
375 using parent_t = function_traits<decltype(&T::operator())>;
376 static const size_t arity = parent_t::arity;
377 using result_type = typename parent_t::result_type;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500378 template <size_t i>
379 using arg = typename parent_t::template arg<i>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700380};
Ed Tanous3dac7492017-08-02 13:46:20 -0700381
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700382template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700383struct function_traits<r (ClassType::*)(Args...) const>
384{
385 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700386
Ed Tanous1abe55e2018-09-05 08:30:59 -0700387 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700388
Ed Tanous1abe55e2018-09-05 08:30:59 -0700389 template <size_t i>
390 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700391};
392
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700393template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700394struct function_traits<r (ClassType::*)(Args...)>
395{
396 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700397
Ed Tanous1abe55e2018-09-05 08:30:59 -0700398 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700399
Ed Tanous1abe55e2018-09-05 08:30:59 -0700400 template <size_t i>
401 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700402};
403
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700404template <typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700405struct function_traits<std::function<r(Args...)>>
406{
407 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700408
Ed Tanous1abe55e2018-09-05 08:30:59 -0700409 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700410
Ed Tanous1abe55e2018-09-05 08:30:59 -0700411 template <size_t i>
412 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700413};
414
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600415inline std::string base64encode(const std::string_view data)
416{
417 const std::array<char, 64> key = {
418 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
419 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
420 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
421 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
422 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
423
424 size_t size = data.size();
425 std::string ret;
426 ret.resize((size + 2) / 3 * 4);
427 auto it = ret.begin();
428
429 size_t i = 0;
430 while (i < size)
431 {
Ed Tanous543f4402022-01-06 13:12:53 -0800432 size_t keyIndex = 0;
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600433
434 keyIndex = static_cast<size_t>(data[i] & 0xFC) >> 2;
435 *it++ = key[keyIndex];
436
437 if (i + 1 < size)
438 {
439 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
440 keyIndex += static_cast<size_t>(data[i + 1] & 0xF0) >> 4;
441 *it++ = key[keyIndex];
442
443 if (i + 2 < size)
444 {
445 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
446 keyIndex += static_cast<size_t>(data[i + 2] & 0xC0) >> 6;
447 *it++ = key[keyIndex];
448
449 keyIndex = static_cast<size_t>(data[i + 2] & 0x3F);
450 *it++ = key[keyIndex];
451 }
452 else
453 {
454 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
455 *it++ = key[keyIndex];
456 *it++ = '=';
457 }
458 }
459 else
460 {
461 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
462 *it++ = key[keyIndex];
463 *it++ = '=';
464 *it++ = '=';
465 }
466
467 i += 3;
468 }
469
470 return ret;
471}
472
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100473// TODO this is temporary and should be deleted once base64 is refactored out of
474// crow
Ed Tanous39e77502019-03-04 17:35:53 -0800475inline bool base64Decode(const std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700476{
Ed Tanous271584a2019-07-09 16:24:22 -0700477 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700478 // See note on encoding_data[] in above function
Jonathan Doman5beaf842020-08-14 11:23:33 -0700479 static const std::array<char, 256> decodingData = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700480 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
481 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
482 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
483 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
484 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
485 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
486 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
487 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
488 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
489 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
490 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
491 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
492 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
493 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
494 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
495 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
496 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
497 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
498 nop, nop, nop, nop};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100499
Ed Tanous1abe55e2018-09-05 08:30:59 -0700500 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100501
Ed Tanous1abe55e2018-09-05 08:30:59 -0700502 // allocate space for output string
503 output.clear();
504 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100505
Jonathan Doman5beaf842020-08-14 11:23:33 -0700506 auto getCodeValue = [](char c) {
507 auto code = static_cast<unsigned char>(c);
508 // Ensure we cannot index outside the bounds of the decoding array
509 static_assert(std::numeric_limits<decltype(code)>::max() <
510 decodingData.size());
511 return decodingData[code];
512 };
513
Ed Tanous1abe55e2018-09-05 08:30:59 -0700514 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500515 // dropping first two bits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700516 // and regenerate into 3 8-bits sequences
James Feist5a806642020-07-31 16:40:33 +0000517
Ed Tanous1abe55e2018-09-05 08:30:59 -0700518 for (size_t i = 0; i < inputLength; i++)
519 {
Ed Tanous543f4402022-01-06 13:12:53 -0800520 char base64code0 = 0;
521 char base64code1 = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700522 char base64code2 = 0; // initialized to 0 to suppress warnings
Ed Tanous543f4402022-01-06 13:12:53 -0800523 char base64code3 = 0;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100524
Jonathan Doman5beaf842020-08-14 11:23:33 -0700525 base64code0 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700526 if (base64code0 == nop)
527 { // non base64 character
528 return false;
529 }
530 if (!(++i < inputLength))
531 { // we need at least two input bytes for first
532 // byte output
533 return false;
534 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700535 base64code1 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 if (base64code1 == nop)
537 { // non base64 character
538 return false;
539 }
540 output +=
541 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100542
Ed Tanous1abe55e2018-09-05 08:30:59 -0700543 if (++i < inputLength)
544 {
545 char c = input[i];
546 if (c == '=')
547 { // padding , end of input
548 return (base64code1 & 0x0f) == 0;
549 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700550 base64code2 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700551 if (base64code2 == nop)
552 { // non base64 character
553 return false;
554 }
555 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
556 ((base64code2 >> 2) & 0x0f));
557 }
558
559 if (++i < inputLength)
560 {
561 char c = input[i];
562 if (c == '=')
563 { // padding , end of input
564 return (base64code2 & 0x03) == 0;
565 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700566 base64code3 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700567 if (base64code3 == nop)
568 { // non base64 character
569 return false;
570 }
571 output +=
572 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
573 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100574 }
575
Ed Tanous1abe55e2018-09-05 08:30:59 -0700576 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100577}
578
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100579namespace details
580{
Ed Tanous22ce5452022-01-11 10:50:23 -0800581constexpr uint64_t maxMilliSeconds = 253402300799999;
582constexpr uint64_t maxSeconds = 253402300799;
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100583inline std::string getDateTime(boost::posix_time::milliseconds timeSinceEpoch)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700584{
Nan Zhou1d8782e2021-11-29 22:23:18 -0800585 boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100586 boost::posix_time::ptime time = epoch + timeSinceEpoch;
Nan Zhou1d8782e2021-11-29 22:23:18 -0800587 // append zero offset to the end according to the Redfish spec for Date-Time
Nan Zhou5ae4b692021-12-14 13:30:37 -0800588 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Nan Zhou1d8782e2021-11-29 22:23:18 -0800589}
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100590} // namespace details
Andrew Geisslercb92c032018-08-17 07:56:14 -0700591
Ed Tanous22ce5452022-01-11 10:50:23 -0800592// Returns the formatted date time string.
593// Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if
594// the given |secondsSinceEpoch| is too large, we return the maximum supported
595// date. This behavior is to avoid exceptions throwed by Boost.
Nan Zhou1d8782e2021-11-29 22:23:18 -0800596inline std::string getDateTimeUint(uint64_t secondsSinceEpoch)
597{
Nan Zhou665479d2022-01-26 12:12:59 -0800598 secondsSinceEpoch = std::min(secondsSinceEpoch, details::maxSeconds);
599 boost::posix_time::seconds boostSeconds(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100600 return details::getDateTime(
601 boost::posix_time::milliseconds(boostSeconds.total_milliseconds()));
602}
603
Ed Tanous22ce5452022-01-11 10:50:23 -0800604// Returns the formatted date time string.
605// Note that the maximum supported date is 9999-12-31T23:59:59.999+00:00, if
606// the given |millisSecondsSinceEpoch| is too large, we return the maximum
607// supported date.
608inline std::string getDateTimeUintMs(uint64_t milliSecondsSinceEpoch)
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100609{
Nan Zhou665479d2022-01-26 12:12:59 -0800610 milliSecondsSinceEpoch =
611 std::min(details::maxMilliSeconds, milliSecondsSinceEpoch);
612 return details::getDateTime(
613 boost::posix_time::milliseconds(milliSecondsSinceEpoch));
Nan Zhou1d8782e2021-11-29 22:23:18 -0800614}
Andrew Geisslercb92c032018-08-17 07:56:14 -0700615
Nan Zhou1d8782e2021-11-29 22:23:18 -0800616inline std::string getDateTimeStdtime(std::time_t secondsSinceEpoch)
617{
Nan Zhou665479d2022-01-26 12:12:59 -0800618 if (secondsSinceEpoch > static_cast<int64_t>(details::maxSeconds))
619 {
620 secondsSinceEpoch = static_cast<std::time_t>(details::maxSeconds);
621 }
622 boost::posix_time::ptime time =
623 boost::posix_time::from_time_t(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100624 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Andrew Geisslercb92c032018-08-17 07:56:14 -0700625}
626
Tejas Patil7c8c4052021-06-04 17:43:14 +0530627/**
628 * Returns the current Date, Time & the local Time Offset
629 * infromation in a pair
630 *
631 * @param[in] None
632 *
633 * @return std::pair<std::string, std::string>, which consist
634 * of current DateTime & the TimeOffset strings respectively.
635 */
636inline std::pair<std::string, std::string> getDateTimeOffsetNow()
Andrew Geisslercb92c032018-08-17 07:56:14 -0700637{
638 std::time_t time = std::time(nullptr);
Nan Zhou1d8782e2021-11-29 22:23:18 -0800639 std::string dateTime = getDateTimeStdtime(time);
Tejas Patil7c8c4052021-06-04 17:43:14 +0530640
641 /* extract the local Time Offset value from the
642 * recevied dateTime string.
643 */
644 std::string timeOffset("Z00:00");
645 std::size_t lastPos = dateTime.size();
646 std::size_t len = timeOffset.size();
647 if (lastPos > len)
648 {
649 timeOffset = dateTime.substr(lastPos - len);
650 }
651
652 return std::make_pair(dateTime, timeOffset);
Andrew Geisslercb92c032018-08-17 07:56:14 -0700653}
654
Ed Tanous51dae672018-09-05 16:07:32 -0700655inline bool constantTimeStringCompare(const std::string_view a,
656 const std::string_view b)
657{
658 // Important note, this function is ONLY constant time if the two input
659 // sizes are the same
660 if (a.size() != b.size())
661 {
662 return false;
663 }
664 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
665}
666
667struct ConstantTimeCompare
668{
669 bool operator()(const std::string_view a, const std::string_view b) const
670 {
671 return constantTimeStringCompare(a, b);
672 }
673};
674
Ed Tanouseae855c2021-10-26 11:26:02 -0700675namespace details
676{
677inline boost::urls::url
678 urlFromPiecesDetail(const std::initializer_list<std::string_view> args)
679{
680 boost::urls::url url("/");
681 for (const std::string_view& arg : args)
682 {
683 url.segments().push_back(arg);
684 }
685 return url;
686}
687} // namespace details
688
689template <typename... AV>
690inline boost::urls::url urlFromPieces(const AV... args)
691{
692 return details::urlFromPiecesDetail({args...});
693}
694
Ed Tanous1abe55e2018-09-05 08:30:59 -0700695} // namespace utility
696} // namespace crow