blob: 664b729034abe9ca418e17f8ff335640f6d9f70e [file] [log] [blame] [edit]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/json/json_reader.h"
#include <string_view>
#include <utility>
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "build/build_config.h"
#include "base/strings/string_view_rust.h"
#include "third_party/rust/serde_json_lenient/v0_2/wrapper/functions.h"
#include "third_party/rust/serde_json_lenient/v0_2/wrapper/lib.rs.h"
namespace {
const char kSecurityJsonParsingTime[] = "Security.JSONParser.ParsingTime";
} // namespace
// This namespace defines FFI-friendly functions that are be called from Rust in
// //third_party/rust/serde_json_lenient/v0_2/wrapper/.
namespace serde_json_lenient {
base::Value::List& list_append_list(base::Value::List& ctx) {
ctx.Append(base::Value::List());
return ctx.back().GetList();
}
base::Value::Dict& list_append_dict(base::Value::List& ctx) {
ctx.Append(base::Value::Dict());
return ctx.back().GetDict();
}
void list_append_none(base::Value::List& ctx) {
ctx.Append(base::Value());
}
void list_append_bool(base::Value::List& ctx, bool val) {
ctx.Append(val);
}
void list_append_i32(base::Value::List& ctx, int32_t val) {
ctx.Append(val);
}
void list_append_f64(base::Value::List& ctx, double val) {
ctx.Append(val);
}
void list_append_str(base::Value::List& ctx, rust::Str val) {
ctx.Append(std::string(val));
}
base::Value::List& dict_set_list(base::Value::Dict& ctx, rust::Str key) {
base::Value* value =
ctx.Set(base::RustStrToStringView(key), base::Value::List());
return value->GetList();
}
base::Value::Dict& dict_set_dict(base::Value::Dict& ctx, rust::Str key) {
base::Value* value =
ctx.Set(base::RustStrToStringView(key), base::Value::Dict());
return value->GetDict();
}
void dict_set_none(base::Value::Dict& ctx, rust::Str key) {
ctx.Set(base::RustStrToStringView(key), base::Value());
}
void dict_set_bool(base::Value::Dict& ctx, rust::Str key, bool val) {
ctx.Set(base::RustStrToStringView(key), val);
}
void dict_set_i32(base::Value::Dict& ctx, rust::Str key, int32_t val) {
ctx.Set(base::RustStrToStringView(key), val);
}
void dict_set_f64(base::Value::Dict& ctx, rust::Str key, double val) {
ctx.Set(base::RustStrToStringView(key), val);
}
void dict_set_str(base::Value::Dict& ctx, rust::Str key, rust::Str val) {
ctx.Set(base::RustStrToStringView(key), std::string(val));
}
namespace {
base::JSONReader::Result DecodeJSONInRust(std::string_view json,
int options,
size_t max_depth) {
const JsonOptions rust_options = {
.allow_trailing_commas =
(options & base::JSON_ALLOW_TRAILING_COMMAS) != 0,
.replace_invalid_characters =
(options & base::JSON_REPLACE_INVALID_CHARACTERS) != 0,
.allow_comments = (options & base::JSON_ALLOW_COMMENTS) != 0,
.allow_newlines = (options & base::JSON_ALLOW_NEWLINES_IN_STRINGS) != 0,
.allow_vert_tab = (options & base::JSON_ALLOW_VERT_TAB) != 0,
.allow_x_escapes = (options & base::JSON_ALLOW_X_ESCAPES) != 0,
.max_depth = max_depth,
};
base::Value::List list;
DecodeError error;
bool ok =
decode_json(base::StringViewToRustSlice(json), rust_options, list, error);
if (!ok) {
return base::unexpected(base::JSONReader::Error{
.message = std::string(error.message),
.line = error.line,
.column = error.column,
});
}
return std::move(list.back());
}
} // namespace
} // namespace serde_json_lenient
namespace base {
std::string JSONReader::Error::ToString() const {
return base::StrCat({"line ", base::NumberToString(line), ", column ",
base::NumberToString(column), ": ", message});
}
// static
std::optional<Value> JSONReader::Read(std::string_view json,
int options,
size_t max_depth) {
SCOPED_UMA_HISTOGRAM_TIMER_MICROS(kSecurityJsonParsingTime);
JSONReader::Result result =
serde_json_lenient::DecodeJSONInRust(json, options, max_depth);
if (!result.has_value()) {
return std::nullopt;
}
return std::move(*result);
}
// static
std::optional<Value::Dict> JSONReader::ReadDict(std::string_view json,
int options,
size_t max_depth) {
std::optional<Value> value = Read(json, options, max_depth);
if (!value || !value->is_dict()) {
return std::nullopt;
}
return std::move(*value).TakeDict();
}
// static
std::optional<Value::List> JSONReader::ReadList(std::string_view json,
int options,
size_t max_depth) {
std::optional<Value> value = Read(json, options, max_depth);
if (!value || !value->is_list()) {
return std::nullopt;
}
return std::move(*value).TakeList();
}
// static
JSONReader::Result JSONReader::ReadAndReturnValueWithError(
std::string_view json,
int options) {
SCOPED_UMA_HISTOGRAM_TIMER_MICROS(kSecurityJsonParsingTime);
return serde_json_lenient::DecodeJSONInRust(json, options,
internal::kAbsoluteMaxDepth);
}
} // namespace base