• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2020 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #ifndef GRPC_SRC_CORE_LIB_JSON_JSON_UTIL_H
20 #define GRPC_SRC_CORE_LIB_JSON_JSON_UTIL_H
21 
22 #include <grpc/support/port_platform.h>
23 
24 #include <algorithm>
25 #include <map>
26 #include <string>
27 #include <type_traits>
28 #include <utility>
29 #include <vector>
30 
31 #include "absl/strings/numbers.h"
32 #include "absl/strings/str_cat.h"
33 #include "absl/strings/string_view.h"
34 
35 #include "src/core/lib/gprpp/time.h"
36 #include "src/core/lib/iomgr/error.h"
37 #include "src/core/lib/json/json.h"
38 
39 namespace grpc_core {
40 
41 // Parses a JSON field of the form generated for a google.proto.Duration
42 // proto message, as per:
43 //   https://developers.google.com/protocol-buffers/docs/proto3#json
44 // Returns true on success, false otherwise.
45 bool ParseDurationFromJson(const Json& field, Duration* duration);
46 
47 //
48 // Helper functions for extracting types from JSON.
49 // Return true on success, false otherwise. If an error is encountered during
50 // parsing, a descriptive error is appended to \a error_list.
51 //
52 template <typename NumericType>
ExtractJsonNumber(const Json & json,absl::string_view field_name,NumericType * output,std::vector<grpc_error_handle> * error_list)53 bool ExtractJsonNumber(const Json& json, absl::string_view field_name,
54                        NumericType* output,
55                        std::vector<grpc_error_handle>* error_list) {
56   static_assert(std::is_integral<NumericType>::value, "Integral required");
57   if (json.type() != Json::Type::kNumber &&
58       json.type() != Json::Type::kString) {
59     error_list->push_back(GRPC_ERROR_CREATE(absl::StrCat(
60         "field:", field_name, " error:type should be NUMBER or STRING")));
61     return false;
62   }
63   if (!absl::SimpleAtoi(json.string(), output)) {
64     error_list->push_back(GRPC_ERROR_CREATE(
65         absl::StrCat("field:", field_name, " error:failed to parse.")));
66     return false;
67   }
68   return true;
69 }
70 
71 bool ExtractJsonBool(const Json& json, absl::string_view field_name,
72                      bool* output, std::vector<grpc_error_handle>* error_list);
73 
74 // OutputType can be std::string or absl::string_view.
75 template <typename OutputType>
ExtractJsonString(const Json & json,absl::string_view field_name,OutputType * output,std::vector<grpc_error_handle> * error_list)76 bool ExtractJsonString(const Json& json, absl::string_view field_name,
77                        OutputType* output,
78                        std::vector<grpc_error_handle>* error_list) {
79   if (json.type() != Json::Type::kString) {
80     *output = "";
81     error_list->push_back(GRPC_ERROR_CREATE(
82         absl::StrCat("field:", field_name, " error:type should be STRING")));
83     return false;
84   }
85   *output = json.string();
86   return true;
87 }
88 
89 bool ExtractJsonArray(const Json& json, absl::string_view field_name,
90                       const Json::Array** output,
91                       std::vector<grpc_error_handle>* error_list);
92 
93 bool ExtractJsonObject(const Json& json, absl::string_view field_name,
94                        const Json::Object** output,
95                        std::vector<grpc_error_handle>* error_list);
96 
97 // Wrappers for automatically choosing one of the above functions based
98 // on output parameter type.
99 template <typename NumericType>
ExtractJsonType(const Json & json,absl::string_view field_name,NumericType * output,std::vector<grpc_error_handle> * error_list)100 inline bool ExtractJsonType(const Json& json, absl::string_view field_name,
101                             NumericType* output,
102                             std::vector<grpc_error_handle>* error_list) {
103   return ExtractJsonNumber(json, field_name, output, error_list);
104 }
ExtractJsonType(const Json & json,absl::string_view field_name,bool * output,std::vector<grpc_error_handle> * error_list)105 inline bool ExtractJsonType(const Json& json, absl::string_view field_name,
106                             bool* output,
107                             std::vector<grpc_error_handle>* error_list) {
108   return ExtractJsonBool(json, field_name, output, error_list);
109 }
ExtractJsonType(const Json & json,absl::string_view field_name,std::string * output,std::vector<grpc_error_handle> * error_list)110 inline bool ExtractJsonType(const Json& json, absl::string_view field_name,
111                             std::string* output,
112                             std::vector<grpc_error_handle>* error_list) {
113   return ExtractJsonString(json, field_name, output, error_list);
114 }
ExtractJsonType(const Json & json,absl::string_view field_name,absl::string_view * output,std::vector<grpc_error_handle> * error_list)115 inline bool ExtractJsonType(const Json& json, absl::string_view field_name,
116                             absl::string_view* output,
117                             std::vector<grpc_error_handle>* error_list) {
118   return ExtractJsonString(json, field_name, output, error_list);
119 }
ExtractJsonType(const Json & json,absl::string_view field_name,const Json::Array ** output,std::vector<grpc_error_handle> * error_list)120 inline bool ExtractJsonType(const Json& json, absl::string_view field_name,
121                             const Json::Array** output,
122                             std::vector<grpc_error_handle>* error_list) {
123   return ExtractJsonArray(json, field_name, output, error_list);
124 }
ExtractJsonType(const Json & json,absl::string_view field_name,const Json::Object ** output,std::vector<grpc_error_handle> * error_list)125 inline bool ExtractJsonType(const Json& json, absl::string_view field_name,
126                             const Json::Object** output,
127                             std::vector<grpc_error_handle>* error_list) {
128   return ExtractJsonObject(json, field_name, output, error_list);
129 }
130 
131 // Extracts a field from a JSON object, automatically selecting the type
132 // of parsing based on the output parameter type.
133 // If the field is not present, returns false, and if required is true,
134 // adds an error to error_list.
135 // Upon any other error, adds an error to error_list and returns false.
136 template <typename T>
137 bool ParseJsonObjectField(const Json::Object& object,
138                           absl::string_view field_name, T* output,
139                           std::vector<grpc_error_handle>* error_list,
140                           bool required = true) {
141   // TODO(roth): Once we can use C++14 heterogenous lookups, stop
142   // creating a std::string here.
143   auto it = object.find(std::string(field_name));
144   if (it == object.end()) {
145     if (required) {
146       error_list->push_back(GRPC_ERROR_CREATE(
147           absl::StrCat("field:", field_name, " error:does not exist.")));
148     }
149     return false;
150   }
151   auto& child_object_json = it->second;
152   return ExtractJsonType(child_object_json, field_name, output, error_list);
153 }
154 
155 // Alternative to ParseJsonObjectField() for duration-value fields.
156 bool ParseJsonObjectFieldAsDuration(const Json::Object& object,
157                                     absl::string_view field_name,
158                                     Duration* output,
159                                     std::vector<grpc_error_handle>* error_list,
160                                     bool required = true);
161 
162 }  // namespace grpc_core
163 
164 #endif  // GRPC_SRC_CORE_LIB_JSON_JSON_UTIL_H
165