• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <sstream>
20 #include <string>
21 #include <vector>
22 
23 #include <google/protobuf/message.h>
24 #include <json/reader.h>
25 #include <json/value.h>
26 #include <jsonpb/jsonpb.h>
27 
28 namespace android {
29 namespace jsonpb {
30 
31 // Ensure that the JSON file has no unknown fields that is not defined in proto.
32 // Because we want forwards compatibility, the parser of JSON files must ignore
33 // unknown fields. This is achievable with libprotobuf version > 3.0-beta.
34 // - <= 3.0-beta: we have to check unknown fields manually, and parser cannot
35 // use libprotobuf
36 //   to parse JSON files.
37 // - < 3.5: libprotobuf discards all unknown fields. We can still check unknown
38 // fields manually, but
39 //   an easier way to check is `json == FormatJson(json)` (schematically)
40 // - >= 3.5: Unknown fields are preserved, so FormatJson() may contain these
41 // unknown fields. We can
42 //   still check fields manually, or use reflection mechanism.
43 //
44 // For example, if a new field "foo" is added to cgroups.json but not to
45 // cgroups.proto, libprocessgroup could technically read the value of "foo" by
46 // using other libraries that parse JSON strings, effectively working around the
47 // schema.
48 //
49 // This test also ensures that the parser does not use alternative key names.
50 // For example, if the proto file states: message Foo { string foo_bar = 1;
51 // string bar_baz = 2 [json_name = "BarBaz"]; } Then the parser accepts
52 // "foo_bar" "fooBar", "bar_baz", "BarBaz" as valid key names. Here, we enforce
53 // that the JSON file must use "foo_bar" and "BarBaz".
54 //
55 // Requiring this avoids surprises like:
56 //     message Foo { string FooBar = 1; }
57 //     { "fooBar" : "s" }
58 // conforms with the schema, because libprotobuf accept "fooBar" as a valid key.
59 // The correct schema should be:
60 //     message Foo { string foo_bar = 1 [json_name="fooBar"]; }
61 //
62 // Params:
63 //    path: path to navigate inside JSON tree. For example, {"foo", "bar"} for
64 //    the value "string" in
65 //          {"foo": {"bar" : "string"}}
66 bool AllFieldsAreKnown(const google::protobuf::Message& message, const std::string& json,
67                        std::string* error);
68 
69 // Format the given JSON string according to Prototype T. This will serialize
70 // the JSON string to a Prototype message, then re-print the message as JSON. By
71 // reformatting the JSON string, we effectively enforces that the JSON source
72 // file uses conventions of Protobuf's JSON writer; e.g. 64-bit integers /
73 // special floating point numbers (inf, NaN, etc.) in strings, enum values in
74 // names, etc.
75 //
76 // Params:
77 //   scratch_space: The scratch space to use to store the Protobuf message. It
78 //   must be a pointer
79 //                  to the schema that the JSON string conforms to.
80 bool EqReformattedJson(const std::string& json, google::protobuf::Message* scratch_space,
81                        std::string* error);
82 
83 namespace internal {
84 // See EqReformattedJson().
85 ErrorOr<std::string> FormatJson(const std::string& json, google::protobuf::Message* scratch_space);
86 
87 }  // namespace internal
88 
89 }  // namespace jsonpb
90 }  // namespace android
91