blob: 6a21eb555fc9c09d91a28b10ae4fa6460caa3123 [file] [log] [blame]
#include "json_utils.h"
#include <cstddef>
#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
#include "absl/log/log.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "nlohmann/json.hpp"
namespace milotic::authz {
namespace {
template <typename ReturnType>
const ReturnType* GetValueAsType(const nlohmann::json& root,
std::string_view key,
[[maybe_unused]] std::string_view type_name) {
if (root.is_discarded()) {
LOG(WARNING) << "Invalid JSON object";
return nullptr;
}
auto it = root.find(key);
if (it == root.end()) {
return nullptr;
}
if constexpr (std::is_same_v<ReturnType, nlohmann::json>) {
return &(*it);
} else {
return it->get_ptr<const ReturnType*>();
}
}
} // namespace
const std::string* GetValueAsString(const nlohmann::json& root,
std::string_view key) {
return GetValueAsType<std::string>(root, key, "string");
}
const std::string* GetValueAsString(
const nlohmann::json& root, const nlohmann::json::json_pointer& pointer) {
if (!root.contains(pointer)) {
return nullptr;
}
return root[pointer].get_ptr<const std::string*>();
}
const nlohmann::json* GetValueAsJson(const nlohmann::json& root,
std::string_view key) {
return GetValueAsType<nlohmann::json>(root, key, "object");
}
const nlohmann::json::array_t* GetValueAsArray(const nlohmann::json& root,
std::string_view key) {
return GetValueAsType<nlohmann::json::array_t>(root, key, "array");
}
const double* GetValueAsDouble(const nlohmann::json& root,
std::string_view key) {
return GetValueAsType<nlohmann::json::number_float_t>(root, key, "number");
}
const int64_t* GetValueAsInt(const nlohmann::json& root, std::string_view key) {
return GetValueAsType<nlohmann::json::number_integer_t>(root, key, "number");
}
const bool* GetValueAsBool(const nlohmann::json& root, std::string_view key) {
return GetValueAsType<nlohmann::json::boolean_t>(root, key, "boolean");
}
const uint64_t* GetValueAsUint(const nlohmann::json& root,
std::string_view key) {
return GetValueAsType<nlohmann::json::number_unsigned_t>(root, key, "number");
}
// The following functions are used to parse from json where the type may vary
// and conversion is accepted. Return a value directly since a pointer cannot be
// made to the temporary value after being converted to desired type.
std::optional<uint64_t> GetValueAsUintFromStringOrInteger(
const nlohmann::json& root, std::string_view key) {
const uint64_t* unsigned_ptr =
GetValueAsType<nlohmann::json::number_unsigned_t>(root, key, "number");
if (unsigned_ptr != nullptr) {
return *unsigned_ptr;
}
const std::string* string_ptr =
GetValueAsType<std::string>(root, key, "string");
if (string_ptr == nullptr) {
LOG(INFO) << absl::StrCat("Invalid json: ", key, " field does not exist ",
root.dump());
return std::nullopt;
}
uint64_t unsigned_value;
bool result;
result = absl::SimpleAtoi(*string_ptr, &unsigned_value);
if (!result) {
LOG(INFO) << absl::StrCat("Invalid json: Failed to convert value at ", key,
" to unsigned value: ", root.dump());
return std::nullopt;
}
LOG(INFO) << "Successfully converted string to unsigned value: "
<< unsigned_value;
return unsigned_value;
}
std::optional<double> GetValueAsDoubleFromFloatOrInteger(
const nlohmann::json& root, std::string_view key) {
const double* double_ptr =
GetValueAsType<nlohmann::json::number_float_t>(root, key, "number");
if (double_ptr != nullptr) {
return *double_ptr;
}
double double_value;
const uint64_t* unsigned_ptr = GetValueAsType<uint64_t>(root, key, "number");
if (unsigned_ptr == nullptr) {
LOG(INFO) << absl::StrCat("Invalid json: Failed to convert value at ", key,
" to double ", root.dump());
return std::nullopt;
}
double_value = static_cast<double>(*unsigned_ptr);
LOG(INFO) << "Successfully converted integer to unsigned value: "
<< double_value;
return double_value;
}
const std::string* GetValueAsStringFromArray(
const nlohmann::json::array_t& array, std::size_t index) {
if (index >= array.size()) {
LOG(INFO) << absl::StrCat("Invalid index: Index ", index,
" is out of range for array of size ",
array.size());
return nullptr;
}
return array[index].get_ptr<const std::string*>();
}
} // namespace milotic::authz