blob: 32e3b28b512225053ff341814c2692d728612209 [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{
Ed Tanous46666f32022-03-03 14:55:16 -0800619 // secondsSinceEpoch >= maxSeconds
620 if constexpr (std::cmp_less_equal(details::maxSeconds,
621 std::numeric_limits<std::time_t>::max()))
Nan Zhou665479d2022-01-26 12:12:59 -0800622 {
Ed Tanous46666f32022-03-03 14:55:16 -0800623 if (std::cmp_greater_equal(secondsSinceEpoch, details::maxSeconds))
624 {
625 secondsSinceEpoch = details::maxSeconds;
626 }
Nan Zhou665479d2022-01-26 12:12:59 -0800627 }
628 boost::posix_time::ptime time =
629 boost::posix_time::from_time_t(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100630 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Andrew Geisslercb92c032018-08-17 07:56:14 -0700631}
632
Tejas Patil7c8c4052021-06-04 17:43:14 +0530633/**
634 * Returns the current Date, Time & the local Time Offset
635 * infromation in a pair
636 *
637 * @param[in] None
638 *
639 * @return std::pair<std::string, std::string>, which consist
640 * of current DateTime & the TimeOffset strings respectively.
641 */
642inline std::pair<std::string, std::string> getDateTimeOffsetNow()
Andrew Geisslercb92c032018-08-17 07:56:14 -0700643{
644 std::time_t time = std::time(nullptr);
Nan Zhou1d8782e2021-11-29 22:23:18 -0800645 std::string dateTime = getDateTimeStdtime(time);
Tejas Patil7c8c4052021-06-04 17:43:14 +0530646
647 /* extract the local Time Offset value from the
648 * recevied dateTime string.
649 */
650 std::string timeOffset("Z00:00");
651 std::size_t lastPos = dateTime.size();
652 std::size_t len = timeOffset.size();
653 if (lastPos > len)
654 {
655 timeOffset = dateTime.substr(lastPos - len);
656 }
657
658 return std::make_pair(dateTime, timeOffset);
Andrew Geisslercb92c032018-08-17 07:56:14 -0700659}
660
Ed Tanous51dae672018-09-05 16:07:32 -0700661inline bool constantTimeStringCompare(const std::string_view a,
662 const std::string_view b)
663{
664 // Important note, this function is ONLY constant time if the two input
665 // sizes are the same
666 if (a.size() != b.size())
667 {
668 return false;
669 }
670 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
671}
672
673struct ConstantTimeCompare
674{
675 bool operator()(const std::string_view a, const std::string_view b) const
676 {
677 return constantTimeStringCompare(a, b);
678 }
679};
680
Ed Tanouseae855c2021-10-26 11:26:02 -0700681namespace details
682{
683inline boost::urls::url
684 urlFromPiecesDetail(const std::initializer_list<std::string_view> args)
685{
686 boost::urls::url url("/");
687 for (const std::string_view& arg : args)
688 {
689 url.segments().push_back(arg);
690 }
691 return url;
692}
693} // namespace details
694
695template <typename... AV>
696inline boost::urls::url urlFromPieces(const AV... args)
697{
698 return details::urlFromPiecesDetail({args...});
699}
700
Ed Tanous11baefe2022-02-09 12:14:12 -0800701inline bool validateAndSplitUrl(std::string_view destUrl, std::string& urlProto,
702 std::string& host, std::string& port,
703 std::string& path)
704{
705 // Validate URL using regex expression
706 // Format: <protocol>://<host>:<port>/<path>
707 // protocol: http/https
708 const std::regex urlRegex(
709 "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
710 "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
711 std::cmatch match;
712 if (!std::regex_match(destUrl.begin(), destUrl.end(), match, urlRegex))
713 {
714 return false;
715 }
716
717 urlProto = std::string(match[1].first, match[1].second);
718 if (urlProto == "http")
719 {
720#ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
721 return false;
722#endif
723 }
724
725 host = std::string(match[2].first, match[2].second);
726 port = std::string(match[3].first, match[3].second);
727 path = std::string(match[4].first, match[4].second);
728 if (port.empty())
729 {
730 if (urlProto == "http")
731 {
732 port = "80";
733 }
734 else
735 {
736 port = "443";
737 }
738 }
739 if (path.empty())
740 {
741 path = "/";
742 }
743 return true;
744}
745
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746} // namespace utility
747} // namespace crow