diff options
Diffstat (limited to 'chromium/base/json')
-rw-r--r-- | chromium/base/json/json_common.h | 2 | ||||
-rw-r--r-- | chromium/base/json/json_file_value_serializer.h | 2 | ||||
-rw-r--r-- | chromium/base/json/json_parser.cc | 129 | ||||
-rw-r--r-- | chromium/base/json/json_parser.h | 38 | ||||
-rw-r--r-- | chromium/base/json/json_parser_unittest.cc | 161 | ||||
-rw-r--r-- | chromium/base/json/json_perftest_decodebench.cc | 1 | ||||
-rw-r--r-- | chromium/base/json/json_reader.cc | 94 | ||||
-rw-r--r-- | chromium/base/json/json_reader.h | 73 | ||||
-rw-r--r-- | chromium/base/json/json_reader_fuzzer.cc | 2 | ||||
-rw-r--r-- | chromium/base/json/json_reader_unittest.cc | 52 | ||||
-rw-r--r-- | chromium/base/json/json_string_value_serializer.cc | 12 | ||||
-rw-r--r-- | chromium/base/json/json_value_serializer_unittest.cc | 14 |
12 files changed, 282 insertions, 298 deletions
diff --git a/chromium/base/json/json_common.h b/chromium/base/json/json_common.h index c0fd3eab82b..f98fb00455f 100644 --- a/chromium/base/json/json_common.h +++ b/chromium/base/json/json_common.h @@ -7,7 +7,7 @@ #include <stddef.h> -#include "base/logging.h" +#include "base/check_op.h" #include "base/macros.h" namespace base { diff --git a/chromium/base/json/json_file_value_serializer.h b/chromium/base/json/json_file_value_serializer.h index a93950a6080..f38cec24cf7 100644 --- a/chromium/base/json/json_file_value_serializer.h +++ b/chromium/base/json/json_file_value_serializer.h @@ -67,7 +67,7 @@ class BASE_EXPORT JSONFileValueDeserializer : public base::ValueDeserializer { // This enum is designed to safely overlap with JSONReader::JsonParseError. enum JsonFileError { JSON_NO_ERROR = 0, - JSON_ACCESS_DENIED = 1000, + JSON_ACCESS_DENIED = kErrorCodeFirstMetadataError, JSON_CANNOT_READ_FILE, JSON_FILE_LOCKED, JSON_NO_SUCH_FILE diff --git a/chromium/base/json/json_parser.cc b/chromium/base/json/json_parser.cc index e1e44c9781f..fcb479ceabd 100644 --- a/chromium/base/json/json_parser.cc +++ b/chromium/base/json/json_parser.cc @@ -9,7 +9,9 @@ #include <vector> #include "base/check_op.h" +#include "base/json/json_reader.h" #include "base/macros.h" +#include "base/notreached.h" #include "base/numerics/safe_conversions.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" @@ -18,13 +20,47 @@ #include "base/strings/utf_string_conversion_utils.h" #include "base/strings/utf_string_conversions.h" #include "base/third_party/icu/icu_utf.h" -#include "base/values.h" namespace base { namespace internal { namespace { +// Values 1000 and above are used by JSONFileValueSerializer::JsonFileError. +static_assert(JSONParser::JSON_PARSE_ERROR_COUNT < 1000, + "JSONParser error out of bounds"); + +std::string ErrorCodeToString(JSONParser::JsonParseError error_code) { + switch (error_code) { + case JSONParser::JSON_NO_ERROR: + return std::string(); + case JSONParser::JSON_SYNTAX_ERROR: + return JSONParser::kSyntaxError; + case JSONParser::JSON_INVALID_ESCAPE: + return JSONParser::kInvalidEscape; + case JSONParser::JSON_UNEXPECTED_TOKEN: + return JSONParser::kUnexpectedToken; + case JSONParser::JSON_TRAILING_COMMA: + return JSONParser::kTrailingComma; + case JSONParser::JSON_TOO_MUCH_NESTING: + return JSONParser::kTooMuchNesting; + case JSONParser::JSON_UNEXPECTED_DATA_AFTER_ROOT: + return JSONParser::kUnexpectedDataAfterRoot; + case JSONParser::JSON_UNSUPPORTED_ENCODING: + return JSONParser::kUnsupportedEncoding; + case JSONParser::JSON_UNQUOTED_DICTIONARY_KEY: + return JSONParser::kUnquotedDictionaryKey; + case JSONParser::JSON_TOO_LARGE: + return JSONParser::kInputTooLarge; + case JSONParser::JSON_UNREPRESENTABLE_NUMBER: + return JSONParser::kUnrepresentableNumber; + case JSONParser::JSON_PARSE_ERROR_COUNT: + break; + } + NOTREACHED(); + return std::string(); +} + const int32_t kExtendedASCIIStart = 0x80; constexpr uint32_t kUnicodeReplacementPoint = 0xFFFD; @@ -45,6 +81,21 @@ bool UnprefixedHexStringToInt(StringPiece input, int* output) { // This is U+FFFD. const char kUnicodeReplacementString[] = "\xEF\xBF\xBD"; +const char JSONParser::kSyntaxError[] = "Syntax error."; +const char JSONParser::kInvalidEscape[] = "Invalid escape sequence."; +const char JSONParser::kUnexpectedToken[] = "Unexpected token."; +const char JSONParser::kTrailingComma[] = "Trailing comma not allowed."; +const char JSONParser::kTooMuchNesting[] = "Too much nesting."; +const char JSONParser::kUnexpectedDataAfterRoot[] = + "Unexpected data after root element."; +const char JSONParser::kUnsupportedEncoding[] = + "Unsupported encoding. JSON must be UTF-8."; +const char JSONParser::kUnquotedDictionaryKey[] = + "Dictionary keys must be quoted."; +const char JSONParser::kInputTooLarge[] = "Input string is too large (>2GB)."; +const char JSONParser::kUnrepresentableNumber[] = + "Number cannot be represented."; + JSONParser::JSONParser(int options, size_t max_depth) : options_(options), max_depth_(max_depth), @@ -52,7 +103,7 @@ JSONParser::JSONParser(int options, size_t max_depth) stack_depth_(0), line_number_(0), index_last_line_(0), - error_code_(JSONReader::JSON_NO_ERROR), + error_code_(JSON_NO_ERROR), error_line_(0), error_column_(0) { CHECK_LE(max_depth, kAbsoluteMaxDepth); @@ -77,14 +128,14 @@ Optional<Value> JSONParser::Parse(StringPiece input) { line_number_ = 1; index_last_line_ = -1; - error_code_ = JSONReader::JSON_NO_ERROR; + error_code_ = JSON_NO_ERROR; error_line_ = 0; error_column_ = 0; // ICU and ReadUnicodeCharacter() use int32_t for lengths, so ensure // that the index_ will not overflow when parsing. if (!base::IsValueInRangeForNumericType<int32_t>(input.length())) { - ReportError(JSONReader::JSON_TOO_LARGE, -1); + ReportError(JSON_TOO_LARGE, -1); return nullopt; } @@ -100,20 +151,20 @@ Optional<Value> JSONParser::Parse(StringPiece input) { // Make sure the input stream is at an end. if (GetNextToken() != T_END_OF_INPUT) { - ReportError(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, 0); + ReportError(JSON_UNEXPECTED_DATA_AFTER_ROOT, 0); return nullopt; } return root; } -JSONReader::JsonParseError JSONParser::error_code() const { +JSONParser::JsonParseError JSONParser::error_code() const { return error_code_; } std::string JSONParser::GetErrorMessage() const { return FormatErrorMessage(error_line_, error_column_, - JSONReader::ErrorCodeToString(error_code_)); + ErrorCodeToString(error_code_)); } int JSONParser::error_line() const { @@ -323,20 +374,20 @@ Optional<Value> JSONParser::ParseToken(Token token) { case T_NULL: return ConsumeLiteral(); default: - ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 0); + ReportError(JSON_UNEXPECTED_TOKEN, 0); return nullopt; } } Optional<Value> JSONParser::ConsumeDictionary() { if (ConsumeChar() != '{') { - ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 0); + ReportError(JSON_UNEXPECTED_TOKEN, 0); return nullopt; } StackMarker depth_check(max_depth_, &stack_depth_); if (depth_check.IsTooDeep()) { - ReportError(JSONReader::JSON_TOO_MUCH_NESTING, -1); + ReportError(JSON_TOO_MUCH_NESTING, -1); return nullopt; } @@ -345,7 +396,7 @@ Optional<Value> JSONParser::ConsumeDictionary() { Token token = GetNextToken(); while (token != T_OBJECT_END) { if (token != T_STRING) { - ReportError(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, 0); + ReportError(JSON_UNQUOTED_DICTIONARY_KEY, 0); return nullopt; } @@ -358,7 +409,7 @@ Optional<Value> JSONParser::ConsumeDictionary() { // Read the separator. token = GetNextToken(); if (token != T_OBJECT_PAIR_SEPARATOR) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); + ReportError(JSON_SYNTAX_ERROR, 0); return nullopt; } @@ -378,11 +429,11 @@ Optional<Value> JSONParser::ConsumeDictionary() { ConsumeChar(); token = GetNextToken(); if (token == T_OBJECT_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) { - ReportError(JSONReader::JSON_TRAILING_COMMA, 0); + ReportError(JSON_TRAILING_COMMA, 0); return nullopt; } } else if (token != T_OBJECT_END) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); + ReportError(JSON_SYNTAX_ERROR, 0); return nullopt; } } @@ -396,13 +447,13 @@ Optional<Value> JSONParser::ConsumeDictionary() { Optional<Value> JSONParser::ConsumeList() { if (ConsumeChar() != '[') { - ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 0); + ReportError(JSON_UNEXPECTED_TOKEN, 0); return nullopt; } StackMarker depth_check(max_depth_, &stack_depth_); if (depth_check.IsTooDeep()) { - ReportError(JSONReader::JSON_TOO_MUCH_NESTING, -1); + ReportError(JSON_TOO_MUCH_NESTING, -1); return nullopt; } @@ -423,11 +474,11 @@ Optional<Value> JSONParser::ConsumeList() { ConsumeChar(); token = GetNextToken(); if (token == T_ARRAY_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) { - ReportError(JSONReader::JSON_TRAILING_COMMA, 0); + ReportError(JSON_TRAILING_COMMA, 0); return nullopt; } } else if (token != T_ARRAY_END) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); + ReportError(JSON_SYNTAX_ERROR, 0); return nullopt; } } @@ -446,7 +497,7 @@ Optional<Value> JSONParser::ConsumeString() { bool JSONParser::ConsumeStringRaw(StringBuilder* out) { if (ConsumeChar() != '"') { - ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 0); + ReportError(JSON_UNEXPECTED_TOKEN, 0); return false; } @@ -462,7 +513,7 @@ bool JSONParser::ConsumeStringRaw(StringBuilder* out) { &next_char) || !IsValidCodepoint(next_char)) { if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0) { - ReportError(JSONReader::JSON_UNSUPPORTED_ENCODING, 0); + ReportError(JSON_UNSUPPORTED_ENCODING, 0); return false; } ConsumeChar(); @@ -501,7 +552,7 @@ bool JSONParser::ConsumeStringRaw(StringBuilder* out) { // Read past the escape '\' and ensure there's a character following. Optional<StringPiece> escape_sequence = ConsumeChars(2); if (!escape_sequence) { - ReportError(JSONReader::JSON_INVALID_ESCAPE, -1); + ReportError(JSON_INVALID_ESCAPE, -1); return false; } @@ -512,14 +563,14 @@ bool JSONParser::ConsumeStringRaw(StringBuilder* out) { // are supported here for backwards-compatiblity with the old parser. escape_sequence = ConsumeChars(2); if (!escape_sequence) { - ReportError(JSONReader::JSON_INVALID_ESCAPE, -3); + ReportError(JSON_INVALID_ESCAPE, -3); return false; } int hex_digit = 0; if (!UnprefixedHexStringToInt(*escape_sequence, &hex_digit) || !IsValidCharacter(hex_digit)) { - ReportError(JSONReader::JSON_INVALID_ESCAPE, -3); + ReportError(JSON_INVALID_ESCAPE, -3); return false; } @@ -530,7 +581,7 @@ bool JSONParser::ConsumeStringRaw(StringBuilder* out) { // UTF units are of the form \uXXXX. uint32_t code_point; if (!DecodeUTF16(&code_point)) { - ReportError(JSONReader::JSON_INVALID_ESCAPE, -1); + ReportError(JSON_INVALID_ESCAPE, -1); return false; } string.Append(code_point); @@ -565,13 +616,13 @@ bool JSONParser::ConsumeStringRaw(StringBuilder* out) { break; // All other escape squences are illegal. default: - ReportError(JSONReader::JSON_INVALID_ESCAPE, -1); + ReportError(JSON_INVALID_ESCAPE, -1); return false; } } } - ReportError(JSONReader::JSON_SYNTAX_ERROR, -1); + ReportError(JSON_SYNTAX_ERROR, -1); return false; } @@ -589,10 +640,13 @@ bool JSONParser::DecodeUTF16(uint32_t* out_code_point) { // If this is a high surrogate, consume the next code unit to get the // low surrogate. if (CBU16_IS_SURROGATE(code_unit16_high)) { - // Make sure this is the high surrogate. If not, it's an encoding - // error. - if (!CBU16_IS_SURROGATE_LEAD(code_unit16_high)) - return false; + // Make sure this is the high surrogate. + if (!CBU16_IS_SURROGATE_LEAD(code_unit16_high)) { + if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0) + return false; + *out_code_point = kUnicodeReplacementPoint; + return true; + } // Make sure that the token has more characters to consume the // lower surrogate. @@ -641,7 +695,7 @@ Optional<Value> JSONParser::ConsumeNumber() { ConsumeChar(); if (!ReadInt(false)) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); + ReportError(JSON_SYNTAX_ERROR, 0); return nullopt; } end_index = index_; @@ -650,7 +704,7 @@ Optional<Value> JSONParser::ConsumeNumber() { if (PeekChar() == '.') { ConsumeChar(); if (!ReadInt(true)) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); + ReportError(JSON_SYNTAX_ERROR, 0); return nullopt; } end_index = index_; @@ -664,7 +718,7 @@ Optional<Value> JSONParser::ConsumeNumber() { ConsumeChar(); } if (!ReadInt(true)) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); + ReportError(JSON_SYNTAX_ERROR, 0); return nullopt; } end_index = index_; @@ -683,7 +737,7 @@ Optional<Value> JSONParser::ConsumeNumber() { case T_END_OF_INPUT: break; default: - ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); + ReportError(JSON_SYNTAX_ERROR, 0); return nullopt; } @@ -701,7 +755,7 @@ Optional<Value> JSONParser::ConsumeNumber() { return Value(num_double); } - ReportError(JSONReader::JSON_UNREPRESENTABLE_NUMBER, 0); + ReportError(JSON_UNREPRESENTABLE_NUMBER, 0); return nullopt; } @@ -736,7 +790,7 @@ Optional<Value> JSONParser::ConsumeLiteral() { return Value(false); if (ConsumeIfMatch("null")) return Value(Value::Type::NONE); - ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); + ReportError(JSON_SYNTAX_ERROR, 0); return nullopt; } @@ -748,8 +802,7 @@ bool JSONParser::ConsumeIfMatch(StringPiece match) { return false; } -void JSONParser::ReportError(JSONReader::JsonParseError code, - int column_adjust) { +void JSONParser::ReportError(JsonParseError code, int column_adjust) { error_code_ = code; error_line_ = line_number_; error_column_ = index_ - index_last_line_ + column_adjust; diff --git a/chromium/base/json/json_parser.h b/chromium/base/json/json_parser.h index 523062e6812..1481a8d2ba7 100644 --- a/chromium/base/json/json_parser.h +++ b/chromium/base/json/json_parser.h @@ -15,10 +15,10 @@ #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/json/json_common.h" -#include "base/json/json_reader.h" #include "base/macros.h" #include "base/optional.h" #include "base/strings/string_piece.h" +#include "base/values.h" namespace base { @@ -44,7 +44,35 @@ class JSONParserTest; // of the next token. class BASE_EXPORT JSONParser { public: - JSONParser(int options, size_t max_depth = kAbsoluteMaxDepth); + // Error codes during parsing. + enum JsonParseError { + JSON_NO_ERROR = base::ValueDeserializer::kErrorCodeNoError, + JSON_SYNTAX_ERROR = base::ValueDeserializer::kErrorCodeInvalidFormat, + JSON_INVALID_ESCAPE, + JSON_UNEXPECTED_TOKEN, + JSON_TRAILING_COMMA, + JSON_TOO_MUCH_NESTING, + JSON_UNEXPECTED_DATA_AFTER_ROOT, + JSON_UNSUPPORTED_ENCODING, + JSON_UNQUOTED_DICTIONARY_KEY, + JSON_TOO_LARGE, + JSON_UNREPRESENTABLE_NUMBER, + JSON_PARSE_ERROR_COUNT + }; + + // String versions of parse error codes. + static const char kSyntaxError[]; + static const char kInvalidEscape[]; + static const char kUnexpectedToken[]; + static const char kTrailingComma[]; + static const char kTooMuchNesting[]; + static const char kUnexpectedDataAfterRoot[]; + static const char kUnsupportedEncoding[]; + static const char kUnquotedDictionaryKey[]; + static const char kInputTooLarge[]; + static const char kUnrepresentableNumber[]; + + explicit JSONParser(int options, size_t max_depth = kAbsoluteMaxDepth); ~JSONParser(); // Parses the input string according to the set options and returns the @@ -54,7 +82,7 @@ class BASE_EXPORT JSONParser { Optional<Value> Parse(StringPiece input); // Returns the error code. - JSONReader::JsonParseError error_code() const; + JsonParseError error_code() const; // Returns the human-friendly error message. std::string GetErrorMessage() const; @@ -205,7 +233,7 @@ class BASE_EXPORT JSONParser { // Sets the error information to |code| at the current column, based on // |index_| and |index_last_line_|, with an optional positive/negative // adjustment by |column_adjust|. - void ReportError(JSONReader::JsonParseError code, int column_adjust); + void ReportError(JsonParseError code, int column_adjust); // Given the line and column number of an error, formats one of the error // message contants from json_reader.h for human display. @@ -234,7 +262,7 @@ class BASE_EXPORT JSONParser { int index_last_line_; // Error information. - JSONReader::JsonParseError error_code_; + JsonParseError error_code_; int error_line_; int error_column_; diff --git a/chromium/base/json/json_parser_unittest.cc b/chromium/base/json/json_parser_unittest.cc index c4926423433..9e89afe3f7d 100644 --- a/chromium/base/json/json_parser_unittest.cc +++ b/chromium/base/json/json_parser_unittest.cc @@ -210,76 +210,103 @@ TEST_F(JSONParserTest, ConsumeNumbers) { } TEST_F(JSONParserTest, ErrorMessages) { - JSONReader::ValueWithError root = - JSONReader::ReadAndReturnValueWithError("[42]", JSON_PARSE_RFC); - EXPECT_TRUE(root.error_message.empty()); - EXPECT_EQ(0, root.error_code); + { + JSONParser parser(JSON_PARSE_RFC); + Optional<Value> value = parser.Parse("[42]"); + EXPECT_TRUE(value); + EXPECT_TRUE(parser.GetErrorMessage().empty()); + EXPECT_EQ(0, parser.error_code()); + } // Test each of the error conditions - root = JSONReader::ReadAndReturnValueWithError("{},{}", JSON_PARSE_RFC); - EXPECT_FALSE(root.value); - EXPECT_EQ(JSONParser::FormatErrorMessage( - 1, 3, JSONReader::kUnexpectedDataAfterRoot), - root.error_message); - EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, root.error_code); - - std::string nested_json; - for (int i = 0; i < 201; ++i) { - nested_json.insert(nested_json.begin(), '['); - nested_json.append(1, ']'); + { + JSONParser parser(JSON_PARSE_RFC); + Optional<Value> value = parser.Parse("{},{}"); + EXPECT_FALSE(value); + EXPECT_EQ(JSONParser::FormatErrorMessage( + 1, 3, JSONParser::kUnexpectedDataAfterRoot), + parser.GetErrorMessage()); + EXPECT_EQ(JSONParser::JSON_UNEXPECTED_DATA_AFTER_ROOT, parser.error_code()); + } + + { + std::string nested_json; + for (int i = 0; i < 201; ++i) { + nested_json.insert(nested_json.begin(), '['); + nested_json.append(1, ']'); + } + JSONParser parser(JSON_PARSE_RFC); + Optional<Value> value = parser.Parse(nested_json); + EXPECT_FALSE(value); + EXPECT_EQ( + JSONParser::FormatErrorMessage(1, 200, JSONParser::kTooMuchNesting), + parser.GetErrorMessage()); + EXPECT_EQ(JSONParser::JSON_TOO_MUCH_NESTING, parser.error_code()); + } + + { + JSONParser parser(JSON_PARSE_RFC); + Optional<Value> value = parser.Parse("[1,]"); + EXPECT_FALSE(value); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONParser::kTrailingComma), + parser.GetErrorMessage()); + EXPECT_EQ(JSONParser::JSON_TRAILING_COMMA, parser.error_code()); + } + + { + JSONParser parser(JSON_PARSE_RFC); + Optional<Value> value = parser.Parse("{foo:\"bar\"}"); + EXPECT_FALSE(value); + EXPECT_EQ(JSONParser::FormatErrorMessage( + 1, 2, JSONParser::kUnquotedDictionaryKey), + parser.GetErrorMessage()); + EXPECT_EQ(JSONParser::JSON_UNQUOTED_DICTIONARY_KEY, parser.error_code()); + } + + { + JSONParser parser(JSON_PARSE_RFC); + Optional<Value> value = parser.Parse("{\"foo\":\"bar\",}"); + EXPECT_FALSE(value); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONParser::kTrailingComma), + parser.GetErrorMessage()); + EXPECT_EQ(JSONParser::JSON_TRAILING_COMMA, parser.error_code()); + } + + { + JSONParser parser(JSON_PARSE_RFC); + Optional<Value> value = parser.Parse("[nu]"); + EXPECT_FALSE(value); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONParser::kSyntaxError), + parser.GetErrorMessage()); + EXPECT_EQ(JSONParser::JSON_SYNTAX_ERROR, parser.error_code()); + } + + { + JSONParser parser(JSON_PARSE_RFC); + Optional<Value> value = parser.Parse("[\"xxx\\xq\"]"); + EXPECT_FALSE(value); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONParser::kInvalidEscape), + parser.GetErrorMessage()); + EXPECT_EQ(JSONParser::JSON_INVALID_ESCAPE, parser.error_code()); + } + + { + JSONParser parser(JSON_PARSE_RFC); + Optional<Value> value = parser.Parse("[\"xxx\\uq\"]"); + EXPECT_FALSE(value); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONParser::kInvalidEscape), + parser.GetErrorMessage()); + EXPECT_EQ(JSONParser::JSON_INVALID_ESCAPE, parser.error_code()); + } + + { + JSONParser parser(JSON_PARSE_RFC); + Optional<Value> value = parser.Parse("[\"xxx\\q\"]"); + EXPECT_FALSE(value); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONParser::kInvalidEscape), + parser.GetErrorMessage()); + EXPECT_EQ(JSONParser::JSON_INVALID_ESCAPE, parser.error_code()); } - root = JSONReader::ReadAndReturnValueWithError(nested_json, JSON_PARSE_RFC); - EXPECT_FALSE(root.value); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 200, JSONReader::kTooMuchNesting), - root.error_message); - EXPECT_EQ(JSONReader::JSON_TOO_MUCH_NESTING, root.error_code); - - root = JSONReader::ReadAndReturnValueWithError("[1,]", JSON_PARSE_RFC); - EXPECT_FALSE(root.value); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONReader::kTrailingComma), - root.error_message); - EXPECT_EQ(JSONReader::JSON_TRAILING_COMMA, root.error_code); - - root = - JSONReader::ReadAndReturnValueWithError("{foo:\"bar\"}", JSON_PARSE_RFC); - EXPECT_FALSE(root.value); - EXPECT_EQ( - JSONParser::FormatErrorMessage(1, 2, JSONReader::kUnquotedDictionaryKey), - root.error_message); - EXPECT_EQ(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, root.error_code); - - root = JSONReader::ReadAndReturnValueWithError("{\"foo\":\"bar\",}", - JSON_PARSE_RFC); - EXPECT_FALSE(root.value); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONReader::kTrailingComma), - root.error_message); - - root = JSONReader::ReadAndReturnValueWithError("[nu]", JSON_PARSE_RFC); - EXPECT_FALSE(root.value); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONReader::kSyntaxError), - root.error_message); - EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, root.error_code); - - root = - JSONReader::ReadAndReturnValueWithError("[\"xxx\\xq\"]", JSON_PARSE_RFC); - EXPECT_FALSE(root.value); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), - root.error_message); - EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, root.error_code); - - root = - JSONReader::ReadAndReturnValueWithError("[\"xxx\\uq\"]", JSON_PARSE_RFC); - EXPECT_FALSE(root.value); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), - root.error_message); - EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, root.error_code); - - root = - JSONReader::ReadAndReturnValueWithError("[\"xxx\\q\"]", JSON_PARSE_RFC); - EXPECT_FALSE(root.value); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), - root.error_message); - EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, root.error_code); } } // namespace internal diff --git a/chromium/base/json/json_perftest_decodebench.cc b/chromium/base/json/json_perftest_decodebench.cc index e0f265dde5f..47a659623cb 100644 --- a/chromium/base/json/json_perftest_decodebench.cc +++ b/chromium/base/json/json_perftest_decodebench.cc @@ -24,6 +24,7 @@ #include "base/command_line.h" #include "base/files/file_util.h" #include "base/json/json_reader.h" +#include "base/logging.h" #include "base/time/time.h" int main(int argc, char* argv[]) { diff --git a/chromium/base/json/json_reader.cc b/chromium/base/json/json_reader.cc index 53e3df9fdf3..9456cfde1aa 100644 --- a/chromium/base/json/json_reader.cc +++ b/chromium/base/json/json_reader.cc @@ -8,30 +8,10 @@ #include <vector> #include "base/json/json_parser.h" -#include "base/notreached.h" #include "base/optional.h" namespace base { -// Values 1000 and above are used by JSONFileValueSerializer::JsonFileError. -static_assert(JSONReader::JSON_PARSE_ERROR_COUNT < 1000, - "JSONReader error out of bounds"); - -const char JSONReader::kInvalidEscape[] = "Invalid escape sequence."; -const char JSONReader::kSyntaxError[] = "Syntax error."; -const char JSONReader::kUnexpectedToken[] = "Unexpected token."; -const char JSONReader::kTrailingComma[] = "Trailing comma not allowed."; -const char JSONReader::kTooMuchNesting[] = "Too much nesting."; -const char JSONReader::kUnexpectedDataAfterRoot[] = - "Unexpected data after root element."; -const char JSONReader::kUnsupportedEncoding[] = - "Unsupported encoding. JSON must be UTF-8."; -const char JSONReader::kUnquotedDictionaryKey[] = - "Dictionary keys must be quoted."; -const char JSONReader::kInputTooLarge[] = "Input string is too large (>2GB)."; -const char JSONReader::kUnrepresentableNumber[] = - "Number cannot be represented."; - JSONReader::ValueWithError::ValueWithError() = default; JSONReader::ValueWithError::ValueWithError(ValueWithError&& other) = default; @@ -41,11 +21,6 @@ JSONReader::ValueWithError::~ValueWithError() = default; JSONReader::ValueWithError& JSONReader::ValueWithError::operator=( ValueWithError&& other) = default; -JSONReader::JSONReader(int options, size_t max_depth) - : parser_(new internal::JSONParser(options, max_depth)) {} - -JSONReader::~JSONReader() = default; - // static Optional<Value> JSONReader::Read(StringPiece json, int options, @@ -54,6 +29,7 @@ Optional<Value> JSONReader::Read(StringPiece json, return parser.Parse(json); } +// static std::unique_ptr<Value> JSONReader::ReadDeprecated(StringPiece json, int options, size_t max_depth) { @@ -77,72 +53,4 @@ JSONReader::ValueWithError JSONReader::ReadAndReturnValueWithError( return ret; } -// static -std::unique_ptr<Value> JSONReader::ReadAndReturnErrorDeprecated( - StringPiece json, - int options, - int* error_code_out, - std::string* error_msg_out, - int* error_line_out, - int* error_column_out) { - ValueWithError ret = ReadAndReturnValueWithError(json, options); - if (ret.value) - return Value::ToUniquePtrValue(std::move(*ret.value)); - - if (error_code_out) - *error_code_out = ret.error_code; - if (error_msg_out) - *error_msg_out = ret.error_message; - if (error_line_out) - *error_line_out = ret.error_line; - if (error_column_out) - *error_column_out = ret.error_column; - return nullptr; -} - -// static -std::string JSONReader::ErrorCodeToString(JsonParseError error_code) { - switch (error_code) { - case JSON_NO_ERROR: - return std::string(); - case JSON_INVALID_ESCAPE: - return kInvalidEscape; - case JSON_SYNTAX_ERROR: - return kSyntaxError; - case JSON_UNEXPECTED_TOKEN: - return kUnexpectedToken; - case JSON_TRAILING_COMMA: - return kTrailingComma; - case JSON_TOO_MUCH_NESTING: - return kTooMuchNesting; - case JSON_UNEXPECTED_DATA_AFTER_ROOT: - return kUnexpectedDataAfterRoot; - case JSON_UNSUPPORTED_ENCODING: - return kUnsupportedEncoding; - case JSON_UNQUOTED_DICTIONARY_KEY: - return kUnquotedDictionaryKey; - case JSON_TOO_LARGE: - return kInputTooLarge; - case JSON_UNREPRESENTABLE_NUMBER: - return kUnrepresentableNumber; - case JSON_PARSE_ERROR_COUNT: - break; - } - NOTREACHED(); - return std::string(); -} - -Optional<Value> JSONReader::ReadToValue(StringPiece json) { - return parser_->Parse(json); -} - -std::unique_ptr<Value> JSONReader::ReadToValueDeprecated(StringPiece json) { - Optional<Value> value = parser_->Parse(json); - return value ? std::make_unique<Value>(std::move(*value)) : nullptr; -} - -std::string JSONReader::GetErrorMessage() const { - return parser_->GetErrorMessage(); -} - } // namespace base diff --git a/chromium/base/json/json_reader.h b/chromium/base/json/json_reader.h index 511fffe32e7..007f843d736 100644 --- a/chromium/base/json/json_reader.h +++ b/chromium/base/json/json_reader.h @@ -49,10 +49,6 @@ namespace base { -namespace internal { -class JSONParser; -} - enum JSONParserOptions { // Parses the input strictly according to RFC 8259, except for where noted // above. @@ -70,22 +66,6 @@ enum JSONParserOptions { class BASE_EXPORT JSONReader { public: - // Error codes during parsing. - enum JsonParseError { - JSON_NO_ERROR = 0, - JSON_INVALID_ESCAPE, - JSON_SYNTAX_ERROR, - JSON_UNEXPECTED_TOKEN, - JSON_TRAILING_COMMA, - JSON_TOO_MUCH_NESTING, - JSON_UNEXPECTED_DATA_AFTER_ROOT, - JSON_UNSUPPORTED_ENCODING, - JSON_UNQUOTED_DICTIONARY_KEY, - JSON_TOO_LARGE, - JSON_UNREPRESENTABLE_NUMBER, - JSON_PARSE_ERROR_COUNT - }; - struct BASE_EXPORT ValueWithError { ValueWithError(); ValueWithError(ValueWithError&& other); @@ -96,7 +76,7 @@ class BASE_EXPORT JSONReader { // Contains default values if |value| exists, or the error status if |value| // is base::nullopt. - JsonParseError error_code = JSON_NO_ERROR; + int error_code = ValueDeserializer::kErrorCodeNoError; std::string error_message; int error_line = 0; int error_column = 0; @@ -104,24 +84,6 @@ class BASE_EXPORT JSONReader { DISALLOW_COPY_AND_ASSIGN(ValueWithError); }; - // String versions of parse error codes. - static const char kInvalidEscape[]; - static const char kSyntaxError[]; - static const char kUnexpectedToken[]; - static const char kTrailingComma[]; - static const char kTooMuchNesting[]; - static const char kUnexpectedDataAfterRoot[]; - static const char kUnsupportedEncoding[]; - static const char kUnquotedDictionaryKey[]; - static const char kInputTooLarge[]; - static const char kUnrepresentableNumber[]; - - // Constructs a reader. - JSONReader(int options = JSON_PARSE_RFC, - size_t max_depth = internal::kAbsoluteMaxDepth); - - ~JSONReader(); - // Reads and parses |json|, returning a Value. // If |json| is not a properly formed JSON string, returns base::nullopt. static Optional<Value> Read(StringPiece json, @@ -145,36 +107,9 @@ class BASE_EXPORT JSONReader { StringPiece json, int options = JSON_PARSE_RFC); - // Deprecated. Use the ReadAndReturnValueWithError() method above. - // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out| - // are optional. If specified and nullptr is returned, they will be populated - // an error code and a formatted error message (including error location if - // appropriate). Otherwise, they will be unmodified. - static std::unique_ptr<Value> ReadAndReturnErrorDeprecated( - StringPiece json, - int options, // JSONParserOptions - int* error_code_out, - std::string* error_msg_out, - int* error_line_out = nullptr, - int* error_column_out = nullptr); - - // Converts a JSON parse error code into a human readable message. - // Returns an empty string if error_code is JSON_NO_ERROR. - static std::string ErrorCodeToString(JsonParseError error_code); - - // Non-static version of Read() above. - Optional<Value> ReadToValue(StringPiece json); - - // Deprecated. Use the ReadToValue() method above. - // Non-static version of Read() above. - std::unique_ptr<Value> ReadToValueDeprecated(StringPiece json); - - // Converts error_code_ to a human-readable string, including line and column - // numbers if appropriate. - std::string GetErrorMessage() const; - - private: - std::unique_ptr<internal::JSONParser> parser_; + // This class contains only static methods. + JSONReader() = delete; + DISALLOW_COPY_AND_ASSIGN(JSONReader); }; } // namespace base diff --git a/chromium/base/json/json_reader_fuzzer.cc b/chromium/base/json/json_reader_fuzzer.cc index 68b4dc0231a..5f27ac23b17 100644 --- a/chromium/base/json/json_reader_fuzzer.cc +++ b/chromium/base/json/json_reader_fuzzer.cc @@ -24,7 +24,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { JSONReader::ValueWithError json_val = JSONReader::ReadAndReturnValueWithError(input_string, options); - CHECK((json_val.error_code == JSONReader::JSON_NO_ERROR) == + CHECK((json_val.error_code == base::ValueDeserializer::kErrorCodeNoError) == json_val.value.has_value()); if (json_val.value) { diff --git a/chromium/base/json/json_reader_unittest.cc b/chromium/base/json/json_reader_unittest.cc index 33570ad4b48..519a8845ea5 100644 --- a/chromium/base/json/json_reader_unittest.cc +++ b/chromium/base/json/json_reader_unittest.cc @@ -189,7 +189,8 @@ TEST(JSONReaderTest, Doubles) { auto value_with_error = JSONReader::ReadAndReturnValueWithError("1e1000", JSON_PARSE_RFC); ASSERT_FALSE(value_with_error.value); - ASSERT_NE(value_with_error.error_code, JSONReader::JSON_NO_ERROR); + ASSERT_NE(base::ValueDeserializer::kErrorCodeNoError, + value_with_error.error_code); } TEST(JSONReaderTest, FractionalNumbers) { @@ -647,10 +648,10 @@ TEST(JSONReaderTest, ReadFromFile) { std::string input; ASSERT_TRUE(ReadFileToString(path.AppendASCII("bom_feff.json"), &input)); - JSONReader reader; - Optional<Value> root(reader.ReadToValue(input)); - ASSERT_TRUE(root) << reader.GetErrorMessage(); - EXPECT_TRUE(root->is_dict()); + JSONReader::ValueWithError root = + JSONReader::ReadAndReturnValueWithError(input); + ASSERT_TRUE(root.value) << root.error_message; + EXPECT_TRUE(root.value->is_dict()); } // Tests that the root of a JSON object can be deleted safely while its @@ -736,19 +737,21 @@ TEST(JSONReaderTest, InvalidSanity) { }; for (size_t i = 0; i < base::size(kInvalidJson); ++i) { - JSONReader reader; LOG(INFO) << "Sanity test " << i << ": <" << kInvalidJson[i] << ">"; - EXPECT_FALSE(reader.ReadToValue(kInvalidJson[i])); - EXPECT_NE("", reader.GetErrorMessage()); + JSONReader::ValueWithError root = + JSONReader::ReadAndReturnValueWithError(kInvalidJson[i]); + EXPECT_FALSE(root.value); + EXPECT_NE("", root.error_message); } } TEST(JSONReaderTest, IllegalTrailingNull) { const char json[] = {'"', 'n', 'u', 'l', 'l', '"', '\0'}; std::string json_string(json, sizeof(json)); - JSONReader reader; - EXPECT_FALSE(reader.ReadToValue(json_string)); - EXPECT_NE("", reader.GetErrorMessage()); + JSONReader::ValueWithError root = + JSONReader::ReadAndReturnValueWithError(json_string); + EXPECT_FALSE(root.value); + EXPECT_NE("", root.error_message); } TEST(JSONReaderTest, ASCIIControlCodes) { @@ -833,10 +836,18 @@ TEST(JSONReaderTest, DecodeNegativeEscapeSequence) { // Verifies invalid code points are replaced. TEST(JSONReaderTest, ReplaceInvalidCharacters) { - // U+D800 is a lone surrogate. - const std::string invalid = "\"\xED\xA0\x80\""; + // U+D800 is a lone high surrogate. + const std::string invalid_high = "\"\xED\xA0\x80\""; Optional<Value> value = - JSONReader::Read(invalid, JSON_REPLACE_INVALID_CHARACTERS); + JSONReader::Read(invalid_high, JSON_REPLACE_INVALID_CHARACTERS); + ASSERT_TRUE(value); + ASSERT_TRUE(value->is_string()); + // Expect three U+FFFD (one for each UTF-8 byte in the invalid code point). + EXPECT_EQ("\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD", value->GetString()); + + // U+DFFF is a lone low surrogate. + const std::string invalid_low = "\"\xED\xBF\xBF\""; + value = JSONReader::Read(invalid_low, JSON_REPLACE_INVALID_CHARACTERS); ASSERT_TRUE(value); ASSERT_TRUE(value->is_string()); // Expect three U+FFFD (one for each UTF-8 byte in the invalid code point). @@ -844,10 +855,17 @@ TEST(JSONReaderTest, ReplaceInvalidCharacters) { } TEST(JSONReaderTest, ReplaceInvalidUTF16EscapeSequence) { - // U+D800 is a lone surrogate. - const std::string invalid = "\"_\\uD800_\""; + // U+D800 is a lone high surrogate. + const std::string invalid_high = "\"_\\uD800_\""; Optional<Value> value = - JSONReader::Read(invalid, JSON_REPLACE_INVALID_CHARACTERS); + JSONReader::Read(invalid_high, JSON_REPLACE_INVALID_CHARACTERS); + ASSERT_TRUE(value); + ASSERT_TRUE(value->is_string()); + EXPECT_EQ("_\xEF\xBF\xBD_", value->GetString()); + + // U+DFFF is a lone low surrogate. + const std::string invalid_low = "\"_\\uDFFF_\""; + value = JSONReader::Read(invalid_low, JSON_REPLACE_INVALID_CHARACTERS); ASSERT_TRUE(value); ASSERT_TRUE(value->is_string()); EXPECT_EQ("_\xEF\xBF\xBD_", value->GetString()); diff --git a/chromium/base/json/json_string_value_serializer.cc b/chromium/base/json/json_string_value_serializer.cc index 0ec48ca57fe..d98a62e37f9 100644 --- a/chromium/base/json/json_string_value_serializer.cc +++ b/chromium/base/json/json_string_value_serializer.cc @@ -49,6 +49,14 @@ JSONStringValueDeserializer::~JSONStringValueDeserializer() = default; std::unique_ptr<Value> JSONStringValueDeserializer::Deserialize( int* error_code, std::string* error_str) { - return base::JSONReader::ReadAndReturnErrorDeprecated(json_string_, options_, - error_code, error_str); + base::JSONReader::ValueWithError ret = + base::JSONReader::ReadAndReturnValueWithError(json_string_, options_); + if (ret.value) + return base::Value::ToUniquePtrValue(std::move(*ret.value)); + + if (error_code) + *error_code = ret.error_code; + if (error_str) + *error_str = std::move(ret.error_message); + return nullptr; } diff --git a/chromium/base/json/json_value_serializer_unittest.cc b/chromium/base/json/json_value_serializer_unittest.cc index 5722cb0f0dd..3b102a12274 100644 --- a/chromium/base/json/json_value_serializer_unittest.cc +++ b/chromium/base/json/json_value_serializer_unittest.cc @@ -133,12 +133,15 @@ TEST(JSONValueDeserializerTest, ReadJSONWithTrailingCommasFromString) { ASSERT_FALSE(value); ASSERT_NE(0, error_code); ASSERT_FALSE(error_message.empty()); - // Repeat with commas allowed. + // Repeat with commas allowed. The Deserialize call shouldn't change the + // value of error_code. To test that, we first set it to a nonsense value + // (-789) and ASSERT_EQ that it remains that nonsense value. + error_code = -789; JSONStringValueDeserializer str_deserializer2(kProperJSONWithCommas, JSON_ALLOW_TRAILING_COMMAS); value = str_deserializer2.Deserialize(&error_code, &error_message); ASSERT_TRUE(value); - ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code); + ASSERT_EQ(-789, error_code); // Verify if the same JSON is still there. CheckJSONIsStillTheSame(*value); } @@ -184,12 +187,15 @@ TEST(JSONValueDeserializerTest, ReadJSONWithCommasFromFile) { ASSERT_FALSE(value); ASSERT_NE(0, error_code); ASSERT_FALSE(error_message.empty()); - // Repeat with commas allowed. + // Repeat with commas allowed. The Deserialize call shouldn't change the + // value of error_code. To test that, we first set it to a nonsense value + // (-789) and ASSERT_EQ that it remains that nonsense value. + error_code = -789; JSONFileValueDeserializer file_deserializer2(temp_file, JSON_ALLOW_TRAILING_COMMAS); value = file_deserializer2.Deserialize(&error_code, &error_message); ASSERT_TRUE(value); - ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code); + ASSERT_EQ(-789, error_code); // Verify if the same JSON is still there. CheckJSONIsStillTheSame(*value); } |