rippled
json_get_or_throw.h
1 #ifndef PROTOCOL_GET_OR_THROW_H_
2 #define PROTOCOL_GET_OR_THROW_H_
3 
4 #include <ripple/basics/Buffer.h>
5 #include <ripple/basics/StringUtilities.h>
6 #include <ripple/basics/contract.h>
7 #include <ripple/json/json_value.h>
8 #include <ripple/protocol/SField.h>
9 
10 #include <charconv>
11 #include <exception>
12 #include <optional>
13 #include <string>
14 
15 namespace Json {
17 {
18  char const* const key;
19  mutable std::string msg;
21  {
22  }
23  const char*
24  what() const noexcept override
25  {
26  if (msg.empty())
27  {
28  msg = std::string("Missing json key: ") + key;
29  }
30  return msg.c_str();
31  }
32 };
33 
35 {
36  char const* const key;
38  mutable std::string msg;
40  : key{k.c_str()}, expectedType{std::move(et)}
41  {
42  }
43  const char*
44  what() const noexcept override
45  {
46  if (msg.empty())
47  {
48  msg = std::string("Type mismatch on json key: ") + key +
49  "; expected type: " + expectedType;
50  }
51  return msg.c_str();
52  }
53 };
54 
55 template <class T>
56 T
57 getOrThrow(Json::Value const& v, ripple::SField const& field)
58 {
59  static_assert(sizeof(T) == -1, "This function must be specialized");
60 }
61 
62 template <>
63 inline std::string
64 getOrThrow(Json::Value const& v, ripple::SField const& field)
65 {
66  using namespace ripple;
67  Json::StaticString const& key = field.getJsonName();
68  if (!v.isMember(key))
69  Throw<JsonMissingKeyError>(key);
70 
71  Json::Value const& inner = v[key];
72  if (!inner.isString())
73  Throw<JsonTypeMismatchError>(key, "string");
74  return inner.asString();
75 }
76 
77 // Note, this allows integer numeric fields to act as bools
78 template <>
79 inline bool
80 getOrThrow(Json::Value const& v, ripple::SField const& field)
81 {
82  using namespace ripple;
83  Json::StaticString const& key = field.getJsonName();
84  if (!v.isMember(key))
85  Throw<JsonMissingKeyError>(key);
86  Json::Value const& inner = v[key];
87  if (inner.isBool())
88  return inner.asBool();
89  if (!inner.isIntegral())
90  Throw<JsonTypeMismatchError>(key, "bool");
91 
92  return inner.asInt() != 0;
93 }
94 
95 template <>
96 inline std::uint64_t
97 getOrThrow(Json::Value const& v, ripple::SField const& field)
98 {
99  using namespace ripple;
100  Json::StaticString const& key = field.getJsonName();
101  if (!v.isMember(key))
102  Throw<JsonMissingKeyError>(key);
103  Json::Value const& inner = v[key];
104  if (inner.isUInt())
105  return inner.asUInt();
106  if (inner.isInt())
107  {
108  auto const r = inner.asInt();
109  if (r < 0)
110  Throw<JsonTypeMismatchError>(key, "uint64");
111  return r;
112  }
113  if (inner.isString())
114  {
115  auto const s = inner.asString();
116  // parse as hex
117  std::uint64_t val;
118 
119  auto [p, ec] = std::from_chars(s.data(), s.data() + s.size(), val, 16);
120 
121  if (ec != std::errc() || (p != s.data() + s.size()))
122  Throw<JsonTypeMismatchError>(key, "uint64");
123  return val;
124  }
125  Throw<JsonTypeMismatchError>(key, "uint64");
126 }
127 
128 template <>
129 inline ripple::Buffer
130 getOrThrow(Json::Value const& v, ripple::SField const& field)
131 {
132  using namespace ripple;
133  std::string const hex = getOrThrow<std::string>(v, field);
134  if (auto const r = strUnHex(hex))
135  {
136  // TODO: mismatch between a buffer and a blob
137  return Buffer{r->data(), r->size()};
138  }
139  Throw<JsonTypeMismatchError>(field.getJsonName(), "Buffer");
140 }
141 
142 // This function may be used by external projects (like the witness server).
143 template <class T>
145 getOptional(Json::Value const& v, ripple::SField const& field)
146 {
147  try
148  {
149  return getOrThrow<T>(v, field);
150  }
151  catch (...)
152  {
153  }
154  return {};
155 }
156 
157 } // namespace Json
158 
159 #endif // PROTOCOL_GET_OR_THROW_H_
Json::Value::isInt
bool isInt() const
Definition: json_value.cpp:979
Json::JsonMissingKeyError::key
char const *const key
Definition: json_get_or_throw.h:18
Json::JsonTypeMismatchError::key
char const *const key
Definition: json_get_or_throw.h:36
std::string
STL class.
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
exception
charconv
Json::JsonMissingKeyError::JsonMissingKeyError
JsonMissingKeyError(Json::StaticString const &k)
Definition: json_get_or_throw.h:20
Json::JsonTypeMismatchError::what
const char * what() const noexcept override
Definition: json_get_or_throw.h:44
Json::JsonMissingKeyError
Definition: json_get_or_throw.h:16
Json::getOrThrow
ripple::AccountID getOrThrow(Json::Value const &v, ripple::SField const &field)
Definition: AccountID.h:132
ripple::Buffer
Like std::vector<char> but better.
Definition: Buffer.h:35
Json::StaticString::c_str
constexpr const char * c_str() const
Definition: json_value.h:73
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:619
std::hex
T hex(T... args)
Json::JsonTypeMismatchError::expectedType
const std::string expectedType
Definition: json_get_or_throw.h:37
Json
JSON (JavaScript Object Notation).
Definition: DeliverMax.h:28
Json::JsonTypeMismatchError::msg
std::string msg
Definition: json_get_or_throw.h:38
std::string::c_str
T c_str(T... args)
Json::JsonMissingKeyError::what
const char * what() const noexcept override
Definition: json_get_or_throw.h:24
std::errc
ripple::Buffer::data
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition: Buffer.h:150
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
std::uint64_t
std::from_chars
T from_chars(T... args)
Json::JsonTypeMismatchError::JsonTypeMismatchError
JsonTypeMismatchError(Json::StaticString const &k, std::string et)
Definition: json_get_or_throw.h:39
Json::JsonTypeMismatchError
Definition: json_get_or_throw.h:34
beast::field
field_t< CharT, Traits, Allocator > field(std::basic_string< CharT, Traits, Allocator > const &text, int width=8, int pad=0, bool right=false)
Definition: iosformat.h:162
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::SField
Identifies fields.
Definition: SField.h:141
Json::StaticString
Lightweight wrapper to tag static string.
Definition: json_value.h:60
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
Json::Value::isUInt
bool isUInt() const
Definition: json_value.cpp:985
Json::Value::isIntegral
bool isIntegral() const
Definition: json_value.cpp:991
std::string::empty
T empty(T... args)
optional
Json::Value::isBool
bool isBool() const
Definition: json_value.cpp:973
Json::JsonMissingKeyError::msg
std::string msg
Definition: json_get_or_throw.h:19
Json::Value::asInt
Int asInt() const
Definition: json_value.cpp:503
Json::getOptional
std::optional< T > getOptional(Json::Value const &v, ripple::SField const &field)
Definition: json_get_or_throw.h:145
ripple::strUnHex
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Definition: StringUtilities.h:52
Json::Value
Represents a JSON value.
Definition: json_value.h:145
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
string