blob: 07fc1ee2dd628753859fe012babe03d7084b75cd [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 utility
338{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700339
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500340template <typename T>
341struct function_traits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700342
Ed Tanous7045c8d2017-04-03 10:04:37 -0700343template <typename T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700344struct function_traits : public function_traits<decltype(&T::operator())>
345{
346 using parent_t = function_traits<decltype(&T::operator())>;
347 static const size_t arity = parent_t::arity;
348 using result_type = typename parent_t::result_type;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500349 template <size_t i>
350 using arg = typename parent_t::template arg<i>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700351};
Ed Tanous3dac7492017-08-02 13:46:20 -0700352
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700353template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700354struct function_traits<r (ClassType::*)(Args...) const>
355{
356 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700357
Ed Tanous1abe55e2018-09-05 08:30:59 -0700358 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700359
Ed Tanous1abe55e2018-09-05 08:30:59 -0700360 template <size_t i>
361 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700362};
363
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700364template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700365struct function_traits<r (ClassType::*)(Args...)>
366{
367 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700368
Ed Tanous1abe55e2018-09-05 08:30:59 -0700369 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700370
Ed Tanous1abe55e2018-09-05 08:30:59 -0700371 template <size_t i>
372 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700373};
374
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700375template <typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700376struct function_traits<std::function<r(Args...)>>
377{
378 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700379
Ed Tanous1abe55e2018-09-05 08:30:59 -0700380 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700381
Ed Tanous1abe55e2018-09-05 08:30:59 -0700382 template <size_t i>
383 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700384};
385
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600386inline std::string base64encode(const std::string_view data)
387{
388 const std::array<char, 64> key = {
389 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
390 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
391 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
392 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
393 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
394
395 size_t size = data.size();
396 std::string ret;
397 ret.resize((size + 2) / 3 * 4);
398 auto it = ret.begin();
399
400 size_t i = 0;
401 while (i < size)
402 {
Ed Tanous543f4402022-01-06 13:12:53 -0800403 size_t keyIndex = 0;
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600404
405 keyIndex = static_cast<size_t>(data[i] & 0xFC) >> 2;
406 *it++ = key[keyIndex];
407
408 if (i + 1 < size)
409 {
410 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
411 keyIndex += static_cast<size_t>(data[i + 1] & 0xF0) >> 4;
412 *it++ = key[keyIndex];
413
414 if (i + 2 < size)
415 {
416 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
417 keyIndex += static_cast<size_t>(data[i + 2] & 0xC0) >> 6;
418 *it++ = key[keyIndex];
419
420 keyIndex = static_cast<size_t>(data[i + 2] & 0x3F);
421 *it++ = key[keyIndex];
422 }
423 else
424 {
425 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
426 *it++ = key[keyIndex];
427 *it++ = '=';
428 }
429 }
430 else
431 {
432 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
433 *it++ = key[keyIndex];
434 *it++ = '=';
435 *it++ = '=';
436 }
437
438 i += 3;
439 }
440
441 return ret;
442}
443
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100444// TODO this is temporary and should be deleted once base64 is refactored out of
445// crow
Ed Tanous39e77502019-03-04 17:35:53 -0800446inline bool base64Decode(const std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700447{
Ed Tanous271584a2019-07-09 16:24:22 -0700448 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700449 // See note on encoding_data[] in above function
Jonathan Doman5beaf842020-08-14 11:23:33 -0700450 static const std::array<char, 256> decodingData = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700451 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
452 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
453 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
454 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
455 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
456 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
457 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
458 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
459 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
460 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
461 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
462 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
463 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
464 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
465 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
466 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
467 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
468 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
469 nop, nop, nop, nop};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100470
Ed Tanous1abe55e2018-09-05 08:30:59 -0700471 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100472
Ed Tanous1abe55e2018-09-05 08:30:59 -0700473 // allocate space for output string
474 output.clear();
475 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100476
Jonathan Doman5beaf842020-08-14 11:23:33 -0700477 auto getCodeValue = [](char c) {
478 auto code = static_cast<unsigned char>(c);
479 // Ensure we cannot index outside the bounds of the decoding array
480 static_assert(std::numeric_limits<decltype(code)>::max() <
481 decodingData.size());
482 return decodingData[code];
483 };
484
Ed Tanous1abe55e2018-09-05 08:30:59 -0700485 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500486 // dropping first two bits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700487 // and regenerate into 3 8-bits sequences
James Feist5a806642020-07-31 16:40:33 +0000488
Ed Tanous1abe55e2018-09-05 08:30:59 -0700489 for (size_t i = 0; i < inputLength; i++)
490 {
Ed Tanous543f4402022-01-06 13:12:53 -0800491 char base64code0 = 0;
492 char base64code1 = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700493 char base64code2 = 0; // initialized to 0 to suppress warnings
Ed Tanous543f4402022-01-06 13:12:53 -0800494 char base64code3 = 0;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100495
Jonathan Doman5beaf842020-08-14 11:23:33 -0700496 base64code0 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700497 if (base64code0 == nop)
498 { // non base64 character
499 return false;
500 }
501 if (!(++i < inputLength))
502 { // we need at least two input bytes for first
503 // byte output
504 return false;
505 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700506 base64code1 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700507 if (base64code1 == nop)
508 { // non base64 character
509 return false;
510 }
511 output +=
512 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100513
Ed Tanous1abe55e2018-09-05 08:30:59 -0700514 if (++i < inputLength)
515 {
516 char c = input[i];
517 if (c == '=')
518 { // padding , end of input
519 return (base64code1 & 0x0f) == 0;
520 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700521 base64code2 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700522 if (base64code2 == nop)
523 { // non base64 character
524 return false;
525 }
526 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
527 ((base64code2 >> 2) & 0x0f));
528 }
529
530 if (++i < inputLength)
531 {
532 char c = input[i];
533 if (c == '=')
534 { // padding , end of input
535 return (base64code2 & 0x03) == 0;
536 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700537 base64code3 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700538 if (base64code3 == nop)
539 { // non base64 character
540 return false;
541 }
542 output +=
543 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
544 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100545 }
546
Ed Tanous1abe55e2018-09-05 08:30:59 -0700547 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100548}
549
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100550namespace details
551{
Ed Tanous22ce5452022-01-11 10:50:23 -0800552constexpr uint64_t maxMilliSeconds = 253402300799999;
553constexpr uint64_t maxSeconds = 253402300799;
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100554inline std::string getDateTime(boost::posix_time::milliseconds timeSinceEpoch)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700555{
Nan Zhou1d8782e2021-11-29 22:23:18 -0800556 boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100557 boost::posix_time::ptime time = epoch + timeSinceEpoch;
Nan Zhou1d8782e2021-11-29 22:23:18 -0800558 // append zero offset to the end according to the Redfish spec for Date-Time
Nan Zhou5ae4b692021-12-14 13:30:37 -0800559 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Nan Zhou1d8782e2021-11-29 22:23:18 -0800560}
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100561} // namespace details
Andrew Geisslercb92c032018-08-17 07:56:14 -0700562
Ed Tanous22ce5452022-01-11 10:50:23 -0800563// Returns the formatted date time string.
564// Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if
565// the given |secondsSinceEpoch| is too large, we return the maximum supported
566// date. This behavior is to avoid exceptions throwed by Boost.
Nan Zhou1d8782e2021-11-29 22:23:18 -0800567inline std::string getDateTimeUint(uint64_t secondsSinceEpoch)
568{
Nan Zhou665479d2022-01-26 12:12:59 -0800569 secondsSinceEpoch = std::min(secondsSinceEpoch, details::maxSeconds);
570 boost::posix_time::seconds boostSeconds(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100571 return details::getDateTime(
572 boost::posix_time::milliseconds(boostSeconds.total_milliseconds()));
573}
574
Ed Tanous22ce5452022-01-11 10:50:23 -0800575// Returns the formatted date time string.
576// Note that the maximum supported date is 9999-12-31T23:59:59.999+00:00, if
577// the given |millisSecondsSinceEpoch| is too large, we return the maximum
578// supported date.
579inline std::string getDateTimeUintMs(uint64_t milliSecondsSinceEpoch)
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100580{
Nan Zhou665479d2022-01-26 12:12:59 -0800581 milliSecondsSinceEpoch =
582 std::min(details::maxMilliSeconds, milliSecondsSinceEpoch);
583 return details::getDateTime(
584 boost::posix_time::milliseconds(milliSecondsSinceEpoch));
Nan Zhou1d8782e2021-11-29 22:23:18 -0800585}
Andrew Geisslercb92c032018-08-17 07:56:14 -0700586
Nan Zhou1d8782e2021-11-29 22:23:18 -0800587inline std::string getDateTimeStdtime(std::time_t secondsSinceEpoch)
588{
Ed Tanous46666f32022-03-03 14:55:16 -0800589 // secondsSinceEpoch >= maxSeconds
590 if constexpr (std::cmp_less_equal(details::maxSeconds,
591 std::numeric_limits<std::time_t>::max()))
Nan Zhou665479d2022-01-26 12:12:59 -0800592 {
Ed Tanous46666f32022-03-03 14:55:16 -0800593 if (std::cmp_greater_equal(secondsSinceEpoch, details::maxSeconds))
594 {
595 secondsSinceEpoch = details::maxSeconds;
596 }
Nan Zhou665479d2022-01-26 12:12:59 -0800597 }
598 boost::posix_time::ptime time =
599 boost::posix_time::from_time_t(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100600 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Andrew Geisslercb92c032018-08-17 07:56:14 -0700601}
602
Tejas Patil7c8c4052021-06-04 17:43:14 +0530603/**
604 * Returns the current Date, Time & the local Time Offset
605 * infromation in a pair
606 *
607 * @param[in] None
608 *
609 * @return std::pair<std::string, std::string>, which consist
610 * of current DateTime & the TimeOffset strings respectively.
611 */
612inline std::pair<std::string, std::string> getDateTimeOffsetNow()
Andrew Geisslercb92c032018-08-17 07:56:14 -0700613{
614 std::time_t time = std::time(nullptr);
Nan Zhou1d8782e2021-11-29 22:23:18 -0800615 std::string dateTime = getDateTimeStdtime(time);
Tejas Patil7c8c4052021-06-04 17:43:14 +0530616
617 /* extract the local Time Offset value from the
618 * recevied dateTime string.
619 */
620 std::string timeOffset("Z00:00");
621 std::size_t lastPos = dateTime.size();
622 std::size_t len = timeOffset.size();
623 if (lastPos > len)
624 {
625 timeOffset = dateTime.substr(lastPos - len);
626 }
627
628 return std::make_pair(dateTime, timeOffset);
Andrew Geisslercb92c032018-08-17 07:56:14 -0700629}
630
Ed Tanous51dae672018-09-05 16:07:32 -0700631inline bool constantTimeStringCompare(const std::string_view a,
632 const std::string_view b)
633{
634 // Important note, this function is ONLY constant time if the two input
635 // sizes are the same
636 if (a.size() != b.size())
637 {
638 return false;
639 }
640 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
641}
642
643struct ConstantTimeCompare
644{
645 bool operator()(const std::string_view a, const std::string_view b) const
646 {
647 return constantTimeStringCompare(a, b);
648 }
649};
650
Ed Tanouseae855c2021-10-26 11:26:02 -0700651namespace details
652{
653inline boost::urls::url
654 urlFromPiecesDetail(const std::initializer_list<std::string_view> args)
655{
656 boost::urls::url url("/");
657 for (const std::string_view& arg : args)
658 {
659 url.segments().push_back(arg);
660 }
661 return url;
662}
663} // namespace details
664
665template <typename... AV>
666inline boost::urls::url urlFromPieces(const AV... args)
667{
668 return details::urlFromPiecesDetail({args...});
669}
670
Ed Tanous11baefe2022-02-09 12:14:12 -0800671inline bool validateAndSplitUrl(std::string_view destUrl, std::string& urlProto,
672 std::string& host, std::string& port,
673 std::string& path)
674{
675 // Validate URL using regex expression
676 // Format: <protocol>://<host>:<port>/<path>
677 // protocol: http/https
678 const std::regex urlRegex(
679 "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
680 "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
681 std::cmatch match;
682 if (!std::regex_match(destUrl.begin(), destUrl.end(), match, urlRegex))
683 {
684 return false;
685 }
686
687 urlProto = std::string(match[1].first, match[1].second);
688 if (urlProto == "http")
689 {
690#ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
691 return false;
692#endif
693 }
694
695 host = std::string(match[2].first, match[2].second);
696 port = std::string(match[3].first, match[3].second);
697 path = std::string(match[4].first, match[4].second);
698 if (port.empty())
699 {
700 if (urlProto == "http")
701 {
702 port = "80";
703 }
704 else
705 {
706 port = "443";
707 }
708 }
709 if (path.empty())
710 {
711 path = "/";
712 }
713 return true;
714}
715
Ed Tanous1abe55e2018-09-05 08:30:59 -0700716} // namespace utility
717} // namespace crow