xref: /aosp_15_r20/external/cronet/base/json/json_reader.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/json/json_reader.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <string_view>
8*6777b538SAndroid Build Coastguard Worker #include <utility>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include "base/features.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/rust_buildflags.h"
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(BUILD_RUST_JSON_READER)
16*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_piece_rust.h"
17*6777b538SAndroid Build Coastguard Worker #include "third_party/rust/serde_json_lenient/v0_2/wrapper/functions.h"
18*6777b538SAndroid Build Coastguard Worker #include "third_party/rust/serde_json_lenient/v0_2/wrapper/lib.rs.h"
19*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(BUILD_RUST_JSON_READER)
20*6777b538SAndroid Build Coastguard Worker #include "base/json/json_parser.h"
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker namespace base {
23*6777b538SAndroid Build Coastguard Worker 
24*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(BUILD_RUST_JSON_READER)
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker namespace {
27*6777b538SAndroid Build Coastguard Worker using serde_json_lenient::ContextPointer;
28*6777b538SAndroid Build Coastguard Worker 
29*6777b538SAndroid Build Coastguard Worker const char kSecurityJsonParsingTime[] = "Security.JSONParser.ParsingTime";
30*6777b538SAndroid Build Coastguard Worker 
ListAppendList(ContextPointer & ctx,size_t reserve)31*6777b538SAndroid Build Coastguard Worker ContextPointer& ListAppendList(ContextPointer& ctx, size_t reserve) {
32*6777b538SAndroid Build Coastguard Worker   auto& value = reinterpret_cast<base::Value&>(ctx);
33*6777b538SAndroid Build Coastguard Worker   value.GetList().reserve(reserve);
34*6777b538SAndroid Build Coastguard Worker   value.GetList().Append(base::Value::List());
35*6777b538SAndroid Build Coastguard Worker   return reinterpret_cast<ContextPointer&>(value.GetList().back());
36*6777b538SAndroid Build Coastguard Worker }
37*6777b538SAndroid Build Coastguard Worker 
ListAppendDict(ContextPointer & ctx)38*6777b538SAndroid Build Coastguard Worker ContextPointer& ListAppendDict(ContextPointer& ctx) {
39*6777b538SAndroid Build Coastguard Worker   auto& value = reinterpret_cast<base::Value&>(ctx);
40*6777b538SAndroid Build Coastguard Worker   value.GetList().Append(base::Value::Dict());
41*6777b538SAndroid Build Coastguard Worker   return reinterpret_cast<ContextPointer&>(value.GetList().back());
42*6777b538SAndroid Build Coastguard Worker }
43*6777b538SAndroid Build Coastguard Worker 
ListAppendNone(ContextPointer & ctx)44*6777b538SAndroid Build Coastguard Worker void ListAppendNone(ContextPointer& ctx) {
45*6777b538SAndroid Build Coastguard Worker   auto& value = reinterpret_cast<base::Value&>(ctx);
46*6777b538SAndroid Build Coastguard Worker   value.GetList().Append(base::Value());
47*6777b538SAndroid Build Coastguard Worker }
48*6777b538SAndroid Build Coastguard Worker 
49*6777b538SAndroid Build Coastguard Worker template <class T, class As = T>
ListAppendValue(ContextPointer & ctx,T v)50*6777b538SAndroid Build Coastguard Worker void ListAppendValue(ContextPointer& ctx, T v) {
51*6777b538SAndroid Build Coastguard Worker   auto& value = reinterpret_cast<base::Value&>(ctx);
52*6777b538SAndroid Build Coastguard Worker   value.GetList().Append(As{v});
53*6777b538SAndroid Build Coastguard Worker }
54*6777b538SAndroid Build Coastguard Worker 
DictSetList(ContextPointer & ctx,rust::Str key,size_t reserve)55*6777b538SAndroid Build Coastguard Worker ContextPointer& DictSetList(ContextPointer& ctx,
56*6777b538SAndroid Build Coastguard Worker                             rust::Str key,
57*6777b538SAndroid Build Coastguard Worker                             size_t reserve) {
58*6777b538SAndroid Build Coastguard Worker   auto& dict = reinterpret_cast<base::Value&>(ctx).GetDict();
59*6777b538SAndroid Build Coastguard Worker   base::Value::List list;
60*6777b538SAndroid Build Coastguard Worker   list.reserve(reserve);
61*6777b538SAndroid Build Coastguard Worker   dict.Set(base::RustStrToStringPiece(key), std::move(list));
62*6777b538SAndroid Build Coastguard Worker   return reinterpret_cast<ContextPointer&>(
63*6777b538SAndroid Build Coastguard Worker       *dict.Find(base::RustStrToStringPiece(key)));
64*6777b538SAndroid Build Coastguard Worker }
65*6777b538SAndroid Build Coastguard Worker 
DictSetDict(ContextPointer & ctx,rust::Str key)66*6777b538SAndroid Build Coastguard Worker ContextPointer& DictSetDict(ContextPointer& ctx, rust::Str key) {
67*6777b538SAndroid Build Coastguard Worker   auto& dict = reinterpret_cast<base::Value&>(ctx).GetDict();
68*6777b538SAndroid Build Coastguard Worker   dict.Set(base::RustStrToStringPiece(key), base::Value(base::Value::Dict()));
69*6777b538SAndroid Build Coastguard Worker   return reinterpret_cast<ContextPointer&>(
70*6777b538SAndroid Build Coastguard Worker       *dict.Find(base::RustStrToStringPiece(key)));
71*6777b538SAndroid Build Coastguard Worker }
72*6777b538SAndroid Build Coastguard Worker 
DictSetNone(ContextPointer & ctx,rust::Str key)73*6777b538SAndroid Build Coastguard Worker void DictSetNone(ContextPointer& ctx, rust::Str key) {
74*6777b538SAndroid Build Coastguard Worker   auto& dict = reinterpret_cast<base::Value&>(ctx).GetDict();
75*6777b538SAndroid Build Coastguard Worker   dict.Set(base::RustStrToStringPiece(key), base::Value());
76*6777b538SAndroid Build Coastguard Worker }
77*6777b538SAndroid Build Coastguard Worker 
78*6777b538SAndroid Build Coastguard Worker template <class T, class As = T>
DictSetValue(ContextPointer & ctx,rust::Str key,T v)79*6777b538SAndroid Build Coastguard Worker void DictSetValue(ContextPointer& ctx, rust::Str key, T v) {
80*6777b538SAndroid Build Coastguard Worker   auto& dict = reinterpret_cast<base::Value&>(ctx).GetDict();
81*6777b538SAndroid Build Coastguard Worker   dict.Set(base::RustStrToStringPiece(key), base::Value(As{v}));
82*6777b538SAndroid Build Coastguard Worker }
83*6777b538SAndroid Build Coastguard Worker 
DecodeJSONInRust(std::string_view json,int options,size_t max_depth)84*6777b538SAndroid Build Coastguard Worker JSONReader::Result DecodeJSONInRust(std::string_view json,
85*6777b538SAndroid Build Coastguard Worker                                     int options,
86*6777b538SAndroid Build Coastguard Worker                                     size_t max_depth) {
87*6777b538SAndroid Build Coastguard Worker   const serde_json_lenient::JsonOptions rust_options = {
88*6777b538SAndroid Build Coastguard Worker       .allow_trailing_commas =
89*6777b538SAndroid Build Coastguard Worker           (options & base::JSON_ALLOW_TRAILING_COMMAS) != 0,
90*6777b538SAndroid Build Coastguard Worker       .replace_invalid_characters =
91*6777b538SAndroid Build Coastguard Worker           (options & base::JSON_REPLACE_INVALID_CHARACTERS) != 0,
92*6777b538SAndroid Build Coastguard Worker       .allow_comments = (options & base::JSON_ALLOW_COMMENTS) != 0,
93*6777b538SAndroid Build Coastguard Worker       .allow_newlines = (options & base::JSON_ALLOW_NEWLINES_IN_STRINGS) != 0,
94*6777b538SAndroid Build Coastguard Worker       .allow_control_chars = (options & base::JSON_ALLOW_CONTROL_CHARS) != 0,
95*6777b538SAndroid Build Coastguard Worker       .allow_vert_tab = (options & base::JSON_ALLOW_VERT_TAB) != 0,
96*6777b538SAndroid Build Coastguard Worker       .allow_x_escapes = (options & base::JSON_ALLOW_X_ESCAPES) != 0,
97*6777b538SAndroid Build Coastguard Worker       .max_depth = max_depth,
98*6777b538SAndroid Build Coastguard Worker   };
99*6777b538SAndroid Build Coastguard Worker   static constexpr serde_json_lenient::Functions functions = {
100*6777b538SAndroid Build Coastguard Worker       .list_append_none_fn = ListAppendNone,
101*6777b538SAndroid Build Coastguard Worker       .list_append_bool_fn = ListAppendValue<bool>,
102*6777b538SAndroid Build Coastguard Worker       .list_append_i32_fn = ListAppendValue<int32_t>,
103*6777b538SAndroid Build Coastguard Worker       .list_append_f64_fn = ListAppendValue<double>,
104*6777b538SAndroid Build Coastguard Worker       .list_append_str_fn = ListAppendValue<rust::Str, std::string>,
105*6777b538SAndroid Build Coastguard Worker       .list_append_list_fn = ListAppendList,
106*6777b538SAndroid Build Coastguard Worker       .list_append_dict_fn = ListAppendDict,
107*6777b538SAndroid Build Coastguard Worker       .dict_set_none_fn = DictSetNone,
108*6777b538SAndroid Build Coastguard Worker       .dict_set_bool_fn = DictSetValue<bool>,
109*6777b538SAndroid Build Coastguard Worker       .dict_set_i32_fn = DictSetValue<int32_t>,
110*6777b538SAndroid Build Coastguard Worker       .dict_set_f64_fn = DictSetValue<double>,
111*6777b538SAndroid Build Coastguard Worker       .dict_set_str_fn = DictSetValue<rust::Str, std::string>,
112*6777b538SAndroid Build Coastguard Worker       .dict_set_list_fn = DictSetList,
113*6777b538SAndroid Build Coastguard Worker       .dict_set_dict_fn = DictSetDict,
114*6777b538SAndroid Build Coastguard Worker   };
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker   base::Value value(base::Value::Type::LIST);
117*6777b538SAndroid Build Coastguard Worker   auto& ctx = reinterpret_cast<ContextPointer&>(value);
118*6777b538SAndroid Build Coastguard Worker   serde_json_lenient::DecodeError error;
119*6777b538SAndroid Build Coastguard Worker   bool ok = serde_json_lenient::decode_json(
120*6777b538SAndroid Build Coastguard Worker       base::StringPieceToRustSlice(json), rust_options, functions, ctx, error);
121*6777b538SAndroid Build Coastguard Worker 
122*6777b538SAndroid Build Coastguard Worker   if (!ok) {
123*6777b538SAndroid Build Coastguard Worker     return base::unexpected(base::JSONReader::Error{
124*6777b538SAndroid Build Coastguard Worker         .message = std::string(error.message),
125*6777b538SAndroid Build Coastguard Worker         .line = error.line,
126*6777b538SAndroid Build Coastguard Worker         .column = error.column,
127*6777b538SAndroid Build Coastguard Worker     });
128*6777b538SAndroid Build Coastguard Worker   }
129*6777b538SAndroid Build Coastguard Worker 
130*6777b538SAndroid Build Coastguard Worker   return std::move(std::move(value.GetList()).back());
131*6777b538SAndroid Build Coastguard Worker }
132*6777b538SAndroid Build Coastguard Worker 
133*6777b538SAndroid Build Coastguard Worker }  // anonymous namespace
134*6777b538SAndroid Build Coastguard Worker 
135*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(BUILD_RUST_JSON_READER)
136*6777b538SAndroid Build Coastguard Worker 
137*6777b538SAndroid Build Coastguard Worker // static
Read(std::string_view json,int options,size_t max_depth)138*6777b538SAndroid Build Coastguard Worker std::optional<Value> JSONReader::Read(std::string_view json,
139*6777b538SAndroid Build Coastguard Worker                                       int options,
140*6777b538SAndroid Build Coastguard Worker                                       size_t max_depth) {
141*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(BUILD_RUST_JSON_READER)
142*6777b538SAndroid Build Coastguard Worker   SCOPED_UMA_HISTOGRAM_TIMER_MICROS(kSecurityJsonParsingTime);
143*6777b538SAndroid Build Coastguard Worker   if (UsingRust()) {
144*6777b538SAndroid Build Coastguard Worker     JSONReader::Result result = DecodeJSONInRust(json, options, max_depth);
145*6777b538SAndroid Build Coastguard Worker     if (!result.has_value()) {
146*6777b538SAndroid Build Coastguard Worker       return std::nullopt;
147*6777b538SAndroid Build Coastguard Worker     }
148*6777b538SAndroid Build Coastguard Worker     return std::move(*result);
149*6777b538SAndroid Build Coastguard Worker   } else {
150*6777b538SAndroid Build Coastguard Worker     internal::JSONParser parser(options, max_depth);
151*6777b538SAndroid Build Coastguard Worker     return parser.Parse(json);
152*6777b538SAndroid Build Coastguard Worker   }
153*6777b538SAndroid Build Coastguard Worker #else   // BUILDFLAG(BUILD_RUST_JSON_READER)
154*6777b538SAndroid Build Coastguard Worker   internal::JSONParser parser(options, max_depth);
155*6777b538SAndroid Build Coastguard Worker   return parser.Parse(json);
156*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(BUILD_RUST_JSON_READER)
157*6777b538SAndroid Build Coastguard Worker }
158*6777b538SAndroid Build Coastguard Worker 
159*6777b538SAndroid Build Coastguard Worker // static
ReadDict(std::string_view json,int options,size_t max_depth)160*6777b538SAndroid Build Coastguard Worker std::optional<Value::Dict> JSONReader::ReadDict(std::string_view json,
161*6777b538SAndroid Build Coastguard Worker                                                 int options,
162*6777b538SAndroid Build Coastguard Worker                                                 size_t max_depth) {
163*6777b538SAndroid Build Coastguard Worker   std::optional<Value> value = Read(json, options, max_depth);
164*6777b538SAndroid Build Coastguard Worker   if (!value || !value->is_dict()) {
165*6777b538SAndroid Build Coastguard Worker     return std::nullopt;
166*6777b538SAndroid Build Coastguard Worker   }
167*6777b538SAndroid Build Coastguard Worker   return std::move(*value).TakeDict();
168*6777b538SAndroid Build Coastguard Worker }
169*6777b538SAndroid Build Coastguard Worker 
170*6777b538SAndroid Build Coastguard Worker // static
ReadAndReturnValueWithError(std::string_view json,int options)171*6777b538SAndroid Build Coastguard Worker JSONReader::Result JSONReader::ReadAndReturnValueWithError(
172*6777b538SAndroid Build Coastguard Worker     std::string_view json,
173*6777b538SAndroid Build Coastguard Worker     int options) {
174*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(BUILD_RUST_JSON_READER)
175*6777b538SAndroid Build Coastguard Worker   SCOPED_UMA_HISTOGRAM_TIMER_MICROS(kSecurityJsonParsingTime);
176*6777b538SAndroid Build Coastguard Worker   if (UsingRust()) {
177*6777b538SAndroid Build Coastguard Worker     return DecodeJSONInRust(json, options, internal::kAbsoluteMaxDepth);
178*6777b538SAndroid Build Coastguard Worker   } else {
179*6777b538SAndroid Build Coastguard Worker     internal::JSONParser parser(options);
180*6777b538SAndroid Build Coastguard Worker     auto value = parser.Parse(json);
181*6777b538SAndroid Build Coastguard Worker     if (!value) {
182*6777b538SAndroid Build Coastguard Worker       Error error;
183*6777b538SAndroid Build Coastguard Worker       error.message = parser.GetErrorMessage();
184*6777b538SAndroid Build Coastguard Worker       error.line = parser.error_line();
185*6777b538SAndroid Build Coastguard Worker       error.column = parser.error_column();
186*6777b538SAndroid Build Coastguard Worker       return base::unexpected(std::move(error));
187*6777b538SAndroid Build Coastguard Worker     }
188*6777b538SAndroid Build Coastguard Worker 
189*6777b538SAndroid Build Coastguard Worker     return std::move(*value);
190*6777b538SAndroid Build Coastguard Worker   }
191*6777b538SAndroid Build Coastguard Worker #else   // BUILDFLAG(BUILD_RUST_JSON_READER)
192*6777b538SAndroid Build Coastguard Worker   internal::JSONParser parser(options);
193*6777b538SAndroid Build Coastguard Worker   auto value = parser.Parse(json);
194*6777b538SAndroid Build Coastguard Worker   if (!value) {
195*6777b538SAndroid Build Coastguard Worker     Error error;
196*6777b538SAndroid Build Coastguard Worker     error.message = parser.GetErrorMessage();
197*6777b538SAndroid Build Coastguard Worker     error.line = parser.error_line();
198*6777b538SAndroid Build Coastguard Worker     error.column = parser.error_column();
199*6777b538SAndroid Build Coastguard Worker     return base::unexpected(std::move(error));
200*6777b538SAndroid Build Coastguard Worker   }
201*6777b538SAndroid Build Coastguard Worker 
202*6777b538SAndroid Build Coastguard Worker   return std::move(*value);
203*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(BUILD_RUST_JSON_READER)
204*6777b538SAndroid Build Coastguard Worker }
205*6777b538SAndroid Build Coastguard Worker 
206*6777b538SAndroid Build Coastguard Worker // static
UsingRust()207*6777b538SAndroid Build Coastguard Worker bool JSONReader::UsingRust() {
208*6777b538SAndroid Build Coastguard Worker   // If features have not yet been enabled, we cannot check the feature, so fall
209*6777b538SAndroid Build Coastguard Worker   // back to the C++ parser. In practice, this seems to apply to
210*6777b538SAndroid Build Coastguard Worker   // `ReadPrefsFromDisk()`, which is parsing trusted JSON.
211*6777b538SAndroid Build Coastguard Worker   if (!base::FeatureList::GetInstance()) {
212*6777b538SAndroid Build Coastguard Worker     return false;
213*6777b538SAndroid Build Coastguard Worker   }
214*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(BUILD_RUST_JSON_READER)
215*6777b538SAndroid Build Coastguard Worker   return base::FeatureList::IsEnabled(base::features::kUseRustJsonParser);
216*6777b538SAndroid Build Coastguard Worker #else   // BUILDFLAG(BUILD_RUST_JSON_READER)
217*6777b538SAndroid Build Coastguard Worker   return false;
218*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(BUILD_RUST_JSON_READER)
219*6777b538SAndroid Build Coastguard Worker }
220*6777b538SAndroid Build Coastguard Worker 
221*6777b538SAndroid Build Coastguard Worker }  // namespace base
222