910e62b5创建于 1月15日历史提交
// 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