summaryrefslogtreecommitdiff
path: root/http/utility.hpp
diff options
context:
space:
mode:
authorEd Tanous <ed@tanous.net>2020-10-03 18:06:26 +0300
committerEd Tanous <ed@tanous.net>2020-10-23 18:03:17 +0300
commit04e438cbad66838724d78ce12f28aff1fb892a63 (patch)
tree8d8c42a8b3d3e9f8e10c108dd6273e8185d04530 /http/utility.hpp
parentdc511aa73001a593a16dbcdaa5d53f320e4c7818 (diff)
downloadbmcweb-04e438cbad66838724d78ce12f28aff1fb892a63.tar.xz
fix include names
cppcheck isn't smart enough to recognize these are c++ headers, not c headers. Considering we're already inconsistent about our naming, it's easier to just be consistent, and move the last few files to use .hpp instead of .h. Tested: Code builds, no changes. Signed-off-by: Ed Tanous <ed@tanous.net> Change-Id: Ic348d695f8527fa4a0ded53f433e1558c319db40
Diffstat (limited to 'http/utility.hpp')
-rw-r--r--http/utility.hpp573
1 files changed, 573 insertions, 0 deletions
diff --git a/http/utility.hpp b/http/utility.hpp
new file mode 100644
index 0000000000..5a184cce18
--- /dev/null
+++ b/http/utility.hpp
@@ -0,0 +1,573 @@
+#pragma once
+
+#include "nlohmann/json.hpp"
+
+#include <openssl/crypto.h>
+
+#include <cstdint>
+#include <cstring>
+#include <functional>
+#include <regex>
+#include <stdexcept>
+#include <string>
+#include <tuple>
+
+namespace crow
+{
+namespace black_magic
+{
+
+constexpr unsigned findClosingTag(std::string_view s, unsigned p)
+{
+ return s[p] == '>' ? p : findClosingTag(s, p + 1);
+}
+
+constexpr bool isInt(std::string_view s, unsigned i)
+{
+ return s.substr(i, 5) == "<int>";
+}
+
+constexpr bool isUint(std::string_view s, unsigned i)
+{
+ return s.substr(i, 6) == "<uint>";
+}
+
+constexpr bool isFloat(std::string_view s, unsigned i)
+{
+ return s.substr(i, 7) == "<float>" || s.substr(i, 8) == "<double>";
+}
+
+constexpr bool isStr(std::string_view s, unsigned i)
+{
+ return s.substr(i, 5) == "<str>" || s.substr(i, 8) == "<string>";
+}
+
+constexpr bool isPath(std::string_view s, unsigned i)
+{
+ return s.substr(i, 6) == "<path>";
+}
+
+template <typename T>
+constexpr int getParameterTag()
+{
+ if constexpr (std::is_same_v<int, T>)
+ {
+ return 1;
+ }
+ if constexpr (std::is_same_v<char, T>)
+ {
+ return 1;
+ }
+ if constexpr (std::is_same_v<short, T>)
+ {
+ return 1;
+ }
+ if constexpr (std::is_same_v<long, T>)
+ {
+ return 1;
+ }
+ if constexpr (std::is_same_v<long long, T>)
+ {
+ return 1;
+ }
+ if constexpr (std::is_same_v<unsigned int, T>)
+ {
+ return 2;
+ }
+ if constexpr (std::is_same_v<unsigned char, T>)
+ {
+ return 2;
+ }
+ if constexpr (std::is_same_v<unsigned short, T>)
+ {
+ return 2;
+ }
+ if constexpr (std::is_same_v<unsigned long, T>)
+ {
+ return 2;
+ }
+ if constexpr (std::is_same_v<unsigned long long, T>)
+ {
+ return 2;
+ }
+ if constexpr (std::is_same_v<double, T>)
+ {
+ return 3;
+ }
+ if constexpr (std::is_same_v<std::string, T>)
+ {
+ return 4;
+ }
+ return 0;
+}
+
+template <typename... Args>
+struct computeParameterTagFromArgsList;
+
+template <>
+struct computeParameterTagFromArgsList<>
+{
+ static constexpr int value = 0;
+};
+
+template <typename Arg, typename... Args>
+struct computeParameterTagFromArgsList<Arg, Args...>
+{
+ static constexpr int subValue =
+ computeParameterTagFromArgsList<Args...>::value;
+ static constexpr int value =
+ getParameterTag<typename std::decay<Arg>::type>()
+ ? subValue * 6 + getParameterTag<typename std::decay<Arg>::type>()
+ : subValue;
+};
+
+inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
+{
+ if (a == 0)
+ {
+ return b == 0;
+ }
+ if (b == 0)
+ {
+ return a == 0;
+ }
+ uint64_t sa = a % 6;
+ uint64_t sb = a % 6;
+ if (sa == 5)
+ {
+ sa = 4;
+ }
+ if (sb == 5)
+ {
+ sb = 4;
+ }
+ if (sa != sb)
+ {
+ return false;
+ }
+ return isParameterTagCompatible(a / 6, b / 6);
+}
+
+constexpr uint64_t getParameterTag(std::string_view s, unsigned p = 0)
+{
+ if (p == s.size())
+ {
+ return 0;
+ }
+
+ if (s[p] != '<')
+ {
+ return getParameterTag(s, p + 1);
+ }
+
+ if (isInt(s, p))
+ {
+ return getParameterTag(s, findClosingTag(s, p)) * 6 + 1;
+ }
+
+ if (isUint(s, p))
+ {
+ return getParameterTag(s, findClosingTag(s, p)) * 6 + 2;
+ }
+
+ if (isFloat(s, p))
+ {
+ return getParameterTag(s, findClosingTag(s, p)) * 6 + 3;
+ }
+
+ if (isStr(s, p))
+ {
+ return getParameterTag(s, findClosingTag(s, p)) * 6 + 4;
+ }
+
+ if (isPath(s, p))
+ {
+ return getParameterTag(s, findClosingTag(s, p)) * 6 + 5;
+ }
+
+ throw std::runtime_error("invalid parameter type");
+}
+
+template <typename... T>
+struct S
+{
+ template <typename U>
+ using push = S<U, T...>;
+ template <typename U>
+ using push_back = S<T..., U>;
+ template <template <typename... Args> class U>
+ using rebind = U<T...>;
+};
+
+template <typename F, typename Set>
+struct CallHelper;
+
+template <typename F, typename... Args>
+struct CallHelper<F, S<Args...>>
+{
+ template <typename F1, typename... Args1,
+ typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
+ static char test(int);
+
+ template <typename...>
+ static int test(...);
+
+ static constexpr bool value = sizeof(test<F, Args...>(0)) == sizeof(char);
+};
+
+template <uint64_t N>
+struct SingleTagToType
+{};
+
+template <>
+struct SingleTagToType<1>
+{
+ using type = int64_t;
+};
+
+template <>
+struct SingleTagToType<2>
+{
+ using type = uint64_t;
+};
+
+template <>
+struct SingleTagToType<3>
+{
+ using type = double;
+};
+
+template <>
+struct SingleTagToType<4>
+{
+ using type = std::string;
+};
+
+template <>
+struct SingleTagToType<5>
+{
+ using type = std::string;
+};
+
+template <uint64_t Tag>
+struct Arguments
+{
+ using subarguments = typename Arguments<Tag / 6>::type;
+ using type = typename subarguments::template push<
+ typename SingleTagToType<Tag % 6>::type>;
+};
+
+template <>
+struct Arguments<0>
+{
+ using type = S<>;
+};
+
+template <typename T>
+struct Promote
+{
+ using type = T;
+};
+
+template <typename T>
+using PromoteT = typename Promote<T>::type;
+
+template <>
+struct Promote<char>
+{
+ using type = int64_t;
+};
+template <>
+struct Promote<short>
+{
+ using type = int64_t;
+};
+template <>
+struct Promote<int>
+{
+ using type = int64_t;
+};
+template <>
+struct Promote<long>
+{
+ using type = int64_t;
+};
+template <>
+struct Promote<long long>
+{
+ using type = int64_t;
+};
+template <>
+struct Promote<unsigned char>
+{
+ using type = uint64_t;
+};
+template <>
+struct Promote<unsigned short>
+{
+ using type = uint64_t;
+};
+template <>
+struct Promote<unsigned int>
+{
+ using type = uint64_t;
+};
+template <>
+struct Promote<unsigned long>
+{
+ using type = uint64_t;
+};
+template <>
+struct Promote<unsigned long long>
+{
+ using type = uint64_t;
+};
+
+} // namespace black_magic
+
+namespace detail
+{
+
+template <class T, std::size_t N, class... Args>
+struct GetIndexOfElementFromTupleByTypeImpl
+{
+ static constexpr std::size_t value = N;
+};
+
+template <class T, std::size_t N, class... Args>
+struct GetIndexOfElementFromTupleByTypeImpl<T, N, T, Args...>
+{
+ static constexpr std::size_t value = N;
+};
+
+template <class T, std::size_t N, class U, class... Args>
+struct GetIndexOfElementFromTupleByTypeImpl<T, N, U, Args...>
+{
+ static constexpr std::size_t value =
+ GetIndexOfElementFromTupleByTypeImpl<T, N + 1, Args...>::value;
+};
+
+} // namespace detail
+
+namespace utility
+{
+template <class T, class... Args>
+T& getElementByType(std::tuple<Args...>& t)
+{
+ return std::get<
+ detail::GetIndexOfElementFromTupleByTypeImpl<T, 0, Args...>::value>(t);
+}
+
+template <typename T>
+struct function_traits;
+
+template <typename T>
+struct function_traits : public function_traits<decltype(&T::operator())>
+{
+ using parent_t = function_traits<decltype(&T::operator())>;
+ static const size_t arity = parent_t::arity;
+ using result_type = typename parent_t::result_type;
+ template <size_t i>
+ using arg = typename parent_t::template arg<i>;
+};
+
+template <typename ClassType, typename r, typename... Args>
+struct function_traits<r (ClassType::*)(Args...) const>
+{
+ static const size_t arity = sizeof...(Args);
+
+ using result_type = r;
+
+ template <size_t i>
+ using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
+};
+
+template <typename ClassType, typename r, typename... Args>
+struct function_traits<r (ClassType::*)(Args...)>
+{
+ static const size_t arity = sizeof...(Args);
+
+ using result_type = r;
+
+ template <size_t i>
+ using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
+};
+
+template <typename r, typename... Args>
+struct function_traits<std::function<r(Args...)>>
+{
+ static const size_t arity = sizeof...(Args);
+
+ using result_type = r;
+
+ template <size_t i>
+ using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
+};
+
+// TODO this is temporary and should be deleted once base64 is refactored out of
+// crow
+inline bool base64Decode(const std::string_view input, std::string& output)
+{
+ static const char nop = static_cast<char>(-1);
+ // See note on encoding_data[] in above function
+ static const std::array<char, 256> decodingData = {
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop};
+
+ size_t inputLength = input.size();
+
+ // allocate space for output string
+ output.clear();
+ output.reserve(((inputLength + 2) / 3) * 4);
+
+ auto getCodeValue = [](char c) {
+ auto code = static_cast<unsigned char>(c);
+ // Ensure we cannot index outside the bounds of the decoding array
+ static_assert(std::numeric_limits<decltype(code)>::max() <
+ decodingData.size());
+ return decodingData[code];
+ };
+
+ // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
+ // dropping first two bits
+ // and regenerate into 3 8-bits sequences
+
+ for (size_t i = 0; i < inputLength; i++)
+ {
+ char base64code0;
+ char base64code1;
+ char base64code2 = 0; // initialized to 0 to suppress warnings
+ char base64code3;
+
+ base64code0 = getCodeValue(input[i]);
+ if (base64code0 == nop)
+ { // non base64 character
+ return false;
+ }
+ if (!(++i < inputLength))
+ { // we need at least two input bytes for first
+ // byte output
+ return false;
+ }
+ base64code1 = getCodeValue(input[i]);
+ if (base64code1 == nop)
+ { // non base64 character
+ return false;
+ }
+ output +=
+ static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
+
+ if (++i < inputLength)
+ {
+ char c = input[i];
+ if (c == '=')
+ { // padding , end of input
+ return (base64code1 & 0x0f) == 0;
+ }
+ base64code2 = getCodeValue(input[i]);
+ if (base64code2 == nop)
+ { // non base64 character
+ return false;
+ }
+ output += static_cast<char>(((base64code1 << 4) & 0xf0) |
+ ((base64code2 >> 2) & 0x0f));
+ }
+
+ if (++i < inputLength)
+ {
+ char c = input[i];
+ if (c == '=')
+ { // padding , end of input
+ return (base64code2 & 0x03) == 0;
+ }
+ base64code3 = getCodeValue(input[i]);
+ if (base64code3 == nop)
+ { // non base64 character
+ return false;
+ }
+ output +=
+ static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Method returns Date Time information according to requested format
+ *
+ * @param[in] time time in second since the Epoch
+ *
+ * @return Date Time according to requested format
+ */
+inline std::string getDateTime(const std::time_t& time)
+{
+ std::array<char, 128> dateTime;
+ std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
+
+ if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
+ std::localtime(&time)))
+ {
+ // insert the colon required by the ISO 8601 standard
+ redfishDateTime = std::string(dateTime.data());
+ redfishDateTime.insert(redfishDateTime.end() - 2, ':');
+ }
+
+ return redfishDateTime;
+}
+
+inline std::string dateTimeNow()
+{
+ std::time_t time = std::time(nullptr);
+ return getDateTime(time);
+}
+
+inline bool constantTimeStringCompare(const std::string_view a,
+ const std::string_view b)
+{
+ // Important note, this function is ONLY constant time if the two input
+ // sizes are the same
+ if (a.size() != b.size())
+ {
+ return false;
+ }
+ return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
+}
+
+struct ConstantTimeCompare
+{
+ bool operator()(const std::string_view a, const std::string_view b) const
+ {
+ return constantTimeStringCompare(a, b);
+ }
+};
+
+inline std::time_t getTimestamp(uint64_t millisTimeStamp)
+{
+ // Retrieve Created property with format:
+ // yyyy-mm-ddThh:mm:ss
+ std::chrono::milliseconds chronoTimeStamp(millisTimeStamp);
+ return std::chrono::duration_cast<std::chrono::duration<int>>(
+ chronoTimeStamp)
+ .count();
+}
+
+} // namespace utility
+} // namespace crow