• 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_UTIL_JSON_JSON_UTIL_H
20 #define GRPC_SRC_CORE_UTIL_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 #include "src/core/lib/iomgr/error.h"
35 #include "src/core/util/json/json.h"
36 #include "src/core/util/time.h"
37 
38 namespace grpc_core {
39 
40 // Parses a JSON field of the form generated for a google.proto.Duration
41 // proto message, as per:
42 //   https://developers.google.com/protocol-buffers/docs/proto3#json
43 // Returns true on success, false otherwise.
44 bool ParseDurationFromJson(const Json& field, Duration* duration);
45 
46 //
47 // Helper functions for extracting types from JSON.
48 // Return true on success, false otherwise. If an error is encountered during
49 // parsing, a descriptive error is appended to \a error_list.
50 //
51 template <typename NumericType>
ExtractJsonNumber(const Json & json,absl::string_view field_name,NumericType * output,std::vector<grpc_error_handle> * error_list)52 bool ExtractJsonNumber(const Json& json, absl::string_view field_name,
53                        NumericType* output,
54                        std::vector<grpc_error_handle>* error_list) {
55   static_assert(std::is_integral<NumericType>::value, "Integral required");
56   if (json.type() != Json::Type::kNumber &&
57       json.type() != Json::Type::kString) {
58     error_list->push_back(GRPC_ERROR_CREATE(absl::StrCat(
59         "field:", field_name, " error:type should be NUMBER or STRING")));
60     return false;
61   }
62   if (!absl::SimpleAtoi(json.string(), output)) {
63     error_list->push_back(GRPC_ERROR_CREATE(
64         absl::StrCat("field:", field_name, " error:failed to parse.")));
65     return false;
66   }
67   return true;
68 }
69 
70 bool ExtractJsonBool(const Json& json, absl::string_view field_name,
71                      bool* output, std::vector<grpc_error_handle>* error_list);
72 
73 // OutputType can be std::string or absl::string_view.
74 template <typename OutputType>
ExtractJsonString(const Json & json,absl::string_view field_name,OutputType * output,std::vector<grpc_error_handle> * error_list)75 bool ExtractJsonString(const Json& json, absl::string_view field_name,
76                        OutputType* output,
77                        std::vector<grpc_error_handle>* error_list) {
78   if (json.type() != Json::Type::kString) {
79     *output = "";
80     error_list->push_back(GRPC_ERROR_CREATE(
81         absl::StrCat("field:", field_name, " error:type should be STRING")));
82     return false;
83   }
84   *output = json.string();
85   return true;
86 }
87 
88 bool ExtractJsonArray(const Json& json, absl::string_view field_name,
89                       const Json::Array** output,
90                       std::vector<grpc_error_handle>* error_list);
91 
92 bool ExtractJsonObject(const Json& json, absl::string_view field_name,
93                        const Json::Object** output,
94                        std::vector<grpc_error_handle>* error_list);
95 
96 // Wrappers for automatically choosing one of the above functions based
97 // on output parameter type.
98 template <typename NumericType>
ExtractJsonType(const Json & json,absl::string_view field_name,NumericType * output,std::vector<grpc_error_handle> * error_list)99 inline bool ExtractJsonType(const Json& json, absl::string_view field_name,
100                             NumericType* output,
101                             std::vector<grpc_error_handle>* error_list) {
102   return ExtractJsonNumber(json, field_name, output, error_list);
103 }
ExtractJsonType(const Json & json,absl::string_view field_name,bool * output,std::vector<grpc_error_handle> * error_list)104 inline bool ExtractJsonType(const Json& json, absl::string_view field_name,
105                             bool* output,
106                             std::vector<grpc_error_handle>* error_list) {
107   return ExtractJsonBool(json, field_name, output, error_list);
108 }
ExtractJsonType(const Json & json,absl::string_view field_name,std::string * output,std::vector<grpc_error_handle> * error_list)109 inline bool ExtractJsonType(const Json& json, absl::string_view field_name,
110                             std::string* output,
111                             std::vector<grpc_error_handle>* error_list) {
112   return ExtractJsonString(json, field_name, output, error_list);
113 }
ExtractJsonType(const Json & json,absl::string_view field_name,absl::string_view * output,std::vector<grpc_error_handle> * error_list)114 inline bool ExtractJsonType(const Json& json, absl::string_view field_name,
115                             absl::string_view* output,
116                             std::vector<grpc_error_handle>* error_list) {
117   return ExtractJsonString(json, field_name, output, error_list);
118 }
ExtractJsonType(const Json & json,absl::string_view field_name,const Json::Array ** output,std::vector<grpc_error_handle> * error_list)119 inline bool ExtractJsonType(const Json& json, absl::string_view field_name,
120                             const Json::Array** output,
121                             std::vector<grpc_error_handle>* error_list) {
122   return ExtractJsonArray(json, field_name, output, error_list);
123 }
ExtractJsonType(const Json & json,absl::string_view field_name,const Json::Object ** output,std::vector<grpc_error_handle> * error_list)124 inline bool ExtractJsonType(const Json& json, absl::string_view field_name,
125                             const Json::Object** output,
126                             std::vector<grpc_error_handle>* error_list) {
127   return ExtractJsonObject(json, field_name, output, error_list);
128 }
129 
130 // Extracts a field from a JSON object, automatically selecting the type
131 // of parsing based on the output parameter type.
132 // If the field is not present, returns false, and if required is true,
133 // adds an error to error_list.
134 // Upon any other error, adds an error to error_list and returns false.
135 template <typename T>
136 bool ParseJsonObjectField(const Json::Object& object,
137                           absl::string_view field_name, T* output,
138                           std::vector<grpc_error_handle>* error_list,
139                           bool required = true) {
140   // TODO(roth): Once we can use C++14 heterogenous lookups, stop
141   // creating a std::string here.
142   auto it = object.find(std::string(field_name));
143   if (it == object.end()) {
144     if (required) {
145       error_list->push_back(GRPC_ERROR_CREATE(
146           absl::StrCat("field:", field_name, " error:does not exist.")));
147     }
148     return false;
149   }
150   auto& child_object_json = it->second;
151   return ExtractJsonType(child_object_json, field_name, output, error_list);
152 }
153 
154 // Alternative to ParseJsonObjectField() for duration-value fields.
155 bool ParseJsonObjectFieldAsDuration(const Json::Object& object,
156                                     absl::string_view field_name,
157                                     Duration* output,
158                                     std::vector<grpc_error_handle>* error_list,
159                                     bool required = true);
160 
161 }  // namespace grpc_core
162 
163 #endif  // GRPC_SRC_CORE_UTIL_JSON_JSON_UTIL_H
164