• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/core/util/json/json_object_loader.h"
16 
17 #include <grpc/support/json.h>
18 #include <grpc/support/port_platform.h>
19 
20 #include <utility>
21 
22 #include "absl/strings/ascii.h"
23 #include "absl/strings/str_cat.h"
24 #include "absl/strings/strip.h"
25 
26 namespace grpc_core {
27 namespace json_detail {
28 
LoadInto(const Json & json,const JsonArgs &,void * dst,ValidationErrors * errors) const29 void LoadScalar::LoadInto(const Json& json, const JsonArgs& /*args*/, void* dst,
30                           ValidationErrors* errors) const {
31   // We accept either kString or kNumber for numeric values, as per
32   // https://developers.google.com/protocol-buffers/docs/proto3#json.
33   if (json.type() != Json::Type::kString &&
34       (!IsNumber() || json.type() != Json::Type::kNumber)) {
35     errors->AddError(
36         absl::StrCat("is not a ", IsNumber() ? "number" : "string"));
37     return;
38   }
39   return LoadInto(json.string(), dst, errors);
40 }
41 
IsNumber() const42 bool LoadString::IsNumber() const { return false; }
43 
LoadInto(const std::string & value,void * dst,ValidationErrors *) const44 void LoadString::LoadInto(const std::string& value, void* dst,
45                           ValidationErrors*) const {
46   *static_cast<std::string*>(dst) = value;
47 }
48 
IsNumber() const49 bool LoadDuration::IsNumber() const { return false; }
50 
LoadInto(const std::string & value,void * dst,ValidationErrors * errors) const51 void LoadDuration::LoadInto(const std::string& value, void* dst,
52                             ValidationErrors* errors) const {
53   absl::string_view buf(value);
54   if (!absl::ConsumeSuffix(&buf, "s")) {
55     errors->AddError("Not a duration (no s suffix)");
56     return;
57   }
58   buf = absl::StripAsciiWhitespace(buf);
59   auto decimal_point = buf.find('.');
60   int32_t nanos = 0;
61   if (decimal_point != absl::string_view::npos) {
62     absl::string_view after_decimal = buf.substr(decimal_point + 1);
63     buf = buf.substr(0, decimal_point);
64     if (!absl::SimpleAtoi(after_decimal, &nanos)) {
65       errors->AddError("Not a duration (not a number of nanoseconds)");
66       return;
67     }
68     if (after_decimal.length() > 9) {
69       // We don't accept greater precision than nanos.
70       errors->AddError("Not a duration (too many digits after decimal)");
71       return;
72     }
73     for (size_t i = 0; i < (9 - after_decimal.length()); ++i) {
74       nanos *= 10;
75     }
76   }
77   int64_t seconds;
78   if (!absl::SimpleAtoi(buf, &seconds)) {
79     errors->AddError("Not a duration (not a number of seconds)");
80     return;
81   }
82   // Acceptable range for seconds documented at
83   // https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Duration
84   if (seconds < 0 || seconds > 315576000000) {
85     errors->AddError("seconds must be in the range [0, 315576000000]");
86   }
87   *static_cast<Duration*>(dst) =
88       Duration::FromSecondsAndNanoseconds(seconds, nanos);
89 }
90 
IsNumber() const91 bool LoadNumber::IsNumber() const { return true; }
92 
LoadInto(const Json & json,const JsonArgs &,void * dst,ValidationErrors * errors) const93 void LoadBool::LoadInto(const Json& json, const JsonArgs&, void* dst,
94                         ValidationErrors* errors) const {
95   if (json.type() != Json::Type::kBoolean) {
96     errors->AddError("is not a boolean");
97     return;
98   }
99   *static_cast<bool*>(dst) = json.boolean();
100 }
101 
LoadInto(const Json & json,const JsonArgs &,void * dst,ValidationErrors * errors) const102 void LoadUnprocessedJsonObject::LoadInto(const Json& json, const JsonArgs&,
103                                          void* dst,
104                                          ValidationErrors* errors) const {
105   if (json.type() != Json::Type::kObject) {
106     errors->AddError("is not an object");
107     return;
108   }
109   *static_cast<Json::Object*>(dst) = json.object();
110 }
111 
LoadInto(const Json & json,const JsonArgs &,void * dst,ValidationErrors * errors) const112 void LoadUnprocessedJsonArray::LoadInto(const Json& json, const JsonArgs&,
113                                         void* dst,
114                                         ValidationErrors* errors) const {
115   if (json.type() != Json::Type::kArray) {
116     errors->AddError("is not an array");
117     return;
118   }
119   *static_cast<Json::Array*>(dst) = json.array();
120 }
121 
LoadInto(const Json & json,const JsonArgs & args,void * dst,ValidationErrors * errors) const122 void LoadVector::LoadInto(const Json& json, const JsonArgs& args, void* dst,
123                           ValidationErrors* errors) const {
124   if (json.type() != Json::Type::kArray) {
125     errors->AddError("is not an array");
126     return;
127   }
128   const auto& array = json.array();
129   const LoaderInterface* element_loader = ElementLoader();
130   for (size_t i = 0; i < array.size(); ++i) {
131     ValidationErrors::ScopedField field(errors, absl::StrCat("[", i, "]"));
132     void* element = EmplaceBack(dst);
133     element_loader->LoadInto(array[i], args, element, errors);
134   }
135 }
136 
LoadInto(const Json & json,const JsonArgs & args,void * dst,ValidationErrors * errors) const137 void AutoLoader<std::vector<bool>>::LoadInto(const Json& json,
138                                              const JsonArgs& args, void* dst,
139                                              ValidationErrors* errors) const {
140   if (json.type() != Json::Type::kArray) {
141     errors->AddError("is not an array");
142     return;
143   }
144   const auto& array = json.array();
145   const LoaderInterface* element_loader = LoaderForType<bool>();
146   std::vector<bool>* vec = static_cast<std::vector<bool>*>(dst);
147   for (size_t i = 0; i < array.size(); ++i) {
148     ValidationErrors::ScopedField field(errors, absl::StrCat("[", i, "]"));
149     bool elem = false;
150     element_loader->LoadInto(array[i], args, &elem, errors);
151     vec->push_back(elem);
152   }
153 }
154 
LoadInto(const Json & json,const JsonArgs & args,void * dst,ValidationErrors * errors) const155 void LoadMap::LoadInto(const Json& json, const JsonArgs& args, void* dst,
156                        ValidationErrors* errors) const {
157   if (json.type() != Json::Type::kObject) {
158     errors->AddError("is not an object");
159     return;
160   }
161   const LoaderInterface* element_loader = ElementLoader();
162   for (const auto& pair : json.object()) {
163     ValidationErrors::ScopedField field(errors,
164                                         absl::StrCat("[\"", pair.first, "\"]"));
165     void* element = Insert(pair.first, dst);
166     element_loader->LoadInto(pair.second, args, element, errors);
167   }
168 }
169 
LoadInto(const Json & json,const JsonArgs & args,void * dst,ValidationErrors * errors) const170 void LoadWrapped::LoadInto(const Json& json, const JsonArgs& args, void* dst,
171                            ValidationErrors* errors) const {
172   void* element = Emplace(dst);
173   size_t starting_error_size = errors->size();
174   ElementLoader()->LoadInto(json, args, element, errors);
175   if (errors->size() > starting_error_size) Reset(dst);
176 }
177 
LoadObject(const Json & json,const JsonArgs & args,const Element * elements,size_t num_elements,void * dst,ValidationErrors * errors)178 bool LoadObject(const Json& json, const JsonArgs& args, const Element* elements,
179                 size_t num_elements, void* dst, ValidationErrors* errors) {
180   if (json.type() != Json::Type::kObject) {
181     errors->AddError("is not an object");
182     return false;
183   }
184   for (size_t i = 0; i < num_elements; ++i) {
185     const Element& element = elements[i];
186     if (element.enable_key != nullptr && !args.IsEnabled(element.enable_key)) {
187       continue;
188     }
189     ValidationErrors::ScopedField field(errors,
190                                         absl::StrCat(".", element.name));
191     const auto& it = json.object().find(element.name);
192     if (it == json.object().end() || it->second.type() == Json::Type::kNull) {
193       if (element.optional) continue;
194       errors->AddError("field not present");
195       continue;
196     }
197     char* field_dst = static_cast<char*>(dst) + element.member_offset;
198     element.loader->LoadInto(it->second, args, field_dst, errors);
199   }
200   return true;
201 }
202 
GetJsonObjectField(const Json::Object & json,absl::string_view field,ValidationErrors * errors,bool required)203 const Json* GetJsonObjectField(const Json::Object& json,
204                                absl::string_view field,
205                                ValidationErrors* errors, bool required) {
206   auto it = json.find(std::string(field));
207   if (it == json.end()) {
208     if (required) errors->AddError("field not present");
209     return nullptr;
210   }
211   return &it->second;
212 }
213 
214 }  // namespace json_detail
215 }  // namespace grpc_core
216