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