blob: da457bec7bebcbe1712f54abd68af2cc1450ada8 [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
Ed Tanous1abe55e2018-09-05 08:30:59 -07002
Ed Tanouseb1c47d2022-02-09 11:47:27 -08003#include <bmcweb_config.h>
Ed Tanous51dae672018-09-05 16:07:32 -07004#include <openssl/crypto.h>
5
Ed Tanousc867a832022-03-10 14:17:00 -08006#include <boost/callable_traits.hpp>
Nan Zhou1d8782e2021-11-29 22:23:18 -08007#include <boost/date_time/posix_time/posix_time.hpp>
Ed Tanouseae855c2021-10-26 11:26:02 -07008#include <boost/url/url.hpp>
Nan Zhou1d8782e2021-11-29 22:23:18 -08009
Ed Tanous9ea15c32022-01-04 14:18:22 -080010#include <array>
Ed Tanous74849be2021-02-05 09:47:47 -080011#include <chrono>
Ed Tanous7045c8d2017-04-03 10:04:37 -070012#include <cstdint>
Ed Tanous9ea15c32022-01-04 14:18:22 -080013#include <ctime>
Ed Tanous7045c8d2017-04-03 10:04:37 -070014#include <functional>
Ed Tanous9ea15c32022-01-04 14:18:22 -080015#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070016#include <stdexcept>
17#include <string>
Ed Tanous9ea15c32022-01-04 14:18:22 -080018#include <string_view>
Ed Tanous7045c8d2017-04-03 10:04:37 -070019#include <tuple>
Ed Tanous9ea15c32022-01-04 14:18:22 -080020#include <type_traits>
21#include <utility>
Szymon Dompkeca1600c2022-03-03 14:42:52 +010022#include <variant>
Ed Tanous7045c8d2017-04-03 10:04:37 -070023
Ed Tanous1abe55e2018-09-05 08:30:59 -070024namespace crow
25{
26namespace black_magic
27{
Ed Tanous7045c8d2017-04-03 10:04:37 -070028
Gunnar Mills1214b7e2020-06-04 10:11:30 -050029template <typename T>
Ed Tanous1c30e502022-03-08 18:02:24 -080030constexpr uint64_t getParameterTag()
Ed Tanous1abe55e2018-09-05 08:30:59 -070031{
Ed Tanous69509012019-10-24 16:53:05 -070032 if constexpr (std::is_same_v<int, T>)
33 {
34 return 1;
Ed Tanous1abe55e2018-09-05 08:30:59 -070035 }
Ed Tanous69509012019-10-24 16:53:05 -070036 if constexpr (std::is_same_v<char, T>)
37 {
38 return 1;
39 }
40 if constexpr (std::is_same_v<short, T>)
41 {
42 return 1;
43 }
44 if constexpr (std::is_same_v<long, T>)
45 {
46 return 1;
47 }
48 if constexpr (std::is_same_v<long long, T>)
49 {
50 return 1;
51 }
52 if constexpr (std::is_same_v<unsigned int, T>)
53 {
54 return 2;
55 }
56 if constexpr (std::is_same_v<unsigned char, T>)
57 {
58 return 2;
59 }
60 if constexpr (std::is_same_v<unsigned short, T>)
61 {
62 return 2;
63 }
64 if constexpr (std::is_same_v<unsigned long, T>)
65 {
66 return 2;
67 }
68 if constexpr (std::is_same_v<unsigned long long, T>)
69 {
70 return 2;
71 }
72 if constexpr (std::is_same_v<double, T>)
73 {
74 return 3;
75 }
76 if constexpr (std::is_same_v<std::string, T>)
77 {
78 return 4;
79 }
80 return 0;
81}
82
Gunnar Mills1214b7e2020-06-04 10:11:30 -050083template <typename... Args>
Ed Tanous988403c2020-08-24 11:29:49 -070084struct computeParameterTagFromArgsList;
Ed Tanous7045c8d2017-04-03 10:04:37 -070085
Gunnar Mills1214b7e2020-06-04 10:11:30 -050086template <>
Ed Tanous988403c2020-08-24 11:29:49 -070087struct computeParameterTagFromArgsList<>
Ed Tanous1abe55e2018-09-05 08:30:59 -070088{
Ed Tanous69509012019-10-24 16:53:05 -070089 static constexpr int value = 0;
Ed Tanous7045c8d2017-04-03 10:04:37 -070090};
91
92template <typename Arg, typename... Args>
Ed Tanous988403c2020-08-24 11:29:49 -070093struct computeParameterTagFromArgsList<Arg, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -070094{
Ed Tanous69509012019-10-24 16:53:05 -070095 static constexpr int subValue =
Ed Tanous988403c2020-08-24 11:29:49 -070096 computeParameterTagFromArgsList<Args...>::value;
Ed Tanous69509012019-10-24 16:53:05 -070097 static constexpr int value =
Ed Tanous1c30e502022-03-08 18:02:24 -080098 getParameterTag<typename std::decay<Arg>::type>() != 0
Ed Tanous69509012019-10-24 16:53:05 -070099 ? subValue * 6 + getParameterTag<typename std::decay<Arg>::type>()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700100 : subValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700101};
102
Ed Tanous988403c2020-08-24 11:29:49 -0700103inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700104{
Ed Tanous1c30e502022-03-08 18:02:24 -0800105 while (true)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700106 {
Ed Tanous1c30e502022-03-08 18:02:24 -0800107 if (a == 0)
108 {
109 return b == 0;
110 }
111 if (b == 0)
112 {
113 return a == 0;
114 }
115 uint64_t sa = a % 6;
116 uint64_t sb = a % 6;
117 if (sa == 5)
118 {
119 sa = 4;
120 }
121 if (sb == 5)
122 {
123 sb = 4;
124 }
125 if (sa != sb)
126 {
127 return false;
128 }
129 a /= 6;
130 b /= 6;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700131 }
Ed Tanous1c30e502022-03-08 18:02:24 -0800132 return false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700133}
134
Ed Tanous1c30e502022-03-08 18:02:24 -0800135constexpr inline uint64_t getParameterTag(std::string_view url)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700136{
Ed Tanous1c30e502022-03-08 18:02:24 -0800137 uint64_t tagValue = 0;
138 size_t urlSegmentIndex = std::string_view::npos;
Ed Tanousb00dcc22021-02-23 12:52:50 -0800139
Ed Tanous1c30e502022-03-08 18:02:24 -0800140 size_t paramIndex = 0;
141
142 for (size_t urlIndex = 0; urlIndex < url.size(); urlIndex++)
143 {
144 char character = url[urlIndex];
145 if (character == '<')
146 {
147 if (urlSegmentIndex != std::string_view::npos)
148 {
149 return 0;
150 }
151 urlSegmentIndex = urlIndex;
152 }
153 if (character == '>')
154 {
155 if (urlSegmentIndex == std::string_view::npos)
156 {
157 return 0;
158 }
159 std::string_view tag =
160 url.substr(urlSegmentIndex, urlIndex + 1 - urlSegmentIndex);
161
162 // Note, this is a really lame way to do std::pow(6, paramIndex)
163 // std::pow doesn't work in constexpr in clang.
164 // Ideally in the future we'd move this to use a power of 2 packing
165 // (probably 8 instead of 6) so that these just become bit shifts
166 uint64_t insertIndex = 1;
167 for (size_t unused = 0; unused < paramIndex; unused++)
168 {
169 insertIndex *= 6;
170 }
171
172 if (tag == "<int>")
173 {
174 tagValue += insertIndex * 1;
175 }
176 if (tag == "<uint>")
177 {
178 tagValue += insertIndex * 2;
179 }
180 if (tag == "<float>" || tag == "<double>")
181 {
182 tagValue += insertIndex * 3;
183 }
184 if (tag == "<str>" || tag == "<string>")
185 {
186 tagValue += insertIndex * 4;
187 }
188 if (tag == "<path>")
189 {
190 tagValue += insertIndex * 5;
191 }
192 paramIndex++;
193 urlSegmentIndex = std::string_view::npos;
194 }
195 }
196 if (urlSegmentIndex != std::string_view::npos)
Ed Tanous988403c2020-08-24 11:29:49 -0700197 {
198 return 0;
199 }
Ed Tanous1c30e502022-03-08 18:02:24 -0800200 return tagValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700201}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700202
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500203template <typename... T>
204struct S
Ed Tanous1abe55e2018-09-05 08:30:59 -0700205{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500206 template <typename U>
207 using push = S<U, T...>;
208 template <typename U>
209 using push_back = S<T..., U>;
210 template <template <typename... Args> class U>
211 using rebind = U<T...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700212};
Ed Tanous988403c2020-08-24 11:29:49 -0700213
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500214template <typename F, typename Set>
215struct CallHelper;
Ed Tanous988403c2020-08-24 11:29:49 -0700216
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500217template <typename F, typename... Args>
218struct CallHelper<F, S<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700219{
220 template <typename F1, typename... Args1,
221 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
Ed Tanous2c70f802020-09-28 14:29:23 -0700222 static char test(int);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700223
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500224 template <typename...>
Ed Tanous2c70f802020-09-28 14:29:23 -0700225 static int test(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700226
Ed Tanous2c70f802020-09-28 14:29:23 -0700227 static constexpr bool value = sizeof(test<F, Args...>(0)) == sizeof(char);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700228};
229
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500230template <uint64_t N>
231struct SingleTagToType
232{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700233
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500234template <>
235struct SingleTagToType<1>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700236{
237 using type = int64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700238};
239
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500240template <>
241struct SingleTagToType<2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700242{
243 using type = uint64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700244};
245
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500246template <>
247struct SingleTagToType<3>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700248{
249 using type = double;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700250};
251
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500252template <>
253struct SingleTagToType<4>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700254{
255 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700256};
257
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500258template <>
259struct SingleTagToType<5>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700260{
261 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700262};
263
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500264template <uint64_t Tag>
265struct Arguments
Ed Tanous1abe55e2018-09-05 08:30:59 -0700266{
267 using subarguments = typename Arguments<Tag / 6>::type;
268 using type = typename subarguments::template push<
269 typename SingleTagToType<Tag % 6>::type>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700270};
271
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500272template <>
273struct Arguments<0>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700274{
275 using type = S<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700276};
277
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500278template <typename T>
Ed Tanous988403c2020-08-24 11:29:49 -0700279struct Promote
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280{
281 using type = T;
282};
283
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500284template <typename T>
Ed Tanous988403c2020-08-24 11:29:49 -0700285using PromoteT = typename Promote<T>::type;
286
287template <>
288struct Promote<char>
289{
290 using type = int64_t;
291};
292template <>
293struct Promote<short>
294{
295 using type = int64_t;
296};
297template <>
298struct Promote<int>
299{
300 using type = int64_t;
301};
302template <>
303struct Promote<long>
304{
305 using type = int64_t;
306};
307template <>
308struct Promote<long long>
309{
310 using type = int64_t;
311};
312template <>
313struct Promote<unsigned char>
314{
315 using type = uint64_t;
316};
317template <>
318struct Promote<unsigned short>
319{
320 using type = uint64_t;
321};
322template <>
323struct Promote<unsigned int>
324{
325 using type = uint64_t;
326};
327template <>
328struct Promote<unsigned long>
329{
330 using type = uint64_t;
331};
332template <>
333struct Promote<unsigned long long>
334{
335 using type = uint64_t;
336};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700337
Ed Tanous1abe55e2018-09-05 08:30:59 -0700338} // namespace black_magic
Ed Tanous7045c8d2017-04-03 10:04:37 -0700339
Ed Tanous1abe55e2018-09-05 08:30:59 -0700340namespace utility
341{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700342
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500343template <typename T>
Ed Tanousc867a832022-03-10 14:17:00 -0800344struct FunctionTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700345{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500346 template <size_t i>
Ed Tanousc867a832022-03-10 14:17:00 -0800347 using arg = std::tuple_element_t<i, boost::callable_traits::args_t<T>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700348};
349
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600350inline std::string base64encode(const std::string_view data)
351{
352 const std::array<char, 64> key = {
353 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
354 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
355 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
356 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
357 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
358
359 size_t size = data.size();
360 std::string ret;
361 ret.resize((size + 2) / 3 * 4);
362 auto it = ret.begin();
363
364 size_t i = 0;
365 while (i < size)
366 {
Ed Tanous543f4402022-01-06 13:12:53 -0800367 size_t keyIndex = 0;
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600368
369 keyIndex = static_cast<size_t>(data[i] & 0xFC) >> 2;
370 *it++ = key[keyIndex];
371
372 if (i + 1 < size)
373 {
374 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
375 keyIndex += static_cast<size_t>(data[i + 1] & 0xF0) >> 4;
376 *it++ = key[keyIndex];
377
378 if (i + 2 < size)
379 {
380 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
381 keyIndex += static_cast<size_t>(data[i + 2] & 0xC0) >> 6;
382 *it++ = key[keyIndex];
383
384 keyIndex = static_cast<size_t>(data[i + 2] & 0x3F);
385 *it++ = key[keyIndex];
386 }
387 else
388 {
389 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
390 *it++ = key[keyIndex];
391 *it++ = '=';
392 }
393 }
394 else
395 {
396 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
397 *it++ = key[keyIndex];
398 *it++ = '=';
399 *it++ = '=';
400 }
401
402 i += 3;
403 }
404
405 return ret;
406}
407
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100408// TODO this is temporary and should be deleted once base64 is refactored out of
409// crow
Ed Tanous39e77502019-03-04 17:35:53 -0800410inline bool base64Decode(const std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700411{
Ed Tanous271584a2019-07-09 16:24:22 -0700412 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700413 // See note on encoding_data[] in above function
Jonathan Doman5beaf842020-08-14 11:23:33 -0700414 static const std::array<char, 256> decodingData = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700415 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
416 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
417 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
418 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
419 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
420 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
421 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
422 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
423 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
424 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
425 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
426 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
427 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
428 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
429 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
430 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
431 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
432 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
433 nop, nop, nop, nop};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100434
Ed Tanous1abe55e2018-09-05 08:30:59 -0700435 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100436
Ed Tanous1abe55e2018-09-05 08:30:59 -0700437 // allocate space for output string
438 output.clear();
439 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100440
Jonathan Doman5beaf842020-08-14 11:23:33 -0700441 auto getCodeValue = [](char c) {
442 auto code = static_cast<unsigned char>(c);
443 // Ensure we cannot index outside the bounds of the decoding array
444 static_assert(std::numeric_limits<decltype(code)>::max() <
445 decodingData.size());
446 return decodingData[code];
447 };
448
Ed Tanous1abe55e2018-09-05 08:30:59 -0700449 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500450 // dropping first two bits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700451 // and regenerate into 3 8-bits sequences
James Feist5a806642020-07-31 16:40:33 +0000452
Ed Tanous1abe55e2018-09-05 08:30:59 -0700453 for (size_t i = 0; i < inputLength; i++)
454 {
Ed Tanous543f4402022-01-06 13:12:53 -0800455 char base64code0 = 0;
456 char base64code1 = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700457 char base64code2 = 0; // initialized to 0 to suppress warnings
Ed Tanous543f4402022-01-06 13:12:53 -0800458 char base64code3 = 0;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100459
Jonathan Doman5beaf842020-08-14 11:23:33 -0700460 base64code0 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700461 if (base64code0 == nop)
462 { // non base64 character
463 return false;
464 }
465 if (!(++i < inputLength))
466 { // we need at least two input bytes for first
467 // byte output
468 return false;
469 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700470 base64code1 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700471 if (base64code1 == nop)
472 { // non base64 character
473 return false;
474 }
475 output +=
476 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100477
Ed Tanous1abe55e2018-09-05 08:30:59 -0700478 if (++i < inputLength)
479 {
480 char c = input[i];
481 if (c == '=')
482 { // padding , end of input
483 return (base64code1 & 0x0f) == 0;
484 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700485 base64code2 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700486 if (base64code2 == nop)
487 { // non base64 character
488 return false;
489 }
490 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
491 ((base64code2 >> 2) & 0x0f));
492 }
493
494 if (++i < inputLength)
495 {
496 char c = input[i];
497 if (c == '=')
498 { // padding , end of input
499 return (base64code2 & 0x03) == 0;
500 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700501 base64code3 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700502 if (base64code3 == nop)
503 { // non base64 character
504 return false;
505 }
506 output +=
507 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
508 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100509 }
510
Ed Tanous1abe55e2018-09-05 08:30:59 -0700511 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100512}
513
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100514namespace details
515{
Ed Tanous22ce5452022-01-11 10:50:23 -0800516constexpr uint64_t maxMilliSeconds = 253402300799999;
517constexpr uint64_t maxSeconds = 253402300799;
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100518inline std::string getDateTime(boost::posix_time::milliseconds timeSinceEpoch)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700519{
Nan Zhou1d8782e2021-11-29 22:23:18 -0800520 boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100521 boost::posix_time::ptime time = epoch + timeSinceEpoch;
Nan Zhou1d8782e2021-11-29 22:23:18 -0800522 // append zero offset to the end according to the Redfish spec for Date-Time
Nan Zhou5ae4b692021-12-14 13:30:37 -0800523 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Nan Zhou1d8782e2021-11-29 22:23:18 -0800524}
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100525} // namespace details
Andrew Geisslercb92c032018-08-17 07:56:14 -0700526
Ed Tanous22ce5452022-01-11 10:50:23 -0800527// Returns the formatted date time string.
528// Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if
529// the given |secondsSinceEpoch| is too large, we return the maximum supported
530// date. This behavior is to avoid exceptions throwed by Boost.
Nan Zhou1d8782e2021-11-29 22:23:18 -0800531inline std::string getDateTimeUint(uint64_t secondsSinceEpoch)
532{
Nan Zhou665479d2022-01-26 12:12:59 -0800533 secondsSinceEpoch = std::min(secondsSinceEpoch, details::maxSeconds);
534 boost::posix_time::seconds boostSeconds(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100535 return details::getDateTime(
536 boost::posix_time::milliseconds(boostSeconds.total_milliseconds()));
537}
538
Ed Tanous22ce5452022-01-11 10:50:23 -0800539// Returns the formatted date time string.
540// Note that the maximum supported date is 9999-12-31T23:59:59.999+00:00, if
541// the given |millisSecondsSinceEpoch| is too large, we return the maximum
542// supported date.
543inline std::string getDateTimeUintMs(uint64_t milliSecondsSinceEpoch)
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100544{
Nan Zhou665479d2022-01-26 12:12:59 -0800545 milliSecondsSinceEpoch =
546 std::min(details::maxMilliSeconds, milliSecondsSinceEpoch);
547 return details::getDateTime(
548 boost::posix_time::milliseconds(milliSecondsSinceEpoch));
Nan Zhou1d8782e2021-11-29 22:23:18 -0800549}
Andrew Geisslercb92c032018-08-17 07:56:14 -0700550
Nan Zhou1d8782e2021-11-29 22:23:18 -0800551inline std::string getDateTimeStdtime(std::time_t secondsSinceEpoch)
552{
Ed Tanous46666f32022-03-03 14:55:16 -0800553 // secondsSinceEpoch >= maxSeconds
554 if constexpr (std::cmp_less_equal(details::maxSeconds,
555 std::numeric_limits<std::time_t>::max()))
Nan Zhou665479d2022-01-26 12:12:59 -0800556 {
Ed Tanous46666f32022-03-03 14:55:16 -0800557 if (std::cmp_greater_equal(secondsSinceEpoch, details::maxSeconds))
558 {
559 secondsSinceEpoch = details::maxSeconds;
560 }
Nan Zhou665479d2022-01-26 12:12:59 -0800561 }
562 boost::posix_time::ptime time =
563 boost::posix_time::from_time_t(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100564 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Andrew Geisslercb92c032018-08-17 07:56:14 -0700565}
566
Tejas Patil7c8c4052021-06-04 17:43:14 +0530567/**
568 * Returns the current Date, Time & the local Time Offset
569 * infromation in a pair
570 *
571 * @param[in] None
572 *
573 * @return std::pair<std::string, std::string>, which consist
574 * of current DateTime & the TimeOffset strings respectively.
575 */
576inline std::pair<std::string, std::string> getDateTimeOffsetNow()
Andrew Geisslercb92c032018-08-17 07:56:14 -0700577{
578 std::time_t time = std::time(nullptr);
Nan Zhou1d8782e2021-11-29 22:23:18 -0800579 std::string dateTime = getDateTimeStdtime(time);
Tejas Patil7c8c4052021-06-04 17:43:14 +0530580
581 /* extract the local Time Offset value from the
582 * recevied dateTime string.
583 */
584 std::string timeOffset("Z00:00");
585 std::size_t lastPos = dateTime.size();
586 std::size_t len = timeOffset.size();
587 if (lastPos > len)
588 {
589 timeOffset = dateTime.substr(lastPos - len);
590 }
591
592 return std::make_pair(dateTime, timeOffset);
Andrew Geisslercb92c032018-08-17 07:56:14 -0700593}
594
Ed Tanous51dae672018-09-05 16:07:32 -0700595inline bool constantTimeStringCompare(const std::string_view a,
596 const std::string_view b)
597{
598 // Important note, this function is ONLY constant time if the two input
599 // sizes are the same
600 if (a.size() != b.size())
601 {
602 return false;
603 }
604 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
605}
606
607struct ConstantTimeCompare
608{
609 bool operator()(const std::string_view a, const std::string_view b) const
610 {
611 return constantTimeStringCompare(a, b);
612 }
613};
614
Ed Tanouseae855c2021-10-26 11:26:02 -0700615namespace details
616{
617inline boost::urls::url
618 urlFromPiecesDetail(const std::initializer_list<std::string_view> args)
619{
620 boost::urls::url url("/");
621 for (const std::string_view& arg : args)
622 {
623 url.segments().push_back(arg);
624 }
625 return url;
626}
627} // namespace details
628
629template <typename... AV>
630inline boost::urls::url urlFromPieces(const AV... args)
631{
632 return details::urlFromPiecesDetail({args...});
633}
634
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100635namespace details
636{
637
638// std::reference_wrapper<std::string> - extracts segment to variable
639// std::string_view - checks if segment is equal to variable
640using UrlSegment =
641 std::variant<std::reference_wrapper<std::string>, std::string_view>;
642
643class UrlSegmentMatcherVisitor
644{
645 public:
646 bool operator()(std::string& output)
647 {
648 output = std::string_view(segment.data(), segment.size());
649 return true;
650 }
651
652 bool operator()(std::string_view expected)
653 {
654 return std::string_view(segment.data(), segment.size()) == expected;
655 }
656
657 UrlSegmentMatcherVisitor(const boost::urls::string_value& segmentIn) :
658 segment(segmentIn)
659 {}
660
661 private:
662 const boost::urls::string_value& segment;
663};
664
665inline bool readUrlSegments(const boost::urls::url_view& urlView,
666 std::initializer_list<UrlSegment>&& segments)
667{
668 const boost::urls::segments_view& urlSegments = urlView.segments();
669
670 if (!urlSegments.is_absolute() || segments.size() != urlSegments.size())
671 {
672 return false;
673 }
674
675 boost::urls::segments_view::iterator it = urlSegments.begin();
676 boost::urls::segments_view::iterator end = urlSegments.end();
677
678 for (const auto& segment : segments)
679 {
680 if (!std::visit(UrlSegmentMatcherVisitor(*it), segment))
681 {
682 return false;
683 }
684 it++;
685 }
686 return true;
687}
688
689} // namespace details
690
691template <typename... Args>
692inline bool readUrlSegments(const boost::urls::url_view& urlView,
693 Args&&... args)
694{
695 return details::readUrlSegments(urlView, {std::forward<Args>(args)...});
696}
697
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800698inline std::string setProtocolDefaults(const boost::urls::url_view& url)
699{
700 if (url.scheme() == "https")
701 {
702 return "https";
703 }
704 if (url.scheme() == "http")
705 {
706 if (bmcwebInsecureEnableHttpPushStyleEventing)
707 {
708 return "http";
709 }
710 return "";
711 }
712 return "";
713}
714
715inline uint16_t setPortDefaults(const boost::urls::url_view& url)
716{
717 uint16_t port = url.port_number();
718 if (port != 0)
719 {
720 // user picked a port already.
721 return port;
722 }
723
724 // If the user hasn't explicitly stated a port, pick one explicitly for them
725 // based on the protocol defaults
726 if (url.scheme() == "http")
727 {
728 return 80;
729 }
730 if (url.scheme() == "https")
731 {
732 return 443;
733 }
734 return 0;
735}
736
Ed Tanous11baefe2022-02-09 12:14:12 -0800737inline bool validateAndSplitUrl(std::string_view destUrl, std::string& urlProto,
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800738 std::string& host, uint16_t& port,
Ed Tanous11baefe2022-02-09 12:14:12 -0800739 std::string& path)
740{
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800741 boost::string_view urlBoost(destUrl.data(), destUrl.size());
742 boost::urls::result<boost::urls::url_view> url =
743 boost::urls::parse_uri(urlBoost);
744 if (!url)
745 {
746 return false;
747 }
748 urlProto = setProtocolDefaults(url.value());
749 if (urlProto.empty())
Ed Tanous11baefe2022-02-09 12:14:12 -0800750 {
751 return false;
752 }
753
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800754 port = setPortDefaults(url.value());
Ed Tanous11baefe2022-02-09 12:14:12 -0800755
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800756 host = std::string_view(url->encoded_host().data(),
757 url->encoded_host().size());
758
759 path = std::string_view(url->encoded_path().data(),
760 url->encoded_path().size());
Ed Tanous11baefe2022-02-09 12:14:12 -0800761 if (path.empty())
762 {
763 path = "/";
764 }
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800765 if (url->has_fragment())
766 {
767 path += '#';
768 path += std::string_view(url->encoded_fragment().data(),
769 url->encoded_fragment().size());
770 }
771
772 if (url->has_query())
773 {
774 path += '?';
775 path += std::string_view(url->encoded_query().data(),
776 url->encoded_query().size());
777 }
778
Ed Tanous11baefe2022-02-09 12:14:12 -0800779 return true;
780}
781
Ed Tanous1abe55e2018-09-05 08:30:59 -0700782} // namespace utility
783} // namespace crow