blob: 37c06cd7ed4ca2d38f2290bf56f95bf08a9f6cf3 [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 Tanous11baefe2022-02-09 12:14:12 -080014#include <regex>
Ed Tanous7045c8d2017-04-03 10:04:37 -070015#include <stdexcept>
16#include <string>
Ed Tanous9ea15c32022-01-04 14:18:22 -080017#include <string_view>
Ed Tanous7045c8d2017-04-03 10:04:37 -070018#include <tuple>
Ed Tanous9ea15c32022-01-04 14:18:22 -080019#include <type_traits>
20#include <utility>
Ed Tanous7045c8d2017-04-03 10:04:37 -070021
Ed Tanous1abe55e2018-09-05 08:30:59 -070022namespace crow
23{
24namespace black_magic
25{
Ed Tanous7045c8d2017-04-03 10:04:37 -070026
Ed Tanous988403c2020-08-24 11:29:49 -070027constexpr unsigned findClosingTag(std::string_view s, unsigned p)
Ed Tanous1abe55e2018-09-05 08:30:59 -070028{
29 return s[p] == '>' ? p : findClosingTag(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070030}
31
Ed Tanous988403c2020-08-24 11:29:49 -070032constexpr bool isInt(std::string_view s, unsigned i)
Ed Tanous1abe55e2018-09-05 08:30:59 -070033{
Ed Tanous988403c2020-08-24 11:29:49 -070034 return s.substr(i, 5) == "<int>";
Ed Tanous7045c8d2017-04-03 10:04:37 -070035}
36
Ed Tanous988403c2020-08-24 11:29:49 -070037constexpr bool isUint(std::string_view s, unsigned i)
Ed Tanous1abe55e2018-09-05 08:30:59 -070038{
Ed Tanous988403c2020-08-24 11:29:49 -070039 return s.substr(i, 6) == "<uint>";
Ed Tanous7045c8d2017-04-03 10:04:37 -070040}
41
Ed Tanous988403c2020-08-24 11:29:49 -070042constexpr bool isFloat(std::string_view s, unsigned i)
Ed Tanous1abe55e2018-09-05 08:30:59 -070043{
Ed Tanous988403c2020-08-24 11:29:49 -070044 return s.substr(i, 7) == "<float>" || s.substr(i, 8) == "<double>";
Ed Tanous7045c8d2017-04-03 10:04:37 -070045}
46
Ed Tanous988403c2020-08-24 11:29:49 -070047constexpr bool isStr(std::string_view s, unsigned i)
Ed Tanous1abe55e2018-09-05 08:30:59 -070048{
Ed Tanous988403c2020-08-24 11:29:49 -070049 return s.substr(i, 5) == "<str>" || s.substr(i, 8) == "<string>";
Ed Tanous7045c8d2017-04-03 10:04:37 -070050}
51
Ed Tanous988403c2020-08-24 11:29:49 -070052constexpr bool isPath(std::string_view s, unsigned i)
Ed Tanous1abe55e2018-09-05 08:30:59 -070053{
Ed Tanous988403c2020-08-24 11:29:49 -070054 return s.substr(i, 6) == "<path>";
Ed Tanous7045c8d2017-04-03 10:04:37 -070055}
Ed Tanous3dac7492017-08-02 13:46:20 -070056
Gunnar Mills1214b7e2020-06-04 10:11:30 -050057template <typename T>
58constexpr int getParameterTag()
Ed Tanous1abe55e2018-09-05 08:30:59 -070059{
Ed Tanous69509012019-10-24 16:53:05 -070060 if constexpr (std::is_same_v<int, T>)
61 {
62 return 1;
Ed Tanous1abe55e2018-09-05 08:30:59 -070063 }
Ed Tanous69509012019-10-24 16:53:05 -070064 if constexpr (std::is_same_v<char, T>)
65 {
66 return 1;
67 }
68 if constexpr (std::is_same_v<short, T>)
69 {
70 return 1;
71 }
72 if constexpr (std::is_same_v<long, T>)
73 {
74 return 1;
75 }
76 if constexpr (std::is_same_v<long long, T>)
77 {
78 return 1;
79 }
80 if constexpr (std::is_same_v<unsigned int, T>)
81 {
82 return 2;
83 }
84 if constexpr (std::is_same_v<unsigned char, T>)
85 {
86 return 2;
87 }
88 if constexpr (std::is_same_v<unsigned short, T>)
89 {
90 return 2;
91 }
92 if constexpr (std::is_same_v<unsigned long, T>)
93 {
94 return 2;
95 }
96 if constexpr (std::is_same_v<unsigned long long, T>)
97 {
98 return 2;
99 }
100 if constexpr (std::is_same_v<double, T>)
101 {
102 return 3;
103 }
104 if constexpr (std::is_same_v<std::string, T>)
105 {
106 return 4;
107 }
108 return 0;
109}
110
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500111template <typename... Args>
Ed Tanous988403c2020-08-24 11:29:49 -0700112struct computeParameterTagFromArgsList;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700113
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500114template <>
Ed Tanous988403c2020-08-24 11:29:49 -0700115struct computeParameterTagFromArgsList<>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700116{
Ed Tanous69509012019-10-24 16:53:05 -0700117 static constexpr int value = 0;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700118};
119
120template <typename Arg, typename... Args>
Ed Tanous988403c2020-08-24 11:29:49 -0700121struct computeParameterTagFromArgsList<Arg, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700122{
Ed Tanous69509012019-10-24 16:53:05 -0700123 static constexpr int subValue =
Ed Tanous988403c2020-08-24 11:29:49 -0700124 computeParameterTagFromArgsList<Args...>::value;
Ed Tanous69509012019-10-24 16:53:05 -0700125 static constexpr int value =
126 getParameterTag<typename std::decay<Arg>::type>()
127 ? subValue * 6 + getParameterTag<typename std::decay<Arg>::type>()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128 : subValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700129};
130
Ed Tanous988403c2020-08-24 11:29:49 -0700131inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700132{
Ed Tanousb00dcc22021-02-23 12:52:50 -0800133
Ed Tanous1abe55e2018-09-05 08:30:59 -0700134 if (a == 0)
135 {
136 return b == 0;
137 }
138 if (b == 0)
139 {
140 return a == 0;
141 }
Ed Tanous271584a2019-07-09 16:24:22 -0700142 uint64_t sa = a % 6;
143 uint64_t sb = a % 6;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700144 if (sa == 5)
145 {
146 sa = 4;
147 }
148 if (sb == 5)
149 {
150 sb = 4;
151 }
152 if (sa != sb)
153 {
154 return false;
155 }
156 return isParameterTagCompatible(a / 6, b / 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700157}
158
Ed Tanous988403c2020-08-24 11:29:49 -0700159constexpr uint64_t getParameterTag(std::string_view s, unsigned p = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700160{
Ed Tanousb00dcc22021-02-23 12:52:50 -0800161
Ed Tanous988403c2020-08-24 11:29:49 -0700162 if (p == s.size())
163 {
164 return 0;
165 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700166
Ed Tanous988403c2020-08-24 11:29:49 -0700167 if (s[p] != '<')
168 {
169 return getParameterTag(s, p + 1);
170 }
Ed Tanous3dac7492017-08-02 13:46:20 -0700171
Ed Tanous988403c2020-08-24 11:29:49 -0700172 if (isInt(s, p))
173 {
174 return getParameterTag(s, findClosingTag(s, p)) * 6 + 1;
175 }
176
177 if (isUint(s, p))
178 {
179 return getParameterTag(s, findClosingTag(s, p)) * 6 + 2;
180 }
181
182 if (isFloat(s, p))
183 {
184 return getParameterTag(s, findClosingTag(s, p)) * 6 + 3;
185 }
186
187 if (isStr(s, p))
188 {
189 return getParameterTag(s, findClosingTag(s, p)) * 6 + 4;
190 }
191
192 if (isPath(s, p))
193 {
194 return getParameterTag(s, findClosingTag(s, p)) * 6 + 5;
195 }
196
197 throw std::runtime_error("invalid parameter type");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700198}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700199
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500200template <typename... T>
201struct S
Ed Tanous1abe55e2018-09-05 08:30:59 -0700202{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500203 template <typename U>
204 using push = S<U, T...>;
205 template <typename U>
206 using push_back = S<T..., U>;
207 template <template <typename... Args> class U>
208 using rebind = U<T...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700209};
Ed Tanous988403c2020-08-24 11:29:49 -0700210
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500211template <typename F, typename Set>
212struct CallHelper;
Ed Tanous988403c2020-08-24 11:29:49 -0700213
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500214template <typename F, typename... Args>
215struct CallHelper<F, S<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700216{
217 template <typename F1, typename... Args1,
218 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
Ed Tanous2c70f802020-09-28 14:29:23 -0700219 static char test(int);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700220
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500221 template <typename...>
Ed Tanous2c70f802020-09-28 14:29:23 -0700222 static int test(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700223
Ed Tanous2c70f802020-09-28 14:29:23 -0700224 static constexpr bool value = sizeof(test<F, Args...>(0)) == sizeof(char);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700225};
226
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500227template <uint64_t N>
228struct SingleTagToType
229{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700230
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500231template <>
232struct SingleTagToType<1>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700233{
234 using type = int64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700235};
236
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500237template <>
238struct SingleTagToType<2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700239{
240 using type = uint64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700241};
242
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500243template <>
244struct SingleTagToType<3>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700245{
246 using type = double;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700247};
248
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500249template <>
250struct SingleTagToType<4>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700251{
252 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700253};
254
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500255template <>
256struct SingleTagToType<5>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700257{
258 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700259};
260
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500261template <uint64_t Tag>
262struct Arguments
Ed Tanous1abe55e2018-09-05 08:30:59 -0700263{
264 using subarguments = typename Arguments<Tag / 6>::type;
265 using type = typename subarguments::template push<
266 typename SingleTagToType<Tag % 6>::type>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700267};
268
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500269template <>
270struct Arguments<0>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700271{
272 using type = S<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700273};
274
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500275template <typename T>
Ed Tanous988403c2020-08-24 11:29:49 -0700276struct Promote
Ed Tanous1abe55e2018-09-05 08:30:59 -0700277{
278 using type = T;
279};
280
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500281template <typename T>
Ed Tanous988403c2020-08-24 11:29:49 -0700282using PromoteT = typename Promote<T>::type;
283
284template <>
285struct Promote<char>
286{
287 using type = int64_t;
288};
289template <>
290struct Promote<short>
291{
292 using type = int64_t;
293};
294template <>
295struct Promote<int>
296{
297 using type = int64_t;
298};
299template <>
300struct Promote<long>
301{
302 using type = int64_t;
303};
304template <>
305struct Promote<long long>
306{
307 using type = int64_t;
308};
309template <>
310struct Promote<unsigned char>
311{
312 using type = uint64_t;
313};
314template <>
315struct Promote<unsigned short>
316{
317 using type = uint64_t;
318};
319template <>
320struct Promote<unsigned int>
321{
322 using type = uint64_t;
323};
324template <>
325struct Promote<unsigned long>
326{
327 using type = uint64_t;
328};
329template <>
330struct Promote<unsigned long long>
331{
332 using type = uint64_t;
333};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700334
Ed Tanous1abe55e2018-09-05 08:30:59 -0700335} // namespace black_magic
Ed Tanous7045c8d2017-04-03 10:04:37 -0700336
Ed Tanous1abe55e2018-09-05 08:30:59 -0700337namespace detail
338{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700339
340template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700341struct GetIndexOfElementFromTupleByTypeImpl
342{
Ed Tanous271584a2019-07-09 16:24:22 -0700343 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700344};
345
346template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700347struct GetIndexOfElementFromTupleByTypeImpl<T, N, T, Args...>
348{
Ed Tanous271584a2019-07-09 16:24:22 -0700349 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700350};
351
352template <class T, std::size_t N, class U, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700353struct GetIndexOfElementFromTupleByTypeImpl<T, N, U, Args...>
354{
Ed Tanous271584a2019-07-09 16:24:22 -0700355 static constexpr std::size_t value =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700356 GetIndexOfElementFromTupleByTypeImpl<T, N + 1, Args...>::value;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700357};
358
Ed Tanous1abe55e2018-09-05 08:30:59 -0700359} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700360
Ed Tanous1abe55e2018-09-05 08:30:59 -0700361namespace utility
362{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500363template <class T, class... Args>
364T& getElementByType(std::tuple<Args...>& t)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700365{
366 return std::get<
367 detail::GetIndexOfElementFromTupleByTypeImpl<T, 0, Args...>::value>(t);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700368}
369
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500370template <typename T>
371struct function_traits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700372
Ed Tanous7045c8d2017-04-03 10:04:37 -0700373template <typename T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700374struct function_traits : public function_traits<decltype(&T::operator())>
375{
376 using parent_t = function_traits<decltype(&T::operator())>;
377 static const size_t arity = parent_t::arity;
378 using result_type = typename parent_t::result_type;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500379 template <size_t i>
380 using arg = typename parent_t::template arg<i>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700381};
Ed Tanous3dac7492017-08-02 13:46:20 -0700382
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700383template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700384struct function_traits<r (ClassType::*)(Args...) const>
385{
386 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700387
Ed Tanous1abe55e2018-09-05 08:30:59 -0700388 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700389
Ed Tanous1abe55e2018-09-05 08:30:59 -0700390 template <size_t i>
391 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700392};
393
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700394template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700395struct function_traits<r (ClassType::*)(Args...)>
396{
397 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700398
Ed Tanous1abe55e2018-09-05 08:30:59 -0700399 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700400
Ed Tanous1abe55e2018-09-05 08:30:59 -0700401 template <size_t i>
402 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700403};
404
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700405template <typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700406struct function_traits<std::function<r(Args...)>>
407{
408 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700409
Ed Tanous1abe55e2018-09-05 08:30:59 -0700410 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700411
Ed Tanous1abe55e2018-09-05 08:30:59 -0700412 template <size_t i>
413 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700414};
415
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600416inline std::string base64encode(const std::string_view data)
417{
418 const std::array<char, 64> key = {
419 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
420 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
421 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
422 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
423 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
424
425 size_t size = data.size();
426 std::string ret;
427 ret.resize((size + 2) / 3 * 4);
428 auto it = ret.begin();
429
430 size_t i = 0;
431 while (i < size)
432 {
Ed Tanous543f4402022-01-06 13:12:53 -0800433 size_t keyIndex = 0;
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600434
435 keyIndex = static_cast<size_t>(data[i] & 0xFC) >> 2;
436 *it++ = key[keyIndex];
437
438 if (i + 1 < size)
439 {
440 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
441 keyIndex += static_cast<size_t>(data[i + 1] & 0xF0) >> 4;
442 *it++ = key[keyIndex];
443
444 if (i + 2 < size)
445 {
446 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
447 keyIndex += static_cast<size_t>(data[i + 2] & 0xC0) >> 6;
448 *it++ = key[keyIndex];
449
450 keyIndex = static_cast<size_t>(data[i + 2] & 0x3F);
451 *it++ = key[keyIndex];
452 }
453 else
454 {
455 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
456 *it++ = key[keyIndex];
457 *it++ = '=';
458 }
459 }
460 else
461 {
462 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
463 *it++ = key[keyIndex];
464 *it++ = '=';
465 *it++ = '=';
466 }
467
468 i += 3;
469 }
470
471 return ret;
472}
473
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100474// TODO this is temporary and should be deleted once base64 is refactored out of
475// crow
Ed Tanous39e77502019-03-04 17:35:53 -0800476inline bool base64Decode(const std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700477{
Ed Tanous271584a2019-07-09 16:24:22 -0700478 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479 // See note on encoding_data[] in above function
Jonathan Doman5beaf842020-08-14 11:23:33 -0700480 static const std::array<char, 256> decodingData = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481 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, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
484 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
485 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
486 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
487 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
488 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
489 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 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, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
499 nop, nop, nop, nop};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100500
Ed Tanous1abe55e2018-09-05 08:30:59 -0700501 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100502
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503 // allocate space for output string
504 output.clear();
505 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100506
Jonathan Doman5beaf842020-08-14 11:23:33 -0700507 auto getCodeValue = [](char c) {
508 auto code = static_cast<unsigned char>(c);
509 // Ensure we cannot index outside the bounds of the decoding array
510 static_assert(std::numeric_limits<decltype(code)>::max() <
511 decodingData.size());
512 return decodingData[code];
513 };
514
Ed Tanous1abe55e2018-09-05 08:30:59 -0700515 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500516 // dropping first two bits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700517 // and regenerate into 3 8-bits sequences
James Feist5a806642020-07-31 16:40:33 +0000518
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519 for (size_t i = 0; i < inputLength; i++)
520 {
Ed Tanous543f4402022-01-06 13:12:53 -0800521 char base64code0 = 0;
522 char base64code1 = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700523 char base64code2 = 0; // initialized to 0 to suppress warnings
Ed Tanous543f4402022-01-06 13:12:53 -0800524 char base64code3 = 0;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100525
Jonathan Doman5beaf842020-08-14 11:23:33 -0700526 base64code0 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700527 if (base64code0 == nop)
528 { // non base64 character
529 return false;
530 }
531 if (!(++i < inputLength))
532 { // we need at least two input bytes for first
533 // byte output
534 return false;
535 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700536 base64code1 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700537 if (base64code1 == nop)
538 { // non base64 character
539 return false;
540 }
541 output +=
542 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100543
Ed Tanous1abe55e2018-09-05 08:30:59 -0700544 if (++i < inputLength)
545 {
546 char c = input[i];
547 if (c == '=')
548 { // padding , end of input
549 return (base64code1 & 0x0f) == 0;
550 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700551 base64code2 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700552 if (base64code2 == nop)
553 { // non base64 character
554 return false;
555 }
556 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
557 ((base64code2 >> 2) & 0x0f));
558 }
559
560 if (++i < inputLength)
561 {
562 char c = input[i];
563 if (c == '=')
564 { // padding , end of input
565 return (base64code2 & 0x03) == 0;
566 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700567 base64code3 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700568 if (base64code3 == nop)
569 { // non base64 character
570 return false;
571 }
572 output +=
573 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
574 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100575 }
576
Ed Tanous1abe55e2018-09-05 08:30:59 -0700577 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100578}
579
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100580namespace details
581{
Ed Tanous22ce5452022-01-11 10:50:23 -0800582constexpr uint64_t maxMilliSeconds = 253402300799999;
583constexpr uint64_t maxSeconds = 253402300799;
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100584inline std::string getDateTime(boost::posix_time::milliseconds timeSinceEpoch)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700585{
Nan Zhou1d8782e2021-11-29 22:23:18 -0800586 boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100587 boost::posix_time::ptime time = epoch + timeSinceEpoch;
Nan Zhou1d8782e2021-11-29 22:23:18 -0800588 // append zero offset to the end according to the Redfish spec for Date-Time
Nan Zhou5ae4b692021-12-14 13:30:37 -0800589 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Nan Zhou1d8782e2021-11-29 22:23:18 -0800590}
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100591} // namespace details
Andrew Geisslercb92c032018-08-17 07:56:14 -0700592
Ed Tanous22ce5452022-01-11 10:50:23 -0800593// Returns the formatted date time string.
594// Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if
595// the given |secondsSinceEpoch| is too large, we return the maximum supported
596// date. This behavior is to avoid exceptions throwed by Boost.
Nan Zhou1d8782e2021-11-29 22:23:18 -0800597inline std::string getDateTimeUint(uint64_t secondsSinceEpoch)
598{
Nan Zhou665479d2022-01-26 12:12:59 -0800599 secondsSinceEpoch = std::min(secondsSinceEpoch, details::maxSeconds);
600 boost::posix_time::seconds boostSeconds(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100601 return details::getDateTime(
602 boost::posix_time::milliseconds(boostSeconds.total_milliseconds()));
603}
604
Ed Tanous22ce5452022-01-11 10:50:23 -0800605// Returns the formatted date time string.
606// Note that the maximum supported date is 9999-12-31T23:59:59.999+00:00, if
607// the given |millisSecondsSinceEpoch| is too large, we return the maximum
608// supported date.
609inline std::string getDateTimeUintMs(uint64_t milliSecondsSinceEpoch)
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100610{
Nan Zhou665479d2022-01-26 12:12:59 -0800611 milliSecondsSinceEpoch =
612 std::min(details::maxMilliSeconds, milliSecondsSinceEpoch);
613 return details::getDateTime(
614 boost::posix_time::milliseconds(milliSecondsSinceEpoch));
Nan Zhou1d8782e2021-11-29 22:23:18 -0800615}
Andrew Geisslercb92c032018-08-17 07:56:14 -0700616
Nan Zhou1d8782e2021-11-29 22:23:18 -0800617inline std::string getDateTimeStdtime(std::time_t secondsSinceEpoch)
618{
Nan Zhou665479d2022-01-26 12:12:59 -0800619 if (secondsSinceEpoch > static_cast<int64_t>(details::maxSeconds))
620 {
621 secondsSinceEpoch = static_cast<std::time_t>(details::maxSeconds);
622 }
623 boost::posix_time::ptime time =
624 boost::posix_time::from_time_t(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100625 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Andrew Geisslercb92c032018-08-17 07:56:14 -0700626}
627
Tejas Patil7c8c4052021-06-04 17:43:14 +0530628/**
629 * Returns the current Date, Time & the local Time Offset
630 * infromation in a pair
631 *
632 * @param[in] None
633 *
634 * @return std::pair<std::string, std::string>, which consist
635 * of current DateTime & the TimeOffset strings respectively.
636 */
637inline std::pair<std::string, std::string> getDateTimeOffsetNow()
Andrew Geisslercb92c032018-08-17 07:56:14 -0700638{
639 std::time_t time = std::time(nullptr);
Nan Zhou1d8782e2021-11-29 22:23:18 -0800640 std::string dateTime = getDateTimeStdtime(time);
Tejas Patil7c8c4052021-06-04 17:43:14 +0530641
642 /* extract the local Time Offset value from the
643 * recevied dateTime string.
644 */
645 std::string timeOffset("Z00:00");
646 std::size_t lastPos = dateTime.size();
647 std::size_t len = timeOffset.size();
648 if (lastPos > len)
649 {
650 timeOffset = dateTime.substr(lastPos - len);
651 }
652
653 return std::make_pair(dateTime, timeOffset);
Andrew Geisslercb92c032018-08-17 07:56:14 -0700654}
655
Ed Tanous51dae672018-09-05 16:07:32 -0700656inline bool constantTimeStringCompare(const std::string_view a,
657 const std::string_view b)
658{
659 // Important note, this function is ONLY constant time if the two input
660 // sizes are the same
661 if (a.size() != b.size())
662 {
663 return false;
664 }
665 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
666}
667
668struct ConstantTimeCompare
669{
670 bool operator()(const std::string_view a, const std::string_view b) const
671 {
672 return constantTimeStringCompare(a, b);
673 }
674};
675
Ed Tanouseae855c2021-10-26 11:26:02 -0700676namespace details
677{
678inline boost::urls::url
679 urlFromPiecesDetail(const std::initializer_list<std::string_view> args)
680{
681 boost::urls::url url("/");
682 for (const std::string_view& arg : args)
683 {
684 url.segments().push_back(arg);
685 }
686 return url;
687}
688} // namespace details
689
690template <typename... AV>
691inline boost::urls::url urlFromPieces(const AV... args)
692{
693 return details::urlFromPiecesDetail({args...});
694}
695
Ed Tanous11baefe2022-02-09 12:14:12 -0800696inline bool validateAndSplitUrl(std::string_view destUrl, std::string& urlProto,
697 std::string& host, std::string& port,
698 std::string& path)
699{
700 // Validate URL using regex expression
701 // Format: <protocol>://<host>:<port>/<path>
702 // protocol: http/https
703 const std::regex urlRegex(
704 "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
705 "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
706 std::cmatch match;
707 if (!std::regex_match(destUrl.begin(), destUrl.end(), match, urlRegex))
708 {
709 return false;
710 }
711
712 urlProto = std::string(match[1].first, match[1].second);
713 if (urlProto == "http")
714 {
715#ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
716 return false;
717#endif
718 }
719
720 host = std::string(match[2].first, match[2].second);
721 port = std::string(match[3].first, match[3].second);
722 path = std::string(match[4].first, match[4].second);
723 if (port.empty())
724 {
725 if (urlProto == "http")
726 {
727 port = "80";
728 }
729 else
730 {
731 port = "443";
732 }
733 }
734 if (path.empty())
735 {
736 path = "/";
737 }
738 return true;
739}
740
Ed Tanous1abe55e2018-09-05 08:30:59 -0700741} // namespace utility
742} // namespace crow